实验3 MODBUS主站实验
1. 实验目的
串口屏作为Modbus主站,读取和设置温湿度模块的参数。
说明:型号名称中带有字母M的,表示支持modbus协议。
2. 页面设计
项目设置里面,勾选Modbus主机,表示显示屏作为modbus主站。
Page0页面控件
(1)浮点数控件,显示温度值
(2)整数控件,显示湿度值
(3)按钮控件,点击按钮切到第二页
(4)定时控件,定时每秒发送读取帧,获取从机寄存器值,并显示。选中可以查看事件脚本代码。
(5)modbus控件
page1页面控件
(1)浮点数控件,显示温度告警值
(2)按钮控件,调用modbus写函数,设置温度告警值
(3)文本控件,显示温度告警设置是否成功
(4)整数控件,显示湿度告警值
(5)按钮控件,调用modbus写函数,设置湿度告警值
(6)文本控件,显示湿度告警设置是否成功
3. 串口屏协议处理
modbus协议简单介绍
注:modbus介绍取自于《MODBUS协议中文版》部分,详细介绍请查阅modbus相关资料。
MODBUS 协议定义了一个与基础通信层无关的P简单协议数据单元(DU)。特定总线或网络上的 MODBUS 协议映射能够在应用数据单元(ADU)上引入一些附加域
modbus有主站和从站的区分,一个完整的总线上有一个主站和若干从站,每个从站有自己独特的地址,区分哪个是从站设备。
地址域:即从站地址,1字节,用一个字节编码 MODBUS 数据单元的功能码域。有效的码字范围是十进制 1-255(128-255 为异常响应保留)。
功能码:1字节,当从客户机向服务器设备发送报文时,功能码通知服务器执行哪种操作。
数据:根据不同功能码,有着不同的数据格式和长度
差错校验:循环冗余校验 (CRC)
有两种串行传输模式被定义: RTU 模式 和 ASCII 模式。
它定义了报文域的位内容在线路上串行的传送。它确定了信息如何打包为报文和解码。
Modbus 串行链路上所有设备的传输模式 (和串行口参数) 必须相同。
尽管在特定的领域 ASCII 模式是要求的,但达到 Modbus 设备之间的互操作性只有每个设备都有
相同的模式: 所有设备必须必须实现 RTU 模式。 ASCII 传输模式是选项。
设备应该由用户设成期望的模式, RTU 或 ASCII。 默认设置必须为 RTU 模式。
RTU传输模式是常用的方式,报文帧格式如下:
Modbus RTU 帧最大为 256 字节。
本实验,显示屏作为主站,通过modbus协议标准获取温度模块的参数。
温度模块modbus参数如下:
设备地址 |
寄存器地址 |
|||
---|---|---|---|---|
1 |
0x0000 |
温度H |
只读 |
float类型,两个寄存器表示温度,单位0.1℃ |
0x0001 |
温度L |
|||
0x0002 |
温度报警值H |
读写 |
float类型,两个寄存器表示温度,单位0.1℃ |
|
0x0003 |
温度报警值L |
|||
0x0004 |
湿度 |
只读 |
16位整数类型,单位%rh |
|
0x0005 |
湿度报警值 |
读写 |
||
读功能码0x03,写功能码0x10 |
modbus为控件控件名称(也可以改为其他名字),与modbus协议帧对应的控件属性如下:
从站地址 |
功能码 |
数据 |
校验 |
---|---|---|---|
modbus.addr |
Modbus.fcode |
modbus.rxBuf |
定时器控件用于定时查询寄存器值,脚本代码如下:
//定时每秒查询一次寄存器状态
//从机的寄存器有0x0000~0x0005,一共6个寄存器,是连续地址,可以一次读多个寄存器
//如果地址不连续,可能需要分多次读取,或许按需要读取
/**********************本实验寄存器列表**********************************
0x0000 温度H 只读 float类型,两个寄存器表示温度,单位0.1℃
0x0001 温度L
0x0002 温度报警值H 读写 float类型,两个寄存器表示温度,单位0.1℃
0x0003 温度报警值L
0x0004 湿度 只读 16位整数类型,单位%rh
0x0005 湿度报警值 读写
**********************************************************************/
int Return;
/*********modbus帧与控件属性的对应关系***********
从站地址 功能码 数据 校验
modbus.addr Modbus.fcode modbus.rxBuf
**********************************************/
/*从Modbus总线读数据
设备地址0x01,功能码0x03,起始地址0x0000,读寄存器数量6,超时50mS
超时时间一般情况50ms足够,根据波特率不同可以调整。
注意:定时器脚本里面的所有读写函数的超时时间 总和 不要超过定时器间隔时间
*/
//读寄存器 参数(从机地址 功能码 寄存器起始地址 寄存器数量 超时时间)
Return = modbusRead(0x01,0x03,0x0000,6,50);
if(Return == 0) //一定要检测返回值,返回值为0,表示读取成功
{
//获取温度值
temp.valf = bytesToFloat(modbus.rxBuf,1,1); //将4个字节转换成一个浮点数。modbus.rxBuf[1~4]
//读寄存器值时,返回数据缓存在modbus控件的rxBuf属性中,其中modbus.rxBuf[0]为属性modbus.rxLen的值,
//所以数据从modbus.rxBuf[1]开始取
//获取温度告警值
page1.temp_alarm.valf = bytesToFloat(modbus.rxBuf,5,1);//将4个字节转换成一个浮点数。modbus.rxBuf[5~8]
//获取湿度值
hum.val = (modbus.rxBuf[9]<<8) | modbus.rxBuf[10];
//获取湿度告警值
page1.hum_alarm.val = (modbus.rxBuf[11]<<8) | modbus.rxBuf[12];
}
Page1的设置按钮,弹起事件主要是寄存器写操作,脚本代码如下
int res;
byte a[4];
floatToBytes(temp_alarm.valf,a,0,1);
//写操作函数:参数(从机地址 功能码 寄存器地址 寄存器数量 数组 数组长度 超时时间)
res = modbusWrites (0x01, 0x10, 0x0002, 2, a, 4, 50);
if(res == 0)
{
text5.txt = "Set OK";
}
else
{
text5.txt = "Set Fail";
}
page0.timer2.en = 1;
解析的主要过程,是对modbus.rxBuf字节数组的处理。上面读操作,使用了移位+按位或操作得到一个无符号的整数并赋值为控件,用于显示;还使用字节转浮点数的函数bytesToFloat,将4个字节转换成一个浮点数。具体函数相关的介绍,可以参考第五章函数的介绍。
4. 下载验证
编译成功后,点击下载按钮,选择正确的端口号和波特率,下载到串口屏。可以看到显示如下显示:
用VP软件将例程下载到串口屏,连接温湿度模块,即可看到温湿度模块的参数。
调试时,将显示屏的串口数据发送到电脑的串口助手上,查看读命令、写命令是否正确: