STM32的串口接收机制

  与阻塞式发送函数HAL_UART_Transmit配套,有个阻塞式的接收函数,HAL_UART_Receive,但此函数不常用,串口接收通常使用中断函数HAL_UART_Receive_IT。HAL库的串口中断比较复杂,主要流程如下:

  USART1_IRQHandler:由硬件调用,不是HAL库函数,寄存器编程或固件库编程也需要调用此函数;
  HAL_UART_IRQHandler:通过中断类型(发送中断还是接收中断)来判断调用哪个函数;
  UART_Receive_IT:此函数可以指定,每收到若干个数据,调用一次回调函数;这是因为,每收到一个字节,都会把此函数的接收计数器-1,如果接收计数器为零,调用串口接收回调函数HAL_UART_RxCpltCallback(实际上HAL库一共提供了5个回调函数,只有这个函数在接收完成时调用)。
  HAL_UART_RxCpltCallback:弱函数,用户可以在此函数中编写业务逻辑。清除中断标记,是中断处理函数一定要做的事情,但是对于用户函数,把这个操作给隐藏了

使能串口接收中断

  由于串口不方便传参数,所以我通常会定义一些用于串口通信的全局变量。也可以模仿库函数,把这些变量打包成一个结构体。

//UART.c
unsigned char UART1_Rx_Buf[MAX_REC_LENGTH] = {0}; //USART1存储接收数据
unsigned char UART1_Rx_flg = 0;                   //USART1接收完成标志
unsigned int  UART1_Rx_cnt = 0;                   //USART1接受数据计数器
unsigned char UART1_temp[REC_LENGTH] = {0};       //USART1接收数据缓存

  由于这些变量也要在main.c文件中使用,跨文件使用,可以在头文件中做外部声明:

#ifndef __UART_H
#define __UART_H#ifdef __cplusplus
extern "C" {#endif#define REC_LENGTH  1
#define MAX_REC_LENGTH  1024 extern unsigned char UART1_Rx_Buf[MAX_REC_LENGTH];
extern unsigned char UART1_Rx_flg ;
extern unsigned int  UART1_Rx_cnt ;
extern unsigned char UART1_temp[REC_LENGTH];#ifdef __cplusplus
}
#endif#endif 

  要使用中断来接收串口数据,则必须开启中断。并且,每次处理完串口接收中断以后,会自动关闭中断,如果想循环接收数据,则必须在处理完中断以后,再次开启中断。
  我们希望完成初始化以后就开始接收串口数据,所以要修改串口初始化函数。

//main.c
static void MX_USART1_UART_Init(void)
{/* USER CODE BEGIN USART1_Init 2 */HAL_UART_Receive_IT(&huart1,(uint8_t *)UART1_temp,REC_LENGTH);/* USER CODE END USART1_Init 2 */
}

串口接收中断函数处理

  程序的逻辑:

  如果接收到了指定数量的串口数据(在本例中,指定的数量是1字节),则会执行回调函数HAL_UART_RxCpltCallback。此函数是个弱函数,用户可以根据业务逻辑来“重载”。我们要在此函数中,把串口收到的数据打包,并判断结束符判断数据结束。我们规定,只发送ASCII码,并以0x0a作为结束符。

//UART.c
/*** @brief 串口中断回调函数* @param 调用回调函数的串口* @note  串口每次收到数据以后都会关闭中断,如需重复使用,必须再次开启* @retval None*/
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{if(huart->Instance==USART1){UART1_Rx_Buf[UART1_Rx_cnt] = UART1_temp[0];UART1_Rx_cnt++;if(0x0a == UART1_temp[0]){UART1_Rx_flg = 1;}HAL_UART_Receive_IT(&huart1,(uint8_t *)UART1_temp,REC_LENGTH);}
}

  主函数中,实现“串口应声虫”的功能,收到什么就发送什么。如果串口数据接收完成,则发送出去然后把数组,计数器,标志都恢复初始状态。

//main() while(1)if(UART1_Rx_flg){HAL_UART_Transmit(&huart1,UART1_Rx_Buf,UART1_Rx_cnt,0x10);    //发送接收到的数据for(int i = 0;i<UART1_Rx_cnt;i++)UART1_Rx_Buf[i] = 0;UART1_Rx_cnt = 0;UART1_Rx_flg = 0;}   

  现象:向串口发送ASCII码,单片机收到什么数据,就返回什么数据。注意,发送给串口的数据结尾要有回车键。

数据阶段的方法与ASCII码

  一组数据怎么判断是否结束?
  2种方法:
  1特定时间,特定的时间内没有收到新的数据,认为这一组数据就结束了。这种方法在定时器的章节来实现。
  2特定字符,通信双方约定,用特定的字符作为结束,比如把0xff作为结束符。收到0xff就把数据截断。就像我们演讲,最后说一句谢谢大家,下边的人就知道了你讲完了,该鼓掌了。谢谢就是结束符。
  但是这种做法有一个弊端,就是正常通信的数据不允许在使用0xff。
  对于ASCII码,正常情况下是不会发送0x0d与0x0a(回车与换行)的,所以可以用作结束符。
  ASCII(American Standard Code for Information Interchange,美国信息交换标准代码)是基于拉丁字母的一套电脑编码系统,主要用于显示现代英语和其他西欧语言。它是现今最通用的系统,并等同于国际标准ISO/IEC 646。
  ASCII码主要用于英文字符的显示,不包含中文。标准ASCII码只有7位(最高位是校验位),所以只能显示2^7=128个字符,其中0-31还是不能显示的字符,例如回车,作用是控制字符或通信字符。

  假如,发送的数据是0x31,它可能代表着十六进制的数字0x31,也可能表示十进制的数字49(十六进制与十进制虽然看上去不一样,但表示的数是同样的大小),还可能表示ASCII码,字符’1’。这三者,在传输线上使用示波器来观察,波形是一模一样的,接收方把它理解为0x31还是理解为字符,要看通信双方的约定。

