极度优雅的用stm32串口接收并分析不定长数据的方法(可用于发送和接收浮点数)

这篇具有很好参考价值的文章主要介绍了极度优雅的用stm32串口接收并分析不定长数据的方法(可用于发送和接收浮点数)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

应用场景

比赛需要

我准备电赛的时候参加了学校为了准备电赛而举办的的积分赛,队友通过树莓派用给stm32发送执行指令,而我在队里作为写单片机的就需要分析数据包,每一个数据包都比较大也比较复杂,而且不定长,用传统的一个字节一个字节接收数据的方式收串口在代码层面上就显得和很复杂,因此我需要一个能定长接收数据并分析的方法。

ESP-01s

在我之前用AT指令玩ESP-01s模块的时候,服务器下发的数据往往是不定长的,因此我也需要一个用单片机接收不定长数据的方式。

因此我在网上找了一些方法,整合了一些我认为比较优雅的基于stm32的解决方案。

废话少说,开始实现。

原理

因为我手上拥有最多的单片机是stm32f401ccu6,因此这里以stm32f401为例演示

根据stm32f4的数据手册stm32串口接收不定长数据,stm32,单片机,嵌入式硬件,mcu
从这张表中可以看出stm32有RXNE(RX寄存器非空,代表有数据输入)中断,和IDLE(串口空闲,代表发送端发送结束)中断,那么我们只需要从有数据输入,一直接受直到串口出现空闲即可接收下整包不定长的数据。

但是在此之前,如果配置RXNE中断,发送端每发送一个字节,CPU就要进一次中断去处理该字节,那这样就和一个个字节接收无异了,那这时候就需要请出CPU的小弟:DMA出场,让每个字节进入单片机时都产生一个接收请求,然后让DMA一个个字节搬入内存,CPU在IDLE中断中再对所有数据进行处理,并重置DMA,则可大大减小CPU的占用,也方便了代码的编写。

STM32CUBEMX配置

stm32串口接收不定长数据,stm32,单片机,嵌入式硬件,mcu
配置Debug接口
stm32串口接收不定长数据,stm32,单片机,嵌入式硬件,mcu配置HSE和LSE(LSE其实可以不配)
stm32串口接收不定长数据,stm32,单片机,嵌入式硬件,mcu
配置时钟树
stm32串口接收不定长数据,stm32,单片机,嵌入式硬件,mcu
配置USART1为异步模式
stm32串口接收不定长数据,stm32,单片机,嵌入式硬件,mcu
打开USART1全局中断
stm32串口接收不定长数据,stm32,单片机,嵌入式硬件,mcu
打开USART1 DMA接收请求,配置默认就好,主要的是Increment Address勾选Memery,Data Width外设和内存都选择BYTE(这两个必须相同)

然后接下来的就是工程配置,那个就按照自己的情况来,该怎么样就怎么样

代码编写

stm32串口接收不定长数据,stm32,单片机,嵌入式硬件,mcu
在USER CODE BEGIN Include之后加上两个头文件

#include "stdio.h"
#include "string.h"

stm32串口接收不定长数据,stm32,单片机,嵌入式硬件,mcu
点开魔术棒勾选Use MicroLIB
stm32串口接收不定长数据,stm32,单片机,嵌入式硬件,mcu
在工程的任意地方添加重定向代码(我这里添加在了/* USER CODE BEGIN 4 */的后面)

int fputc(int ch, FILE *f)
{
//	HAL_UART_Transmit (&huart2 ,(uint8_t *)&ch,1,HAL_MAX_DELAY);
	while((USART1->SR&0x40)==0);
		USART1->DR = (uint8_t)ch;
	//采用轮询方式发送一个字节的数据,没有发送成功就一直等待
	return ch;
}
int fgetc(FILE *f)
//int fgetc(int ch, FILE *F)
{
	uint8_t ch;
	HAL_UART_Receive(&huart1 ,(uint8_t *)&ch,1,HAL_MAX_DELAY );
	return ch;
}

stm32串口接收不定长数据,stm32,单片机,嵌入式硬件,mcu

在工程的任意位置添加串口接收事件服务函数(我这里添加在了/* USER CODE BEGIN 4 */的后面)

void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size)
{
	if(huart == &huart1)
	{
		//获取帧长
		usart1_data_len = 1024 - huart->hdmarx->Instance->NDTR;
		
		sscanf(usart1_rx_buf,"N%dM%d",&test1,&test2);
		
		HAL_UART_Transmit(&huart1,usart1_rx_buf,usart1_data_len,100);
		
		printf("%d,%d\r\n",test1,test2);
		
		//使dma从头存数据
		huart->hdmarx->Instance -> NDTR =  1024;
		//重新打开dma接收,ILDE中断
		HAL_UARTEx_ReceiveToIdle_DMA(&huart1,usart1_rx_buf,1024);
	}
}

stm32串口接收不定长数据,stm32,单片机,嵌入式硬件,mcu
在主函数的while(1)之前加上一句话

HAL_UARTEx_ReceiveToIdle_DMA(&huart1,usart1_rx_buf,1024);

这句话是串口接收数据直至IDLE事件,记得定义usart1_rx_buf作为串口接收数据缓冲区,第三个参数是你定义的接收缓冲区的大小,建议用宏定义,我这里为了演示就懒得用宏定义了XD.

这样就程序就编写完成啦,目前的程序作用是:串口使用DMA接收数据至IDLE事件,当IDLE事件发生时进入中断服务函数对数据进行处理。

细心的小伙伴应该已经发现中断服务函数中不仅有一个

HAL_UART_Transmit(&huart1,usart1_rx_buf,usart1_data_len,100);

将接收的数据从新发送,还有一个

sscanf(usart1_rx_buf,“N%dM%d”,&test1,&test2);

用于按格式提取数据,当发送端是使用print来发送数据的,那么它每个字节都是用ASCII编码的,例如对方printf(“%d”,123)的时候,发送的数据为0X31 0X32 0X33,这就对我们接收端分析数据包时产生了障碍。

因此我们可以使用stdio.h中的sscanf函数对数据包按照格式提取数据

例如我这里格式为:“N%dM%d”
则发送端按照这个格式发送数据的话,我就可以把这两个%d位置的整数提取出来

所以以上代码的实际效果be like:
stm32串口接收不定长数据,stm32,单片机,嵌入式硬件,mcu

总结&扩展

总的来说,大致思路就是,打开USART1的中断,打开USART1的DMA接收请求,让DMA一个个字节搬运数据到内存中,然后在检测串口空闲,当串口空闲时,代表发送端发送完毕,则进入中断服务函数中处理数据包

看起来是不是很优雅?
但是这还是有部分不是很优雅的地方,例如:
当发送端因某些原因发送数据的速度较慢,使得每发送一个字节之间时间间隔较大,而在字节之间出现空闲,则目前这个方法就不适用,会出bug,大家可以自己想想为什么会出bug,这里就不过多赘述。

而有了这个方法,爱动脑子的小伙伴应该发现了这个方法的一个新用途。
既然可以按照格式发送接收数据,那么在两个单片机之间,用串口收发浮点数将不再是难事。

例如可以将中断服务函数改为:
stm32串口接收不定长数据,stm32,单片机,嵌入式硬件,mcu

void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size)
{
	if(huart == &huart1)
	{
		//获取帧长
		usart1_data_len = 1024 - huart->hdmarx->Instance->NDTR;
		sscanf(usart1_rx_buf,"N%fM%f",&test1,&test2);
		HAL_UART_Transmit(&huart1,usart1_rx_buf,usart1_data_len,100);
		printf("%.2f,%.2f\r\n",test1,test2);
		//使dma从头存数据
		huart->hdmarx->Instance -> NDTR =  1024;
		//重新打开dma接收,ILDE中断
		HAL_UARTEx_ReceiveToIdle_DMA(&huart1,usart1_rx_buf,1024);
	}
}

则在发送端和接收端之间则可以直接使用printf函数来实现浮点数的收发,而再也不需要将浮点数拆成一个个字节发送,然后再在接收端将数据拼起来了

效果be like:
stm32串口接收不定长数据,stm32,单片机,嵌入式硬件,mcu

好啦,此贴到这里就结束啦,希望各位能开发出更优雅的串口收发的方式,该贴为博主第一次写文章,若是有任何问题欢迎讨论 😄文章来源地址https://www.toymoban.com/news/detail-757460.html

