STM32F10X DMA发送例程详解,测试无误

硬件平台:STM32F10X内部DMA模块 + USART模块 + JLink

软件平台:Keil 4 

一、基础知识

DMA 直接内存访问----Directional Memory Access大二 《微机原理》里面讲8086的时候就已经讲过了,只是当时没有实际用过而已。

自己理解:DMA,其实就相当于一个公司的库管而已,当CPU--老板把数据的传送,即相当于货物的运输交给库管DMA的时候,数据的传送就不用老板自己实时查看管理了,由DMA模块自动完成,提高了CPU的使用效率。

DMA一种高速的数据传输操作,允许在外部设备和存储器之间直接读写数据,既不通过CPU,也不需要CPU干预。整个数据传输操作在一个称为"DMA控制器"的控制下进行的。CPU除了在数据传输开始和结束时做一点处理外,在传输过程中CPU可以进行其他的工作。这样,在大部分时间里,CPU和输入输出都处于并行操作。

DMA组成:

1、主存地址寄存器

2、数据数量计数器

3、DMA的控制/状态逻辑

4、DMA请求触发器

5、数据缓冲寄存器

6、中断机构

DMA的缺点:

因为DMA允许外设直接访问内存,从而形成对总线的独占。

这在实时性强的硬实时系统的嵌入式开发中将会造成中断延时过长


二、发送程序例程

程序涉及的模块有:

RCC:复位及时钟控制模块,用于初始化STM32 外设时钟及IO口复用时钟;

USART:通用同步异步收发器,即串口,用于发送数据至上位机显示已发送的数据;

GPIO:通用输入输出口复用配置模块;

DMA: DMA模块配置;

Delay:延时等待模块;

NVIC:中断配置模块。


RCC

  //RCC时钟配置
  void RCC_cfg(void)
  {	 
  	 ErrorStatus HSEStartUpStatus;
  	//定义错误状态变量	
  	 
  	 RCC_DeInit();将RcC初始化,重新设置为默认值
  		
  	 RCC_HSEConfig(RCC_HSE_ON);
  	 //打开外部高速时钟晶振,使能HSE
  	/*RCC_HSE_ON  开
  	 _off 关  _bypass hse晶振被外部时钟旁路*/	
  	 
  	HSEStartUpStatus = RCC_WaitForHSEStartUp();
  	/*RCC_WaitForHSEStartUp()返回一个ErrorStatus枚举值,
  	success好,error未好*/
  	
  	 if(HSEStartUpStatus == SUCCESS)//HES就绪
  	 {		 
  		 RCC_HCLKConfig(RCC_SYSCLK_Div1);
  		 //AHB时钟(HCLK)=系统时钟		
  
  			RCC_PCLK1Config(RCC_HCLK_Div2);
  		 //设置低速AHB时钟(APB1)为HCLK的2分频			 
  		 
  		 RCC_PCLK2Config(RCC_HCLK_Div1);
  		 //设置高速AHB时钟(APB2)=HCLK时钟			 	
  		 
  		 FLASH_SetLatency(FLASH_Latency_2);
  		 //设置FLASH代码延时
  		 
  		 //使能领取指缓存
  		 FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);
  		 
  		 RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9);
  		 //设置PLL时钟源及倍频系数,为HSE的9倍频 8MHz * 9 = 72MHz
  		 /*void RCC_PLLConfig(u32 RCC_PLLSource, u32 RCC_PLLMul)
  		 RCC_PLLSource_HSI_Div2   pll输入时钟=hsi/2;
  		 RCC_PLLSource_HSE_Div1   pll输入时钟 =hse
  		 RCC_PLLSource_HSE_Div2   pll输入时钟=hse/2
  		 
  		 RCC_PLLMul_2  ------_16       pll输入时钟*2---16
  		 pll输出时钟不得超过72MHZ*/	 
  		 
  		 RCC_PLLCmd(ENABLE);
  		 //ENABLE  / DISABLE
  		 
  		 while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET);//等待就绪
  		 /*FlagStatus RCC_GetFlagStatus(u8 RCC_FLAG)  检查指定RCC标志位
  		 返回SET OR RESET
  		 RCC_FLAG_HSIRDY  HSI晶振就绪
  		 RCC_FLAG_HSERDY
  		 RCC_FLAG_PLLRDY
  		 RCC_FLAG_LSERDY 
  		 RCC_FLAG_LSIRDY.......*/		 
  		 
  		 RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);
  		 //设置PLL为系统时钟源
  		 /*void RCC_SYSCLKConfig(u32 RCC_SYSCLKSource)  设置系统时钟
  		 RCC_SYSCLKSource_HSI 
  		 RCC_SYSCLKSource_HSE 
  		 RCC_SYSCLKSource_PLLCLK  选HSI  HSE PLL 作为系统时钟*/ 		 
  		 
  		 while(RCC_GetSYSCLKSource() != 0x08);
  		 //判断PLL是否是系统时钟
  		 /*u8 RCC_GetSYSCLKSource(void)  返回用作系统时钟的时钟源
  		 0x00:HSI   0x04:HSE 0x08:PLL */
  	 }	 
  	 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB |RCC_APB2Periph_AFIO , ENABLE);
  	 
  	 RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3,ENABLE);
  	 //打开串口对应的外设时钟
  	
  	 /*EN/DIS AHB外设时钟   启动DMA1 时钟
  	 RCC_AHBPeriph_DMA1
     RCC_AHBPeriph_DMA2
     RCC_AHBPeriph_SRAM
     RCC_AHBPeriph_FLITF
     RCC_AHBPeriph_CRC
     RCC_AHBPeriph_FSMC
     RCC_AHBPeriph_SDIO  等时钟 其中 SRAM 和FLITF 时钟只可在睡眠 SLEEP 模式下被失能*/
  	 
  	 
  	 //U2  U3 时钟在APB1
  	 //打开GPIO时钟,复用功能,串口1的时钟
  	 /*void RCC_APB2PeriphClockCmd(u32 RCC_APB2Periph, FunctionalState NewState) 
  		enable 或 disable apb2 外设时钟
  	 RCC_APB2Periph_AFIO  功能复用IO 时钟
  	 RCC_APB2Periph_GPIOA/B/C/D/E   GPIOA/B/C/D/E 时钟
  	 RCC_APB2Periph_ADC1/ADC2			ADC1/2 时钟
  	 RCC_APB2Periph_TIM1 
  	 RCC_APB2Periph_SPI1
  	 RCC_APB2Periph_USART1 
  	 RCC_APB2Periph_ALL			全部APB2外设时钟*/
  }

