网站建设理论网站开发 思维导图
网站建设理论,网站开发 思维导图,那个网站可以做攻略,flash网站策划书Modbus RTU
与 Modbus TCP 的区别
一般在工业场景中#xff0c;使用 Modbus RTU 的场景更多一些#xff0c;Modbus RTU 基于串行协议进行收发数据#xff0c;包括 RS232/485 等工业总线协议。采用主从问答式#xff08;master / slave#xff09;通信。 与 Modbus TCP 不…Modbus RTU
与 Modbus TCP 的区别
一般在工业场景中使用 Modbus RTU 的场景更多一些Modbus RTU 基于串行协议进行收发数据包括 RS232/485 等工业总线协议。采用主从问答式master / slave通信。 与 Modbus TCP 不同的是RTU 没有报文头 MBAP 字段但是在尾部增加了两个 CRC 检验字节CRC16因为网络协议中自带校验所以在 TCP 协议中不需要使用 CRC 校验码。 RTU 和 TCP 的总体使用方法基本一致只是在创建 Modbus 对象时有所不同。TCP 需要传入网络socket 信息而 RTU 需要传入串口相关信息。
特点
通信
采用主从问答式master / slave通信由主机发起一问一答。
设置串口参数
波特率9600
数据位8
停止位1
无流控
协议格式地址码 功能码 数据 校验码 Modbus RTU 数据帧包含地址码、功能码、数据、校验码。 地址码 从机 ID 功能码 同 Modbus TCP 数据: 起始地址、数量、数据 CRC 校验码 两个字节对 地址码、功能码、数据 进行校验可以通过函数自动生成 报文详解 链接至另一博主放心跳转
以 03 功能码为例
主机 —— 从机 从机 —— 主机 模拟器的安装、配置、使用
实际硬件产品成本较高可以使用一系列 Modbus 软件模拟器进行数据模拟从而分析 Modbus RTU 协议。
所用工具
Modbus Slave、vspd 虚拟串口、UartAssist 串口调试工具、虚拟机
安装与配置
一vspd 虚拟串口的安装
1将压缩包解压后双击 vspd.exe 文件进行安装
2打开软件添加 COM1 和 COM2 端口用完之后记得删除端口
3打开设备管理器出现如下图所示即可
4可以汉化将 Cracked 下的文件复制到软件安装目录即可。
二虚拟机绑定端口
1VMware 虚拟机注意不是 ubuntu在系统关机必须是关机状态挂起不行状态下 点击虚拟机 —— 设置 —— 硬件 —— 添加串行端口添加 COM1
2添加完成后第一次使用需要将电脑重启 3重启之后打开虚拟机点击虚拟机 —— 可移动设备 —— 串行端口 —— 连接
4在终端输入dmesg|grep tty查看对应的设备文件其中默认的会有 ttyS0 文件 其余一个ttyS1 或 ttyS2就是虚拟串口对应的设备文件。
三测试通信
1Windows 下打开串口调试工具选择好串口 COM2 —— COM1设置对应的波特率
2以下步骤在虚拟机下完成在虚拟机安装 minicom 软件sudo apt-get install minicom
3在终端执行 sudo minicom -s 选择 Serial port setup
4设置设备文件波特率关闭流控按 Ctrl 相应字母
5回车保存修改选择 Save setup as dfl
6可以在以下界面输入字符查看串口助手的显示情况
7测试通信终端输入不可见
8退出Ctrl A然后按 Z在弹出的界面里输入X即可退出。
四将 Modbus Slave 模拟器作为 RTU 设备的从机
虚拟机绑定 COM1 端口Modbus Slave 连接 COM2 端口虚拟机通过编程测试串口通信
五可能遇到的问题
虚拟串口完成主机与 vmware 下虚拟机进行串口通信 VSPD 虚拟串口工具 —— 从此告别硬件串口调试 vmware 虚拟机检测不到 vspd 虚拟串口问题 链接至其他博主放心跳转
Modbus 库
库的安装
安装与配置
1在 linux 中解压压缩包tar -xvf libmodbus-3.1.7.tar.gz 2进入源码目录创建文件夹存放头文件、库文件 cd libmodbus-3.1.7 mkdir install 3执行脚本 configure进行安装配置指定安装目录 ./configure--prefix$PWD/install 4执行 make 和 make install make // 编译make install // 安装5执行完成后会在 install 文件夹下产生对应的头文件、库文件。
使用
1、一般操作
gcc xxx.c -I ./install/include/modbus -L ./install/lib -lmodbus
./a.out-I 后需要指定出头文件的路径大写的i -L 后需要指定库的路径 -l : 后需要指定库名小写的L 2、要想编译方便可以将头文件和库文件放到系统路径下
sudo cp install/include/modbus/*.h /usr/include
sudo cp install/lib/* -r /lib -d 后期编译时就可以直接 gcc xxx.c -lmodbus 头文件默认搜索路径/usr/include、/usr/local/include 库文件默认搜索路径/lib、/usr/lib
函数接口
0x01modbus_read_bits
int modbus_read_bits(modbus_t *ctx, int addr, int nb, uint8_t *dest); 功能读取线圈状态可读取多个连续线圈的状态对应功能码为0x01
参数ctx Modbus实例addr 寄存器起始地址nb 寄存器个数dest 得到的状态值0x02modbus_read_input_bits
int modbus_read_input_bits(modbus_t *ctx, int addr, int nb, uint8_t *dest); 功能读取输入状态可读取多个连续输入的状态对应功能码为0x02
参数ctx Modbus 实例addr 寄存器起始地址nb 寄存器个数dest 得到的状态值
返回值成功返回nb的值0x03modbus_read_registers
int modbus_read_registers(modbus_t *ctx, int addr, int nb, uint16_t *dest); 功能读取保持寄存器的值可读取多个连续保持寄存器的值对应功能码为0x03
参数ctx Modbus 实例addr 寄存器起始地址nb 寄存器个数dest 得到的寄存器的值
返回值成功读到寄存器的个数失败-10x04modbus_read_input_registers
int modbus_read_input_registers(modbus_t *ctx, int addr, int nb, uint16_t *dest);功能读输入寄存器的值可读取多个连续输入寄存器的值对应功能码为0x04
参数ctx Modbus 实例addr 寄存器起始地址nb 寄存器个数dest 得到的寄存器的值
返回值成功读到寄存器的个数失败-10x05modbus_write_bit
int modbus_write_bit(modbus_t *ctx, int addr, int status);功能写入单个线圈的状态对应功能码为0x05
参数ctx Modbus 实例addr 线圈地址status 线圈状态
返回值成功0失败-10x06modbus_write_register
int modbus_write_register(modbus_t *ctx, int addr, int value);功能写入单个寄存器对应功能码为0x06
参数 ctx Modbus 实例addr 寄存器地址value 寄存器的值
返回值成功0失败-10x0Fmodbus_write_bits
int modbus_write_bits(modbus_t *ctx, int addr, int nb, const uint8_t *src);功能写入多个连续线圈的状态对应功能码为15
参数ctx Modbus 实例addr 线圈地址nb 线圈个数src 多个线圈状态
返回值成功0失败-10x10modbus_write_registers
int modbus_write_registers(modbus_t *ctx, int addr, int nb, const uint16_t *src);功能写入多个连续寄存器对应功能码为16
参数ctx Modbus 实例addr 寄存器地址nb 寄存器的个数src 多个寄存器的值
返回值成功0失败-1编程流程
1创建实例modbus_new_tcp / modbus_new_rtu
modbus_t *modbus_new_tcp(const char *ip, int port); 功能以 TCP 方式创建 Modbus 实例并初始化
参数ip ip 地址port 端口号
返回值成功Modbus 实例失败NULLmodbus_t *modbus_new_rtu(const char *device, int baud, char parity, int data_bit, int stop_bit);功能用于创建一个用于 Modbus RTU 通信的 modbus_t 结构体实例
参数device 要打开的串口设备的路径例如/dev/ttyUSB0baud 波特率如 9600、19200 等parity 校验位可选值N - 无校验、E - 偶校验、O - 奇校验data_bit 数据位常用值为 8stop_bit 停止位常用值为 1返回值成功Modbus 实例失败NULL2设置从机地址modbus_set_slave
int modbus_set_slave(modbus_t *ctx, int slave);
功能设置从机ID
参数ctx Modbus 实例slave 从机 ID
返回值成功0失败-13建立连接modbus_connect
int modbus_connect(modbus_t *ctx);
功能和从机slave建立连接
参数ctx Modbus 实例
返回值成功0失败-14各种操作见函数接口
5关闭套接字modbus_close
void modbus_close(modbus_t *ctx);
功能关闭套接字
参数ctxModbus 实例6释放实例modbus_free
void modbus_free(modbus_t *ctx);
功能释放 Modbus 实例
参数ctxModbus 实例练习
// 和 Slave 通信读保持寄存器的三个值#include stdio.h
#include modbus.h
#include stdlib.h
#include string.h
#include modbus-rtu.hint main(int argc, char const *argv[])
{ if (argc ! 3){printf(Please input %s ip port. \n, argv[0]);return -1;}modbus_t *ctx;ctx modbus_new_tcp(argv[1], atoi(argv[2]));// ctx modbus_new_rtu(/dev/ttyS1, 9600, N, 8, 1);if (ctx NULL){perror(Failed to modbus_new_tcp); // Failed to modbus_new_rtureturn -1;}if (modbus_set_slave(ctx, 1) 0){perror(Failed to modbus_set_slave);return -1;}if (modbus_connect(ctx) 0){perror(Failed to modbus_connect);return -1;}uint16_t dest[32] {};if (modbus_read_registers(ctx, 0, 3, dest) 0){perror(Failed to modbus_read_registers);return -1;}for (int i 0; i 3; i)printf(%#x , dest[i]);putchar(10);for (int i 0; i 3; i)printf(%d , dest[i]);putchar(10);modbus_close(ctx);modbus_free(ctx);return 0;
}运行结果如下
注意
1、使用 Modbus TCP 协议时将 slave 的 connect 设置为“Modbus TCP/IP”。 2、使用 Modbus RTU 协议时将 slave 的 connect 设置为“Serial Port”。
小目标
编程实现采集传感器数据和控制硬件设备传感器和硬件通过 slave 模拟。 传感器2个光线传感器、加速度传感器x \ y \ z 硬件设备2个LED灯、蜂鸣器。 要求 1、多任务编程多线程、多进程 2、循环 1s 采集一次数据并将数据打印至终端 3、同时从终端输入指令控制硬件设备 0 1LED 灯开 0 0LED 灯关 1 1蜂鸣器开 1 0蜂鸣器关
// 同步实现#include stdio.h
#include modbus.h
#include stdlib.h
#include string.h
#include pthread.h
#include unistd.h
#include semaphore.hmodbus_t *ctx;
sem_t sem1, sem2;void *collector(void *arg){uint16_t *dest (uint16_t *)arg;while (1){sleep(5);sem_wait(sem1);if (modbus_read_registers(ctx, 0, 4, dest) 0){perror(Failed to modbus_read_registers);return NULL;}for (int i 0; i 4; i)printf(%d , dest[i]);putchar(10);sem_post(sem2);}pthread_exit(0);
}void *control(void *arg){uint8_t writer[2];while (1){sem_wait(sem2);printf(Please set status of LED or BUZZER: );for (int i 0; i 2; i)scanf(%hhu, writer[i]);modbus_write_bit(ctx, writer[0], writer[1]);sem_post(sem1);}pthread_exit(0);
}int main(int argc, char const *argv[])
{ if (argc ! 3){printf(Please input %s ip port. \n, argv[0]);return -1;}ctx modbus_new_tcp(argv[1], atoi(argv[2]));if (ctx NULL){perror(Failed to modbus_new_tcp);return -1;}if (modbus_set_slave(ctx, 1) 0){perror(Failed to modbus_set_slave);return -1;}if (modbus_connect(ctx) 0){perror(Failed to modbus_connect);return -1;}uint16_t dest[32] {};pthread_t tid1, tid2;sem_init(sem1, 0, 1);sem_init(sem2, 0, 0);if (pthread_create(tid1, NULL, collector, dest)){perror(Failed to create a thread named collector);return -1;}pthread_detach(tid1);if (pthread_create(tid2, NULL, control, NULL)){perror(Failed to create a thread named input);return -1;}pthread_detach(tid2);while (1);modbus_close(ctx);modbus_free(ctx);return 0;
}实现效果如下
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/90066.shtml
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!