DMA接收串口数据(定长与不定长)

Posted 文某9

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了DMA接收串口数据(定长与不定长)相关的知识,希望对你有一定的参考价值。

效果如图

串口配置(可以直接拷贝拿去用)

#include "sys.h"
#include "usart.h"	  
// 	 
//
//加入以下代码,支持printf函数,而不需要选择use MicroLIB	  
#if 1
#pragma import(__use_no_semihosting)             
//标准库需要的支持函数                 
struct __FILE 
 
	int handle; 

; 

FILE __stdout;       
//定义_sys_exit()以避免使用半主机模式    
void _sys_exit(int x) 
 
	x = x; 
 
//重定义fputc函数 
int fputc(int ch, FILE *f)
      
	while((USART1->SR&0X40)==0);//循环发送,直到发送完毕   
    USART1->DR = (u8) ch;      
	return ch;

#endif 
#if EN_USART1_RX   //如果使能了接收
//串口1中断服务程序
//注意,读取USARTx->SR能避免莫名其妙的错误   	
u8 USART_RX_BUF[USART_REC_LEN];     //接收缓冲,最大USART_REC_LEN个字节.
//接收状态
//bit15,	接收完成标志
//bit14,	接收到0x0d
//bit13~0,	接收到的有效字节数目
u16 USART_RX_STA=0;       //接收状态标记	  
  
void uart_init(u32 bound)
  //GPIO端口设置
  GPIO_InitTypeDef GPIO_InitStructure;
	USART_InitTypeDef USART_InitStructure;
	NVIC_InitTypeDef NVIC_InitStructure;
	 
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1|RCC_APB2Periph_GPIOA, ENABLE);	//使能USART1,GPIOA时钟
  
	//USART1_TX   GPIOA.9
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; //PA.9
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;	//复用推挽输出
  GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.9
   
  //USART1_RX	  GPIOA.10初始化
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;//PA10
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入
  GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.10  

  //Usart1 NVIC 配置
  NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3 ;//抢占优先级3
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;		//子优先级3
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;			//IRQ通道使能
	NVIC_Init(&NVIC_InitStructure);	//根据指定的参数初始化VIC寄存器
  
   //USART 初始化设置

	USART_InitStructure.USART_BaudRate = bound;//串口波特率
	USART_InitStructure.USART_WordLength = USART_WordLength_8b;//字长为8位数据格式
	USART_InitStructure.USART_StopBits = USART_StopBits_1;//一个停止位
	USART_InitStructure.USART_Parity = USART_Parity_No;//无奇偶校验位
	USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//无硬件数据流控制
	USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;	//收发模式

  USART_Init(USART1, &USART_InitStructure); //初始化串口1
  USART_DMACmd(USART1,USART_DMAReq_Rx,ENABLE); //使能串口1的DMA发送
  



void USART1_IRQHandler(void)                	//串口1中断服务程序
	
	u8 Res;
	if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)  //接收中断(接收到的数据必须是0x0d 0x0a结尾)
		
		Res =USART_ReceiveData(USART1);	//读取接收到的数据
		  		 
      
 
#endif	


DMA配置

#include "dma.h"
//	 
//本程序只供学习使用,未经作者许可,不得用于其它任何用途
//ALIENTEK精英STM32开发板
//DMA 代码	   
//正点原子@ALIENTEK
//技术论坛:www.openedv.com
//修改日期:2012/9/8
//版本:V1.0
//版权所有,盗版必究。
//Copyright(C) 广州市星翼电子科技有限公司 2009-2019
//All rights reserved									  
//

DMA_InitTypeDef DMA_InitStructure;

u16 DMA1_MEM_LEN;//保存DMA每次数据传送的长度 	    
//DMA1的各通道配置
//这里的传输形式是固定的,这点要根据不同的情况来修改
//从存储器->外设模式/8位数据宽度/存储器增量模式
//DMA_CHx:DMA通道CHx
//cpar:外设地址
//cmar:存储器地址
//cndtr:数据传输量 

void MYDMA_Config(DMA_Channel_TypeDef* DMA_CHx,u32 cpar,u32 cmar,u16 cndtr)

RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);    //使能DMA传输
DMA_DeInit(DMA_CHx); //将DMA的通道1寄存器重设为缺省值
DMA1_MEM_LEN=cndtr;
DMA_InitStructure.DMA_PeripheralBaseAddr = cpar; //DMA外设基地址
DMA_InitStructure.DMA_MemoryBaseAddr = cmar; //DMA内存基地址
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC; //数据传输方向,从内存读取发送到外设
DMA_InitStructure.DMA_BufferSize = cndtr; //DMA通道的DMA缓存的大小
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; //外设地址寄存器不变
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; //内存地址寄存器递增
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; //数据宽度为8位
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; //数据宽度为8位
DMA_InitStructure.DMA_Mode = DMA_Mode_Normal; //工作在正常模式
DMA_InitStructure.DMA_Priority = DMA_Priority_Medium; //DMA通道 x拥有中优先级 
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; //DMA通道x没有设置为内存到内存传输
DMA_Init(DMA_CHx, &DMA_InitStructure); //根据DMA_InitStruct中指定的参数初始化DMA的通道USART1_Rx_DMA 所标识的寄存器
USART_Cmd(USART1, ENABLE); //使能串口1 
DMA_Cmd(DMA_CHx, ENABLE); //使能USART1 TX DMA1 所指示的通道 
MYDMA_Enable(DMA1_Channel5);//开始一次DMA传输!


//开启一次DMA传输
void MYDMA_Enable(DMA_Channel_TypeDef*DMA_CHx)
 
	DMA_Cmd(DMA_CHx, DISABLE );  //关闭USART1 TX DMA1 所指示的通道      
 	DMA_SetCurrDataCounter(DMA_CHx,DMA1_MEM_LEN);//DMA通道的DMA缓存的大小
 	DMA_Cmd(DMA_CHx, ENABLE);  //使能USART1 TX DMA1 所指示的通道 
	  


主函数(定长)

#include "stm32f10x.h"
#include "usart.h"	
#include "delay.h"
#include "dma.h"
#include "string.h"
 int main(void)
 	
  u8 USART_RX_BUF1[50];
  delay_init();
  uart_init(115200);
  MYDMA_Config(DMA1_Channel5,(u32)&USART1->DR,(u32)USART_RX_BUF1,50);//DMA1通道5,外设为串口1,存储器为SendBuff,长度35,
  while(1)

   
if(DMA_GetFlagStatus(DMA1_FLAG_TC5)!=RESET)	//判断通道5传输完成

DMA_ClearFlag(DMA1_FLAG_TC5);//清除通道4传输完成标志
delay_ms(10); //延时10ms,让DMA继续接收后面数据的同时,也能跑跑其它进程 
printf("1:%s\\r\\n",USART_RX_BUF1); //打印
memset(USART_RX_BUF1,0,35);    //清空数组
MYDMA_Enable(DMA1_Channel5);//开始一次DMA传输!


 

主函数(不定长)

#include "stm32f10x.h"
#include "usart.h"	
#include "delay.h"
#include "dma.h"
#include "string.h"
 int main(void)
 	
  u8 USART_RX_BUF1[50];
  delay_init();
  uart_init(115200);
  MYDMA_Config(DMA1_Channel5,(u32)&USART1->DR,(u32)USART_RX_BUF1,50);//DMA1通道5,外设为串口1,存储器为SendBuff,长度35,
  while(1)

   
if(USART_RX_BUF1[0]!=0)	//判断通道4传输完成

delay_ms(10); //延时10ms,让DMA继续接收后面数据的同时,也能跑跑其它进程 
printf("1:%s\\r\\n",USART_RX_BUF1); //打印
memset(USART_RX_BUF1,0,35);    //清空数组
MYDMA_Enable(DMA1_Channel5);//开始一次DMA传输!


 

标志位说明

以上是关于DMA接收串口数据(定长与不定长)的主要内容,如果未能解决你的问题,请参考以下文章

STM32F4 DMA接收串口定长数据,串口每秒来1000个数据,使用DMA-Normal模式

STM32F103VET6基于STM32CubeMX创建串口中断+ DMA 不定长数据接收

STM32 | 串口空闲中断接收不定长数据(DMA方式)

STM32HAL库DMA和串口接收不定长字符串

STM32HAL库DMA和串口接收不定长字符串

STM32怎么接收不定长串口数据