GPIO

  //IO口配置
  void GPIO_cfg(void)
  {
  	 GPIO_InitTypeDef GPIO_InitStructure;
  	//GPIO_InitStructure初始化结构体为GPIO_InitTypeDef结构
  		
  	 GPIO_StructInit(&GPIO_InitStructure);
  	//B10  U3_TX
  	 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
  	//1、选中引脚GPIO_PIN_0--15 OR GPIO_PIN_ALL 选中全部管脚
  	
  	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  	//2、GPIO_SPEED:GPIO_SPEED_10MHz/_2MHz/_50MHz   最高输出速率
  	
  	 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
  	/*Mode,工作状态:GPIO_MODE_AIN  ----- 模拟输入
  														_IN_FLOATING  ----- 浮空输入
  														_IPD  ----- 上拉输出
  														_IPU  ----- 上拉输入
  														_OUT_OD  ----- 开漏输出
  														_OUT_PP  ----- 推挽输出
  														_AF_OD  ----- 复用开漏输出
  														_AF_PP  ----- 复用推挽输出*/	
  	 GPIO_Init(GPIOB , &GPIO_InitStructure);
  	 
  	
  	 //B11  U3_RX
  	 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;
  	 
  	 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
  	 //IO浮空输入
  	 GPIO_Init(GPIOB, &GPIO_InitStructure);
  	 
  	 //提示标示:LED显示串口正在发送数据/接收数据
  	 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;
  	 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
  	 //推挽输出
  	 GPIO_Init(GPIOA, &GPIO_InitStructure);
  }

USART

  //串口初始化
  void USART3_cfg(void)
  {
  	 USART_InitTypeDef USART_InitStructure;
  	 
  	 USART_StructInit(&USART_InitStructure);
  	//将结构体设置为缺省状态
  	/*USART_StructInit通用同步异步串行口初始结构成员:
  	USART_BaudRate----9600,默认9600
  	IntegerDivider = ((APBClock) / (16 *  (USART_InitStruct->USART_BaudRate))) 
  FractionalDivider = ((IntegerDivider - ((u32) IntegerDivider)) * 16) + 0.5
  	
  			 _WordLength  帧中传输的数据位----USART_WordLength_8b/_9b,字长宽8位
  			 _StopBits  停止位  可为 USART_StopBits_1 ---帧结尾传输1个停止位
  																USART_StopBits_0.5  0.5个
  																USART_StopBits_2
  																USART_StopBits_1.5
  				 _parity  奇偶模式  USART_Parity_No//奇偶失能,无奇偶
  														USART_Parity_even oumoshi
  														USART_Parity_odd  jimoshi
  	       奇偶使能时,在数据的MSB位插入奇偶位,字长9位时的第九位,8位时的第八位
  				 _HardwareFlowControl  //  _none,硬件流控制失能
  																	_rts 发送请求rts使能
  																	_cts 清除发送cts使能
  																	_rts_cts rts and cts 使能*/
  				
  	 //波特率设置为115200
  	 USART_InitStructure.USART_BaudRate = 115200;
  	 //一帧数据的宽度设置为8bits
  	 USART_InitStructure.USART_WordLength = USART_WordLength_8b;
  	 //在帧尾传输1个停止位
  	 USART_InitStructure.USART_StopBits = USART_StopBits_1;
  	 //奇偶检验失能模式,无奇偶校验位
  	 USART_InitStructure.USART_Parity = USART_Parity_No;
  	 //发送/接收使能
  	 USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
  	 //硬件流控制失能
  	 USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
  	 //设置串口1
  	 USART_Init(USART3, &USART_InitStructure);
  		 
  	 USART_ITConfig(USART3, USART_IT_RXNE, ENABLE);
  	 /*void USART_ITConfig(USART_TypeDef* USARTx, u16 USART_IT, FunctionalState NewState) 
  		失能或使能相应的USART中断,x---1/2/3
  		_IT : _IT_PE  奇偶错误中断
  					_IT_TXE FASONG中断
  					_IT_TC  传输完成中断
  					_IT_RXNE  接收中断
  					_IT_IDLE  空闲总线中断
  					_IT_LBD  LIN中断检测中断
  					_IT_CTS  CTS中断
  					_IT_ERR  错误中断*/
  					
  	 USART_Cmd(USART3, ENABLE);
  	 /*void USART_Cmd(USART_TypeDef* USARTx, FunctionalState NewState)
  	 失能或使能外设 x--1/2/3
  	 NewState: USARTx ENABLE /DISABLE*/
  }

