STM32使用串口1配合DMA接收不定长数据,减轻CPU载荷 http://www.openedv.com/thread-63849-1-1.html

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

关键代码分析:
usart.H
#ifndef __USART_H
#define __USART_H
#include "stdio.h"
#include "sys.h" #define DMA_Rec_Len 200      //定义一个长度为200个字节的数据缓冲区。(建议定义的长度比你可能接收到的最长单帧数据长度长!)void uart_init(u32 bound);
void MYDMA_Enable(DMA_Channel_TypeDef*DMA_CHx);#endifusart.C
//初始化IO 串口1
//bound:波特率
void uart_init(u32 bound)
{//GPIO端口设置
    GPIO_InitTypeDef GPIO_InitStructure;USART_InitTypeDef USART_InitStructure;NVIC_InitTypeDef NVIC_InitStructure;DMA_InitTypeDef DMA_InitStructure;RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1|RCC_APB2Periph_GPIOA, ENABLE); //使能USART1,GPIOA时钟RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE); //使能DMA传输RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2,ENABLE);//使能USART2时钟
USART_DeInit(USART1);  //复位串口1//USART1_TX   PA.9GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; //PA.9GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出GPIO_Init(GPIOA, &GPIO_InitStructure); //初始化PA9//USART1_RX  A.10GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入GPIO_Init(GPIOA, &GPIO_InitStructure);  //初始化PA10//Usart1 NVIC 配置NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3 ;//抢占优先级3NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; //子优先级3NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道使能NVIC_Init(&NVIC_InitStructure); //根据指定的参数初始化VIC寄存器//USART 初始化设置USART_InitStructure.USART_BaudRate = bound;//一般设置为9600;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); //初始化串口USART_ITConfig(USART1, USART_IT_IDLE, ENABLE);//开启空闲中断USART_DMACmd(USART1,USART_DMAReq_Rx,ENABLE);   //使能串口1 DMA接收USART_Cmd(USART1, ENABLE);                    //使能串口 //相应的DMA配置DMA_DeInit(DMA1_Channel5);   //将DMA的通道5寄存器重设为缺省值  串口1对应的是DMA通道5DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)&USART1->DR;  //DMA外设ADC基地址DMA_InitStructure.DMA_MemoryBaseAddr = (u32)DMA_Rece_Buf;  //DMA内存基地址DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;  //数据传输方向,从外设读取发送到内存DMA_InitStructure.DMA_BufferSize = DMA_Rec_Len;  //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(DMA1_Channel5, &DMA_InitStructure);  //根据DMA_InitStruct中指定的参数初始化DMA的通道
DMA_Cmd(DMA1_Channel5, ENABLE);  //正式驱动DMA传输
}//串口中断函数
void USART1_IRQHandler(void)                 //串口1中断服务程序
{if(USART_GetITStatus(USART1, USART_IT_IDLE) != RESET)  //接收中断(接收到的数据必须是0x0d 0x0a结尾)
      {USART_ReceiveData(USART1);//读取数据 注意:这句必须要,否则不能够清除中断标志位。Usart1_Rec_Cnt = DMA_Rec_Len-DMA_GetCurrDataCounter(DMA1_Channel5); //算出接本帧数据长度//***********帧数据处理函数************//
          printf ("The lenght:%d\r\n",Usart1_Rec_Cnt);printf ("The data:\r\n");Usart1_Send(DMA_Rece_Buf,Usart1_Rec_Cnt);printf ("\r\nOver! \r\n");//*************************************//
         USART_ClearITPendingBit(USART1, USART_IT_IDLE);         //清除中断标志MYDMA_Enable(DMA1_Channel5);                   //恢复DMA指针,等待下一次的接收
     } } 

这种方式和传统的uart接收中断里面处理数据(解析协议的比较):

//普通方式
uart_rcv_irq()
{
    DISABLE_UARTX
    
    if G_Counter >= MAXLEN
        clear buffer and counter;
    else
        G_Buffer[G_Counter]= GetData(UARTX);
        G_Counter++;

if OK==unpack(G_Buffer,G_Counter)
            clear buffer and counter;
            set flag;
            
    ENABLE_UARTX
}

//idle中断 + dma方式
G_Buffer
G_Counter
G_DMARcvBuffer
uart_idle_irq()
{
    G_Counter += MAXLEN - DMAGetCurDataCounter(DMAx);
    copy G_DMARcvBuffer to G_Buffer;
    if OK==unpack(G_Buffer,G_Counter)
        clear buffers and counter;
        set flag;
            
    USART_ClearITPendingBit(USARTx, USART_IT_IDLE);
}

DMAx_OVERFLOW_IRQHandler()
{
    G_Counter += MAXLEN - DMAGetCurDataCounter(DMAx);
    copy G_DMARcvBuffer to G_Buffer;
    if OK==unpack(G_Buffer,G_Counter)
        clear buffers and counter;
        set flag;
    
    RESET DMA
}

转载于:https://www.cnblogs.com/mylinux/p/5374134.html

