STM32的HAL库串口编程

2023-05-16

1、需求

1、收到数据,放入缓存
2、取出数据进行协议解析

2、问题

HAL库的接收函数,指定接收固定数长的数据。

//中断方式接收
HAL_StatusTypeDef HAL_UART_Receive_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size);
//非中断方式接收
HAL_StatusTypeDef HAL_UART_Receive(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size, uint32_t Timeout);

按照常规思维,我们会有以下几个问题。
1、是不是一直要在主循环里面去调用这个函数,以免漏掉数据。
2、如果我的数据不是定长的,我该如何来接收这些数据呢?

3、解决

3.1、以前的解决方法

放在以前呢,我们是重写了HAL库的中断接收函数,直接在里面对DR寄存器进行操作,然后放在自己的缓冲区,相当于回到了以前非HAL库的那种操作方式。这种解决方式并没有什么不好,甚至会提升代码运行效率。但是这种方式,HAL库的优势并没有发挥出来,程序的一致性也没有得到体现。甚至在每一次cubeMX重新生成代码后,还需要手动去修改中断函数。
下面是以前我们团队大牛重写的中断接收函数。

/**
  * @brief 	void Uart_Fifo_IRQHandler(UART_HandleTypeDef *huart)
	* @auther MSA
	* @param 	UART_HandleTypeDef *huart
	
	* @note	 	使用Uart_Fifo时的中断处理函数
	* @note		注意参考hal库HAL_UART_IRQHandler函数中关于错误标志的处理
  */
uint8_t uc_ore_cnt = 0;  //test
void Uart_Fifo_IRQHandler(UART_FIFO_Typedef *st_uart_fifo_tx_p, UART_FIFO_Typedef *st_uart_fifo_rx_p)
{
	//错误处理,
	//errorflags = (isrflags & (uint32_t)(USART_ISR_PE | USART_ISR_FE | USART_ISR_ORE | USART_ISR_NE));
	//以上错误标志中ORE和FE在EIE使能的时候会产生中断,不清楚会一直进入中断
	//错误中断标志使能位是EIE,不知道hal库的初始化是否会使能该中断,应该不会
  
  //RXNE中断或者EIE中断使能后,ORE中断自动使能
  if( (__HAL_UART_GET_IT(st_uart_fifo_tx_p->st_uart_handle_p, UART_IT_ORE) != RESET)&&
      ((__HAL_UART_GET_IT_SOURCE(st_uart_fifo_tx_p->st_uart_handle_p, UART_IT_RXNE) != RESET)||(__HAL_UART_GET_IT_SOURCE(st_uart_fifo_tx_p->st_uart_handle_p, UART_IT_ERR) != RESET))
    )
  {
    uc_ore_cnt++;
    __HAL_UART_CLEAR_IT(st_uart_fifo_tx_p->st_uart_handle_p, UART_CLEAR_OREF);
  }
	
	//发送中断的处理
	if((__HAL_UART_GET_IT(st_uart_fifo_tx_p->st_uart_handle_p, UART_IT_TXE) != RESET) && (__HAL_UART_GET_IT_SOURCE(st_uart_fifo_tx_p->st_uart_handle_p, UART_IT_TXE) != RESET))
   {     
	  	if(st_uart_fifo_tx_p->uw_fifo_cnt)
	  	{
		 		--(st_uart_fifo_tx_p->uw_fifo_cnt);
				st_uart_fifo_tx_p->st_uart_handle_p->Instance->TDR = *(st_uart_fifo_tx_p->uc_fifo_addr_p + st_uart_fifo_tx_p->uw_fifo_read_index);		
		 		if(++(st_uart_fifo_tx_p->uw_fifo_read_index) >= st_uart_fifo_tx_p->uw_fifo_size)
				{
		   		  st_uart_fifo_tx_p->uw_fifo_read_index = 0;
				}
	  	}
			
			if(st_uart_fifo_tx_p->uw_fifo_cnt == 0)
			{
				/* Disable the UART Transmit Data Register Empty Interrupt */
				__HAL_UART_DISABLE_IT(st_uart_fifo_tx_p->st_uart_handle_p, UART_IT_TXE);
			}
   } 
	 
	 
	//接收中断处理
	uint8_t ucData;
	if((__HAL_UART_GET_IT(st_uart_fifo_rx_p->st_uart_handle_p, UART_IT_RXNE) != RESET) && (__HAL_UART_GET_IT_SOURCE(st_uart_fifo_rx_p->st_uart_handle_p, UART_IT_RXNE) != RESET))
  {
		ucData = (uint8_t)(st_uart_fifo_rx_p->st_uart_handle_p->Instance->RDR&0x01FF);
			
	  if(((st_uart_fifo_rx_p->st_uart_handle_p->Instance->ISR) & 0x0000) == 0)//无错误
	  {
	    /*buf满了则清除缓冲区*/
			if(++(st_uart_fifo_rx_p->uw_fifo_cnt) > st_uart_fifo_rx_p->uw_fifo_size)  
			{
//		   			st_uart_fifo_rx_p->uw_fifo_cnt = st_uart_fifo_rx_p->uw_fifo_size;   //test
				st_uart_fifo_rx_p->uw_fifo_cnt = 0;  //test
				st_uart_fifo_rx_p->uw_fifo_write_index = st_uart_fifo_rx_p->uw_fifo_read_index;
		   	st_uart_fifo_rx_p->uc_fifo_overflow = 1;
			}
			else
			{
                //增加一个接受回调函数       
				*(st_uart_fifo_rx_p->uc_fifo_addr_p + st_uart_fifo_rx_p->uw_fifo_write_index) = ucData;     

                
				if(++(st_uart_fifo_rx_p->uw_fifo_write_index) >= st_uart_fifo_rx_p->uw_fifo_size)
				{
					st_uart_fifo_rx_p->uw_fifo_write_index = 0; 
				}	
			}	
                
	  }//接收到数据
      MSA_UART_RxCpltCallback(ucData, st_uart_fifo_rx_p);
  }
}