NVIC

  //配置中断
  void NVIC_cfg(void)
  {	
  	 NVIC_InitTypeDef NVIC_InitStructure;
  	//定义NVIC初始化结构体 NVIC_InitStructure
  	
  	//DMA 优先级
  	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_3); 
  	//优先级 先占3 位 从占 1 位 		
  	 NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel2_IRQn; 
  	//DAM1 通道4 中断   3.5的库  USART3_IRQn	
  	 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;	
  	//抢占式,先占   NVIC_IRQChannel 的先占优先级
  	 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;			
  	//响应式,从  NVIC_IRQChannel
  	 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  	//使能
  	 NVIC_Init(&NVIC_InitStructure);
  	
  	//usart3 优先级
  	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);  
  	//设置优先级分组 ,先占0 从占 4
  	NVIC_InitStructure.NVIC_IRQChannel = USART3_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;	
  	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
  	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  	NVIC_Init(&NVIC_InitStructure); 
  }

DMA

void DMA_cfg(void)
{
	DMA_InitTypeDef DMA_InitStructure;
	RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
	DMA_DeInit(DMA1_Channel2);
	//将DMA的通道 X 寄存器重设为 缺省值
	//DMA Channelx :x 1--7
	//DMA1 通道4 配置 
	DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)(&USART3->DR);
	//定义DMA外设的基地址  U3 的数据寄存器
	DMA_InitStructure.DMA_MemoryBaseAddr = (u32)Uart_Send_Buffer;
	//内存基地址
	DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;
	//DMA 传输方向 外设作为数据的目的地
	DMA_InitStructure.DMA_BufferSize = 100;
	//DMA 传输时 缓冲区的长度
	DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
	//外设地址寄存器增与否  不变
	DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
	//内存地址寄存器增与否 递增
	DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
	//外设数据宽度 _byte 8bit   _halfword  16bit  _word  32bit
	DMA_InitStructure.DMA_MemoryDataSize =  DMA_PeripheralDataSize_Byte;
	//内存数据宽度
	DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
	//mode 设置了CAN 的工作模式  _Circular  循环缓存模式  _Normal 正常缓存模式
	//当制定的DMA通道数据传输配置为内存到内存时  不能使用 循环缓存模式
	DMA_InitStructure.DMA_Priority = DMA_Priority_High;
	/*DMA通道 X 的优先级
		_VeryHigh   有非常高的优先级 
		_High 高   _Medium  中  _Low  低*/
	DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
	//DMA_M2M 使能DMA 通道 内存到内存传输 enable 设置为从内到内 disable 没有设置为从内到内
	DMA_Init(DMA1_Channel2,&DMA_InitStructure);
	//根据DMA_InitStructure指定的参数初始化 DMA 通道 X 的寄存器
	DMA_ITConfig(DMA1_Channel2,DMA_IT_TC,ENABLE);
	/*DMA_Channelx  x: 1--7 ,DMA 通道
	  u32 DMA_IT 使能或失能 DMA 中断源  “ | ”同时选中多个DMA中断源
		       DMA_IT_TC  传输完成中断屏蔽
					 DMA_IT_HT  传输过半中断屏蔽
					 DMA_IT_TE  传输错误中断屏蔽
		NewState  : ENABLE  or DISABLE*/
	//DMA_Cmd(DMA1_Channel2, ENABLE);
	//在主函数中再使能
  //使能或失能指定的通道
	USART_DMACmd(USART3,USART_DMAReq_Tx,ENABLE); 
	//enable or disable 相应USART的DMA———TX / RX 请求
	USART_Cmd(USART3,ENABLE);  
	//开启串口3    
}
欢迎讨论,共同学习



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值