11.5 Modbus RTU客戶(hù)端編程與實(shí)驗(yàn)
瑞米派開(kāi)發(fā)板作為client(主設(shè)備),去訪(fǎng)問(wèn)Modbus傳感器(作為Server)。
本節(jié)源碼位于如下目錄:

11.5.1 硬件連接
硬件連接原理圖如下:

實(shí)物連接圖如下:

11.5.2 傳感器點(diǎn)表
對(duì)于Modbus設(shè)備,怎么訪(fǎng)問(wèn)它們?它們的寄存器分別有什么功能?這在“點(diǎn)表”里描述,每個(gè)寄存器被稱(chēng)為一個(gè)“點(diǎn)”。
百問(wèn)網(wǎng)的溫濕度傳感器的點(diǎn)表如下:
|
設(shè)備 地址 |
寄存器 地址 |
寄存器 類(lèi)別 |
用途 | 描述 |
| 03H | 0000H | DO | 控制器蜂鳴1 | 1-響 |
| 0001H | DO | 控制器蜂鳴2 | 1-響 | |
| 0002H | DO | 控制LED1 | 1-亮 | |
| 0003H | DO | 控制LED2 | 1-亮 | |
| 0004H | DO | 控制LED3 | 1-亮 | |
| 0000H | AI | 讀取溫度 |
單位0.1攝氏度 16位有符號(hào)整數(shù) |
|
| 0001H | AI | 讀取濕度 |
單位0.1%RH 16位有符合整數(shù) |
11.5.3 程序解析
代碼在如下目錄里:

