STM32串口接收中断回调——利用状态机检测接收到的数据(自学笔记)

(一)需实现的功能

在串口1接收到上位机以ASCII码格式发送的字符串“OK!”后,返回两路ADC的采集结果。

(二)状态机状态设定

状态机有三个状态:

  1. 等待 'O' (state 0)
  2. 等待 'K' (state 1)
  3. 等待 '!' (state 2)
状态转换过程:
  1. 初始状态: USART1_State = 0

    • 如果接收到字符 'O',则状态转换到 state 1,即 USART1_State = 1
    • 其他字符不会改变状态,保持在 state 0
  2. 状态 state 1

    • 如果接收到字符 'K',则状态转换到 state 2,即 USART1_State = 2
    • 如果接收到字符 'O',则状态保持在 state 1,即继续等待 'K'。
    • 其他字符会使状态重置到 state 0
  3. 状态 state 2

    • 如果接收到字符 '!',则标志 UART1_Rx_flg 置为 1,状态机重置到 state 0
    • 如果接收到字符 'O',则状态转换到 state 1,即等待 'K'。
    • 其他字符会使状态重置到 state 0

(三)代码实现

1.串口中断回调函数(usart.c中)

注意使用Switch语句需配套break使用否则会造成卡死,且STM32标准串口在接收数据时总是一个字节一个字节的进行接收。若想读取所有接受到的数据则应将所接收的数据存入缓存中

static  uint8_t USART1_State=0; // 初始状态等待,设置状态机标志为0

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
    if(huart->Instance == USART1)
    {
        // 将接收到的字节存入缓冲区
        UART1_Rx_Buf[UART1_Rx_cnt] = UART1_temp[0];
        UART1_Rx_cnt++;

        // 状态机处理接收到的字节
        switch (USART1_State)
        {
            case 0:
                if (UART1_temp[0] == 'O') 
                {
                    USART1_State = 1;//接收到了字符O则将标志置1
                }
                break;

            case 1:
                if (UART1_temp[0] == 'K') 
                {
                    USART1_State = 2;//接收到了字符K则将标志置2
                } 
                else if (UART1_temp[0] == 'O') 
                {                    
                    USART1_State = 1;// 如果接收到 'O',则继续等待 'K'
                } 
                else 
                {                    
                    USART1_State = 0;// 如果不是 'O' 或 'K',重置状态机
                }
                break;

            case 2:
                if (UART1_temp[0] == '!') 
                {
                    UART1_Rx_flg = 1; // 收到 "OK!",置标志位
                    USART1_State = 0; // 重置状态机
                } 
                else if (UART1_temp[0] == 'O') 
                {                    
                    USART1_State = 1;// 如果接收到 'O',则等待 'K'
                } else 
                {                    
                    USART1_State = 0;// 如果不是 'O' 或 '!',重置状态机
                }
                break;

            default:
                USART1_State = 0;
                break;
        }

        // 继续接收下一个字节
        HAL_UART_Receive_IT(&huart1, (uint8_t *)UART1_temp, 1);
    }
}

代码说明

  • UART1_Rx_Buf[UART1_Rx_cnt] = UART1_temp[0];
    • 将接收到的字节存入接收缓冲区。
  • UART1_Rx_cnt++;
    • 增加接收计数器。
  • switch (USART1_State)
    • 根据当前状态机状态,选择对应的状态处理。
  • HAL_UART_Receive_IT(&huart1, (uint8_t *)UART1_temp, 1);
    • 继续接收下一个字节,以中断方式

上述用到的变量及数组需要在usart.h中声明

#define REC_LENGTH  1
#define MAX_REC_LENGTH  1024 
    
extern uint8_t  UART1_Rx_Buf[MAX_REC_LENGTH];//串口1数据接收缓存,最大可缓存1024字节
extern uint8_t  UART1_Rx_flg;//接收完成标志,接收到0a回车键认为接收完成
extern uint32_t UART1_Rx_cnt;//接收计数标志
extern uint8_t  UART1_temp[REC_LENGTH];//串口数据实时缓存
2.主函数检测接收标志(main.c中)

send_string及send_hex_as_decimal为自定义函数,使用时需从已有工程中复制

 while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
    Get_ADC1_Average_Value();//计算ADC1的值并存入缓存数组
    if(UART1_Rx_flg==1)//接收到上位机发送的OK
    {
        send_string("Y_out=",&huart1);
        send_hex_as_decimal(Y_out,&huart1);
        send_string(" ; ",&huart1);
        send_string("Z_out=",&huart1);
        send_hex_as_decimal(Z_out,&huart1);
        send_string("\r\n",&huart1);
        for(uint16_t i=0;i<UART1_Rx_cnt;i++)
        {
            UART1_Rx_Buf[i]=0; //清零接收缓存 
        }        
        UART1_Rx_cnt = 0;
        UART1_Rx_flg = 0;
    }

  }
  /* USER CODE END 3 */
}

  • 5
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值