本文档主要讲述一些高级应用,实现一些特殊功能,大多数项目是用不上这些功能的,如果您的项目用不上,可以忽略此文档。
【章节索引】
屏幕上电默认是被动解析模式,所有串口指令需按照指令集中的格式来对屏幕进行操作,假如你需要自定义协议,不按照指令集格式来发串口数据给屏幕,而使用你自定义的格式,那么就需要把屏幕配置为主动解析模式。要使用此功能,请务必确保你有以下2点基础: 1.明白什么叫HEX,什么叫String,什么叫ASCII,分别什么关系,怎么转换。 2.明白单字节数值,双字节数值,四字节数值,分别有什么区别,它们在内存中是什么样的储存方式,明白什么叫小端模式,什么叫大端模式。明白低位在前是什么含义。 如果以上2点你都比较明白,那么请继续往下看,否则强烈建议不要再继续往下看了,因为大多数的项目是用不上这个功能的,使用默认的被动解析模式就可以了,没必要配置为下面的主动解析模式。 |
此篇幅涉及到以下几个内容:
1. 串口数据解析模式系统变量:recmod
2. 串口缓冲区数据大小系统变量:usize
3. 串口缓冲区数据组:u[index]
4. 串口缓冲区数据拷贝指令:ucopy
5. 串口数据解析模式退出密码
1.串口数据解析模式系统变量recmod(0为被动解析模式,1为主动解析模式)
屏幕上电recmod为0,即被动解析模式,在此模式下,外部设备按照标准指令集的指令格式发送串口指令给屏幕执行;如果你将recmod 设置为1(可以在上电默认页的初始化事件中写上recmod=1即可),那么屏幕进入主动解析模式,然后所有的串口指令都不会被执行(注意:是串口指令不会被执行,上位软件编辑界面时写入事件中的固件指令是不会受影响的,依然正常执行),所有的串口数据均存放在串口缓冲区中,等待您去主动读取。每次读完数据后,使用udelete指令删除缓冲区中已经读取的字节数,否则缓冲区溢出后就无法接收新数据。
注:在屏幕设置主动解析模式,用上位机软件模拟器联机屏幕,屏幕将会强制退出主动解析模式,此时需要将屏重新上电才可以正常模拟器联机调试屏幕。
2.串口缓冲区数据大小系统变量usize(只能读取,不可设置)
读取此变量可以知道当前串口缓冲区已经缓存多少数据。
定时器里每次进入解析之前,必须先判断usize的值大于1个数据帧的长度,才能进入正常的解析!!!
以下代码仅供参考
3.串口缓冲区数据组
串口缓冲区数据组的写法为u[index] (index为序号)
例1:从缓冲区中0位置开始获取一个1字节的数值,赋值给数字控件n0, 写法如下:
n0.val=u[0]
例2: 从缓冲区中0位置开始获取一个2字节的数值(小端模式,低位在前),赋值给数字控件n0, 写法如下:
n0.val=u[1]
n0.val<<=8
n0.val+=u[0]
例3: 从缓冲区中0位置开始获取一个4字节的数值(小端模式,低位在前),赋值给数字控件n0, 写法如下:
n0.val=u[3]
n0.val<<=8
n0.val+=u[2]
n0.val<<=8
n0.val+=u[1]
n0.val<<=8
n0.val+=u[0]
难道对一个4字节的整型变量赋值缓冲区中的内容只能是分4次单字节赋值再加3次移位吗? 当然不是!当然有更方便的做法,请继续往下看!
4.串口缓冲区数据拷贝指令ucopy
格式: ucopy,att, srcstar, lenth, decstar
说明:将串口缓冲区中的数据拷贝到变量中(recmod=1模式下有效)
att:目标变量名称
srcstar:串口缓冲区数据起始位
lenth:拷贝长度
decstar:目标变量数据起始位
此指令可以从串口缓冲区的指定位置连续拷贝指定数量的数据到目标变量(目标变量可以是字符串变量,可以是数值变量)。
例1:从缓冲区中0位置开始获取一个4字节的数值(小端模式,低位在前),赋值给数字控件n0, 写法如下:
ucopy n0.val,0,4,0
udelete 4 删除缓冲区中前面4个字节,如果后面还有其他数据,会自动顶上来
温馨提示:每个数值变量系统都是按4字节分配内存,假如你使用ucopy从缓冲区获取小于4字节的数值,一定要注意剩余部分的字节数据处理,以免出现数据异常,操作方法请参考下面这个例子:
例2: 从缓冲区中0位置开始获取一个2字节的数值(小端模式,低位在前),赋值给数字控件n0.val的低16位, 写法如下:
n0.val=0
ucopy n0.val,0,2,0 如果要赋值给高16位,就写成ucopy n0.val,0,2,2
udelete 2 删除缓冲区中前面2个字节,如果后面还有其他数据,会自动顶上来
解释:先将n0.val赋值为0,目的在于确保n0.val的4个字节全置0,然后再从缓冲区拷贝2个字节进来,否则会因为你只拷了2字节而导致n0.val原来剩下的2字节数据还在,然后导致n0.val最终的数值并不是你想要的数值。
例3: 从缓冲区中0位置开始获取一个10字节的字符串,赋值给文本控件t0, 写法如下:
if(usize>=10) 确保缓冲区数据大小足够10个
{
ucopy t0.txt,0,10,0
udelete 10 删除缓冲区中前面10个字节,如果后面还有其他数据,会自动顶上来
}
重要提示:code_c指令会将缓冲区数据清空,有可能会导致还没有读取的数据就被提前删除,所以在主动解析模式下建议使用udelete指令来删除已经读取的内容,而不要使用code_c指令。
以上案例中使用的所有语句,指令,都是在上位编辑界面下,写入事件中的固件指令,串口一旦配置为主动解析模式,就不能再执行串口指令了,所以必须是由固件指令来操作读取串口数据,而不能是通过串口指令操作(否则就自相矛盾了)。
5.退出主动解析模式
常规的退出主动解析模式方法是在事件中写入recmod=0的固件指令,如果想通过串口数据来退出,串口发送recmod=0是肯定没有用的,可以通过发送一串退出密码来实现退出主动解析模式,退出密码为一串24字节的字符串+3字节的结束符。
24字节的字符串:
DRAKJHSUYDGBNCJHGJKSHBDN (字符串数据,必须大写)
3字节的结束符(Hex数据):
0xff 0xff 0xff
合计27字节
例程: 主动解析-点灯 点击下载
本文讲述的HMI下载协议仅适用于希望自己制作下载程序或者希望单片机去控制HMI下载资源文件的用户,属于高级应用范畴,不属于HMI界面设计的范畴,因此需要有一定基础的用户才能操作。深圳市淘晶驰电子有限公司仅仅只对此协议做一个公布说明,不提供任何跟下载协议有关的技术支持,如果对串口操作不熟悉的朋友建议忽略此说明,请直接使用USART HMI软件进行下载即可,无需对此协议有任何了解。 |
温馨提示:官方有按照本协议开发好的专用下载工具(TFTFileDownload),并且开放源代码,欢迎下载使用:点击此处下载
【下载步骤1:联机操作】
此步骤主要用来搜索HMI设备在哪个串口上,以及设备当前的波特率。如果这两个条件是已知的,那么可以不用做这个步骤,在你的程序中直接固定串口号和设备当前使用的波特率后直接跳到步骤2开始下载。
●搜索方法:
分别向电脑的每个串口分别用不同波特率发送一个联机指令:connect+结束符
设备收到联机指令后会返回联机数据,如果收到正确的联机数据,说明设备联机成功,至此,得到当前设备的串口号和当前使用的波特率.
●联机指令发送说明:
因为一直在循环发送指令,所以当屏幕在正确的波特率上收到数据时,数据的最前面肯定会有部分上一次错误的波特率下的错误数据,因此这个时候第一条指令肯定是会被当成错误指令的。所以每次发送的时候需要发两条指令,第一条发4个字节的HEX空指令(00 ff ff ff),第二条才是connect+结束符
延时说明:每次尝试一次联机指令后需要等待数据返回的最短时间为(单位:ms): (1000000/尝试的波特率)+30
假如在9600波特率下尝试联机,需要等待返回的最短时间为:
1000000/9600+30=134ms
其他波特率以此类推
●数据解释:
以TJC4024T032_011R设备为例,设备返回如下8组数据(每组数据逗号隔开):
comok 1,101,TJC4024T032_011R,52,61488,D264B8204F0E1828,16777216
comok:握手回应
1:表示带触摸(0是不带触摸)
101:设备内部预留数据
TJC4024T032_011R:设备型号
52:设备固件版本号
61488:设备主控芯片内部编码
D264B8204F0E1828:设备唯一序列号
16777216:设备FLASH大小(单位:字节)
【下载步骤2:开始下载】
此时已经知道设备在哪个串口号上,也知道设备当前的波特率了,可以发送下载指令了。
■第一步:发送指令whmi-wri filesize,baud,res0
filesize:tft文件的大小(单位:字节)
baud:强制下载使用的波特率
res0:预留数据,使用任意ASCII字符即可
假如需要下载的tft文件大小为10000字节,需要使用115200波特率下载,那么就发送指令:
whmi-wri 10000,115200,0
发送完此指令以后,需要修改电脑的波特率为刚才设置的强制波特率(如果当前波特率和强制下载波特率不一致的话)
■第二步:下发tft文件的二进制数据
设备收到whmi-wri指令后在250ms左右后会返回一个0x05的数据(仅仅是一个字节,没有3个0XFF的结束符,波特率为刚才设置的强制下载波特率),收到此数据后,可以开始下发tft文件的二进制数据,下发格式为每包下发4096字节,最后一包剩余多少就发多少,每包发送完成以后,需要等待屏幕返回响应信号,响应信号依然为一个单一字节的0x05。
通过x系列屏幕串口透传tft文件更新其他系列屏幕工程文件。 工程下载
正常情况下,指令直接发送即可,不需要校验,如果您的项目对指令传输要求很严格必须开启校验请按照下列说明发送指令 |
切记注意:上位软件版本0.56开始才支持指令CRC,之前的版本是不支持的。
带校验或不带校验无需做任何配置,只需修改指令即可,您可以上一条指令带校验,下一条指令不带校验也是可以的。两种指令的区别如下:
1.变更结束符
普通指令结束符为0xff 0xff 0xff,带校验的指令结束符为0xfe 0xfe 0xfe。
指令CRC16校验算法使用MODBUS的CRC16校验算法,计算函数如下:
需要校验的数据为所有指令数据,如果是带地址的指令,从地址开始算,不带地址的指令,就从指令第一个字节开始计算,结束符不计算在内。
static U8 InvertUint8(U8 data) { int i; U8 newtemp8 = 0; for (i = 0; i < 8; i++) { if ( (data & (1 << i) ) != 0) newtemp8 |= (U8)(1 << (7 - i)); } return newtemp8; } static U16 InvertUint16(U16 data) { int i; U16 newtemp16 = 0; for (i = 0; i < 16; i++) { if ( (data & (1 << i) ) != 0) newtemp16 |= (U16)(1 << (15 - i)); } return newtemp16; } U16 CRC16_MODBUS(U8* data, int lenth) { int i; U16 wCRCin = 0xFFFF; U16 wCPoly = 0x8005; U16 wChar = 0; while (lenth > 0) { wChar = *data; data++; wChar = InvertUint8( (U8)wChar); wCRCin ^= (U16)(wChar << 8); for (i = 0; i < 8; i++) { if ((wCRCin & 0x8000) != 0) { wCRCin = (U16)( (wCRCin << 1) ^ wCPoly); }else { wCRCin = (U16)(wCRCin << 1); } } lenth=lenth-1; } wCRCin = InvertUint16(wCRCin); return (wCRCin); }
3.CRC16校验码写入方式
指令后面,结束符前面,加上2字节的CRC16校验码(HEX)+1字节的常数:0x01(HEX),相当于在指令和结束符中间插入了3个字节,CRC校验码的储存方式是小端模式,低位在前。
如果屏幕收到带校验的指令后发现校验失败,会返回错误:0x09 0xff 0xff 0xff
1.以下代码将实现屏幕给外部设备发送2组常量数据,并在结尾带上Modbus的CRC16校验结果:
crcrest 1,0xffff 复位CRC crcputs "hex date is:",0 CRC校验字符串:hex date is: crcputh 03 25 CRC校验hex:0x03,0x25 prints "hex date is:",0 串口发送字符串:hex date is: printh 03 25 串口发送hex:0x03,0x25 prints crcval,2 串口发送校验结果
2.以下代码将实现屏幕给外部设备发送2组变量数据,并在结尾带上Modbus的CRC16校验结果:
crcrest 1,0xffff 复位CRC crcputs t0.txt,0 CRC校验字符串变量t0.txt crcputs n0.val,0 CRC校验数值变量n0.val prints t0.txt,0 串口发送字符串变量t0.txt prints n0.val,4 串口发送数值变量n0.val prints crcval,2 串口发送校验结果
3.以下代码将实现在主动解析模式下对串口缓冲区的数据进行CRC校验,并将成功与否的结果显示到t0.txt
if(usize>=24) { crcrest 1,0xffff 复位CRC crcputu 0,22 校验串口缓冲区的前面22个字节 sys0=0 sys0是4字节的整形数据,CRC结果只有2字节,所以先给多余字节数据清零 ucopy sys0,22,2,0 将接收缓冲区中接收到的CRC结果赋值给sys0 if(sys0==crcval)校验通过 { t0.txt="校验通过" }else { t0.txt="校验不通过" } udelete 24 删除已经处理的24字节 }
如果要传输图片文件到内存,请先在工程设置里面配置内存文件系统空间大小,默认是0,即没有空间用来储存内存文件。 如果是传输图片文件到SD卡,请确保SD卡磁盘格式为FAT32,最大支持32G容量的卡 |
温馨提示:官方有按照本协议开发好的专用串口透传文件工具(SerialFileUp),并且开放源代码,欢迎下载使用:
1.如何使用内存中的图片文件
使用“外部图片“控件,设置path属性为文件路径,如:ram/0.jpg
2.如何使用SD卡中的图片文件
使用“外部图片“控件,设置path属性为文件路径,如:sd0/0.jpg
3.支持什么类型的图片文件
jpg格式:如果使用jpg格式的图片,务必保证图片编码为:baseline DCT,否则将无法显示,如果屏幕方向设置的是0度,直接使用jpg原图即可,如果屏幕方向设置的是90度,需要将图片顺时钟旋转90度再给屏幕使用,否则显示出来的图片方向是错的。其他方向180度,270度以此类推,屏幕方向是多少度,就需要您提前把图片顺时钟旋转多少度。
xi格式:此格式为HMI专用图片格式,支持透明背景,推荐使用这种格式,xi格式的图片获取方式可以使用软件工具菜单中的图片转换工具:PictureBox转换
目前仅支持以上两种格式的图片文件。
4.串口传输协议
第一步:发送串口传输文件指令:twfile filepath,filesize
filepath:文件存放路径 如:ram/a.jpg 或 sd0/a.jpg
filesize:文件实际大小
假如要传一个文件到内存中,名字为a.jpg,大小为3282,指令为:twfile "ram/a.jpg",3282
假如要传一个文件到SD卡中,名字为a.jpg,大小为3282,指令为:twfile "sd0/a.jpg",3282
屏幕收到此指令后,会立即创建一个指定大小的文件在目标路径上,如果创建成功将返回:0xfe+结束符,表示已经进入透传状态,可以开始分包透传数据。如果创建文件失败会返回:0x06+结束符,并继续工作在指令接收状态。
第二步:分包透传文件数据
收到0xfe+结束符后,可以开始分包透传数据;一个完整的数据包由2部分组成:包头+数据
包头:3a a1 bb 44 7f ff fe +校验类型(1字节整形数据)+包ID(2字节整形数据) +数据大小(2字节整形数据),合计12字节
校验类型:0x00为无校验,0x01为CRC16(MODBUS的CRC16校验算法,指令校验篇幅中有计算函数参考),0x0A为标准CRC32 包ID:文件透传开始第一次包ID为0,每成功透传一包,ID加1. 数据大小:数据大小用户随意指定,最小1字节,最大4096字节(此数据大小不包含12字节的包头,但是包含CRC校验码)
数据:文件数据+CRC校验码数据(小端模式,低位在前),如果是无校验的包,就没有CRC校验码。如果是CRC16就是2字节的校验码,如果是CRC32就是4字节的校验码,切记注意校验码数据要记入包头的数据大小参数中。
CRC16校验算法为MODBUS CRC16,点击此处查看参考函数代码 CRC32校验算法为标准CRC32。
屏幕收到一个完整的包数据后,如果处理成功会返回0x05(单字节,没有结束符),此时可进入下一个包的发送。
如果包ID不按规则累加或者包数据出错,屏幕将会返回本包处理失败的错误:0x04(单字节,无结束符)。
所有包发送完成后,屏幕会返回0xfd+结束符。并自动退出透传模式转为指令模式。
如果本包透传失败(超过500ms没有收到屏幕回应或者收到屏幕返回本包校验失败的错误信息),重新发本包数据,重发本包数据时包ID无需加1。
如果数据包发了一半后悔了,停顿20ms以上重新发本包数据即可。
如果透传文件中途想停止透传,请发一个包ID为65535,无校验,数据大小为0的数据包,即:3a a1 bb 44 7f ff fe 00 ff ff 00 00 屏幕收到这样的包数据后会立刻强制结束透传,并返回透传结束的数据:0xfd+结束符
如果你的文件数据中包含退出包数据是不用担心的,因为这个数据的前面满足不了20ms以上的停顿,屏幕只会把他当数据储存,不会当结束包来处理。