假設(shè)執(zhí)行如下命令:
左右滑動(dòng)查看完整內(nèi)容
./modbus_client /dev/ttySC4 read
程序運(yùn)行的情景分析如下
1. 初始化與連接
代碼如下:
左右滑動(dòng)查看完整內(nèi)容
33 ctx = modbus_new_rtu(argv[1], 115200, 'N', 8, 1);
34 if (ctx == NULL) {
35 fprintf(stderr, "Unable to allocate libmodbus context
");
36 return -1;
37 }
38
39 modbus_set_slave(ctx, SERVER_ID);
40
41 if (modbus_connect(ctx) == -1) {
42 fprintf(stderr, "Connection failed: %s
", modbus_strerror(errno));
43 modbus_free(ctx);
44 return -1;
45 }
第33行:分配一個(gè)modbus_t結(jié)構(gòu)體。
第39行:設(shè)置要訪(fǎng)問(wèn)的Modbus傳感器地址。
第41行:打開(kāi)串口設(shè)備。
2. 讀取傳感器數(shù)據(jù)
代碼如下:
左右滑動(dòng)查看完整內(nèi)容
47 if (!strcmp(argv[2], "read"))
48 {
49 while (1)
50 {
51 rc = modbus_read_input_registers(ctx, 0, 2, vals);
52 if (rc == 2)
53 {
54 printf("Temprature = %d.%dC, Humity = %d.%d%%
", vals[0]/10, val
s[0]%10, vals[1]/10, vals[1]%10);
55 }
56 else
57 {
58 printf("modbus_read_input_registers err: %d, %s
", rc, strerror
(errno));
59 }
60 sleep(2);
61 }
62 }
第51行:讀取2個(gè)AI寄存器。
第54行:打印溫濕度值。
11.5.4 上機(jī)實(shí)驗(yàn)
注意:假設(shè)你在“/home/ubuntu/apps/libmodbus-3.1.10”目錄下編譯了Libmodbus,并且在“/home/ubuntu/apps/libmodbus-3.1.10/tmp”目錄下安裝了Libmodbus。如果你的路徑不一樣,需要修改后續(xù)程序的Makefile。
把代碼上傳到Ubuntu。
然后,在Ubuntu下執(zhí)行如下命令進(jìn)行編譯:
左右滑動(dòng)查看完整內(nèi)容
$ source /opt/remi-sdk/environment-setup-aarch64-poky-linux $ make $ scp modbus_client root@192.168.5.9:/mnt
最后,在開(kāi)發(fā)板上執(zhí)行如下命令:
左右滑動(dòng)查看完整內(nèi)容
# cd /mnt # ./modbus_client /dev/ttySC4 beep1 on modbus_write_bit ok # ./modbus_client /dev/ttySC4 beep1 off modbus_write_bit ok # ./modbus_client /dev/ttySC4 led1 on modbus_write_bit ok # ./modbus_client /dev/ttySC4 led1 off modbus_write_bit ok # ./modbus_client /dev/ttySC4 read Temprature = 32.0C, Humity = 39.2% Temprature = 31.9C, Humity = 39.2%
11.6 Modbus RTU服務(wù)器端編程與實(shí)驗(yàn)
要把瑞米派當(dāng)做一個(gè)Modbus服務(wù)器(傳感器)來(lái)使用,需要有另一個(gè)開(kāi)發(fā)板作為客戶(hù)端。為了方便實(shí)驗(yàn),本課程使用同一個(gè)瑞米派開(kāi)發(fā)板,它運(yùn)行2個(gè)程序:一個(gè)模擬服務(wù)器,另一個(gè)模擬客戶(hù)端。
本節(jié)源碼位于如下目錄:

硬件框圖與連接如下所示。
11.6.1 硬件連接
硬件連接原理圖如下:

實(shí)物連接圖如下:

11.6.2 程序解析
代碼在如下目錄里:

“modbus_server.c”代碼解析如下。
1. 初始化與連接
代碼如下:
左右滑動(dòng)查看完整內(nèi)容
40 ctx = modbus_new_rtu(argv[1], 115200, 'N', 8, 1);
41 if (ctx == NULL) {
42 fprintf(stderr, "Unable to allocate libmodbus context
");
43 return -1;
44 }
45
46 modbus_set_slave(ctx, SERVER_ID);
47
48 mb_mapping = modbus_mapping_new_start_address(0,
49 NB_BITS, /* 5 個(gè) DO 寄存器,對(duì)應(yīng) beep1,beep2,led1,led2,led3 */
50 0,
51 NB_INPUT_BITS,
52 0,
53 NB_REGISTERS,
54 0,
55 NB_INPUT_REGISTERS); /* 2 個(gè) AI 寄存器,對(duì)應(yīng)溫度和濕度 */
56 memset(mb_mapping->tab_bits, 0, NB_BITS);
57 memset(mb_mapping->tab_input_registers, 0, NB_INPUT_REGISTERS*2);
58
59 memset(old_bits, 0, NB_BITS);
60 memset(old_regs, 0, NB_INPUT_REGISTERS*2);
61
62 if (modbus_connect(ctx) == -1) {
63 fprintf(stderr, "Connection failed: %s
", modbus_strerror(errno));
64 modbus_free(ctx);
65 return -1;
66 }
第40行:分配一個(gè)modbus_t結(jié)構(gòu)體。
第46行:設(shè)置自己的傳感器地址。
第48~55行:分配Modbus寄存器。
第56~57行:設(shè)置DO、AI寄存器初始值為0。
第59~60行:設(shè)置2個(gè)數(shù)組的值為0,這2個(gè)數(shù)組將用來(lái)跟Modbus寄存器進(jìn)行比較,這樣才能知道Client程序有沒(méi)有修改這些值。
第62行:打開(kāi)串口設(shè)備。
2. 等待Client程序發(fā)來(lái)請(qǐng)求
代碼如下:
左右滑動(dòng)查看完整內(nèi)容
68 while (1)
69 {
70 do {
71 rc = modbus_receive(ctx, query);
72 /* Filtered queries return 0 */
73 } while (rc == 0);
第71行:讀取請(qǐng)求。
3. 模擬溫濕度傳感器
代碼如下:
左右滑動(dòng)查看完整內(nèi)容
82 /* 使用隨機(jī)數(shù)模擬溫度、濕度 */ 83 mb_mapping->tab_input_registers[0] = rand() % 1000; /* 溫度,單位:0.1C */ 84 mb_mapping->tab_input_registers[1] = rand() % 1000; /* 濕度,單位:0.1% */
4. 回復(fù)數(shù)據(jù)給Client
代碼如下:
左右滑動(dòng)查看完整內(nèi)容
86 rc = modbus_reply(ctx, query, rc, mb_mapping);
87 if (rc == -1) {
88 //break;
89 }
如果Client發(fā)來(lái)的請(qǐng)求是讀取溫濕度值的話(huà),那么第86行就會(huì)回復(fù)數(shù)據(jù)給它。
5. 模擬蜂鳴器和LED操作
代碼如下:
左右滑動(dòng)查看完整內(nèi)容
91 /* 根據(jù) client 設(shè)置的數(shù)值,假裝操作蜂鳴器和 LED */
92 if (mb_mapping->tab_bits[0] != old_bits[0])
93 {
94 printf("set beep1 %s
", mb_mapping->tab_bits[0] ? "on" : "off");
95 old_bits[0] = mb_mapping->tab_bits[0];
96 }
97
98 if (mb_mapping->tab_bits[1] != old_bits[1])
99 {
100 printf("set beep2 %s
", mb_mapping->tab_bits[1] ? "on" : "off");
101 old_bits[1] = mb_mapping->tab_bits[1];
102 }
103
104 if (mb_mapping->tab_bits[2] != old_bits[2])
105 {
106 printf("set led1 %s
", mb_mapping->tab_bits[2] ? "on" : "off");
107 old_bits[2] = mb_mapping->tab_bits[2];
108 }
109
110 if (mb_mapping->tab_bits[3] != old_bits[4])
111 {
112 printf("set led2 %s
", mb_mapping->tab_bits[4] ? "on" : "off");
113 old_bits[3] = mb_mapping->tab_bits[4];
114 }
115
116 if (mb_mapping->tab_bits[4] != old_bits[4])
117 {
118 printf("set led3 %s
", mb_mapping->tab_bits[4] ? "on" : "off");
119 old_bits[4] = mb_mapping->tab_bits[4];
120 }
代碼比較簡(jiǎn)單,不再贅述。
11.6.3 上機(jī)實(shí)驗(yàn)
把代碼上傳到Ubuntu。
然后,在Ubuntu下執(zhí)行如下命令進(jìn)行編譯:
左右滑動(dòng)查看完整內(nèi)容
$ source /opt/remi-sdk/environment-setup-aarch64-poky-linux $ make $ scp modbus_client root@192.168.5.9:/home/root $ scp modbus_server root@192.168.5.9:/home/root
最后,在開(kāi)發(fā)板上執(zhí)行如下命令(先執(zhí)行 modbus_server):
左右滑動(dòng)查看完整內(nèi)容
# cd /home/root # ./modbus_server /dev/ttySC2 & # ./modbus_client /dev/ttySC4 beep1 on modbus_write_bit ok # ./modbus_client /dev/ttySC4 beep1 off modbus_write_bit ok # ./modbus_client /dev/ttySC4 led1 on modbus_write_bit ok # ./modbus_client /dev/ttySC4 led1 off modbus_write_bit ok # ./modbus_client /dev/ttySC4 read Temprature = 64.9C, Humity = 42.1% Temprature = 36.2C, Humity = 2.7% Temprature = 69.0C, Humity = 5.9%
-
傳感器
+關(guān)注
關(guān)注
2573文章
54316瀏覽量
785423 -
MODBUS
+關(guān)注
關(guān)注
28文章
2381瀏覽量
82189 -
服務(wù)器
+關(guān)注
關(guān)注
13文章
10077瀏覽量
90826 -
RTU
+關(guān)注
關(guān)注
0文章
447瀏覽量
30399
發(fā)布評(píng)論請(qǐng)先 登錄
服務(wù)器端模式下的TCP通信
MKW45B41Z客戶(hù)端無(wú)法從服務(wù)器獲取服務(wù)是為什么?
用隊(duì)列實(shí)現(xiàn)的1對(duì)N的TCP服務(wù)器端,自動(dòng)回復(fù)信息總發(fā)錯(cuò)客戶(hù)端
TCP視頻服務(wù)器&客戶(hù)端 - 版本LabVIEW 2012
qt tcp程序在服務(wù)器端發(fā)送數(shù)據(jù)之前能接收客戶(hù)端發(fā)送的數(shù)據(jù)嗎?
一個(gè)服務(wù)器,多個(gè)客戶(hù)端,怎么向指定的客戶(hù)端發(fā)數(shù)據(jù)
labview怎么實(shí)現(xiàn)服務(wù)器端一直等待客戶(hù)端發(fā)送數(shù)據(jù)啊
為什么LWIP的TCP客戶(hù)端服務(wù)器端斷開(kāi)后繼續(xù)發(fā)送數(shù)據(jù)就無(wú)法檢測(cè)到連接狀態(tài)?
4412開(kāi)發(fā)板Qt網(wǎng)絡(luò)編程-TCP實(shí)現(xiàn)服務(wù)器和客戶(hù)端
監(jiān)控系統(tǒng)客戶(hù)端及服務(wù)端設(shè)計(jì)
網(wǎng)絡(luò)調(diào)試和串口調(diào)試集合UDP TCP客戶(hù)端和TCP服務(wù)器端應(yīng)用程序免費(fèi)下載
TCP通信服務(wù)器端和客戶(hù)端同機(jī)互傳的簡(jiǎn)單示例程序免費(fèi)下載
數(shù)據(jù)是怎么樣保證準(zhǔn)確的從客戶(hù)端發(fā)送到服務(wù)器端
Linux下TCP網(wǎng)絡(luò)編程-創(chuàng)建服務(wù)器與客戶(hù)端

Modbus RTU客戶(hù)端及服務(wù)器端的編程與實(shí)驗(yàn)
評(píng)論