ESP32在Arduino环境下使用QUEUE接收串口数据帧

发布时间 2023-12-21 17:52:28作者: peter1990

ESP32在Arduino环境下的串口数据帧接收

测试平台

ESP32-WROOM

测试语言

Arduino @ PlatformIO

注意事项

需要添加Queue的库函数 作者: SMFSW 

PlatformIO环境配置文件 - platformio.ini

[env:esp32doit-devkit-v1]
platform = espressif32
board = esp32doit-devkit-v1
framework = arduino
monitor_speed = 115200
upload_speed = 921600
lib_deps = smfsw/Queue@^1.11

代码实现

  1. CPP主文件
/*
1. 使用串口中断接收串口数据;
2. 使用队列暂存串口接收的数据;
3. 对队列中的数据进行帧格式扫描,筛选完整数据帧。
4. 测试平台:ESP32-WROOM @ PlatformIO
5. 编程环境:Arduino
*/
// 需要添加Queue的库函数 author: SMFSW 
// 
#include <Arduino.h>
#include <Ticker.h>
#include <cppQueue.h>
#include "CRC16.h"

#define	MAX_LENGTH		200 // queue FIFO length is set to 200
#define FRAME_LENGTH    50
#define HEADER_FRAME_LEN_LENGTH 3
#define FRAME_HEADER    0XAA
const uint8_t frame_Header[2] = {0XAA, 0XAA};
uint8_t frame_Recv_Dat[FRAME_LENGTH];
cppQueue	Serialqueue(sizeof(uint8_t), MAX_LENGTH, FIFO, true);

void SerialRecvEvent();
void SerialRecvFrameEvent(cppQueue& uint8queue);
void LED_Blink();
void DetectFrame();

Ticker LEDTask;
Ticker SerialFrameDetection;
void setup() {
    Serial.begin(115200);
    Serial.setRxTimeout(1);
    Serial.onReceive(SerialRecvEvent);
    delay(5);
    pinMode(2, OUTPUT);
    digitalWrite(2, HIGH);
    LEDTask.attach(1, LED_Blink);
    SerialFrameDetection.attach_ms(2, DetectFrame);
}

void loop() {
    delay(5);
}

void LED_Blink(){
    digitalWrite(2,!digitalRead(2));
}

void SerialRecvEvent(){
    if(Serial.available() > 0){
        uint8_t len = Serial.available();
        for(uint8_t i = 0; i < len; i++){
            uint8_t recvbyte = Serial.read(); 
            Serialqueue.push(&recvbyte);	
        } 
    }
}
void DetectFrame(){
    SerialRecvFrameEvent(Serialqueue);
}