3.2、新的解决方法

一次项目机会,重新审视了以前的操作方式,觉得应该是有比较好的解决方案的。于是出现了下面这种方法。好处有以下几点。
1、不需要修改HAL库的基础函数
2、系统可移植性提高
3、不需要去研究寄存器,去判断串口接收错误

这种方式,是利用hal库的接收完成回调函数,当串口数据接收完成后会进入回调函数,我们只需要完善回调函数,就可以了。回调函数是个弱函数,类似于C++里面的虚函数。主要方法如下
1、利用HAL库中断接收方法接收一个数据。当这个数据接收完成后,会进入回调函数。

HAL_UART_Receive_IT(&huart1, &aRxBuffer, 1);

2、在回调函数里面,处理完数据后,重新调用上面这条语句。这样,只要有数据进来,中断就不停的接收数据,并放入自己定义的缓冲区。

//测试版本,没有判断是哪个串口收到的数据
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
			if(++(st_uart1_rx_fifo.uw_fifo_cnt) > st_uart1_rx_fifo.uw_fifo_size)  
			{
		   			st_uart1_rx_fifo.uw_fifo_cnt = st_uart1_rx_fifo.uw_fifo_size;   //test
				st_uart1_rx_fifo.uw_fifo_cnt = 0;  //test
				st_uart1_rx_fifo.uw_fifo_write_index = st_uart1_rx_fifo.uw_fifo_read_index;
		   	st_uart1_rx_fifo.uc_fifo_overflow = 1;
			}
			else
			{
                //增加一个接受回调函数       
				*(st_uart1_rx_fifo.uc_fifo_addr_p + st_uart1_rx_fifo.uw_fifo_write_index) = aRxBuffer;     
     
				if(++(st_uart1_rx_fifo.uw_fifo_write_index) >= st_uart1_rx_fifo.uw_fifo_size)
				{
					st_uart1_rx_fifo.uw_fifo_write_index = 0; 
				}	
			}	
	HAL_UART_Receive_IT(&huart1, &aRxBuffer, 1);
}

4、总结

接收一个字节,然后利用接收完成回调函数,在回调函数里面处理完对应的数据后,继续接收一个字节。如此往复。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

STM32的HAL库串口编程 的相关文章

随机推荐

  • Python 端口扫描器

    目录 前言一 TCP全连接二 程序编写1 获得主机名和端口2 解析主机名和端口3 抓取应用的Banner4 线程扫描5 信号量机制 总结 前言 任何一个靠谱的网络攻击都是起步于侦查的 在这里 xff0c 我们将使用Python来编写一个扫描
  • Windows+VS+OpenCV(多版本)环境配置

    Index 目录索引 写在前面1 OpenCV 的安装2 OpenCV 在 VS 中的配置配置方法一配置方法二 3 不同 OpenCV 版本的切换附录 查看OpenCV 版本的代码 写在前面 本篇文章记录如何安装OpenCV xff0c 以
  • 使用双天线G-RTK+Ardupilot小车完成厘米精度自动导航 pixhawk px4

    作为多年使用PIXHAWK的玩家 xff0c 相信大家或多或少被磁罗盘报错折磨过 由于磁非常容易受周围环境的干扰和自身结构的金属部分干扰 经常我们今天校准好的罗盘 xff0c 什么也没动 xff0c 明天上电发现罗盘报错 对于330 450
  • Cmake基础知识讲解

    本文主要参考https www cnblogs com cv pr p 6206921 html 1 CMake编译原理 CMake是一种跨平台编译工具 xff0c 比make更为高级 xff0c 使用起来要方便得多 CMake主要是编写C
  • 基于opencv的ArUco的视觉定位之ArUco安装

    小编之前在前面的文章里是通过安装opencv 43 contirb来实现使用aruco xff0c 但在进行aruco的源码学习时 xff0c 发现不少类contirb里库是没有的 xff0c 于是不得不再装一个独立的aruco的库 xff
  • 使用opencv的aruco库进行位姿估计

    1 姿态估计在许多计算机视觉应用中非常重要 xff1a 机器人导航 xff0c 增强现实等等 该过程基于查找真实环境中的点与其2D图像投影之间的对应关系 这通常是一个困难的步骤 xff0c 因此通常使用合成或基准标记使其更容易 最流行的方法
  • linux centos 命令行 安装 teamviewers ___yyw合并版

    参考 xff1a 1 http blog csdn net changgongzhao article details 52299314 2 http blog csdn net dreamhai article details 57080
  • aruco字典如DICT_4X4_50含义

    其中DICT是dictionary的缩写 xff0c 4x4位表示marker标记要被划分的位数 xff0c 边界为1比特位 xff0c 所以4x4的marker识别时会被分割为6x6格 xff0c 如下图时6x6的 最下面的个数时字典里包
  • 单片机如何发出类似和弦的声音

    蜂鸣器声音优化 1 优化思路 蜂鸣器的控制 xff0c 在单片机领域 xff0c 大多数人都是给一定周期的脉冲 xff0c 蜂鸣器就会发出声音 xff0c 而本质上 xff0c 蜂鸣器只是一个金属弹片 xff0c 声音大小取决于弹片的幅值
  • 3年5年10年的嵌入式工程师,他们的区别在哪里

    嵌入式工程师与嵌入式工程师的区别在哪里 1 维度1 1 基础知识1 2 项目心态1 3 技术架构1 4 技术视野1 5 成熟方案1 6 一通百通1 7 选型能力1 8 其他能力 2 还有其他要说的 做过很多项目 xff0c 招了一些人 xf
  • 陀螺稳定云台控制流程图

    陀螺稳定云台控制流程图 控制流程图 手持云台控制流程图 xff0c 主要是一个串级PID xff0c 位置环和速度环 xff0c 当然了FOC电流环 xff0c 不在这个流程里 xff0c 位置环100HZ xff0c 速度环500HZ x
  • 电机的力矩计算

    1 转动惯量的公式 1 1 转矩如何计算 转矩等于转动惯量乘以角加速度 xff0c 然后我们要注意一下单位 xff0c 转矩的单位是NM 转动惯量的单位是kg m2 角加速度单位是rad s2 M 61 I B M是转矩 xff0c I 是
  • 电流采样运放参数

    关于运放参数 在我们做电流采样的时候 xff0c 压摆率这个参数很重要 xff0c 如果压摆率太小 xff0c 跟不上电流的变化带来的电压变化 xff0c 那么我们采样就不会准确 xff0c 在FOC算法里面 xff0c 一个完美的正弦波采
  • ICM42688初始化流程

    ICM42688初始化流程 1 陀螺仪复位 2 设置量程 3 关闭FIFO 4 关闭同步时钟 5 配置时间戳 xff0c 打开fifo 6 设置INTI引脚引脚属性为推挽及设置有效极性为高电平 7 配置中断 8 中断异步复位 9 配置陀螺和
  • FOC控制之小A小B小C是如何追求小D的

    1 写在前面 随着电动汽车的热火 xff0c 关于FOC控制技术的文章这几年在网络上可谓是一搜一大把 xff0c 各种理论分析 xff0c 公式推导 xff0c 应有尽有 通过这些文章 xff0c 可以看出大佬还是很多的 另外也有FOC的开
  • 手把手教你调试Pixhawk垂直起降参数

    Pixhawk垂直起降参数 1 写在前面 本来想写个垂直起降手把手教你调试的 xff0c 由于作者也没有太多的时间给大家拍照并现场调试 xff0c 鉴于很多朋友问我里面的参数问题 xff0c 干脆写点东西算了 2 参数列表及解释 VT AR
  • 三分钟教你玩转cubeMX+USB+FATFS+FREERTOS

    1 真的只要三分钟吗 xff1f 可能还不要 xff0c cubeMX的强大 xff0c 你想都想不到 话不多说 xff0c 直接开始 2 配置过程 配置时钟源 配置USB 配置FATFS 配置FREERTOS xff0c 与其说是配置 x
  • 数据清洗总结

  • keil里面while循环条件已经为假了,可是跳不出去的问题

    1 背景 笔者把公司里面很古老的一套程序从IAR的编译环境移植到KEIL环境下 xff0c 启动文件等问题全部都解决了 xff0c 能正常编译了 但是卡在了一个while xff08 send flag xff09 的一个循环里面 send
  • STM32的HAL库串口编程

    1 需求 1 收到数据 xff0c 放入缓存 2 取出数据进行协议解析 2 问题 HAL库的接收函数 xff0c 指定接收固定数长的数据 中断方式接收 HAL StatusTypeDef HAL UART Receive IT UART H