STM32 Uart 接收不定长数据

发布者:知音学友最新更新时间:2019-08-28 来源: eefocus关键字:STM32  Uart  不定长数据 手机看文章 扫描二维码
随时随地手机看文章

      前面讲了Uart三种不同的方式接收数据,请参照《STM32 Uart及其配置》《STM32 Uart中断接收》《STM32 Uart DMA方式接收数据》,但是,它们都需要指定数据的长度,但实际应用中,会出现不定长度的数据,比如,某些模块的@命令,那么,如何接收不定长度的数据呢?今天,我们就来扒一扒STM32 Uart 变长数据的接收。


      问题来了,变长数据包,我们如何确定数据包的长度?


      带着问题思考,我们可以得出以下几种思路:


      1. 制定严格的通信协议,带有一串特殊字符的数据包头、长度、校验、包尾等,比如,一开始收到:0xAA-0xBB-0xCC-0xDD-0xEE,表示数据包头,接下来两个字节是数据包长度,接下来是数据包内容,接下来是校验值,接下来是结尾。


      2. 使用定时器,判定在指定时间内没有收到数据,就算一个数据包结束。可以在收到一个数据后,开启定时器,定时器的超时时间设定为1~2个数据之间的时间,若在此期间有数据,则判定为数据包未结束,重载定时器,若此期间无数据,则判定为数据包结束,关闭定时器。


      这篇章里不讨论1和2,因为STM32有更方便的处理方式,STM32能够检测空闲。


      看RM0033,空闲,可以理解为,下一个起始位之前的全部1,也就是Rx线上高电平


      会不会和数据0xFF冲突呢?不会,因为数据0xFF有起始位,空闲没有。


      看下来这个手画的图,中间那一段高电平,就是空闲。


      

      当空闲被检测到时,如果IDLEIE位设置,就会产生一个IDLE中断。


      我们捕获这个中断,并处理它就行了。

      在空闲中断产生之前,我们收到的数据,怎么处理呢?先收着,存进一个Buffer里面!


      如前面讲的《STM32 Uart中断接收》《STM32 Uart DMA方式接收数据》,接收数据,也可以用中断和DMA两种不同的方式。我们把两种方式都写进代码里面,用两个不同的宏定义区分开来。


      我们就写一个,收到数据,往串口发送出收到的数据长度,以及完整的数据吧。


      理论讲完,就开始实践吧!


      参照《STM32 Uart DMA方式接收数据》,建立工程,生成代码。


   在 usart.c 里面写这样一段代码,#define RCV_RXNEIDLE_PROCESS 表示用RX中断方式接收数据,#define RCV_DMAIDLE_PROCESS 表示用DMA方式接收数据。这段代码主要用于选择接收数据的方式。同一时间只能使用一种方式,#error这里做了个限制,不允许同时打开这两个宏定义,否则会编译出错。


// select oneof two method

//#define RCV_RXNEIDLE_PROCESS

#define RCV_DMAIDLE_PROCESS

 

#if defined(RCV_DMAIDLE_PROCESS)&&defined(RCV_RXNEIDLE_PROCESS)

    #error "Don't Allow #define Two Micro at the same time, Check RCV_RXNEIDLE_PROCESS && RCV_DMAIDLE_PROCESS"

#endif

      接收数据,就定义一个数组来存放数据,就申请1024个字节的数组吧;


      数据要变长,就定义一个变量来表示接收到的数据长度;


      最后,再定义一个指针,用来指向存放数据的数组。


      在 usart.c 里面,这一断代码定义了所需要的数据。


uint8_t uart4Rx[UART4_BUF_MAX];      // 存放接收到的数据

uint8_t *pUart4Rx;    // 指向存认数据的数组

uint16_t uart4RxLength;     // 接收到数据的长度

      整个事件的流程就是,接收一段数据后,产生IDLE中断,IDLE中断服务例程里处理数据。


      那我们就看一下stm32f2xx_it.c里面UART4_IRQHandler()中断服务例程里面,对Idle中断是怎么处理的?


      看一下 HAL_UART_IRQHandler() 这个函数,它对Idle中断没有处理!那怎么办呢?自己写一段咯。


      在HAL_UART_IRQHandler() 函数加上这一段。


/* UART in mode Idle -------------------------------------------------*/

if(((isrflags & USART_SR_IDLE) != RESET) && ((cr1its & USART_CR1_IDLEIE) != RESET))

