组态王与单片机通信协议1.docx
《组态王与单片机通信协议1.docx》由会员分享,可在线阅读,更多相关《组态王与单片机通信协议1.docx(23页珍藏版)》请在冰豆网上搜索。
组态王与单片机通信协议1
一、 通讯参数:
通讯参数包括数据位,停止位,波特率、校验方式。
数据位、停止位、波特率由单片机决定。
组态王中的设定和单片机一致即可。
校验方式参照“数据传输格式”中相关部分。
二、 数据传输格式:
格式1、组态王发送地址请求格式:
(此时检验位为1)
ENQ
Sta
EOT
CRC
格式2、单片机应答地址格式:
(此时检验位为0)
ACK
Sta
ETX
CRC
格式3、组态王读数据请求格式:
(此时检验位为0)
ENQ
R
DataType
DataAddr
DataNum
EOT
CRC
格式4、单片机应答读数据格式(正确):
(此时检验位为0)
ACK
DataLong
Data….
ETX
CRC
格式5、单片机应答读数据格式(错误):
(此时检验位为0)
NAK
ErrorCode
ETX
CRC
格式6、组态王写数据请求格式:
(此时检验位为0)
ENQ
W
DataType
DataAddr
Data….
EOT
CRC
格式7、单片机应答写数据格式(正确):
(此时检验位为0)
ACK
ErrorCode
ETX
CRC
三、时序:
读数据:
组态王
单片机
第一步:
格式1
第二步:
格式2
第三步:
格式3
第四步:
格式4或格式5
第五步:
如果第四步单片机执行格式4,结束。
否则,执行格式1。
第六步:
格式2
第七步:
格式3
第八步:
格式4或格式5
写数据:
组态王
单片机
第一步:
格式1
第二步:
格式2
第三步:
格式6
第四步:
格式7
第五步:
如果第四步单片机执行格式7的ErrorCode=0,结束。
否则,执行格式1。
第六步:
格式2
第七步:
格式6
第八步:
格式7
四、协议说明:
数据传输:
所有数据均为16进制数
ENQ(头)
H05
询问
请求帧的开始代码
ACK(头)
H06
确认
ACK应答帧的开始代码
NAK(头)
H15
否认
NAK应答帧的开始代码
EOT(尾)
H04
正文的结束
请求帧的结束ASCII代码
ETX(尾)
H03
结束正文
应答帧的结束ASCII代码
Sta:
:
设备地址1字节
R:
读标志1字节(0x52)
W:
写标志1字节(0x57)
DataType;需要交换的数据类型,1字节。
1,字节;2,字,3,浮点型。
DataType的值
含义
1
字节
2
字
3
浮点数
DataNum:
要读取的数据的数量,1字节。
DataAddr;为数据偏移地址2字节,低字节在前,高字节在后
Data:
实际传输的数据,低字节在前,高字节在后
DataLong:
单片机返回Data的字节数,2字节,低字节在前,高字节在后
CRC:
为从第一个字节至CRC前的所有字节的异或值,1字节
ErrorCode:
ErrorCode数值
含义
0
正确应答
1
数据类型错误
2
数据范围超限
3
指令无法识别,应为R或W。
4
校验错误
1.通讯口设置:
通讯方式:
RS-232,RS-485,RS-422均可。
波特率:
由单片机决定(2400,4800,9600and19200bps)。
字节数据格式:
由单片机决定。
起始位
数据位
校验位
停止位
注意:
在组态王中设置的通讯参数如波特率,数据位,停止位,奇偶校验必须与单片机编程中的通讯参数一致
2.在组态王中定义设备地址的格式
格式:
##.#
前面的两个字符是设备地址,范围为0-255,此地址为单片机的地址,由单片机中的程序决定;
后面的一个字符是用户设定是否打包,“0”为不打包、“1”为打包,用户一旦在定义设备时确定了打包,组态王将处理读下位机变量时数据打包的工作。
3.在组态王中定义的寄存器格式
寄存器名称
dd上限
dd下限
数据类型
Xdd
65535
0
FLOAT/BYTE/UINT
斜体字dd代表数据地址,此地址与单片机的数据地址相对应。
注意:
在组态王中定义变量时,一个X寄存器根据所选数据类型(BYTE,UINT,FLOAT)的不同分别占用一个、两个,四个字节,定义不同的数据类型要注意寄存器后面的地址,同一数据区内不可交叉定义不同数据类型的变量。
为提高通讯速度建议用户使用连续的数据区。
例如,
1、在单片机中定义从地址0开始的数据类型为BYTE型的变量:
则在组态王中定义相应的变量的寄存器为X0、X1、X2、X3、X4。
。
。
。
。
。
。
。
,数据类型为BYTE,每个变量占一个字节
2、在单片机中定义从地址100开始的数据类型为UINT型的变量:
则在组态王中定义相应的变量的寄存器为X100、X102、X104、X106、X108。
。
。
。
。
。
。
。
,数据类型UINT,每个变量占两个字节
3、在单片机中定义从地址200开始的数据类型为FLOAT型的变量:
则在组态王中定义相应的变量的寄存器为X200、X204、X208、X212。
。
。
。
。
。
。
, 数据类型FLOAT,每个变量占四个字节
3.组态王与单片机通讯的命令格式:
读写格式(除字头、字尾外所有字节均为ASCII码)
字头
设备地址
标志
数据地址
数据字节数
数据…
异或
CR
说明;
字头:
1字节1个ASCII码,40H
设备地址:
1字节2个ASCII码,0—255(即0---0x0ffH)
标志:
1字节2个ASCII码,bit0~bit7,
bit0=0:
读,bit0=1:
写。
bit1=0:
不打包。
bit3bit2=00,数据类型为字节。
bit3bit2=01,数据类型为字。
bit3bit2=1x,数据类型为浮点数。
数据地址:
2字节4个ASCII码,0x0000~0xffff
数据字节数:
1字节2个ASCII码,1—100,实际读写的数据的字节数。
数据…:
为实际的数据转换为ASCII码,个数为字节数乘2。
异或:
异或从设备地址到异或字节前,异或值转换成2个ASCII码
CR:
0x0d。
通讯尝试恢复命令(COMERROR),请求地址为0的一个BYTE数据
3.1.上位机发送读命令
字头
设备地址
标志
数据地址
数据字节数
异或
CR
下位机应答:
若正常:
字头
设备地址
数据字节数
数据…
异或
CR
若不正常:
字头
设备地址
**
异或
CR
例1:
读15号仪表,数据地址为15的数据。
其中数据为100,数据类型为字节,不打包。
组态王所发数据为:
40
30
46
43
30
30
30
30
46
30
31
37
32
0d
字头
设备地址15
标志
读操作
字节型
不打包
数据地址15
数据字节数1
异或
若正确:
40
30
46
30
31
36
34
37
35
0d
字头
设备地址15
数据字节数1
数据100
异或
若不正确:
40
30
46
2a
2a
37
36
0d
字头
设备地址15
**
异或
例2:
读15号仪表,数据地址为15的数据。
其中数据为100,数据类型为字节,打包。
组态王所发数据为:
40
30
46
43
32
30
30
30
46
30
31
37
30
0d
字头
设备地址15
标志
读操作
字节型
打包
数据地址15
数据字节数1
异或
若正确:
40
30
46
30
31
36
34
37
35
0d
字头
设备地址15
数据字节数1
数据100
异或
若不正确:
40
30
46
2a
2a
37
36
0d
设备地址15
**
异或
3.2.上位机发送写命令
字头
设备地址
标志
数据地址
数据字节数
数据…
异或
CR
下位机应答:
若正常:
字头
设备地址
##
异或
CR
若不正常:
字头
设备地址
**
异或
CR
例1:
写15号仪表,数据地址为15。
写数据255,数据类型为字,不打包。
组态王所发数据为:
40
30
46
43
35
30
30
30
46
30
32
30
30
46
46
37
34
0d
字头
设备地址15
标志
写操作
字型
不打包
数据地址15
数据字节数2
数据255
异或
若正确:
40
30
46
23
23
37
36
0d
字头
设备地址15
##
异或
若不正确:
40
30
46
2a
2a
37
36
0d
字头
设备地址15
**
异或
例2:
写15号仪表,数据地址为15。
写数据65535,数据类型为浮点型,打包。
组态王所发数据为:
40
30
46
43
46
30
30
30
46
30
34
31
30
46
46
46
46
30
30
字头
设备地址15
标志
写操作
浮点型
打包
数据地址15
数据字节数4
数据65535
30
30
0d
异或
若正确:
40
30
46
23
23
37
36
0d
字头
设备地址15
##
异或
若不正确:
40
30
46
2a
2a
37
36
0d
字头
设备地址15
**
异或
3、注:
仪表内部数据为十六进制表示的十进制数。
如:
实时测量值为500,则用十六进制表示为1F4H。
仪表通讯传输是将上述十六进制数据转化为标准ASCII码(即一字节的16进制数转化为2个ASCII码──高4位ASCII码+低4位ASCII码)。
如:
上述数据1F4H(16进制),传输时,转化为ASCII码则为30H、31H、46H、34H。
此浮点数格式的转换:
1)ASCII码到浮点数:
floatC4toD(char*c)
{
BYTE Hd[30],Jiema[30];
float DTc[30];
float Decimal=0;
memset(Hd,0,sizeof(Hd));
memset(Jiema,0,sizeof(Jiema));
memset(DTc,0,sizeof(DTc));
float returnflo=0;
BOOL ShuFU=FALSE,JieFU=FALSE;
if((c[7]>0x40)&&(c[7]<0x47))
Hd[7]=((c[7] -0x37)&0x0f);
elseif((c[7]>0x60)&&(c[7]<0x67))
Hd[7]=((c[7] -0x57)&0x0f);
else
Hd[7]=((c[7] -0x30)&0x0f);
if((c[6]>0x40)&&(c[6]<0x47))
Hd[6]=((c[6] -0x37)&0x0f);
elseif((c[6]>0x60)&&(c[6]<0x67))
Hd[6]=((c[6] -0x57)&0x0f);
else
Hd[6]=((c[6] -0x30)&0x0f);
DTc[2]=(float)(((float)(Hd[6]*16.0)+(float)(Hd[7]))/256.0);
if((c[5]>0x40)&&(c[5]<0x47))
Hd[5]=((c[5] -0x37)&0x0f);
elseif((c[5]>0x60)&&(c[5]<0x67))
Hd[5]=((c[5] -0x57)&0x0f);
else
Hd[5]=((c[5] -0x30)&0x0f);
if((c[4]>0x40)&&(c[4]<0x47))
Hd[4]=((c[4] -0x37)&0x0f);
elseif((c[4]>0x60)&&(c[4]<0x67))
Hd[4]=((c[4] -0x57)&0x0f);
else
Hd[4]=((c[4] -0x30)&0x0f);
DTc[1]=(float)((((float)(Hd[4]*16.0)+(float)Hd[5])+DTc[2])/256.0);
if((c[3]>0x40)&&(c[3]<0x47))
Hd[3]=((c[3] -0x37)&0x0f);
elseif((c[3]>0x60)&&(c[3]<0x67))
Hd[3]=((c[3] -0x57)&0x0f);
else
Hd[3]=((c[3] -0x30)&0x0f);
if((c[2]>0x40)&&(c[2]<0x47))
Hd[2]=((c[2] -0x37)&0x0f);
elseif((c[2]>0x60)&&(c[2]<0x67))
Hd[2]=((c[2] -0x57)&0x0f);
else
Hd[2]=((c[2] -0x30)&0x0f);
Decimal=(float)(((float)(Hd[2]*16)+(float)(Hd[3])+DTc[1])/256.0);
if((c[1]>0x40)&&(c[1]<0x47))
Jiema[1]=((c[1] -0x37)&0x0f);
elseif((c[1]>0x60)&&(c[1]<0x67))
Jiema[1]=((c[1] -0x57)&0x0f);
else
Jiema[1]=((c[1] -0x30)&0x0f);
if((c[0]>0x40)&&(c[0]<0x47))
Jiema[0]=((c[0] -0x37)&0x0f);
elseif((c[0]>0x60)&&(c[0]<0x67))
Jiema[0]=((c[0] -0x57)&0x0f);
else
Jiema[0]=((c[0] -0x30)&0x0f);
ShuFU=((Jiema[0]&0x08)>>3)>0;
JieFU=((Jiema[0]&0x04)>>2)>0;
Jiema[2]=(Jiema[0]&0x03)*16+Jiema[1];
if(JieFU)
returnflo=(float)pow(2,(-1)*Jiema[2])*Decimal;
else
returnflo=(float)pow(2,Jiema[2])*Decimal;
if(ShuFU)
returnflo=(-1)*returnflo;
returnreturnflo;
}
2)浮点数到ASCII码:
voidD4toC(char*c,floatd)
{
BYTE i=0,Jiema=0;
char inbyte1[30];
BOOL ShuFu=FALSE,JieFu=FALSE;
int inbyte2=0,inbyte3=0,inbyte4=0;
char afterbyte2[30],afterbyte3[30],afterbyte4[30];
float F_afterbyte2=0,F_afterbyte3=0,F_afterbyte4=0;
memset(inbyte1,0x30,sizeof(inbyte1));
memset(afterbyte2,0x30,sizeof(afterbyte2));
memset(afterbyte3,0x30,sizeof(afterbyte3));
memset(afterbyte4,0x30,sizeof(afterbyte4));
inbyte1[10]=0x0;
afterbyte2[10]=0x0;
afterbyte3[10]=0x0;
afterbyte4[10]=0x0;
if(d==0)
{
for(intj=0;j<8;j++)
c[j]=0x30;
return;
}
if(d<0)
{
ShuFu=TRUE;
d=(-1)*d;
}
while(d>1)
{
d=(float)(d/2.0);
i++;
}
while(d<=0.5)
{
JieFu=TRUE;
d=(float)(d*2.0);
i++;
}
if(d==1)
{
for(intj=2;j<8;j++)
c[j]=0x46;
}
else
{
inbyte2=(int)(d*256);
F_afterbyte2=(d*256)-(int)(d*256);
inbyte3=(int)(F_afterbyte2*256);
F_afterbyte3=(F_afterbyte2*256)-(int)(F_afterbyte2*256);
inbyte4=(int)(F_afterbyte3*256);
F_afterbyte4=(F_afterbyte3*256)-(int)(F_afterbyte3*256);
itoa(inbyte2,afterbyte2,16);
itoa(inbyte3,afterbyte3,16);
itoa(inbyte4,afterbyte4,16);
if(inbyte2==0)
{
c[2]