串口汲取,环形缓冲区+剖析

[复制链接]
发表于 2026-2-9 14:28:55 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

×
串口汲取,环形缓冲区+剖析

环形缓冲区存储布局体
  1. #define RX_RING_SIZE 256
  2. typedef struct {
  3.     uint8_t buf[RX_RING_SIZE];  // 实际存数据
  4.     volatile uint16_t head;     // 写指针(中断在改),(volatile)防止编译器优化导致 中断/主循环不同步
  5.     volatile uint16_t tail;     // 读指针(主循环在改)
  6. } ring_buf_t;
复制代码
初始化串口
  1. void USART3_IRQHandler(void);//提前声明串口接收中断
  2. void uart3_Init(u32 baud)
  3. {         
  4.   GPIO_InitTypeDef GPIO_InitStructure;
  5.   USART_InitTypeDef USART_InitStructure;
  6.   NVIC_InitTypeDef NVIC_InitStruct;
  7.   
  8.   RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);                        
  9.   RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3,ENABLE);                       
  10.   
  11.   GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;                        
  12.   GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;                               
  13.   GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;                               
  14.   GPIO_Init(GPIOB,&GPIO_InitStructure);                                
  15.    
  16.   GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;                        
  17.   GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;                               
  18.   GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;                               
  19.   GPIO_Init(GPIOB,&GPIO_InitStructure);
  20.   
  21.   USART_InitStructure.USART_BaudRate = baud;                               
  22.   USART_InitStructure.USART_WordLength = USART_WordLength_8b;               
  23.   USART_InitStructure.USART_StopBits = USART_StopBits_1;                       
  24.   USART_InitStructure.USART_Parity = USART_Parity_No;                       
  25.   USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
  26.   USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;               
  27.   USART_Init(USART3, &USART_InitStructure);        
  28.   
  29.   NVIC_InitStruct.NVIC_IRQChannel = USART3_IRQn;
  30.   NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
  31.   NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 0;
  32.   NVIC_InitStruct.NVIC_IRQChannelSubPriority = 1;
  33.   NVIC_Init(&NVIC_InitStruct);//配置NVIC
  34.   
  35.   USART_Cmd(USART3, ENABLE);                                         
  36.   
  37.   USART_ITConfig(USART3, USART_IT_RXNE, ENABLE);       
  38.   USART_ITConfig(USART3, USART_IT_ERR, ENABLE);
  39.   
  40.   BSP_IntVectSet(BSP_INT_ID_USART3,USART3_IRQHandler);
  41.   BSP_IntEn(BSP_INT_ID_USART3);
  42. }
复制代码
设置布局体
  1. ring_buf_t rx_ring3 = {0, 0, 0};
复制代码
串口汲取制止(底子)
  1. void USART3_IRQHandler(void)
  2. {
  3.    if (USART_GetITStatus(USART3, USART_IT_RXNE) != RESET) {
  4.        uint8_t ch = (uint8_t)USART_ReceiveData(USART3);
  5.        uint16_t next = (rx_ring3.head + 1) % RX_RING_SIZE;
  6.        // 如果缓冲区没满,存入 数据
  7.        if (next != rx_ring3.tail) {
  8.            rx_ring3.buf[rx_ring3.head] = ch;
  9.            rx_ring3.head = next;
  10.        }
  11.        USART_ClearITPendingBit(USART3, USART_IT_RXNE);
  12.    }
  13. }
复制代码
剖析函数(放循环,壅闭期待)
  1. void Extract_select_Data(void)//判断数据包
  2. {
  3.     static uint8_t state_r4 = 0;
  4.     static uint8_t data_len_r4 = 0;
  5.     static uint8_t count_r4 = 0;
  6.     static uint8_t frame_buf[32];
  7.     // 只要缓冲区里有数据,就一直处理
  8.     while (rx_ring3.head != rx_ring3.tail)
  9.     {
  10.         // 1. 从环形缓冲区读取一个字节  
  11.         uint8_t ch = rx_ring3.buf[rx_ring3.tail];
  12.         rx_ring3.tail = (rx_ring3.tail + 1) % RX_RING_SIZE;
  13.         switch (state_r4)
  14.         {
  15.             case 0: // 等待帧头
  16.                 if (ch == 0x2A)
  17.                 {
  18.                     frame_buf[0] = ch;
  19.                     count_r4 = 1;
  20.                     state_r4 = 1;
  21.                 }
  22.                 break;
  23.             case 1: // 校验 CMD
  24.                 if (ch == 0x11)
  25.                 {
  26.                     frame_buf[count_r4++] = ch;
  27.                     state_r4 = 2;
  28.                 }
  29.                 else
  30.                 {
  31.                     state_r4 = 0;   // CMD 不匹配,丢弃
  32.                 }
  33.                 break;
  34.             case 2: // 校验 LEN
  35.                 if (ch == 0x04)
  36.                 {
  37.                     data_len_r4 = ch;
  38.                     frame_buf[count_r4++] = ch;
  39.                     state_r4 = 3;
  40.                 }
  41.                 else
  42.                 {
  43.                     state_r4 = 0;   // LEN 不匹配,丢弃
  44.                 }
  45.                 break;
  46.             case 3: // 接收 DATA(4字节) + CRC
  47.                 frame_buf[count_r4++] = ch;
  48.                 // 1(2E) + 1(CMD) + 1(LEN) + 4(DATA) + 1(CRC) = 8
  49.                 if (count_r4 >= 8)
  50.                 {
  51.                     /* ========= 业务判断 ========= */
  52.                     uint8_t byte6 = frame_buf[5]; // DATA2
  53.                     if (byte6 & 0x04)   // bit2 = 1
  54.                     {
  55.                         select_bit2_flag = 1;//解析结果
  56.                         BLE_TO_MCU_OK_FLAG=1;
  57.                     }
  58.                     else
  59.                     {
  60.                         BLE_TO_MCU_OK_FLAG=0;
  61.                         select_bit2_flag = 0;
  62.                     }
  63.                     /* ============================ */
  64.                     state_r4 = 0;   // 准备下一帧
  65.                 }
  66.                 break;
  67.             default:
  68.                 state_r4 = 0;
  69.                 break;
  70.         }
  71.     }
  72. }
复制代码
打扫缓存区
  1. void RingBuf3_ClearAndResetParser(void)
  2. {
  3. //    __disable_irq();  // 关中断,保证原子性
  4.     // 1. 清空环形缓冲区数据
  5.     memset(rx_ring3.buf, 0, RX_RING_SIZE);
  6.     // 2. 重置 head/tail
  7.     rx_ring3.head = 0;
  8.     rx_ring3.tail = 0;
  9.     // 3. 重置解析器状态
  10.     state_r3 = 0;
  11.     count_r3 = 0;
  12.     data_len_r3 = 0;
  13.     pkg_ready = 0;
  14. //    __enable_irq();  // 重新使能中断
  15. }
复制代码
回复

使用道具 举报

登录后关闭弹窗

登录参与点评抽奖  加入IT实名职场社区
去登录
快速回复 返回顶部 返回列表