上篇文章实现了串口空闲中断,这次我们使用定时器实现串口空闲中断,话不多说,直接开始配置,本次采用stm32f103c8t6为主控

顺便说下实现的原理:

核心思路

  1. 定时器辅助超时检测

    • 使用独立定时器(TIMER2)产生固定时间基准(如 1ms)。
    • 在串口接收每个字节时重置定时器计数器(rx_timeout_counter)。
  2. 超时判断帧结束

    • 若连续RX_TIMEOUT_MS毫秒(代码中为 5ms)未收到新数据,判定为一帧结束。
    • 定时器中断中递减rx_timeout_counter,减至 0 时标记rx_frame_complete = 1
  3. 数据处理逻辑

    • 在主循环中检测到rx_frame_complete后,解析接收到的数据(如匹配 "ledon"/"ledoff" 指令)。
    • 处理完成后重置缓冲区和标志位。

定时器配置为1ms进一次中断


中断优先级根据项目要求进行设置


串口配置



接下来开始代码编写

#define RX_BUFFER_SIZE 256
uint8_t rx_buffer[RX_BUFFER_SIZE];
uint16_t rx_count;
volatile uint8_t rx_frame_complete;
volatile uint16_t rx_timeout_counter=0;
#define RX_TIMEOUT_MS 5
const char target1[]="ledon";
const char target2[]="ledoff";

全局变量 


void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
    if (huart->Instance == USART1)        //如果串口一触发中断
    {
        if(rx_count<RX_BUFFER_SIZE) rx_buffer[rx_count++]=rx_data;
        //如果接收数据没有超出所能存储的最大个数就存入缓冲区
        
        else
        {
            rx_count = 0;    //如果超出就重置计数值
            unsigned char text="BUFFER OVERFLOW!\r\n";
            HAL_UART_Transmit(&huart1, (char*)text, sizeof(text), 1000);
        }
        rx_timeout_counter=RX_TIMEOUT_MS;//开始定时器倒计时
        HAL_UART_Receive_IT(&huart1, &rx_data, 1);//重新开启串口接收中断
    }
}

串口接收中断处理, 如果接收到数据就重置定时器的计数值


 

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
    if (htim->Instance == TIM2)
    {
        if(rx_timeout_counter>0)    //判断计数值是否被减到0,减到0表示触发空闲
        {
            rx_timeout_counter--;
            if(rx_timeout_counter==0) rx_frame_complete=1;
        }
    }
}

定时器进行检测计算是否达到一定时长未接收到数据从而判断是否触发空闲模式


 

        if(rx_frame_complete)    //触发空闲模式
        {
            if(rx_count<RX_BUFFER_SIZE) rx_buffer[rx_count]='\0';
            //给最后一个位置加上'\0'以便把接收到的数据作为字符串处理

            else rx_buffer[RX_BUFFER_SIZE-1]='\0';

            if(strcmp((char*)rx_buffer,target1)==0) led_ctrl(1,1);  
            //这里直接比较是否未所期望的数据

            else if(strcmp((char*)rx_buffer,target2)==0) led_ctrl(1,0);
            //这里直接比较是否未所期望的数据

            memset(rx_buffer,0,RX_BUFFER_SIZE);//清空缓冲区
            rx_count=0;    //清空计数个数
            rx_frame_complete=0;//重置标志位
        }

主函数中对数据进行处理

更多推荐