{

    HAL_UART_IdleCpltCallback(huart);      

    return;

}  

      这个回调函数HAL_UART_IdleCpltCallback(),仿照着在stm32f2xx_hal_uart.c里面加一个回调函数。


      后面,我们在 usart.c 里面重写它。


/**

  * @brief  Idle callbacks.

  * @param  huart pointer to a UART_HandleTypeDef structure that contains

  *                the configuration information for the specified UART module.

  * @retval None

  */

__weak void HAL_UART_IdleCpltCallback(UART_HandleTypeDef *huart)

{

  /* Prevent unused argument(s) compilation warning */

  UNUSED(huart);

  /* NOTE: This function Should not be modified, when the callback is needed,

           the HAL_UART_TxCpltCallback could be implemented in the user file

   */

}

 


      整个HAL_UART_IRQHandler()函数,是这样的。


void HAL_UART_IRQHandler(UART_HandleTypeDef *huart)

{

   uint32_t isrflags   = READ_REG(huart->Instance->SR);

   uint32_t cr1its     = READ_REG(huart->Instance->CR1);

   uint32_t cr3its     = READ_REG(huart->Instance->CR3);

   uint32_t errorflags = 0x00U;

   uint32_t dmarequest = 0x00U;

 

  /* If no error occurs */

  errorflags = (isrflags & (uint32_t)(USART_SR_PE | USART_SR_FE | USART_SR_ORE | USART_SR_NE));

  if(errorflags == RESET)

  {

    /* UART in mode Receiver -------------------------------------------------*/

    if(((isrflags & USART_SR_RXNE) != RESET) && ((cr1its & USART_CR1_RXNEIE) != RESET))

    {

      UART_Receive_IT(huart);

      return;

    }

  }  

 

  /* If some errors occur */

  if((errorflags != RESET) && (((cr3its & USART_CR3_EIE) != RESET) || ((cr1its & (USART_CR1_RXNEIE | USART_CR1_PEIE)) != RESET)))

  {

    /* UART parity error interrupt occurred ----------------------------------*/

    if(((isrflags & USART_SR_PE) != RESET) && ((cr1its & USART_CR1_PEIE) != RESET))

    {

      huart->ErrorCode |= HAL_UART_ERROR_PE;

    }

    

    /* UART noise error interrupt occurred -----------------------------------*/

    if(((isrflags & USART_SR_NE) != RESET) && ((cr3its & USART_CR3_EIE) != RESET))

    {

      huart->ErrorCode |= HAL_UART_ERROR_NE;

    }

    

    /* UART frame error interrupt occurred -----------------------------------*/

    if(((isrflags & USART_SR_FE) != RESET) && ((cr3its & USART_CR3_EIE) != RESET))

    {

      huart->ErrorCode |= HAL_UART_ERROR_FE;

    }

    

    /* UART Over-Run interrupt occurred --------------------------------------*/

    if(((isrflags & USART_SR_ORE) != RESET) && ((cr3its & USART_CR3_EIE) != RESET))

    {

      huart->ErrorCode |= HAL_UART_ERROR_ORE;

    }

 

    /* Call UART Error Call back function if need be --------------------------*/    

    if(huart->ErrorCode != HAL_UART_ERROR_NONE)

    {

      /* UART in mode Receiver -----------------------------------------------*/

      if(((isrflags & USART_SR_RXNE) != RESET) && ((cr1its & USART_CR1_RXNEIE) != RESET))

      {

        UART_Receive_IT(huart);

      }

 

      /* If Overrun error occurs, or if any error occurs in DMA mode reception,

         consider error as blocking */

      dmarequest = HAL_IS_BIT_SET(huart->Instance->CR3, USART_CR3_DMAR);

      if(((huart->ErrorCode & HAL_UART_ERROR_ORE) != RESET) || dmarequest)

      {

        /* Blocking error : transfer is aborted

           Set the UART state ready to be able to start again the process,

           Disable Rx Interrupts, and disable Rx DMA request, if ongoing */

        UART_EndRxTransfer(huart);

        

        /* Disable the UART DMA Rx request if enabled */

        if(HAL_IS_BIT_SET(huart->Instance->CR3, USART_CR3_DMAR))

        {

          CLEAR_BIT(huart->Instance->CR3, USART_CR3_DMAR);

          

          /* Abort the UART DMA Rx channel */

          if(huart->hdmarx != NULL)

          {

            /* Set the UART DMA Abort callback :

               will lead to call HAL_UART_ErrorCallback() at end of DMA abort procedure */

            huart->hdmarx->XferAbortCallback = UART_DMAAbortOnError;

            if(HAL_DMA_Abort_IT(huart->hdmarx) != HAL_OK)

            {

              /* Call Directly XferAbortCallback function in case of error */

              huart->hdmarx->XferAbortCallback(huart->hdmarx);

            }

          }

          else

          {

            /* Call user error callback */

            HAL_UART_ErrorCallback(huart);

          }

        }

        else

        {

          /* Call user error callback */

          HAL_UART_ErrorCallback(huart);

        }

      }

      else

      {

        /* Non Blocking error : transfer could go on.

           Error is notified to user through user error callback */

        HAL_UART_ErrorCallback(huart);

        huart->ErrorCode = HAL_UART_ERROR_NONE;

      }

    }

    return;

  } /* End if some error occurs */

 

// 这里,就是对Idle中断的处理啊啊啊啊啊!!!

     /* UART in mode Idle -------------------------------------------------*/

    if(((isrflags & USART_SR_IDLE) != RESET) && ((cr1its & USART_CR1_IDLEIE) != RESET))

    {

        HAL_UART_IdleCpltCallback(huart);      

      return;

    }  

 

  /* UART in mode Transmitter ------------------------------------------------*/

  if(((isrflags & USART_SR_TXE) != RESET) && ((cr1its & USART_CR1_TXEIE) != RESET))

  {

    UART_Transmit_IT(huart);

    return;

  }

  

  /* UART in mode Transmitter end --------------------------------------------*/

  if(((isrflags & USART_SR_TC) != RESET) && ((cr1its & USART_CR1_TCIE) != RESET))

[1] [2]
关键字:STM32  Uart  不定长数据 引用地址:STM32 Uart 接收不定长数据

上一篇:STM32使用HAL库实现串口通讯
下一篇:STM32 HAL库学习(二) 串口收发数据

推荐阅读最新更新时间:2024-11-11 15:27

STM32Cube.AI v7.2现可支持深度量化神经网络
意法半导体近期发布的 STM32Cube.AI v7.2 带来了对深度量化神经网络的支持功能,从而可以在现有微控制器上运行更准确的机器学习应用软件。STM32Cube.AI 于 2019 年推出,用于把神经网络转换为适合STM32 MCU 的代码。该解决方案依附于 STM32CubeMX,这是一个帮助开发人员初始化STM32芯片的图形界面软件。同时,STM32Cube.AI 还用到 X-CUBE-AI软件包,其中包含用于转换训练好的神经网络的程序库。开发人员可以参照我们的入门指南,从STM32CubeMX内部开始使用 X-CUBE-AI并体验新功能。 目前,新增加的深度量化神经网络支持已经出现在我们与施耐德电气合作开发的人数
[物联网]
STM32Cube.AI v7.2现可支持深度量化神经网络
STM32 模拟I2C 程序
STM32的硬件I2C不太好用,N多人深受其困扰,本人也不例外.所以干脆一不做二不休,用模拟的I2C算了,虽然速度不及硬件I2C,在一般的应用中还是不错的.帖上代码和协议分析图,造福广大受STM32的I2C困扰的朋友,哈哈!为了跟硬件I2C有所区别,本人把模拟的I2C名字写成TWI. H文件内容如下: #i nclude stm32f10x.h #ifndef _TWI_H_ #define _TWI_H_ //条件编译 1:使用软件模拟I2C #define TWI_ENABLE 1 #define TWI_SCL_0 GPIOB- BRR=GPIO_Pin_8 #define TWI_SCL_1 GPIOB- BSRR=GPI
[单片机]
stm32通过电调带动电机(可按键调速)
这几天在做32通过电调带动电机的实验,上网一查,发现这方面的资料很少,经过自己的亲自实践,总结出以下经验,供大家参考。 论坛上也有很多人说自己在做,但是都遇到了同样的瓶颈。我想他们大多是pwm的频率和占空比没有调到合适的值吧。 首先,我在网上只找到一片很好的文章,是瑞生大神写的:http://www.rationmcu.com/lpc1114/1126.html 我的电机是银燕2212/1400kv经典电机 ,电调也是银燕40A无刷电调。 通过它知道,当pwm设置为500hz的 时候电调才能正常的工作,刚开始时高电平时间要控制在0.7-1.9左右,让电机带电自检。 通过按键控制占空比可以很好地 实现这一点。
[单片机]
STM32在低功耗状态时IO引脚常规的配置内容分享
做有低功耗产品设计经验的朋友都应该知道,一个产品的功耗不光是硬件功耗的事,其实软件也是影响整个产品功耗的一个关键因素。 今天就为大家分享一点关于STM32在低功耗状态时,IO引脚常规的配置内容。 1 将未使用的GPIO输入配置为模拟输入GPIO始终有一个输入通道,可以是数字或模拟通道。如果不需要读取GPIO数据,则优先配置为模拟输入。这节省了输入施密特触发器的消耗。在STM32CubeMX配置中都有这么一个选项:将不用引脚配置为模拟状态。 2 调节GPIO速度上升时间,下降时间和最大频率可使用GPIOx_OSPEEDR配置寄存器进行配置。这种调整对EMI(电磁干扰)和SSO(同时开关输出)有影响,因为开关电流峰值较高。
[单片机]
<font color='red'>STM32</font>在低功耗状态时IO引脚常规的配置内容分享
STM32-异常与中断
在使用单片机的时候我们常用到的中断,但是但是我们常说的中断都是由(内核的)外部事件引起的、正常的紧急事件。而异常与我们所说的中断相似,但也有不同之处。 异常(内核中断)和外部中断 异常是CPU内部产生的中断,即在CPU执行特定指令的时候出现的非法情况,如除数为0等等,所以不可能在执行指令期间发生异常,只会在执行一条指令后有可能发生,所以也称同步中断。而中断则是一种异步的,它与特定的进程是无关的,又称为异步中断。 CM3 内核支持 256 个中断,其中包含了 16 个内核中断(主要用于系统异常)和 240 个外部中断,并且具有 3 个固定的高优先级和256级(8位)的可编程中断设置。因为芯片设计者可以修改 CM3 的硬件描述
[单片机]
STM32-异常与中断
stm32内核外设Systick与普通外设中断优先级比较的验证实验
最近又遇到了使用Systick来产生精确计时,然后又涉及到了Systick的中断优先级的问题。我们老板认为Systick属于内核外 设,中断优先级应该比普通外设高。然后我们说,在网上看到的是,Systick的中断优先级ST官方默认设置15(1111b),然 后换算为4位(M4用4位来表示优先级分组)是3(抢占优先级),3(响应优先级),其实是最低的,但老板说虽然它是最低的,但它是跟CPU紧耦合的内核外设,它依然能打断优先级比它高的普通外设,当然我们也有点不确定网上说的就是对的(还是老板说的就是错的,==)。于是就做了一个对比实验,测试到底是Systick到底能否打断中断优先级比它高的。 实验环境条件如下:MDK v5.21a,
[单片机]
STM32如何实现可调频率、占空比的PWM波形,且可指定输出脉冲个数?
读者朋友“*imYan*”问: pwm实现频率可调和占空比可调后怎么来实现输出10个脉冲呢?我这边看有门控或者单脉冲加重复计数,黄老师平时用的什么方法? 我的回答: 使用两个TIM定时器:一个输出可调频率、占空比的PWM,一个对输出PWM脉冲计数(计时)。 1.门控方式能实现,但需要复杂的配置和计算,不推荐。 2.脉冲计数是比较实际,也是比较简单的方式; 对输出PWM脉冲计数(计时)方法有多种: 1.IO中断计数,或同步定时中断计数:用另外一个定时器,按照相同频率中断计数(类似IO中断); 2.由PWM频率和脉冲个数,计算输出全部所需的时间,使用定时中断,关闭输出PWM; 3.利用定时器外部脉冲
[单片机]
意法半导体STM32C0系列高能效微控制器性能大幅提升
新微控制器 STM32C071扩大闪存和 RAM容量,增加USB控制器,支持 TouchGFX图形软件,让终端产品变得更纤薄、小巧,更具竞争力 2024 年 10 月 16 日,中国——现在, STM32 开发人员可以在 STM32C0微控制器(MCU)上获得更多存储空间和更多功能,在资源有限和成本敏感的嵌入式应用中实现更先进的功能。 STM32C071 MCU配备高达128KB的闪存和 24KB 的 RAM ,还新增不需要外部晶振的USB从设备,支持TouchGFX图形软件。片上 USB控制器让设计人员轻松节省至少一个外部时钟和四个去耦电容,降低物料清单成本,简化 PCB元器件布局。此外,新产品只有一对电源线,这有助
[单片机]
意法半导体STM32C0系列高能效微控制器性能大幅提升
小广播
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved