菜单

加SUM校验串口收发案例

下载

介绍

该案例对应serialTestDemo,对应画面如下:

适用串口自定义协议应用场景

  1. 本文介绍串口控件使用中对数据(字节数组)的收、发处理
  2. 串口控件可以放在普通页也可以放在公共页,使用方式一样
  3. 如果串口控件放在普通页中,则当页面关闭时,串口控件自动关闭
  4. 如果串口控件放在公共页中,因公共页不会关闭,串口控件会一直运行
  5. 支持:帧延时、帧头、帧头+帧尾、固定长度四种通讯格式,使用方法一样

步骤

添加串口控件

在页面上添加串口控件,设置控件属性

  1. "串口参数"用于设置通讯参数,见下一节;
  2. "通讯格式"用于设置四种通讯时采用的格式;
  3. "缓存区大小"用于设置接收数据的缓存区尺寸,达到4/3时数据帧送回调处理;
  4. 如需要开机自启,将“自动启动”设为“是”,否则需要通过代码来启动串口控件。
  5. “翻转延时”属性不用
  6. 在事件处理中,添加收到数据的回调函数。

设置串口参数

注意:

  1. 在电脑上模拟运行时,端口号用实际使用端口号,下载到屏运行前要改为屏上的端口号;
  2. 在屏上时,COM1 为 232 电平,COM2 为 485 电平,COM3 为 TTL 电平。设置其他的端口无效;

设置通讯格式


根据不同的需求设置不同的串口格式参数,如此处本案例所接收到的数据以 AA 为帧头,AB 为帧尾的固定数据格式。

数据收发处理

1)收数据处理

串口控件收到串口数据后触发数据处理回调函数,开发者在回调函数中一次处理一帧或多帧数据。
代码参考下面,

c++ 复制代码
void Frm01::wMCom1_vch_cb(uint16_t code, LvEvent e) {
  //添加一个字节列表变量readData用于存放收到字节数组
  vector<uint8_t> readData;
  //可能一次性收到多帧数据,处理时需要循环读取数据帧队列并放到readData中
  while (wMCom1->readData(readData, 0)) {
    //将收到的字节数组转HEX字符串(用于测试打印输出,仅用于调试用)
    string freadData = stt::util::StringUtil::charsToString(readData.data(), readData.size());
    //测试打印输出,用于调试用
    cout << freadData << endl;
    //按通讯协议进行字节处理--->开始
    vector<uint8_t> checkBuf;
    checkBuf.insert(checkBuf.end(), readData.begin() + 2, readData.begin() + 2 + 6);
    if (readData[8] == getSum(checkBuf)){
      // 检测正确
      uint16_t pm25 = readData[3]<<8 | readData[2];
      uint16_t pm10 = readData[5]<<8 | readData[4];
      uint16_t id = readData[6]<<8 | readData[7];
      int ipm25 = static_cast<int>(pm25);
      int ipm10 = static_cast<int>(pm10);
      int iid = static_cast<int>(id);
      //打印出来看看,电脑上测试用
      cout<<"ipm25==="<<ipm25<<"ipm10++++"<<ipm10<<"iid===="<<iid<<endl;
      //通过变量将收到的值抛出去
      vm->setInt("PM2.5",ipm25);
      vm->setInt("PM10",ipm10);
    }
    //按通讯协议进行字节处理<----结束
  }
}

代码说明如下:

测试打印

用于刚开始开发时,打印验证输出看一下HEX字节与发数据是否一致。
通常与串口助手等软件配合验证。
注意:正常情况下,请注释掉,特别是单片机设备发送速度非常快的情况下!!

c++ 复制代码
//将收到的字节数组转HEX字符串(用于测试打印输出,仅用于调试用)
string freadData = stt::util::StringUtil::charsToString(readData.data(), readData.size());
//测试打印输出,用于调试用
cout << freadData << endl;

验证数据

由于案例代码需要进行和校验,因此在此处进行了校验判断。

c++ 复制代码
vector<uint8_t> checkBuf;
// 将需要进行校验的数据放入新的数据包中
checkBuf.insert(checkBuf.end(), readData.begin() + 2, readData.begin() + 2 + 6);
if (readData[8] == getSum(checkBuf))
// 表示数据验证成功

协议数据处理

这里根据具体情况,对字节数组按需进行组合取数。

c++ 复制代码
uint16_t pm25 = readData[3]<<8 | readData[2];
uint16_t pm10 = readData[5]<<8 | readData[4];

注意:一帧数据包含了完整的帧头帧尾,计算位数偏移时要考虑进去!!

赋值给变量

在页面中有两个控件分别绑定了变量名为PM2.5PM10的控件,通过设置变量,从而展示与页面上。

c++ 复制代码
vm->setInt("PM2.5",ipm25);
vm->setInt("PM10",ipm10);

2)数据发送

将要发送的数据放到字节数组中,调用控件的writeData函数就可以通过串口发送出去。
完成参考代码如下:

c++ 复制代码
void Frm01::sendPacket(uint16_t id){
  //准备两个vector字节数组变量
  //pack是真正的指令,sumpack用于求和校验
  vector<uint8_t> pack;
  vector<uint8_t> sumpack;
  pack.push_back(0xAA); //包头
  pack.push_back(0xB4); // 指令码
  pack.push_back(0x04); // 数据1
  sumpack.push_back(0x04);
  for (int i = 0;i<12;i++){
    pack.push_back(0x00); // 数据1
    sumpack.push_back(0x00);
  }
  pack.push_back(id>>8); // id高八位
  sumpack.push_back(id>>8);
  pack.push_back(id&0XFF); // id高八位
  sumpack.push_back(id&0XFF);
  //计算校验和
  uint8_t sum = getSum(sumpack);
  pack.push_back(sum);
  pack.push_back(0xAB); //尾
  //实际发送指令转的HEX字符串,用于调试
  string wData = stt::util::StringUtil::charsToString(pack.data(), pack.size());
  //测试打印HEX字符串
  cout << wData << endl;
  //调用串口控件对外发送指令
  wMCom1->writeData(pack);
}

上述代码中用到了两个字节数组pack、sumpack。
pack放要发送的字节数组(流),sumpack用于中途计算求和校验用。
也包括了打印测试输出HEX字符串的代码,可以视情况注释掉。

最近修改: 2025-09-25Powered by