打印
[APM32E1]

串口+DMA解决数据接收的困扰

[复制链接]
877|3
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
LQM568|  楼主 | 2022-4-6 17:14 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
串口+DMA解决数据接收的难题

   之前由于项目需要不停地利用串口接收数据,刚开始的时候采用单字节中断的方式接收判断。但是用来做通信的时候需要不停的产生串口接收中断,会严重影响主程序的运行。后来采用DMA接收的方式,但是一般情况下配置的DMA都是接收指定长度的串口数据,对于未知长度的串口数据接收并不适用。后来在网上发现了一种方法可以利用串口的 空闲中断+DMA接收的方法可解决此类问题,特别适用于不需要每个就收字节都判断的串口数据接收,下面简单介络一下。

   思路:采用APM32E103的串口1,并配置成空闲中断模式且使能DMA接收,并同时设置接收缓冲区和初始化DMA。当初始化完成之后,外部给MCU发送数据的时候,假设这帧数据长度是100个字节,那么在MCU中接收到一个字节的时候并不会产生串口中断,而是DMA在后台把数据全部搬运到你指定的缓冲区里面,当整帧数据发送完毕之后串口才会产生一次中断,此时可以利用CurrDataCounterBegin = DMA_ReadDataNumber(DMA1_Channel6);计算出本次的数据接受长度,从而进行数据处理。

关键代码分析:
#include "public.h"
#ifndef __USART_H
#define __USART_H
#include "stdio.h"

volatile uint32_t CurrDataCounterBegin = 0;
#define DMA_Rec_Len 256      //定义一个256个字节的数据缓冲区。

void uartInit(void)
{
    //GPIO端口设置
    GPIO_InitTypeDef GPIO_InitStructure;
    USART_InitTypeDef USART_InitStructure;
    NVIC_InitTypeDef NVIC_InitStructure;
    DMA_InitTypeDef DMA_InitStructure;

   RCM_EnableAPB2PeriphClock((RCM_APB2_PERIPH_T)(RCM_APB2_PERIPH_GPIOA | RCM_APB2_PERIPH_USART1)); //使能USART1,GPIOA时钟
   RCM_EnableAHBPeriphClock(RCM_AHB_PERIPH_DMA1); //使能DMA传输
   USART_DeInit(USART1);  //复位串口1
   //USART1_TX   PA9
    GPIO_InitStructure.pin = GPIO_PIN_9; //PA.9
    GPIO_InitStructure.speed = GPIO_SPEED_50MHz;
    GPIO_InitStructure.mode = GPIO_MODE_AF_PP; //复用推挽输出
    GPIO_Config(GPIOA, &GPIO_InitStructure); //初始化PA9
   
    //USART1_RX  A10
    GPIO_InitStructure.pin = GPIO_PIN_10;
    GPIO_InitStructure.mode = GPIO_MODE_IN_FLOATING;//浮空输入
    GPIO_Config(GPIOA, &GPIO_InitStructure);  //初始化PA10
   //USART 初始化设置
  USART_InitStructure.USART_BaudRate = 115200;
  USART_InitStructure.USART_WordLength = USART_WORD_LEN_8B;//字长为8位数据格式
  USART_InitStructure.USART_StopBits = USART_STOP_BIT_1;//一个停止位
  USART_InitStructure.USART_Parity = USART_PARITY_NONE;//无奇偶校验位
  USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//无硬件数据流控制
  USART_InitStructure.USART_Mode = USART_MODE_TX | USART_MODE_RX; //收发模式
  
    USART_Config(USART1, &USART_InitStructure);
   
   USART_EnableInterrupt(USART1, USART_INT_IDLE);//开启空闲中断
       
   USART_EnableDMA(USART1,USART_DMA_RX);   //使能串口1 DMA接收
       
   USART_Enable(USART1);                  //使能串口

   // NVIC 配置
    NVIC_EnableIRQRequest(DMA1_Channel6_IRQn, 3, 2);


    //相应的DMA配置
  DMA_Reset(DMA1_Channel6);  
  DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)&USART1->DR;  //DMA外设ADC基地址
  DMA_InitStructure.DMA_MemoryBaseAddr = (u32)DMA_Rece_Buf;  //DMA内存基地址
  DMA_InitStructure.DMA_DIR = DMA_DIR_PERIPHERAL_SRC;  //数据传输方向,从外设读取发送到内存
  DMA_InitStructure.DMA_BufferSize = DMA_Rec_Len;  //DMA通道的DMA缓存的大小
  DMA_InitStructure.DMA_PeripheralInc = DMA_PERIPHERAL_INC_DISABLE;  //外设地址寄存器不变
  DMA_InitStructure.DMA_MemoryInc = DMA_MEMORY_INC_ENABLE;  //内存地址寄存器递增
  DMA_InitStructure.DMA_PeripheralDataSize = DMA_PERIPHERAL_DATA_SIZE_WOED;  //数据宽度为8位
  DMA_InitStructure.DMA_MemoryDataSize = DMA_MEMORY_DATA_SIZE_WOED; //数据宽度为8位
  DMA_InitStructure.DMA_Mode = DMA_MODE_NORMAL;  //工作在正常缓存模式
  DMA_InitStructure.DMA_Priority = DMA_PRIORITY_HIGH; //DMA通道 x拥有中优先级
  DMA_InitStructure.DMA_M2M = DMA_M2MEN_ENABLE;  //DMA通道x没有设置为内存到内存传输
  DMA_Init(DMA1_Channel6, &DMA_InitStructure);  //根据DMA_InitStruct中指定的参数初始化DMA的通道

  DMA_EnableInterrupt(DMA1_Channel6, DMA_INT_TC);
  CurrDataCounterBegin = DMA_ReadDataNumber(DMA1_Channel6);

   DMA_Enable(DMA1_Channel6);
}

//串口中断函数
void USART1_IRQHandler(void)                 //串口1中断服务程序
{

     if(USART_ReadStatusFlag(USART1, USART_FLAG_IDLE) != RESET)  //接收中断(接收到的数据必须是0x0d 0x0a结尾)
      {
          USART_RxData(USART1);//读取数据 注意:这句必须要,否则不能够清除中断标志位。
          Usart1_Rec_Cnt = DMA_Rec_Len-CurrDataCounterBegin(DMA1_Channel6); //算出接本帧数据长度
   
         //帧数据处理函数
          printf ("The lenght:%d\r\n",Usart1_Rec_Cnt);
          printf ("The data:\r\n");
          USART_TxData(DMA_Rece_Buf,Usart1_Rec_Cnt);
          USART_ClearIntFlag(USART1, USART_FLAG_IDLE);         //清除中断标志
          DMA_Enable(DMA1_Channel6);                   //恢复DMA指针,等待下一次的接收
     }

使用特权

评论回复
沙发
weifeng90| | 2022-4-6 20:31 | 只看该作者
思路不错,谢谢分享。

使用特权

评论回复
板凳
豌豆爹| | 2022-4-18 15:48 | 只看该作者
的确是非常不错的思路

使用特权

评论回复
地板
gouguoccc| | 2022-4-18 19:26 | 只看该作者
看看,写的不错啊!

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

3

主题

3

帖子

0

粉丝