Modbus学习总结2 modbus工作原理
liebian365 2024-10-23 13:46 15 浏览 0 评论
在实际编程过程中需要注意以下一些细节。
1、MODBUS 3.5T是如何计算的?
T = 1000毫秒*(1起始位+数据位+奇偶校验+停止位)/波特率
如果你的通讯方式是:波特率115200(表示每秒传输多少字符),数据位8,无奇偶校验。那么你发送一个字符的时间是:T=1000* (1起始位+8数据位+0奇偶校验+1停止位)/ 115200=0.087ms。
发送端:发送一帧后延时7*T(其中3.5T是停止时间,3.5T是起始时间)再发送第二帧,保证一帧数据里头各字节间间隔延时不能超过1.5T。
接收端:接收一个字节,查询2T时间,是否有接收到下一个字节,有则这帧数据未完,继续循环接收;没有则默认这帧已经接收完毕。
2、串口超时时间设置
COMMTIMEOUTS timeout;
//填充timeout结构
GetCommTimeouts(m_h232Port,&timeout);
timeout.ReadIntervalTimeout=100;//两字符之间最大的延时
timeout.ReadTotalTimeoutConstant=500;
timeout.ReadTotalTimeoutMultiplier=0;//读取每字符间的超时
timeout.WriteTotalTimeoutConstant=2000;
timeout.WriteTotalTimeoutMultiplier=60;//写入每字符间的超时
BOOLerror=SetCommTimeouts(m_hPort,&timeout);
ReadIntervalTimeout:两字符之间最大的延时,当读取串口数据时,一旦两个字符传输的时间差超过该时间,读取函数将返回现有的数据。设置为0表示该参数不起作用。
ReadTotalTimeoutMultiplier:读取每字符间的超时。
ReadTotalTimeoutConstant:一次读取串口数据的固定超时。所以在一次读取串口的操作中,其超时为ReadTotalTimeoutMultiplier乘以读取的字节数再加上 ReadTotalTimeoutConstant。将ReadIntervalTimeout设置为MAXDWORD,并将ReadTotalTimeoutMultiplier 和ReadTotalTimeoutConstant设置为0,表示读取操作将立即返回存放在输入缓冲区的字符。
WriteTotalTimeoutMultiplier:写入每字符间的超时。
WriteTotalTimeoutConstant:一次写入串口数据的固定超时。所以在一次写入串口的操作中,其超时为WriteTotalTimeoutMultiplier乘以写入的字节数再加上 WriteTotalTimeoutConstant。
3、串口编程。
在程序中如果要用到多个串口,而且还要做很多复杂的处理,那么最好不用MSComm通讯控件,网络上有很多封装好的串口类。
C++ class for Win32 serial ports:http://www.naughter.com/serialport.html
CSerialPort:https://github.com/itas109/CSerialPort
4、如何写稳定的modbus代码?
需要从稳定性和易读性来考虑,如果稳定性较差会造成系统控制故障,如果易读性差就会造成难以维护,这些控制指令之间差别很小,如果一个一个单独写命令,非常容易出错。对应举措如下:
1)避免每个指令写一部分代码,需要统一处理,比如校验函数,发送函数,接收函数等。通信协议已知,从中可以知道通信的实际数据长度(不包含包头包尾和校验的部分),所以可以控制读写多少个字节,并且可以知道什么时候启动校验,那些数据参与校验计算。
2)为指令建立指令列表,这样后来需要添加功能,就可以直接把指令字加入列表即可。
3)适当抽象。为每个指令的动作写回调函数,这样就可以在应用层,用一句简单的回调函数指针直接操作具体的动作函数,而不是应用逻辑层操作具体的驱动层面的接口。
4)超时,必须有超时机制。通信失败怎么处理?通信之后一般线断了怎么处理?不能让系统死等后面的几个字节发过来。
5)接收超时机制,不能依靠数传输的字节个数来停止接收来和区分帧间隔,因为可能通信就是断掉了,所以要按照协议,串口通信情况下3~5个T空闲就认为一帧结束。也可以通过协议事先计算出接收数据的总时间(字符数*(字符时间+字符间间隔时间)),使用该使用作为等待超时时间,但最长超时时间不能超过5T时间。
6)响应超时机制,Modbus是请求/应答式通信,那么主机就需要知道到底多久从机才会应答,主机等待从机应答的最长时间就是从机的最大回复间隔,超过这个时间后从机即使已经完成计算也不能回复,因为此时主机可能已经开始给其他从机发送数据了。
7)如果通信都是由你发起的,那么无论此次通信是完成还是超时或失败,都应该关闭通信端口。
8)如果是线程中操作串口,可以提升线程优先级,让操作系统在一定程度上提高串口读写性能。
9)ModbusRTU设备参数设置如下:
(1)内部属性:单击“查看设备内部属性” ,点击按钮进入内部属性
(2)最小采集周期:组态软件对设备进行操作的时间周期, 单位为 ms, 默认为100ms,根据采集数据量的大小,设置值可适当调整
(3)设备地址:必须和实际设备的地址相一致,范围为0-255,默认值为 0。
(4)通讯等待时间:通讯数据接收等待时间,默认设置为 200ms,根据采集数据量的大小,设置值可适当调整。
(5)快速采集次数:对选择了快速采集的通道进行快采的频率(已不使用,为与老驱动兼容,故保留,无需设置) 。
(6)16位整数解码顺序:调整字元件的解码顺序,对于Modicon PLC 及标准 PLC设备,使用默认值即可。
16 位整数解码顺序 举例:0x0001
0―12 表示字元件高低字节不颠倒(默认值) 表示 1
1―21 表示字元件高低字节颠倒 表示 256
(7)32位整数解码顺序:调整双字元件的解码顺序,对于Modicon PLC,请设置为“2-3412”顺序解码。
32 位整数解码顺序 举例: 0x0000 0001
0―1234 表示双字元件不做处理直接解码(默认值) 表示 1
1―2143 表示双字元件高低字不颠倒,但字内高低字节颠倒 表示256
2—3412表示双字元件高低字颠倒,但字内高低字节不颠倒 表示65536
3—4321表示双字元件内4个字节全部颠倒 表示 16777216
(8)32位浮点数解码顺序:调整双字元件的解码顺序,对于Modicon PLC,请设置为“2-3412”顺序解码。
32 位浮点数解码顺序 举例:0x3F80 0000
0―1234 表示双字元件不做处理直接解码(默认值) 表示 1.0
1―2143 表示双字元件高低字不颠倒,但字内高低字节颠倒 表示-5.78564e-039
2—3412表示双字元件高低字颠倒,但字内高低字节不颠倒 表示2.27795e-041
3—4321表示双字元件内4 个字节全部颠倒 表示 4.60060e-041
(9)校验方式: 选择LRC校验值的组合方式, 对于 Modicon PLC及标准 PLC 设备,
使用默认设置即可。
0—LH[低字节,高字节]:校验结果为2 个字节,低字节在前,高字节在后。
1—HL[高字节,低字节]:校验结果为2 个字节,高字节在前,低字节在后。默认值。
(10)分块采集方式:驱动采集数据分块的方式,对于Modicon PLC及标准 PLC设备,使用默认设置可以提高采集效率。
0— 按最大长度分块:采集分块按最大块长处理,对地址不连续但地址相近的多个分块,分为一块一次性读取,以优化采集效率。
1— 按连续地址分块:采集分块按地址连续性处理,对地址不连续的多个分块,每次只采集连续地址,不做优化处理。
例如:有4区寄存器地址分别为 1~5,7,9~12的数据需采集,如果选择“0-按最大长度分块” ,则两块可优化为地址1~12的数据打包1次完成采集;如果选择“1-按连续地址分块” ,则需要采集 3 次。
(11)4区16 位写功能码选择:写 4 区单字时功能码的选择,这个属性主要是针对自己制作设备的用户而设置的,这样的设备4区单字写可能只支持 0x10 功能码,而不支持0x06 功能码。
0—0x06:单字写功能码使用0x06。
1—0x10:单字写功能码使用0x10。
注意:
(1). “解码顺序”及“校验方式”设置:主要是针对非标准 ModbusRTU 协议的不同解码及校验顺序。当用户通过本驱动软件与设备通讯时,如果出现解析数据值不对,或者通讯校验错误(通讯状态为3),可与厂家咨询后对以上两项进行设置。而对于ModiconPLC及支持标准ModbusRTU 的 PLC 及控制器等设备,一般需将“32位整数解码顺序”和“32位浮点数解码顺序”设置为“2-3412” 。 另外,在使用本驱动与“Modbus 串口数据转发设备”构件通讯时, “解码顺序”及“校验方式”均需按默认值设置,否则会导致通讯失败或解析数据错误。
(2). “分块采集方式”设置:主要是针对非标准 ModbusRTU协议设备。当用户通过本驱动软件与设备通讯时,如果按默认“0-按最大长度分块”时,出现读取连续地址正常,而不连续地址不正常时,可与厂家咨询,并设置为“1-按连续地址分块方式”尝试是否可正常通讯。 而对于 Modicon PLC 及支持标准 ModbusRTU 的 PLC 及控制器等设备,直接使用默认设置即可,这样可以提高采集效率。
5、lrc和crc校验算法
//--------------------------------------------------------------------------
// Constants
//--------------------------------------------------------------------------
static const uint16_t modbus_crc_table[256] = {
0x0000, 0xc0c1, 0xc181, 0x0140, 0xc301, 0x03c0, 0x0280, 0xc241,
0xc601, 0x06c0, 0x0780, 0xc741, 0x0500, 0xc5c1, 0xc481, 0x0440,
0xcc01, 0x0cc0, 0x0d80, 0xcd41, 0x0f00, 0xcfc1, 0xce81, 0x0e40,
0x0a00, 0xcac1, 0xcb81, 0x0b40, 0xc901, 0x09c0, 0x0880, 0xc841,
0xd801, 0x18c0, 0x1980, 0xd941, 0x1b00, 0xdbc1, 0xda81, 0x1a40,
0x1e00, 0xdec1, 0xdf81, 0x1f40, 0xdd01, 0x1dc0, 0x1c80, 0xdc41,
0x1400, 0xd4c1, 0xd581, 0x1540, 0xd701, 0x17c0, 0x1680, 0xd641,
0xd201, 0x12c0, 0x1380, 0xd341, 0x1100, 0xd1c1, 0xd081, 0x1040,
0xf001, 0x30c0, 0x3180, 0xf141, 0x3300, 0xf3c1, 0xf281, 0x3240,
0x3600, 0xf6c1, 0xf781, 0x3740, 0xf501, 0x35c0, 0x3480, 0xf441,
0x3c00, 0xfcc1, 0xfd81, 0x3d40, 0xff01, 0x3fc0, 0x3e80, 0xfe41,
0xfa01, 0x3ac0, 0x3b80, 0xfb41, 0x3900, 0xf9c1, 0xf881, 0x3840,
0x2800, 0xe8c1, 0xe981, 0x2940, 0xeb01, 0x2bc0, 0x2a80, 0xea41,
0xee01, 0x2ec0, 0x2f80, 0xef41, 0x2d00, 0xedc1, 0xec81, 0x2c40,
0xe401, 0x24c0, 0x2580, 0xe541, 0x2700, 0xe7c1, 0xe681, 0x2640,
0x2200, 0xe2c1, 0xe381, 0x2340, 0xe101, 0x21c0, 0x2080, 0xe041,
0xa001, 0x60c0, 0x6180, 0xa141, 0x6300, 0xa3c1, 0xa281, 0x6240,
0x6600, 0xa6c1, 0xa781, 0x6740, 0xa501, 0x65c0, 0x6480, 0xa441,
0x6c00, 0xacc1, 0xad81, 0x6d40, 0xaf01, 0x6fc0, 0x6e80, 0xae41,
0xaa01, 0x6ac0, 0x6b80, 0xab41, 0x6900, 0xa9c1, 0xa881, 0x6840,
0x7800, 0xb8c1, 0xb981, 0x7940, 0xbb01, 0x7bc0, 0x7a80, 0xba41,
0xbe01, 0x7ec0, 0x7f80, 0xbf41, 0x7d00, 0xbdc1, 0xbc81, 0x7c40,
0xb401, 0x74c0, 0x7580, 0xb541, 0x7700, 0xb7c1, 0xb681, 0x7640,
0x7200, 0xb2c1, 0xb381, 0x7340, 0xb101, 0x71c0, 0x7080, 0xb041,
0x5000, 0x90c1, 0x9181, 0x5140, 0x9301, 0x53c0, 0x5280, 0x9241,
0x9601, 0x56c0, 0x5780, 0x9741, 0x5500, 0x95c1, 0x9481, 0x5440,
0x9c01, 0x5cc0, 0x5d80, 0x9d41, 0x5f00, 0x9fc1, 0x9e81, 0x5e40,
0x5a00, 0x9ac1, 0x9b81, 0x5b40, 0x9901, 0x59c0, 0x5880, 0x9841,
0x8801, 0x48c0, 0x4980, 0x8941, 0x4b00, 0x8bc1, 0x8a81, 0x4a40,
0x4e00, 0x8ec1, 0x8f81, 0x4f40, 0x8d01, 0x4dc0, 0x4c80, 0x8c41,
0x4400, 0x84c1, 0x8581, 0x4540, 0x8701, 0x47c0, 0x4680, 0x8641,
0x8201, 0x42c0, 0x4380, 0x8341, 0x4100, 0x81c1, 0x8081, 0x4040
};
//--------------------------------------------------------------------------
// Modbus functions
//--------------------------------------------------------------------------
uint8_t modbus_lrc_calc(uint8_t *data, uint16_t len)
{
uint8_t lrc = 0U;
int i;
for (i = 0U; i < len; i++)
{
lrc += data[i];
}
lrc = (0xFFU - lrc)+1U;
return(lrc);
}
uint16_t modbus_crc_calc(uint8_t *buffer, uint16_t size)
{
uint16_t crc = 0xFFFFU;
uint8_t nTemp;
while (size--)
{
nTemp = *buffer++ ^ crc;
crc >>= 8;
crc ^= modbus_crc_table[(nTemp & 0xFFU)];
}
return(crc);
}
LRC算出来的是16进制的字节值,若发送的数据是字符串形式,不需任何转换,直接放在字符串最后位置就行了。若发送的数据是数组形式,则需要转换为ASCII值,即由1字节的16进制转换为2字节的ASCII值,4D应该转换为34 44。
如果你的发送指令是:com.output="xxxxx",就是字符串形式;
如果发送指令形式是:com.output=A[],就是数组形式。
但不管是哪种形式,ModBus ASCII模式最终在数据线上的数据都是ASCII值。字符串形式的数据,编译软件会自动转换。
6、调试工具
Modbus Poll是一个Modbus管理模拟器软件,帮助开发人员进行管理和监控的Mod bus数据区在同一时间和模拟Mod bus协议。支持Modbus RTU / ASCII和Modbus TCP / IP协议。
下载地址:http://www.downcc.com/soft/25945.html
modbus slave是一款功能强大的modbus子设备模拟工具,可以帮助modbus通讯设备开发人员进行modbus通讯协议的模拟和测试,用于模拟、测试、调试modbus通讯设备。
下载地址:http://www.ddooo.com/softdown/70166.htm
7、modbus开源项目
https://github.com/stephane/libmodbus
相关推荐
- 4万多吨豪华游轮遇险 竟是因为这个原因……
-
(观察者网讯)4.7万吨豪华游轮搁浅,竟是因为油量太低?据观察者网此前报道,挪威游轮“维京天空”号上周六(23日)在挪威近海发生引擎故障搁浅。船上载有1300多人,其中28人受伤住院。经过数天的调...
- “菜鸟黑客”必用兵器之“渗透测试篇二”
-
"菜鸟黑客"必用兵器之"渗透测试篇二"上篇文章主要针对伙伴们对"渗透测试"应该如何学习?"渗透测试"的基本流程?本篇文章继续上次的分享,接着介绍一下黑客们常用的渗透测试工具有哪些?以及用实验环境让大家...
- 科幻春晚丨《震动羽翼说“Hello”》两万年星间飞行,探测器对地球的最终告白
-
作者|藤井太洋译者|祝力新【编者按】2021年科幻春晚的最后一篇小说,来自大家喜爱的日本科幻作家藤井太洋。小说将视角放在一颗太空探测器上,延续了他一贯的浪漫风格。...
- 麦子陪你做作业(二):KEGG通路数据库的正确打开姿势
-
作者:麦子KEGG是通路数据库中最庞大的,涵盖基因组网络信息,主要注释基因的功能和调控关系。当我们选到了合适的候选分子,单变量研究也已做完,接着研究机制的时便可使用到它。你需要了解你的分子目前已有哪些...
- 知存科技王绍迪:突破存储墙瓶颈,详解存算一体架构优势
-
智东西(公众号:zhidxcom)编辑|韦世玮智东西6月5日消息,近日,在落幕不久的GTIC2021嵌入式AI创新峰会上,知存科技CEO王绍迪博士以《存算一体AI芯片:AIoT设备的算力新选择》...
- 每日新闻播报(September 14)_每日新闻播报英文
-
AnOscarstatuestandscoveredwithplasticduringpreparationsleadinguptothe87thAcademyAward...
- 香港新巴城巴开放实时到站数据 供科技界研发使用
-
中新网3月22日电据香港《明报》报道,香港特区政府致力推动智慧城市,鼓励公私营机构开放数据,以便科技界研发使用。香港运输署21日与新巴及城巴(两巴)公司签署谅解备忘录,两巴将于2019年第3季度,开...
- 5款不容错过的APP: Red Bull Alert,Flipagram,WifiMapper
-
本周有不少非常出色的app推出,鸵鸟电台做了一个小合集。亮相本周榜单的有WifiMapper's安卓版的app,其中包含了RedBull的一款新型闹钟,还有一款可爱的怪物主题益智游戏。一起来看看我...
- Qt动画效果展示_qt显示图片
-
今天在这篇博文中,主要实践Qt动画,做一个实例来讲解Qt动画使用,其界面如下图所示(由于没有录制为gif动画图片,所以请各位下载查看效果):该程序使用应用程序单窗口,主窗口继承于QMainWindow...
- 如何从0到1设计实现一门自己的脚本语言
-
作者:dong...
- 三年级语文上册 仿写句子 需要的直接下载打印吧
-
描写秋天的好句好段1.秋天来了,山野变成了美丽的图画。苹果露出红红的脸庞,梨树挂起金黄的灯笼,高粱举起了燃烧的火把。大雁在天空一会儿写“人”字,一会儿写“一”字。2.花园里,菊花争奇斗艳,红的似火,粉...
- C++|那些一看就很简洁、优雅、经典的小代码段
-
目录0等概率随机洗牌:1大小写转换2字符串复制...
- 二年级上册语文必考句子仿写,家长打印,孩子照着练
-
二年级上册语文必考句子仿写,家长打印,孩子照着练。具体如下:...
你 发表评论:
欢迎- 一周热门
- 最近发表
- 标签列表
-
- wireshark怎么抓包 (75)
- qt sleep (64)
- cs1.6指令代码大全 (55)
- factory-method (60)
- sqlite3_bind_blob (52)
- hibernate update (63)
- c++ base64 (70)
- nc 命令 (52)
- wm_close (51)
- epollin (51)
- sqlca.sqlcode (57)
- lua ipairs (60)
- tv_usec (64)
- 命令行进入文件夹 (53)
- postgresql array (57)
- statfs函数 (57)
- .project文件 (54)
- lua require (56)
- for_each (67)
- c#工厂模式 (57)
- wxsqlite3 (66)
- dmesg -c (58)
- fopen参数 (53)
- tar -zxvf -c (55)
- 速递查询 (52)