[STM32系列]一、HAL库的串口中断接收

编程入门 行业动态 更新时间:2024-10-08 19:44:42

[STM32系列]一、HAL库的<a href=https://www.elefans.com/category/jswz/34/1769224.html style=串口中断接收"/>

[STM32系列]一、HAL库的串口中断接收

[STM32系列]一、HAL库的串口中断任意长度接收

    • 1、前言
    • 2、回调函数
    • 3、HAL库中断接收函数使用

1、前言

HAL即硬件抽象层(英语:Hardware Abstraction Layer),实现了不同硬件的统一接口操作。这就极大的简化了程序员的移植工作,搭配STM32CubeMX,使用起来非常方便。

2、回调函数

HAL库使用了很多的回调机制,这样写能够更好的实现程序的分层处理,不影响程序的主体框架,方便后期修改移植。

3、HAL库中断接收函数使用

使用HAL_UART_Receive_IT函数前,需要使能串口的接收中断,并配置中断优先级。

 /* Peripheral clock enable */__HAL_RCC_USART2_CLK_ENABLE();__HAL_RCC_GPIOA_CLK_ENABLE();/**USART2 GPIO Configuration    PA2     ------> USART2_TXPA3     ------> USART2_RX */GPIO_InitStruct.Pin = GPIO_PIN_2|GPIO_PIN_3;GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;GPIO_InitStruct.Pull = GPIO_NOPULL;GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;GPIO_InitStruct.Alternate = GPIO_AF4_USART2;HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);/* USART2 interrupt Init */HAL_NVIC_SetPriority(USART2_IRQn, 1, 1);HAL_NVIC_EnableIRQ(USART2_IRQn);

在对应的串口中断函数中需要对应的中断处理

void USART2_IRQHandler(void)
{/* USER CODE BEGIN USART2_IRQn 0 *//* USER CODE END USART2_IRQn 0 */HAL_UART_IRQHandler(&huart2);/* USER CODE BEGIN USART2_IRQn 1 *//* USER CODE END USART2_IRQn 1 */
}

这时就可以使用
HAL_StatusTypeDef HAL_UART_Receive_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)
函数接收了,该函数会打开接收中断接收数据,函数的第一个参数指定接收串口的结构体指针,第二个参数为接收数据指针,第三个参数为接收数据长度。该函数没有超时机制,必须要指定接收的数据长度,在数据没有达到接收长度时该函数会一直阻塞,这就要求接收的数据长度必须为已知,在接收不定长度数据时会不适用。
在使用串口接收Modbus-RTU数据时,需要接收不定长的数据帧,并且要求非阻塞接收。像在标准库中接收数据一样,这里可以通过HAL_UART_Receive_IT接收单个字节的数据,在接收回调函数中加入超时处理即可完成一帧数据的接收。接收流程如下:

Created with Raphaël 2.2.0 开始 接收一个字节 超时? 帧处理 结束 yes no

保证数据帧完整的接收,就需要在接收完一个字节数据的时候将计时清零,继续下一次接收,直到超时退出,然后再处理这一帧数据。具体实现内容如下:

//数据接收结构体
struct M_Rev{uint8_t revcnt;			//接收计数uint8_t revact;			//开始标志uint8_t oldcnt;			//上次计数uint32_t revtick;		//接收计时uint8_t revbuff[MODBUS_MAX_LEN];		//接收缓存
}Modbus_Rev;
//接收回调函数
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{if(huart->Instance == USART2)		//判断串口{if(Modbus_Rev.revcnt == 0)		//帧第一个数据{if(Modbus_Rev.revact == 1)	//首次接收{Modbus_Rev.revact = 2;		}else	//非首次接收{Modbus_Rev.revbuff[0] = Modbus_Rev.revbuff[Modbus_Rev.oldcnt];	//上一次接收数据位置}	HAL_TIM_Base_Start_IT(&htim2);	//开启定时器HAL_GPIO_WritePin(GPIOB, GPIO_PIN_7, GPIO_PIN_SET);	//开启指示灯}		Modbus_Rev.revcnt += 1;	//接收计数if(Modbus_Rev.revcnt >= MODBUS_MAX_LEN)	Modbus_Rev.revcnt = MODBUS_MAX_LEN - 1;	Modbus_Rev.revtick = 0;	//计时清0HAL_UART_Receive_IT(huart, &(Modbus_Rev.revbuff[Modbus_Rev.revcnt]), 1);	//接收下一次数据}
}
//定时器回调函数
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{Modbus_Rev.revtick += 1;				//计时增加if(Modbus_Rev.revtick > MAX_TIM_CNT)	//定时器溢出{Modbus_Rev.revtick =0;				//计时清0}if(Modbus_Rev.revtick >= MODBUS_T35)	//接收超时{if(Modbus_Rev.revact == 2)			//首次接收{Modbus_Rev.revact = 0;			//关闭首次接收}	Modbus_ReciveData(Modbus_Rev.revbuff,Modbus_Rev.revcnt);		//完成一帧接收,处理Modbus_Rev.oldcnt = Modbus_Rev.revcnt;		//保存接受位置Modbus_Rev.revcnt = 0;				//接收计数清0HAL_TIM_Base_Stop_IT(&htim2);	//关闭定时器HAL_GPIO_WritePin(GPIOB, GPIO_PIN_7, GPIO_PIN_RESET);	//关闭指示灯}
}

其中要注意的一点是,在第二帧接收时,由于接收的地址是上一帧的接收位置 + 1所以需要保存其位置,将其数值赋值到这一帧的第一个字节即可。

更多推荐

[STM32系列]一、HAL库的串口中断接收

本文发布于:2024-03-23 20:43:54,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1742614.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:串口   系列   HAL

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!