1 用途
【串口】控件用于与设备(如单片机)进行串口通讯,运行起来后不可见。
2 参考视频
3 属性
3.1 控件
控件名,当前页面唯一。
3.2 串口参数
设置串口的连接参数,包括端口号、波特率、数据位、校验位与停止位。
注意:
1)串口号可以手工输入和修改;
2)模拟器与屏的串口不一样,在模拟器上运行或下载到屏上运行时需要按照实际使用的串口号进行设置。
3.3 通讯格式
设置串口的通讯格式。串口控件运行在独立线程,对收到的串口数据按“通讯格式”设置处理成一帧或多帧数据交由收数据回调函数进行处理。每帧数据包含帧头与帧尾。
支持以下几种格式设置:
1)帧延时
2)帧头(+长度)
帧头+长度
3)帧头+帧尾
4)固定长度
3.4 缓存区大小
设置串口接收数据缓存区的大小,默认1024。
3.5 自动启动
创建后自动开启串口通讯。
3.6 翻转延时
设置485方向脚的延时,不同设备响应不同,可能导致双方首尾字节错误,可以调整此参数。
3.7 事件处理
定义串口数据接收处理函数。
点击生成,再点击确定就会生成接收数据的回调函数,如下:
在回调函数中增加数据处理代码。
4 用法说明
参考串口收发讲解说明
5 应用示例
1.帧延时收发指令
此方式主要用在发送频率不高的情景,如无线物联模块、GPS模块等,帧延时不能小于10ms。
a)串口控件接收回调代码:
//每收到一帧数据的回调
vector<uint8_t> pData;
//从串口控件读取一帧数据
wMCom1->readData(pData, 0);
////判断接收指令的行数不超过21行
string txt;
vm->getChar("接收指令", txt, 0);
int lines = 0;
bool inLine = false; // 用于标记当前是否在一行中
for (char ch : txt) {
if (ch == '\n') {
lines++; // 遇到换行符,行数加1
inLine = false; // 结束当前行
} else if (ch != '\r') { // 忽略回车符
inLine = true; // 如果不是换行符,标记为在一行中
}
}
// 如果最后一行没有换行符,仍然算作一行
if (inLine) {
lines++;
}
if(lines>21){
txt="";
}
char temp[16];
string hexStr;
///将接收的数据转换为字符串并赋值给"接收指令"
hexStr=util::StringUtil::charsToString(&pData[0], pData.size());
for(int i=0;i<pData.size();i++){
sprintf(temp,"%02X ",pData[i]);
txt+=temp;
}
txt+="\n";
vm->setChar("接收指令", txt, 0);
b) 发送按钮处理函数
/*wMButton1(功能键)的点击事件*/
string sendStr;
//获取变量"发送指令"中的指令字符串
vm->getChar("发送指令", sendStr);
//处理字符串为16进制的字节数组
sendStr.erase(std::remove(sendStr.begin(), sendStr.end(), ' '), sendStr.end());
int size=sendStr.size()/2;
unsigned char hexCmd[size];
stt::util::StringUtil::StringToChars(sendStr, hexCmd);
vector<uint8_t> cmd;
cmd.resize(size);
memcpy(&cmd[0],hexCmd,size);
//串口发送出去
wMCom1->writeData(cmd);
2. "帧头"格式收发指令
“帧头+数据”方式解析指令,此方式必须确保“数据”中不会出现帧头。
3. "帧头"+长度格式收发指令
如“数据”块可能出现“帧头”,可以采用“帧头+长度”模式,此长度是指数据长度。例如:
A5 5A 05 82 10 00 01 23
其中:
A5 5A --- 帧头
05 --- 数据长度
82 10 00 01 23 --- 数据
参考视频2:
串口事件处理参考函数:
vector<uint8_t> pData;
uint8_t cmd,AddrNum;
uint16_t startAddr;
char regName[32];
//从串口控件读取每一帧数据
while (wMCom1->readData(pData, 0)) {
cmd=pData[3];
startAddr=(pData[4]<<8)|pData[5];
if(cmd==0x82){//解析寄存器指令
AddrNum=(pData[2]-3)/2;
for(int i=0;i<AddrNum;i++){
//根据地址+前缀获取变量名
sprintf(regName,"DGUS%d",startAddr+i);
//修改变量值
vm->setInt(regName, (pData[2*i+6]<<8)|pData[2*i+7]);
}
}
}