STM32使用串口1配合DMA接收不定长数据,减轻CPU载荷相关推荐

  1. STM32使用串口1配合DMA接收不定长数据,大大减轻CPU载荷

    摘自:http://www.openedv.com/thread-63849-1-1.html 参考:https://blog.csdn.net/heda3/article/details/80602 ...

  2. STM32使用串口1配合DMA接收不定长数据,大大减轻CPU载荷。

    最近经常看见坛友在论坛上问串口接收的问题,我之前刚好由于项目需要用到PLC的PPI协议,需要不停地利用串口接收数据,一开始的时候采用单字节中断的方式接收判断.但是用来做通信的时候需要不停的产生串口接收 ...

  3. STM32单片机串口空闲中断+DMA接收不定长数据

    在上一篇文章STM32单片机串口空闲中断接收不定长数据中介绍了利用串口空闲中断接收不定长数据,这种方式有一个问题就是串口每接收到一个字节就会进入一次中断,如果发送的数据比较频繁,那么串口中断就会不停打 ...

  4. STM32 HAL库 串口DMA接收不定长数据

    STM32 HAL库 串口DMA接收不定长数据 整体思路:我是用的CUBEMX软件生成的工程,使能了两个串口,串口2用来接收不定长的数据,串口1用来发送串口2接收到的数据:串口2我找了一个UBLOX卫 ...

  5. android 串口一直打开_STM32之串口DMA接收不定长数据

    STM32之串口DMA接收不定长数据 引言 在使用stm32或者其他单片机的时候,会经常使用到串口通讯,那么如何有效地接收数据呢?假如这段数据是不定长的有如何高效接收呢? 同学A:数据来了就会进入串口 ...

  6. MM32F3277空闲中断+DMA接收不定长数据

    摘要:在实际项目中经常用到串口接收一些不定长的数据,怎么判断这一帧数据接收完成了呢?通常使用UART非空中断配合简单的数据协议,在数据中加入帧头.帧尾,在程序中判断是否接收到帧尾来确定数据接收完毕,对 ...

  7. 第九章 AT32F403A基于V2库串口 dma接收不定长数据

    目录 概述 硬件 DMA 软件 流程 初始化 初始化代码: 中断服务函数: DMA1通道5设置函数:(重新使能通道) DMA1通道4发送函数:(设置dma长度和内存地址) 测试 最后 概述 本文主要是 ...

  8. STM32使用串口IDLE中断的两种接收不定长数据的方式

    现在有很多数据处理都要用到不定长数据,而单片机串口的RXNE中断一次只能接收一个字节的数据,没有缓冲区,无法接收一帧多个数据,现提供两种利用串口IDLE空闲中断的方式接收一帧数据,方法如下: 方法1: ...

  9. 串口IDLE空闲中断+DMA实现接收不定长数据基于stm32cubemx

    引言:对于串口接收一些不定长的数据,必须面对一个问题:怎么判断一帧数据接收是否完成?通常使用RXNE非空中断配合简单的数据协议,在数据中加入帧头.帧尾,在程序中判断是否接收到帧尾来确定数据接收完毕,因 ...

最新文章

  1. MySQL记住密码_技术分享 | mysqlsh 命令行模式 密码保存
  2. 欢迎来到开源的世界!
  3. Kibana:数据分析的可视化利器
  4. Shiro框架原理及应用分析
  5. 完全二叉树的判断java,判断二叉树是否为完全二叉树的实例
  6. gulp怎么运行html文件,如果gulp-watch监视html文件,它会运行所有任务
  7. java积分签到功能_对于签到功能的一点理解
  8. Android Layout 布局属性全解
  9. 使用 Litho 改进 News Feed 上的 Android 视频表现
  10. javascript 验证 国际格式 电话号码
  11. 读《好好学习:个人知识管理精进指南》
  12. 准确曝光一学就会 数码相机曝光的秘诀
  13. Python Pygame制作简单五子棋游戏(详细代码+解释)
  14. Redis遇到的问题Could not resolve type id ** into a subtype解决办法
  15. 被低估的BIRT报表 二 Birt也可以很漂亮
  16. vue中echarts纵轴添加点击事件
  17. android接入原生第三方登录(微信登录、QQ登录、新浪微博登录)
  18. 百度地图 多轨迹 示例
  19. can总线短距离不用双绞线_CAN 总线(一) 物理层—屏蔽双绞线
  20. draftsight+qgis+mapshaper+leftlet做web地图

热门文章

  1. 谈谈 COS 中国自主知识产权智能手机操作系统
  2. UserWarning: Possibly corrupt EXIF data.
  3. 计算机考研报师范类大学好吗,想考师范类的研究生都有哪些大学招
  4. SciTE Script Editor 解决中文乱码
  5. Java模拟售票窗口代码_java多线程模拟售票,多个窗口售票
  6. 小白兔快开门,我是你爸爸。WEB安全基础入门—访问控制漏洞和权限提升
  7. ACM--South Pacific 2012
  8. 普元王文斌:微服务架构开发模式需要全栈团队
  9. Lichee_RV学习系列--CoreMark-Pro移植
  10. 贺利坚的课程教学链接