stm32串口通信用定时器做超时接收
要使STM32串口通信使用定时器做超时接收,需要设置串口为中断模式并开启串口中断,然后使用定时器定时清0计数器。在中断处理函数中检测接收标志位是否被设置,如果被设置就将数据存到接收缓存中。同时,在中断处理函数中每次接收到数据也要清0定时器计数器。当定时器计数器计数超时时,表示数据接收完成,此时可以将接收缓存中的数据读取出来进行处理。
stm32串口通信接收
STM32 UART 接收数据
高效接收方案:DMA + IDLE 中断模式
为了实现高效的UART数据接收,在STM32微控制器上采用DMA(直接存储器访问)配合IDLE线状态检测中断的方式是一种常见做法[^1]。这种方式允许CPU在数据传输期间执行其他任务,从而提高系统的整体效率。
当使用DMA进行UART接收时,硬件会自动将接收到的数据搬运到指定的内存缓冲区中,直到发生特定事件触发中断——例如线路空闲(IDLE)信号被检测到。此时软件可以通过读取DMA计数寄存器得知实际接收到多少字节,并据此处理完整的消息帧。
// 初始化 DMA 和 UART 的配置结构体
static void MX_USART3_UART_Init(void)
{
huart3.Instance = USART3;
huart3.Init.BaudRate = 115200; // 设置波特率
huart3.Init.WordLength = UART_WORDLENGTH_8B;
huart3.Init.StopBits = UART_STOPBITS_1;
huart3.Init.Parity = UART_PARITY_NONE;
huart3.Init.Mode = UART_MODE_TX_RX;
huart3.Init.HwFlowCtl = UART_HWCONTROL_NONE;
huart3.Init.OverSampling = UART_OVERSAMPLING_16;
if (HAL_UART_Init(&huart3) != HAL_OK){
Error_Handler();
}
}
// 启动 DMA 接收过程
void Start_DMA_Reception(uint8_t *pData, uint16_t Size)
{
/* Enable the UART Data Register not empty Interrupt */
__HAL_UART_ENABLE_IT(&huart3, UART_IT_IDLE);
/* 开启 DMA 流向 SRAM */
HAL_UART_Receive_DMA(&huart3, pData, Size);
}
定长数据包接收与超时机制
对于需要解析具有固定长度报文的应用场合,则可以利用定时器来设置合理的等待时间窗口,防止无限期挂起。一旦超过设定时限仍未完成预期数量字符的到来即视为异常情况予以妥善处置[^2]。
下面给出了一段简化版代码片段展示如何通过CRC16算法验证接收到的消息完整性:
uint16_t Calculate_CRC16(const uint8_t* data_p, uint16_t length)
{
uint16_t crc = 0xFFFF;
while(length--){
crc ^= (*data_p++) << 8;
for(int i=0;i<8;++i){
if(crc & 0x8000)crc=(crc<<1)^0x1021;
else crc=crc<<1;
}
}
return crc;
}
bool Check_Packet_Integrity(uint8_t *packet, size_t packet_size)
{
uint16_t received_crc = ((uint16_t)packet[packet_size-2]<<8)|packet[packet_size-1];
uint16_t calculated_crc = Calculate_CRC16(packet, packet_size-2);
return received_crc == calculated_crc;
}
stm32怎么用定时器实现判断接收数据时停止位与开始位之间超过3.5字节时间
使用定时器实现判断接收数据时停止位与开始位之间超过3.5字节时间的方法如下:
配置串口接收中断,当接收到数据时触发中断。
在中断服务函数中,启动定时器并设置计数值,计数值应为3.5个字节的时间(根据波特率计算得出)。
在定时器中断服务函数中,停止定时器并判断是否超时,如果超时则表示停止位与开始位之间超过3.5个字节的时间,可以认为当前接收的数据帧已经接收完整。
如果未超时,则继续等待接收数据或启动新的定时器。
在主程序中,可以根据中断服务函数中的标志位来判断是否接收到完整的数据帧。
下面是一个简单的代码示例:
#include "stm32f1xx_hal.h"
#define UART_RX_BUF_LEN 128 // 串口接收缓冲区长度
#define UART_TIMEOUT_MS 10 // 串口接收超时时间(ms)
uint8_t uart_rx_buf[UART_RX_BUF_LEN]; // 串口接收缓冲区
uint8_t uart_rx_index = 0; // 串口接收缓冲区当前索引
uint8_t uart_rx_complete = 0; // 串口接收完成标志位
TIM_HandleTypeDef htim;
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
// 串口接收中断服务函数
if (uart_rx_index < UART_RX_BUF_LEN)
{
uart_rx_buf[uart_rx_index++] = huart->Instance->DR; // 保存接收数据到缓冲区
}
// 启动定时器
HAL_TIM_Base_Start_IT(&htim);
}
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
// 定时器中断服务函数
if (uart_rx_index > 0)
{
// 计算当前接收数据的字节数
uint16_t byte_count = (htim->Instance->ARR + 1) * 10 / UART_TIMEOUT_MS;
if (uart_rx_index >= byte_count)
{
// 接收到足够的数据,认为数据帧已经接收完整
uart_rx_complete = 1;
}
else
{
// 继续等待接收数据
HAL_TIM_Base_Start_IT(&htim);
}
}
}
int main(void)
{
// 初始化串口和定时器
HAL_UART_Receive_IT(&huart1, &uart_rx_buf[0], 1);
HAL_TIM_Base_Start_IT(&htim);
while (1)
{
if (uart_rx_complete)
{
// 处理接收到的完整数据帧
// ...
// 重置接收缓冲区和标志位
uart_rx_index = 0;
uart_rx_complete = 0;
// 继续等待接收数据
HAL_UART_Receive_IT(&huart1, &uart_rx_buf[0], 1);
HAL_TIM_Base_Start_IT(&htim);
}
}
}
相关推荐













