DMA是個好東西,他可以幫助CPU分擔好多工作,減輕CPU的工作壓力,我們可以一邊傳輸數據,一邊干別的事情,很不錯!
今天可謂是配置的好艱辛啊,看電視把我看蒙了,好多注意事項都木有看見,浪費了我好多時間。
好吧,開始進入主題!
時鐘配置我就不用羅嗦了!大家自己去RCC里面的AHBENR找:
RCC->AHBENR |= 1<<0;//DAM1 Clock Enable
主要來看看DMAx的控制寄存器CCR




這個寄存器看著很容易理解,今天對控制寄存器有了新的認識,一般的寄存器可能要在控制寄存器的某一位關閉或者打開才能修改,而控制寄存器基本上可以在任意時刻進行修改,所以,在配置控制寄存器的時候我們沒必要考慮那么多!
我今天準備把一個字符串通過DMA與USART1建立一個通道,把數據發送出去!
所以我們不從外設讀數據,我們需要Read From Register,如果我們從ADC里面讀數據我們就可以把這位置0
dma->CCR |= 1<<4;//Read from register
我們可以采用循環發送,也可以不循環發送,如果是ADC的話,那就用循環發送
dma->CCR &= ~(1<<5);//normal mode
因為USART1的地址不進行偏移或者改變
dma->CCR &= ~(1<<6);//Device Address non-Rise
在一個字符串中我們要不斷尋址去發送該為地址上的數據
dma->CCR |= 1<<7;//Memary Address Rise
所有設備和存儲都按8bit進行存儲和讀取
dma->CCR &= ~(3<<8);//Device 8 Bit Data
dma->CCR &= ~(3<<10);//Memary 8 Bit
在設置兩位或兩位以上的數據是一定要把其全部清空在進行設置,這樣方便一點
dma->CCR &= ~(3<<12);//clear 12:13
dma->CCR |= 1<<12;//Set Priority level
14bit的配置我不用說了,大家看一下就肯定知道了
dma->CCR &= ~(1<<14);//non M2M mode
DMA還有這么幾個寄存器
DMA_CNDTR :要發送的數據個數
DM_CPAR:外設地址寄存器
DM_CMAR:存儲器地址寄存器
這3個寄存器必須在DMA_CCRx的EN=0時才能進行修改!我今天就在這個地方淪陷了,后來看了李想老師的視頻,他的感覺他的配置有問題,但是還是。。。
可能我們的板子不一樣吧,反正我他那幾個配置違背了EN=0時才能修改的原則
dma->CCR &= ~(1<<0);
dma->CPAR = cpar;
dma->CMAR = cmar;
dma->CNDTR = cndtr;
dma->CCR |= 1<<0;
還有其他規則,大家可以看看!DMA還是相對比較簡單的,不過是建立在你細心的基礎上!
另外我們要用到USART1的發送,所以我們也要去打開USART1里面的dma功能
在USART1的控制寄存器里面有這么兩個配置:

我們要什么功能就選什么功能了!
這里我選USART1->CR3 |= 1<<7;
好了,那幾天就這樣,下面附上我的代碼
~~~
/* dma.c */
#include <stm32f10x.h>
#include "stdio.h"
#include "usart.h"
#include "init.h"
void dma1_init(DMA_Channel_TypeDef * dma)
{
RCC->AHBENR |= 1<<0;//DAM1 Clock Enable
dma->CCR |= 1<<4; //Read from register
dma->CCR &= ~(1<<5); //normal mode
dma->CCR &= ~(1<<6); //Device Address non-Rise
dma->CCR |= 1<<7; //Memary Address Rise
dma->CCR &= ~(3<<8); //Device 8 Bit Data
dma->CCR &= ~(3<<10); //Memary 8 Bit
dma->CCR &= ~(3<<12); //clear 12:13
dma->CCR |= 1<<12; //Set Priority level
dma->CCR &= ~(1<<14); //non M2M mode
USART1->CR3 |= 1<<7;
}
void dma1_enable(DMA_Channel_TypeDef * dma,u32 cpar,u32 cmar,u32 cndtr)
{
#ifdef __DEBUG
char buff[255];
#endif
dma->CCR &= ~(1<<0);
dma->CPAR = cpar;
dma->CMAR = cmar;
dma->CNDTR = cndtr;
dma->CCR |= 1<<0;
#ifdef __DEBUG
sprintf(buff,"Initialize<start>.....\ndma:0x%08x\nCPAR:0x%08x\nCMAR:0x%08x\nCNDTR:0x%08x\n",\
(u32)dma,(u32)cpar,(u32)cmar,cndtr);
rs232_send_str(buff,strlen(buff));
sprintf(buff,"Initialize.....\ndma:0x%08x\nCPAR:0x%08x\nCMAR:0x%08x\nCNDTR:0x%08x\n",\
(u32)dma,dma->CPAR,dma->CMAR,dma->CNDTR);
rs232_send_str(buff,strlen(buff));
#endif
}
~~~
主函數:
~~~
#include <stm32f10x.h>
#include "init.h"
#include "usart.h"
#include "dma.h"
#include "stdio.h"
int main()
{
char str[512];
rs232_init(CPU_72M,9600);
RCC->APB2ENR |= 1<<4;
GPIOC->CRH = 0x33333333;
GPIOC->ODR |= 0xff00;
sprintf(str,"This is a DMA1 Channel4 Test!\n");
dma1_init(DMA1_Channel4);
while(1)
{
delay_ms(1000);
dma1_enable(DMA1_Channel4,(u32)&USART1->DR,(u32)str,strlen(str));
while(1)
{
if(DMA1->ISR&(1<<13))
break;
delay_ms(1000);
}
DMA1->IFCR |= 1<<13;
}
}
~~~
效果圖:

,
PS:最近在研究庫,感覺庫挺好用的,所以關于寄存器配置的進度比較慢!
- 前言
- 【菜鳥入門】stm32的第一個程序--LED
- 【菜鳥入門】stm32 之 掃描按鍵
- 【菜鳥入門】stm32 之 中斷按鍵
- 【菜鳥入門】stm32 之 USART
- 【菜鳥入門】stm32 之 iic
- 【菜鳥入門】stm32 之 eeprom
- 【菜鳥入門】stm32 之 pwm
- 【菜鳥入門】stm32 之 ADC 模數轉換
- 【菜鳥入門】stm32 之 實時時鐘
- 【菜鳥入門】stm32 之 DMA
- 【菜鳥入門】stm32 之 DAC
- 【STM庫應用】stm32 之 USART
- 中斷源去抖辦法
- stm32 啟動代碼應用技巧
- 【STM庫應用】stm32 之 IIC應用
- 【STM庫應用】stm32 之 中斷按鍵初始化(注意事項)
- 關于結構體初始化
- 【STM庫應用】stm32 之 TIM (詳解一 通用定時器)
- 【STM庫應用】stm32 之 TIM (詳解二 脈沖寬度、周期測量)
- 【stm32庫應用】SD驅動移植(基于SDIO外設)
- SD卡fat文件系統移植
- stm32 DMA初始化選項研究
- stm32 靈活靜態存儲控制器(FSMC)(NORFLASH\PSRAM)
- 【stm32+uC/OS-II】ucosii移植簡單詳細步驟
- STM32 加入調試信息來調試代碼
- NRF24L01 無線通信模塊使用