void SerialRecvFrameEvent(cppQueue& uint8queue){
    uint8_t qbyte;
    uint8_t temp_Recv_Dat[FRAME_LENGTH];
    uint8_t crc16modbussum[2];
    if(uint8queue.getCount() >= HEADER_FRAME_LEN_LENGTH){ // if queue records is longer than header length then read out
        uint8_t header_chk_flag = false; // create header check flag
        uint8_t CRC_16_chk_flag = false; // create crc16 check flag

        uint8queue.pop(&qbyte); // pop one record
        if(qbyte == FRAME_HEADER){ // check the pop record is header or not
            uint8_t header2;
            uint8queue.peekIdx(&header2, 0); //peek the next record in the queue
            if(header2 == FRAME_HEADER){ // double bytes header checks pass
                header_chk_flag = true;
                uint8queue.pop(&header2);
                // save headers to receive cache
                temp_Recv_Dat[0] = qbyte;
                temp_Recv_Dat[1] = header2;
                uint8queue.pop((temp_Recv_Dat + 2)); // read out the frame length from queue
                #ifdef DEBUG
                    Serial.println("frame len is: " + String(temp_Recv_Dat[2]));
                #endif
                
                // waiting the frame tail
                //header and frame length byte is 3 bytes
                uint8_t waitingcount = 0;
                if((uint8queue.getCount() < (temp_Recv_Dat[2] - HEADER_FRAME_LEN_LENGTH))||(waitingcount < 5)){
                    delayMicroseconds(10);
                    waitingcount++;
                    #ifdef DEBUG
                        Serial.println("queue count left is: " + String(uint8queue.getCount()));
                    #endif
                }
                else{
                    header_chk_flag = false;
                }
                //read out the left part of this frame ,header and the frame length has been read out
                for(uint8_t i = HEADER_FRAME_LEN_LENGTH; i < temp_Recv_Dat[2]; i++){
                    uint8queue.pop((temp_Recv_Dat + i));
                }
                //check CRC result
                CRC_16_chk_flag = update_crc(crc16modbussum, temp_Recv_Dat, temp_Recv_Dat[2]);
                #ifdef DEBUG
                    Serial.println("CRC_16_chk_flag: " + String(CRC_16_chk_flag));
                    Serial.print("0X" + String(crc16modbussum[0],HEX) + ",");
                    Serial.println("0X" + String(crc16modbussum[1],HEX));
                    //print out the received frame
                    for(uint8_t i = 0; i < temp_Recv_Dat[2]; i++){
                        Serial.print("0X" + String(temp_Recv_Dat[i], HEX) + ", ");
                    }  
                    Serial.println();
                #endif
            }
            else{
                header_chk_flag = false;
            }        
        }
        else{
            header_chk_flag = false;
        }
        if(CRC_16_chk_flag == true && header_chk_flag == true){
            memcpy(frame_Recv_Dat, temp_Recv_Dat, temp_Recv_Dat[2]);
            // #ifdef DEBUG
                Serial.println("received data frame: ");
                for(uint8_t i = 0; i < frame_Recv_Dat[2]; i++){
                Serial.print("0X" + String(frame_Recv_Dat[i], HEX) + ", ");
                }  
                Serial.println();
            // #endif
        }
    }
}

  1. CRC16 校验CPP文件
/*standard CRC check cpp files*/
//CRC-16-modbus (LSB-MSB)
//calculation tools online:https://www.23bei.com/tool-59.html
//mode: CRC-16(Modbus)
// remodified at 20231221 suitable for queue data frame
#include "CRC16.h"

/*--------------------------------------------------------------------*/
/**
  * function: Modbus CRC16(LSB-MSB) calculation
  * update in 2022/03/17
  *   input paramenter: 
  *         data_blk_ptr: inital address of waiting calculation data, 
  *         usDataLen: length of data frame
  *   output parameter:
  *         crc_sum: CRC16-modbus results' inital address
  *   returned value:
  *         true: check pass
  *         false: check fail
  */
uint8_t update_crc(uint8_t* crc_sum, uint8_t *data_blk_ptr, uint8_t data_blk_size)
{
    unsigned int i;
    unsigned short crc = 0xFFFF;
    unsigned short crcl;
    uint8_t oriCRC16[2];
    oriCRC16[0] = data_blk_ptr[data_blk_size - 2];
    oriCRC16[1] = data_blk_ptr[data_blk_size - 1];
    data_blk_size = data_blk_size - 2; // remove origin crc16 results addresss
    while(data_blk_size--){
        crc ^= *data_blk_ptr++;
        for (i = 0; i < 8; ++i){
                if (crc & 1)
                    crc = (crc >> 1) ^ 0xA001;
                else
                    crc = (crc >> 1);
        }
    }
    crcl = crc;
    crc_sum[1] = (unsigned char)(crc>>8);
    crc_sum[0] = (unsigned char)(crcl);
    if((oriCRC16[0] == crc_sum[0]) &&((oriCRC16[1] == crc_sum[1])))
        return true;
    else
        return false;
}

/*----------------------End of file----------------------------------*/

  1. CRC16 校验头文件
#ifndef _CRC_16_H_
#define _CRC_16_H_
#include <arduino.h>
// remodified at 20231221 suitable for queue data frame
uint8_t update_crc(uint8_t* crc_sum, uint8_t *data_blk_ptr, uint8_t data_blk_size);
#endif