HAL库教程6:串口数据接收_hal_uart_receive-程序员宅基地

技术标签: HAL库  STM32  教程  

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

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/geek_monkey/article/details/89165040

智能推荐

前端开发之vue-grid-layout的使用和实例-程序员宅基地

文章浏览阅读1.1w次,点赞7次,收藏34次。vue-grid-layout的使用、实例、遇到的问题和解决方案_vue-grid-layout

Power Apps-上传附件控件_powerapps点击按钮上传附件-程序员宅基地

文章浏览阅读218次。然后连接一个数据源,就会在下面自动产生一个添加附件的组件。把这个控件复制粘贴到页面里,就可以单独使用来上传了。插入一个“编辑”窗体。_powerapps点击按钮上传附件

C++ 面向对象(Object-Oriented)的特征 & 构造函数& 析构函数_"object(cnofd[\"ofdrender\"])十条"-程序员宅基地

文章浏览阅读264次。(1) Abstraction (抽象)(2) Polymorphism (多态)(3) Inheritance (继承)(4) Encapsulation (封装)_"object(cnofd[\"ofdrender\"])十条"

修改node_modules源码,并保存,使用patch-package打补丁,git提交代码后,所有人可以用到修改后的_修改 node_modules-程序员宅基地

文章浏览阅读133次。删除node_modules,重新npm install看是否成功。在 package.json 文件中的 scripts 中加入。修改你的第三方库的bug等。然后目录会多出一个目录文件。_修改 node_modules

【】kali--password:su的 Authentication failure问题,&sudo passwd root输入密码时Sorry, try again._password: su: authentication failure-程序员宅基地

文章浏览阅读883次。【代码】【】kali--password:su的 Authentication failure问题,&sudo passwd root输入密码时Sorry, try again._password: su: authentication failure

整理5个优秀的微信小程序开源项目_微信小程序开源模板-程序员宅基地

文章浏览阅读1w次,点赞13次,收藏97次。整理5个优秀的微信小程序开源项目。收集了微信小程序开发过程中会使用到的资料、问题以及第三方组件库。_微信小程序开源模板

随便推点

Centos7最简搭建NFS服务器_centos7 搭建nfs server-程序员宅基地

文章浏览阅读128次。Centos7最简搭建NFS服务器_centos7 搭建nfs server

Springboot整合Mybatis-Plus使用总结(mybatis 坑补充)_mybaitis-plus ruledataobjectattributemapper' and '-程序员宅基地

文章浏览阅读1.2k次,点赞2次,收藏3次。前言mybatis在持久层框架中还是比较火的,一般项目都是基于ssm。虽然mybatis可以直接在xml中通过SQL语句操作数据库,很是灵活。但正其操作都要通过SQL语句进行,就必须写大量的xml文件,很是麻烦。mybatis-plus就很好的解决了这个问题。..._mybaitis-plus ruledataobjectattributemapper' and 'com.picc.rule.management.d

EECE 1080C / Programming for ECESummer 2022 Laboratory 4: Global Functions Practice_eece1080c-程序员宅基地

文章浏览阅读325次。EECE 1080C / Programming for ECESummer 2022Laboratory 4: Global Functions PracticePlagiarism will not be tolerated:Topics covered:function creation and call statements (emphasis on global functions)Objective:To practice program development b_eece1080c

洛谷p4777 【模板】扩展中国剩余定理-程序员宅基地

文章浏览阅读53次。被同机房早就1年前就学过的东西我现在才学,wtcl。设要求的数为\(x\)。设当前处理到第\(k\)个同余式,设\(M = LCM ^ {k - 1} _ {i - 1}\) ,前\(k - 1\)个的通解就是\(x + i * M\)。那么其实第\(k\)个来说,其实就是求一个\(y\)使得\(x + y * M ≡ a_k(mod b_k)\)转化一下就是\(y * M ...

android 退出应用没有走ondestory方法,[Android基础论]为何Activity退出之后,系统没有调用onDestroy方法?...-程序员宅基地

文章浏览阅读1.3k次。首先,问题是如何出现的?晚上复查代码,发现一个activity没有调用自己的ondestroy方法我表示非常的费解,于是我检查了下代码。发现再finish代码之后接了如下代码finish();System.exit(0);//这就是罪魁祸首为什么这样写会出现问题System.exit(0);////看一下函数的原型public static void exit (int code)//Added ..._android 手动杀死app,activity不执行ondestroy

SylixOS快问快答_select函数 导致堆栈溢出 sylixos-程序员宅基地

文章浏览阅读894次。Q: SylixOS 版权是什么形式, 是否分为<开发版税>和<运行时版税>.A: SylixOS 是开源并免费的操作系统, 支持 BSD/GPL 协议(GPL 版本暂未确定). 没有任何的运行时版税. 您可以用她来做任何 您喜欢做的项目. 也可以修改 SylixOS 的源代码, 不需要支付任何费用. 当然笔者希望您可以将使用 SylixOS 开发的项目 (不需要开源)或对 SylixOS 源码的修改及时告知笔者.需要指出: SylixOS 本身仅是笔者用来提升自己水平而开发的_select函数 导致堆栈溢出 sylixos

推荐文章

热门文章

相关标签