首页 > 其他分享 >ESP32在Arduino环境下使用QUEUE接收串口数据帧

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

时间:2023-12-21 17:57:57浏览次数:42  
标签:Arduino data ESP32 uint8 Dat crc 串口 Recv frame

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

标签:Arduino,data,ESP32,uint8,Dat,crc,串口,Recv,frame
From: https://www.cnblogs.com/Mech-Snake/p/17919745.html

相关文章

  • Qt程序接收串口数据存在延迟解决办法
    问题在调试接收串口数据的Qt程序中发现,数据存在延迟和粘包现象。下位机发送数据包频率是100Hz,一包56字节,波特率115200,在打印port->readAll()的值的时候发现并不是每10ms读到一包数据,而是大概每50ms左右一次接收到5包数据,在其他电脑上调试,以及下载其他串口助手调试后发现存在同样......
  • 串口调试工具、方法和步骤
    串口调试工具、方法和步骤魏智勇​爱自控,爱科学,爱读书,爱生活​关注他 4人赞同了该文章串口是工业自动化系统中非常重要的通讯方式,自问世至今,以RS232、RS485为主的串口通讯方式,在工业自动化通讯系统始终占据非常重要的地位。对自动化工程师来说......
  • Mac Arduino ESP8266 ESP32 搭建开发环境
    目录1、安装Arduino2、搭建开发板管理器3、可能出现的错误 1、安装ArduinoArduino下载. 官方下载地址:Arduino官方网站Arduino中文社区:下载地址安装方式:解压后无需安装,拖到应用程序(AppLication)里面就行了2、搭建开发板管理器 打开Ardu......
  • Virtual Serial Port虚拟串口软件无法删除和修改已有串口怎么办?
    之前用的9.2版本,试用期过后绑定的端口都掉了,导致串口通讯报错6.9永久版下载:VirtualSerialPortDriverPro汉化破解版下载(附注册码)v6.9-软件学堂(xue51.com)下载后里面有两个版本,推荐安装6.9版本,7.0版本无Crack文件下载后如果还是无法删除已经绑定的虚拟串口或实际串口......
  • Guide to Arduino & Secure Digital (SD) Storage.
    原文:https://docs.arduino.cc/learn/programming/sd-guideHardware&SoftwareRequiredArduinoBoardwithSDCardSlot*ArduinoIDE(online or offline).FormattedSDCard*Theboards/shieldsthathaveanSDcardslotarelistedbelow:MKRZeroMKRIoT......
  • 串口实现modbus通讯
    代码#include"sys.h"#include"485.h"#include"delay.h"#include"modbus.h"voidRS485_Init(u32bound){//GPIO端口设置GPIO_InitTypeDefGPIO_InitStructure;USART_InitTypeDefUSART_InitStructure;N......
  • Qt之modbus_slave例程的底层串口数据分析
    一.参考网址1. qCDebug输出到日志文件2. HowtoredirectqDebug,qWarning,qCriticaletcoutput?二.问题1. 如何查看slave底层收到的主机发送的消息和回复的消息?解决办法:在main.cpp代码中取消注释 注:QLoggingCategory::setFilterRules函数不能重复使用,其只能最后......
  • s32k-I.MX8 基于串口通讯xrce-dds搭建
    s32k-iMX8平台XRCE-DDS的搭建1.引言XRCE-DDS简述     XRCE-DDS是可以在资源受限的MCU运行的DDS,在MCU侧运行客户端,通过代理服务参与DDS通信。 使用范围      本文将描述整个XRCE-DDS在GEN2平台的搭建过程,包含SOC侧imx8上运行xrce-dds的anget和s32k312单片机......
  • ESP32的SPI外设(SPI HSPI VSPI)
    ESP32的SPI外设(SPIHSPIVSPI)ESP32SPI简介参考文档:ESP32技术参考手册ESP32的SPI一共有4个,分别为SPI0、SPI1、SPI2、SPI3。如下图所示:其中SPI0和SPI1通过一个仲裁器共用一组信号总线,这组信号总线前缀带有SPI,主要用于访问外部存储单元和DMA操作。所以SPI信号总线不是提供给......
  • NRF52832---串口通信
    我在做一个蓝牙demo,蓝牙主控用的nrf52832。在添加DFU功能后,使用“nRFConnect”app连接上demo后,点击“notify”,蓝牙就会断开连接,log打印如下图 没有提示出错的行号。我是用的蓝牙传输方式是透传。我查遍了关于nrf52832内存不足的帖子,都没有解决。我去问了技术售后(我买的开发......