到了这里,关于极度优雅的用stm32串口接收并分析不定长数据的方法(可用于发送和接收浮点数)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • STM32 串口接收不定长数据 HAL_UART_Receive_IT (帧头帧尾)

    最近使用sw4stm32调试串口时发现串口接收不定长数据很不方便,这里是帧头帧尾的接收方式,欢迎大佬指导。 这里要用串口中断接收的数据帧帧头为0xEB,帧尾为0XBE 这里是其中定义的变量  主函数里打开串口接收中断 然后串口接收处理部分全都写在的回调函数中。

    2024年01月19日
    浏览(46)
  • 【STM32】CUBEMX之串口:串口三种模式(轮询模式、中断模式、DMA模式)的配置与使用示例 + 串口重定向 + 使用HAL扩展函数实现不定长数据接收

    目录   总览 使用CUBEMX创建工程的基本配置 CUBEMX中的配置 Keil中的配置 实物连接 串口轮询模式 轮询模式HAL库函数 特点 实验一:发送数据给单片机并让其返回相同值 串口重定向 串口中断模式 在CUBEMX中打开串口中断 中断模式HAL库函数 特点 实验二:使用中断回调完成实验一

    2024年04月10日
    浏览(75)
  • STM32 cubemx配置DMA+空闲中断接收不定长数据

    本篇文章给大家讲解一下DMA+串口空闲中断接收串口不定长数据,之前我们也是讲解过串口接收不定长数据的,那么本篇文章的话将使用DMA来接收不定长数据。 串口空闲中断是指在串口接收到数据后,在数据的传输结束之后,在一段连续的空闲时间内没有接收到新数据时触发

    2024年02月19日
    浏览(56)
  • STM32_HAL库串口接收相关函数分析

    串口接收的程序整体分为三个部分:初始化部分,开启中断部分,中断函数部分: 初始化部分: 该部分主要完成相关引脚的初始化,串口的初始化(设置波特率,校验位,字长等),为了逻辑清晰,把初始化相关代码放在本文的最后。 开启中断部分: 调用HAL_UART_Receive_IT函数

    2024年02月16日
    浏览(42)
  • STM32F407普通IO口模拟串口实现不定长数据收发

    因为项目中用到的串口比较多,STM32F407VET6自带的串口不够用了,所以只能考虑用模拟串口来实现功能。普通的IO口来模拟串口需要先了解串口的时序图,需要用到两个IO引脚即收发引脚,两个定时器,一个用于发送延时使用,一个用于产生中断接收数据。代码的初始化主要用

    2024年02月07日
    浏览(49)
  • STM32 串口DMA接收数据(高效接收数据)

    极度不推荐在使用DMA的时候按照传统的方式进行重定义!!! 非常简单,轮询方式整个CPU 在串口发送时处于等待状态,但是使用DMA时无法确保当前DMA已经传输完成。 有同学可能会认为可以通过判断DMA的传输标志位来进行等待,但如果这样的话就丧失了DMA的设计意图: 再次使

    2024年02月16日
    浏览(52)
  • stm32串口空闲中断+DMA传输接受不定长数据+letter shell 实现命令行

    空闲中断(IDLE),俗称帧中断,即第一帧数据接收完毕到第二帧数据开始接收期间存在一个空闲状态(每接收一帧数据后空闲标志位置1),检测到此空闲状态后即执行中断程序。 空闲中断的优点在于省去了帧头帧尾的检测 ,进入中断程序即意味着已经接收到一组完整数据,仅需

    2024年02月03日
    浏览(60)
  • STM-32:USART串口协议、串口外设—数据发送/数据发送+接收

    通信的目的:将一个设备的数据传送到另一个设备,扩展硬件系统。比如STM32芯片里面集成了很多功能模块,如定时器计数、PWM输出、AD采集等等,这些都是芯片内部的电路,它们的配置寄存器、数据寄存器都在芯片里面,操作简单,直接读写就行。但是有些功能STM32内部没有

    2024年02月04日
    浏览(65)
  • STM32实现DMA接收串口数据

    一..首先我们得配置DMA和USARAT,我们的原理是DMA1的通道5为USART1的RX引脚。  1.USART1的配置 2.DMA的配置 二.中断进行数据处理(stm32f10x_it.c) 我们可以串口打印出数组中的数据,验证DMA是否正常工作。可以到数据处理那个地方进行处理。USART1在初始化中就已经波特率为115200.我们可以

    2024年02月16日
    浏览(47)
  • GD32F4单片机实现接收超时中断+DMA实现串口的不定长接收和DMA发送

    环形缓冲区+定时器超时中断的方式 优点 环形缓冲区可以接收多帧数据 数据帧超时间隔可以设置 缺点 设备任务比较繁重时,使用中断接收可能会丢失数据。尤其是在长时间关闭中断或者串口中断优先级不高时 频繁进出中断。在使用RTOS的系统中,每收到一个数据就会进行一

    2024年02月15日
    浏览(63)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包