资源描述
组态王与单片机协议
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
**
异或
5.浮点数格式:
4字节浮点数 = 第一字节高4位ASCII码+第一字节低4位ASCII码
+第二字节高4位ASCII码+第二字节低4位ASCII码
+第三字节高4位ASCII码+第三字节低4位ASCII码
+第四字节高4位ASCII码+第四字节低4位ASCII码
第1字节低4位 第2字节低4位 第3字节低4位 第4字节低4位
XXXX
XXXX
XXXX
XXXX
XXXX
XXXX
XXXX
XXXX
第1字节高4位 第2字节高4位 第3字节高4位 第4字节高4位
★ 四字节浮点数格式:
(1)第一字节
(2)第二字节
(3)第三字节
(4)第四字节
注: 数符=0——正, 数符=1——负 阶符=0——正, 阶符=1——负
数 符
阶 符
阶 码
D7 D6 D5 ~ D0
★ 浮点数可表示范围: -1×232~1×232
★ 数符: 1位 阶符: 1位 阶码: 6位
例: 流量积算控制仪表瞬时流量测量值数据=100.210
转换成浮点数: 100.210=27´0.7828125=0716+C816+6616+6616
=30ASCII+37ASCII+43ASCII+38ASCII+36ASCII+36ASCII+36ASCII+36ASCII
小数部份: 0.7828125 Þ 0.7828125´256=200.4Þ 0.4´256=102.4Þ0.4´256=102.4
小数部分乘以256
整数部份为第二字节(200)
第二字节小数部分乘以256
整数部份为第三字节(102)
第三字节小数部分乘以256
整数部份为第四字节(102)
10进制:
0
0
7
200
102
102
数 符
阶 符
阶 码
小 数 部 分
小 数 部 分
小 数 部 分
第一字节
第二字节
第三字节
第四字节
十六进制: ASCII码:
0
0
7
C8
66
66
30
37
43( C )、 38(8)
36(6)、 36(6)
36(6)、 36(6)
第一字节
第二字节
第三字节
第四字节
传输格式以下:
第1字节低4位 第2字节低4位 第3字节低4位 第4字节低4位
30
37
43
38
36
36
36
36
第1字节高4位 第2字节高4位 第3字节高4位 第4字节高4位
3、 注:
仪表内部数据为十六进制表示十进制数。如: 实时测量值为500, 则用十六进制表示为1F4H。仪表通讯传输是将上述十六进制数据转化为标准ASCII码(即一字节16进制数转化为2个ASCII码──高4位ASCII码+低4位ASCII码)。
如: 上述数据1F4H(16进制 ), 传输时, 转化为ASCII码则为30H、 31H、 46H、 34H。
6.此浮点数格式转换:
1) ASCII码到浮点数:
/*
in:char* c
要转化ASII码字符, 应为4个字符。
Return :转换后浮点数。
*/
float C4toD(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);
else if((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);
else if((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);
else if((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);
else if((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);
else if((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);
else if((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);
else if((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);
else if((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;
return returnflo;
}
2) 浮点数到ASCII码:
/*
in:char * c:
存放浮点数转换后ASCII码字符。
Float d:
要转换浮点数。
Return : 无。
*/
void D4toC(char * c,float d)
{
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(int j = 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(int j = 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] = 0x30;
c[3] = 0x30;
}
else if(inbyte2 < 16)
{
c[2] = 0x30;
c[3] = afterbyte2[0];
}
else
{
c[2] = afterbyte2[0];
c[3] = afterbyte2[1];
}
if(inbyte3 == 0)
{
c[4] = 0x30;
c[5] = 0x30;
}
else if(inbyte3 < 16)
{
c[4] = 0x30;
c[5] = afterbyte3[0];
}
else
{
c[4] = afterbyte3[0];
c[5] = afterbyte3[1];
}
if(inbyte4 == 0)
{
c[6] = 0x30;
c[7] = 0x30;
}
else if(inbyte4 < 16)
{
c[6] = 0x30;
c[7] = afterbyte4[0];
}
else
{
c[6] = afterbyte4[0];
c[7] = afterbyte4[1];
}
}
if(JieFu)
{
if(i > 0x3f)
i = 0x3f;
}
else if(i > 0x32)
i = 32;
if(ShuFu)
i = i | 0x80;
if(JieFu)
i = i | 0x40;
itoa(i, inbyte1, 16);
if(inbyte1 == 0)
{
c[0] = 0x30;
c[1] = 0x30;
}
else if(i < 16)
{
c[0] = 0x30;
c[1] = inbyte1[0];
}
else
{
c[0] = inbyte1[0];
c[1] = inbyte1[1];
}
for(i = 0; i < 8; i ++)
{
if((c[i] > 0x60) && (c[i] < 0x67))
c[i] = c[i] - 0x20;
}
c[8] = 0x00;
}
展开阅读全文