11、DMA

1、DMA介绍

直接存储器存取(DMA)用来提供在外设和存储器之间或者存储器和存储器之间的高速数据传输。无须CPU干预,数据可以通过DMA快速地移动,这就节省了CPU的资源来做其他操作。两个DMA控制器有12个通道(DMA1有7个通道,DMA2有5个通道),每个通道专门用来管理来自于一个或多个外设对存储器访问的请求。还有一个仲裁器来协调各个DMA请求的优先权。

 

2、DMA主要特征

●  12个独立的可配置的通道(请求):DMA1有7个通道,DMA2有5个通道
●  每个通道都直接连接专用的硬件DMA请求,每个通道都同样支持软件触发。这些功能通过软件来配置。
●  在同一个DMA模块上,多个请求间的优先权可以通过软件编程设置(共有四级:很高、高、中等和低),优先权设置相等时由硬件决定(请求0优先于请求1,依此类推) 。
●  独立数据源和目标数据区的传输宽度(字节、半字、全字),模拟打包和拆包的过程。源和目标地址必须按数据传输宽度对齐。

●  支持循环的缓冲器管理
●  每个通道都有3个事件标志(DMA半传输、DMA传输完成和DMA传输出错),这3个事件标志逻辑或成为一个单独的中断请求。
●  存储器和存储器间的传输
●  外设和存储器、存储器和外设之间的传输
●  闪存、SRAM、外设的SRAM、APB1 、APB2和AHB外设均可作为访问的源和目标。
●  可编程的数据传输数目:最大为65535

 

 

3、DMA1请求映像

从外设(TIMx[x=1、2 、3、4] 、ADC1 、SPI1、SPI/I2S2、I2Cx[x=1、2]和USARTx[x=1、2、3])产生的7个请求,通过逻辑或输入到DMA1控制器,这意味着同时只能有一个请求有效。

 

 

4、DMA2请求映像

从外设(TIMx[5、6 、7 、8] 、ADC3 、SPI/I2S3 、UART4、DAC通道1、2和SDIO)产生的5个请求,经逻辑或输入到DMA2控制器,这意味着同时只能有一个请求有效。

 

 

5、DMA操作

(1)数据传输的目的地和来源

(2)定义DMA通道的DMA缓存的大小

(3)外设地址寄存器递增与否

(4).内存地址寄存器递增与否

(5)设定了外设数据宽度

(6).设定了内存数据宽度

(7)设置了DMA的工作模式

(8)DMA通道的软件优先级

(9).使能DMA通道的内存到内存传输

 

 

 

6、例程代码:

  1 /*************************************************************************************************************************************
  2 *  
  3 *  文件名称:main.c
  4 *  文件功能:主函数文件
  5 *
  6 ***************************************************************************************************************************************/
  7 
  8 #include "pbdata.h"//调用自定义公共函数库
  9 
 10 
 11 /*********************************************************************************
 12 *
 13 * 全局变量声明
 14 *
 15 *********************************************************************************/
 16 
 17 u16 ADCData[50];
 18 
 19 
 20 
 21 
 22 
 23 
 24 
 25 
 26 
 27 
 28 
 29 
 30 
 31 
 32 /*********************************************************************************
 33 *
 34 * 初始化操作
 35 *
 36 *********************************************************************************/
 37 void RCC_Configuration(void);//系统时钟初始化函数声明
 38 void GPIO_Configuration(void);//GPIO初始化函数声明
 39 void NVIC_Configuration(void);//中断优先级配置函数声明
 40 void USART_Configuration(void);//串口配置函数声明
 41 void ADC_Configuration(void);//ADC配置函数声明
 42 void DMA_Configuration(void);//DMA配置函数声明
 43 
 44 
 45 
 46 /********************************************************************************
 47 *
 48 *  函数名称:main(void)
 49 *  函数功能:主函数
 50 *  函数说明:不能用void定义主函数
 51 *
 52 ********************************************************************************/
 53 int main(void)//void不能void定义主函数
 54 {
 55     
 56     u32 ad=0;//取50次转换平均值
 57     u8  i=0;//循环50次
 58         
 59     RCC_Configuration();    //系统时钟初始化
 60     
 61     GPIO_Configuration();//端口初始化
 62     
 63     USART_Configuration();//串口配置
 64     
 65     NVIC_Configuration();
 66     
 67     ADC_DMACmd(ADC1,ENABLE);//将AD和DMA绑定在一起
 68     
 69     ADC_Configuration();//ADC配置
 70     
 71     
 72     while(1)
 73     {
 74         ad=0;
 75         for(i=0;i<50;i++)
 76         {
 77       ad=ad+ADCData[i];//循环取50次,放入数组中,最后取平均值
 78         }
 79         
 80         ad=ad/50;
 81         printf("AD=%.3f\n",ad*3.3/4095);
 82         
 83         delay_ms(1000);
 84         delay_ms(1000);
 85         delay_ms(1000);
 86         delay_ms(1000);
 87         delay_ms(1000);
 88     
 89     }
 90     
 91 }
 92     
 93     
 94 
 95 
 96 /********************************************************************************
 97 *
 98 *  函数名称:RCC_Configuration(void)
 99 *  函数功能:系统时钟高初始化函数
100 *
101 ********************************************************************************/
102     void RCC_Configuration(void)//系统时钟高初始化函数
103   {
104         
105     SystemInit();//系统初始化
106     RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);//串口对应GPIO时钟使能
107         RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);//串口时钟使能
108         RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);//引脚复用
109         
110         RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC,ENABLE);//adc对应GPIO时钟使能
111         RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1,ENABLE);//ADC1时钟使能
112         RCC_ADCCLKConfig(RCC_PCLK2_Div6);//ADC频率不超过14M,所以对它分频,72/6=12
113         
114         RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1,ENABLE);//DMA时钟使能
115 
116     }
117     
118     
119 
120 /*******************************************************************************
121 *
122 * 函数名称:GPIO_Configuration(void)
123 * 函数功能:GPIO初始化函数
124 *
125 ********************************************************************************/    
126     
127     void GPIO_Configuration(void)//GPIO初始化函数
128   {
129               
130         
131 /*串口引脚配置*/
132         GPIO_InitTypeDef GPIO_InitStructure;//定义一个GPIO设置的结构体变量
133 
134 /*输出引脚配置*/        
135         /*结构体变量赋值*/
136       GPIO_InitStructure.GPIO_Pin=GPIO_Pin_9;////引脚配置TX
137       GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;//配置频率
138         GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP;//发送要配置成复用推挽输出
139         /*对应的GPIO初始化*/
140       GPIO_Init(GPIOA,&GPIO_InitStructure);
141         
142     
143 /*输入引脚配置*/        
144         /*结构体变量赋值*/
145       GPIO_InitStructure.GPIO_Pin=GPIO_Pin_10;////引脚配置RX
146         GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IN_FLOATING;//接收引脚配置成浮空输入
147         /*对应的GPIO初始化*/
148       GPIO_Init(GPIOA,&GPIO_InitStructure);        
149 
150 /*ADC输入引脚配置*/        
151         /*结构体变量赋值*/
152       GPIO_InitStructure.GPIO_Pin=GPIO_Pin_0;////引脚配置adc
153         GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AIN;//模拟输入
154         /*对应的GPIO初始化*/
155       GPIO_Init(GPIOC,&GPIO_InitStructure);        
156 
157 
158 
159 
160   }
161     
162 
163 /********************************************************************************
164 *
165 *  函数名称:NVIC_Configuration(void)
166 *  函数功能:配置中断优先级
167 *
168 ********************************************************************************/
169     
170 void NVIC_Configuration(void)
171 {
172   NVIC_InitTypeDef NVIC_InitStructure; //定义一个优先级配置结构体变量
173     
174   NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);//分组
175 
176   NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
177   NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;//抢断优先级
178   NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;//响应优先级
179   NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;//使能
180     
181   NVIC_Init(&NVIC_InitStructure);//初始化
182 }
183     
184 
185 /*********************************************************************************
186 *
187 *  函数名称:USART_Configuration(void)
188 *  函数功能:串口配置函数
189 *
190 *********************************************************************************/
191 void USART_Configuration(void)
192 {
193 /*定义串口配置结构体变量*/
194         USART_InitTypeDef USART_InitStructure;//定义一个串口配置结构体变量
195     
196     
197 /*结构体变量赋值*/
198     USART_InitStructure.USART_BaudRate = 9600;//波特率9600
199     USART_InitStructure.USART_WordLength = USART_WordLength_8b;//位宽,8位
200     USART_InitStructure.USART_StopBits = USART_StopBits_1;//停止位1
201     USART_InitStructure.USART_Parity = USART_Parity_No;//不奇偶校验
202     USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//流控禁止
203     USART_InitStructure.USART_Mode = USART_Mode_Tx | USART_Mode_Rx;//发送使能
204 
205     
206 /*发送串口配置初始化*/
207     USART_Init(USART1, &USART_InitStructure);
208     
209 
210 /*打开串口接收中断*/
211       USART_ITConfig(USART1,USART_IT_RXNE,ENABLE);//当接收到数据时,会产生中断
212     
213     
214 /*打开串口*/
215     USART_Cmd(USART1,ENABLE);//串口使能,打开
216         
217 /*清空中断标志位*/
218     USART_ClearFlag(USART1,USART_FLAG_TC);
219 }
220     
221     
222     
223 /*********************************************************************************
224 *
225 *  函数名称:ADC_Configuration(void)
226 *  函数功能:串口配置函数
227 *
228 *********************************************************************************/    
229 void ADC_Configuration(void)    
230 {
231     
232 /*定义一个ADC配置结构体变量*/
233     ADC_InitTypeDef ADC_InitStructure;
234     
235     
236 /*对结构体变量赋值*/
237   ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;//独立模式
238   ADC_InitStructure.ADC_ScanConvMode = DISABLE;//单通道模式
239   ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;//循环采集
240   ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;//软件触发
241   ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;//右对其
242   ADC_InitStructure.ADC_NbrOfChannel = 1;//转换的通道,只取1个通道
243     
244 /*ADC初始化*/
245   ADC_Init(ADC1, &ADC_InitStructure);
246     
247     
248 /*规则组*/
249   ADC_RegularChannelConfig(ADC1, ADC_Channel_10, 1,ADC_SampleTime_239Cycles5);    //,选择ADC1,通道10,通道数1,采样时间239.5
250     
251 
252 /*使能ADC*/
253    ADC_Cmd(ADC1, ENABLE);
254 
255 
256 /*校准ADC*/
257    ADC_ResetCalibration(ADC1);//对应ADC复位
258      while(ADC_GetResetCalibrationStatus(ADC1));//获取状态,等待复位完成
259      ADC_StartCalibration(ADC1);//开始指定ADC校准状态 
260      while(ADC_GetCalibrationStatus(ADC1));//获取校准状态,等待完成
261      
262      
263 /*启动ADC*/
264      ADC_SoftwareStartConvCmd(ADC1,ENABLE);
265 
266    
267 }
268 
269     
270 /*********************************************************************************
271 *
272 *  函数名称:DMA_Configuration(void)
273 *  函数功能:串口配置函数
274 *
275 *********************************************************************************/        
276 void DMA_Configuration(void)
277 {
278     DMA_InitTypeDef DMA_InitStructure;
279 
280     DMA_DeInit(DMA1_Channel1);//DMA1通道1初始化
281 
282     DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)&ADC1->DR;//AD存放数的地址
283     DMA_InitStructure.DMA_MemoryBaseAddr = (u32)ADCData;//存放的地址,设一个数组存放
284     DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;//外设是数据的来源
285     DMA_InitStructure.DMA_BufferSize = 50;//缓冲区大小,也就是数组大小
286     DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;//AD地址不变
287     DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;//数组地址递增
288     DMA_InitStructure.DMA_PeripheralDataSize =DMA_PeripheralDataSize_HalfWord;//外设数据宽度,16位
289     DMA_InitStructure.DMA_MemoryDataSize =DMA_MemoryDataSize_HalfWord;//DMA数据宽度,16位
290     DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;//工作模式,循环
291     DMA_InitStructure.DMA_Priority = DMA_Priority_High;//DMA优先级,高
292     DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;//
293 
294     DMA_Init(DMA1_Channel1,&DMA_InitStructure);//DMA初始化
295 
296     DMA_Cmd(DMA1_Channel1,ENABLE);//DMA使能
297 
298 }
299     
300 
301     
302     
303     
304     
305     
306     
307     
308     
309     
310     
311     
312     
313     
314     
315     
316     
317     
318     
319     
320     
321     
322     
323     
324     
325     
View Code
  1 /****************************************************************************************************************
  2 *
  3 * 文件名称:pbdata.c
  4 * 文件功能:自定义函数或者全局变量的初始化
  5 *
  6 ****************************************************************************************************************/
  7 
  8 /*头文件声明*/
  9 #include "pbdata.h"
 10 
 11 
 12 
 13 
 14 /********************************************************************************************
 15 *
 16 * 自定义全局变量
 17 *
 18 ********************************************************************************************/
 19 u8 dt=0;
 20 
 21 
 22 
 23 
 24 
 25 /******************************************************************************************
 26 *
 27 * 自定义函数
 28 *
 29 ******************************************************************************************/
 30 
 31 
 32 
 33 /**************************************************
 34 *
 35 *  函数名称:delay_us(u32 nus)
 36 *  函数功能:微秒延时函数
 37 *  输入参数:输入值为延时us
 38 *
 39 ***************************************************/
 40 void delay_us(u32 nus)
 41 {
 42     u32 temp;
 43     SysTick->LOAD = 9*nus;//载入初值,72M/8=9M,也就是1/9us,9*1/9us,所以是执行9次
 44     SysTick->VAL=0X00;//清空计数器,清空后,就自动设置自己设定的计数器的值
 45     SysTick->CTRL=0X01;//使能,减到零动作(不发生中断),采用外部时钟
 46     
 47     do
 48     {
 49           temp=SysTick->CTRL;//标志位,等到一直减到0
 50          }while((temp&0x01)&&(!(temp&(1<<16))));//等待时间到达
 51     
 52     SysTick->CTRL=0x00; //关闭计数器
 53     SysTick->VAL =0X00; //清空计数器
 54 }
 55 
 56 
 57 
 58 
 59 
 60 
 61 
 62 /***************************************************
 63 *
 64 * 函数名称:delay_ms(u16 nms)
 65 * 函数功能:毫秒级延时
 66 * 输入参数:输入值位延时ms
 67 *
 68 ****************************************************/
 69 void delay_ms(u16 nms)
 70 {
 71     u32 temp;
 72     SysTick->LOAD = 9000*nms;//载入初值,72M/8=9M,也就是1/9us,9*1/9us,所以是执行9000次
 73     SysTick->VAL=0X00;//清空计数器,清空后,就自动设置自己设定的计数器的值
 74     SysTick->CTRL=0X01;//使能,减到零动作(不发生中断),采用外部时钟
 75     
 76     do
 77     {
 78           temp=SysTick->CTRL;//标志位,等到一直减到0
 79          }while((temp&0x01)&&(!(temp&(1<<16))));//等待时间到达
 80     
 81     SysTick->CTRL=0x00; //关闭计数器
 82     SysTick->VAL =0X00; //清空计数器
 83 }
 84 
 85 
 86 
 87 /****************************************************
 88 *
 89 * 重定义printf函数部分
 90 *
 91 ****************************************************/
 92 int fputc(int ch,FILE *F)
 93 {
 94     
 95     USART_SendData(USART1,(u8)ch);
 96     
 97     while(USART_GetFlagStatus(USART1,USART_FLAG_TXE)==RESET);//等待发送完成,判断标志位
 98     
 99     return ch;
100 }
View Code
 1 /*pbdata.h*/
 2 /***************************************************************************************************
 3 *
 4 * 文件名称:pbdata.h
 5 * 文件功能:自定义的函数和全局变量的声明头文件
 6 *
 7 ***************************************************************************************************/
 8 
 9 #ifndef _pbdata_H
10 #define _pbdata_H
11 
12 
13 
14 
15 
16 /********************************************************************
17 *
18 *  调用的头文件放在这里
19 *
20 ********************************************************************/
21 #include "stm32f10x.h"
22 
23 
24 #include "misc.h"
25 #include "stm32f10x_exti.h"
26 #include "stm32f10x_tim.h"
27 #include "stm32f10x_usart.h"
28 #include "stm32f10x_adc.h"
29 #include "stm32f10x_dma.h"
30 
31 #include "stdio.h"
32 
33 
34 
35 
36 /********************************************************************
37 *
38 *  自定义全局变量声明
39 *
40 ********************************************************************/
41 extern u8 dt;
42 
43 
44 
45 
46 
47 /********************************************************************
48 *
49 *  自定义全函数声明
50 *
51 ********************************************************************/
52 void delay(u32 nCount);
53 void delay_us(u32 nus);
54 void delay_ms(u16 nms);
55 int fputc(int ch,FILE *F);
56 
57 
58 
59 #endif
View Code

 

 

7、例程下载:

http://download.csdn.net/detail/a1181803348/8752375

 

posted @ 2015-05-29 17:40  如风轻逸  阅读(624)  评论(0编辑  收藏  举报