2020年11月27日更新

有读者反馈不好用,这段代码是经过测试,确认可用的,附上源码如下,供参考
https://download.csdn.net/download/geek_monkey/13195359
另外,此串口数据需要结束符,后续文章中有更好的方法,定时器截断,文章地址是:
https://yatao.blog.csdn.net/article/details/89326199

HAL库教程6:串口数据接收相关推荐

  1. 基于CUBEMX和STM32C8T6的同轴麦轮小车制作(二)——HAL库接受jy61p陀螺仪数据,并解决数据溢出卡死问题。

    基于CUBEMX和STM32C8T6的同轴麦轮小车制作(二)--HAL库接受jy61p陀螺仪数据,并解决数据溢出卡死问题 本文利用STM32C8T6中的串口1于JY61P实时通信,并用串口2将其角度打 ...

  2. STM32CubeMX基于HAL库实现简单串口通信

    STM32CubeMX基于HAL库实现简单串口通信 板子:STM32F103C8 编译工具:Keil+STM32CubeMX 烧录工具:FlyMcu 串口调试程序:XCOM 实验要求: 1)设置波特率 ...

  3. stm32使用hal库向电脑发送数据

    文章目录 USART 几种协议(可跳过) 实验目的与材料 实验目的 实验材料 软件 硬件连接 HAL库项目创建 1.点击ACCESS TO MCU SELECTOR 2.选择芯片类型 3.可视化配置U ...

  4. 【Qt串口调试助手】1.2 - 串口数据接收不发生换行,CH340 / CP2102 多硬件兼容

    上一篇提到:对串口接收的显示,使用的是当前位置插入+移动鼠标光标到末尾的方式.这种方法可以有效解决 串口数据接收发生换行的问题,并且解决 CH340 / CP2102 多硬件显示结果不一致的问题.那有 ...

  5. 串口数据实时处理:定时器+串口 判断串口数据接收完成

    使用背景: 之前在做项目的时候,串口接收的数据要及时进行处理,虽然采用了自定义的串口协议,但是协议的包尾只有一个字节,经常判断不准数据是否接受完毕,所以就采用计时器+串口的方式来判定串口是否接受完成. ...

  6. STM32G070RBT6基于Arduino框架下串口数据接收使用示例

    STM32G070RBT6基于Arduino框架下串口数据接收使用示例 相关篇<STM32G070RBT6基于Arduino串口的使用>

  7. STM32F407霸天虎HAL库学习笔记——串口发送

    STM32F407霸天虎HAL库学习笔记--串口收发 一.软件准备 二.硬件准备 三.CubeMX配置 四.Keil printf重写 main函数 五.实验效果 一.软件准备 软件准备 二.硬件准备 ...

  8. STM32从零到一,从标准库移植到HAL库,UART串口1以DMA模式收发不定长数据代码详解+常见问题 一文解析

    前言 本文的参考资料 感谢提供标准库版本的CSDN同学:这两篇文章至少是我看过的最详细的标准库配置DMA版本.而且代码实测稳定能用. STM32 | DMA配置和使用如此简单(超详细)_...| .. ...

  9. 用STM32F407ZET6的HAL库写一个串口接收,发送代码,支持ringbuff

    你可以参考这个示例代码:https://www.st.com/content/ccc/resource/technical/document/application_note/group0/b5/d4 ...

最新文章

  1. Spring Boot 2.4.5、2.3.10 发布
  2. python定时器 是线程吗_python线程定时器Timer(32)
  3. wpf 在另一个窗体上显示_另一个唐伯虎:大街上裸身奔跑、锒铛入狱多次自裁未遂...
  4. 前端面试题(附上自己的回答)
  5. Windows下,使用dumpcpp 方式访问 COM 接口的方法
  6. 基于插件架构的简单的Winform框架(下)
  7. android学习笔记---1.为应用添加新的Activity,中使用Intent(意图),结果码,请求码,得到新打开Activity 关闭后返回的数据,Bundle类的作用
  8. rhel5 下cacti安装日志
  9. miui12怎么自定义开机动画_MIUI12相机特色功能须知,新增魔法分身与相机上滑启动更多模式...
  10. MySQL数据库餐厅点菜系统_Java实现餐厅点餐系统的实例代码
  11. ubuntu 下WebStorm 无法输入中文
  12. springboot 打卡功能_SpringBoot、SSM、ajax实现考勤打卡功能(详细实现),供新手参考!...
  13. 2009年03月《安全天下事之希望与忧伤》
  14. android studio耗电量检测,[腾讯 TMQ] Android 场景化性能测试专栏之 CPU 耗电性能篇...
  15. Pr 入门教程:如何更改素材属性?
  16. cuda的Pinned Memory(分页锁定内存)
  17. 怎么旋转PDF页面方向?可以只旋转一页吗
  18. CRM项目第一天(2021-12-16)1
  19. 模线性方程ax≡b(mod n) (再结合 程序理解)
  20. Mybatis-Spring源码分析(五) MapperMethod和MappedStatement解析

热门文章

  1. 罗技推出“语音鼠标”,隐藏着百度AI的产业化范式
  2. python编程培训杭州
  3. Java truelicense 实现License授权许可和验证
  4. kettle-新建资源库connect资源库灰色解决
  5. 谷歌手机正式发布 售价179美元(图)
  6. 搭建自己的在线IDE
  7. java的db是什么_java db
  8. mysql的dba是什么_mysql dba是什么意思?
  9. 一步一步实现微信抢红包
  10. 健康生活无需等待,松下罗密欧系列洗衣机守护你的四月天