11.5 Modbus RTU客戶端編程與實驗
瑞米派開發板作為client(主設備),去訪問Modbus傳感器(作為Server)。
本節源碼位于如下目錄:


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

實物連接圖如下:


11.5.2 傳感器點表
對于Modbus設備,怎么訪問它們?它們的寄存器分別有什么功能?這在“點表”里描述,每個寄存器被稱為一個“點”。
百問網的溫濕度傳感器的點表如下:
設備 地址 | 寄存器 地址 | 寄存器 類別 | 用途 | 描述 |
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位有符號整數 | |
0001H | AI | 讀取濕度 | 單位0.1%RH 16位有符合整數 |

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

假設執行如下命令:
./modbus_client /dev/ttySC4 read程序運行的情景分析如下
1. 初始化與連接
代碼如下:
33 ctx = modbus_new_rtu(argv[1], 115200, 'N', 8, 1);34 if (ctx == NULL) {35 fprintf(stderr, "Unable to allocate libmodbus context\n");36 return -1;37 }3839 modbus_set_slave(ctx, SERVER_ID);4041 if (modbus_connect(ctx) == -1) {42 fprintf(stderr, "Connection failed: %s\n", modbus_strerror(errno));43 modbus_free(ctx);44 return -1;45 }
第33行:分配一個modbus_t結構體。
第39行:設置要訪問的Modbus傳感器地址。
第41行:打開串口設備。
2. 讀取傳感器數據
代碼如下:
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%%\r\n", vals[0]/10, vals[0]%10, vals[1]/10, vals[1]%10);55 }56 else57 {58 printf("modbus_read_input_registers err: %d, %s\r\n", rc, strerror(errno));59 }60 sleep(2);61 }62 }
第51行:讀取2個AI寄存器。
第54行:打印溫濕度值。

11.5.4 上機實驗
注意:假設你在“/home/ubuntu/apps/libmodbus-3.1.10”目錄下編譯了Libmodbus,并且在“/home/ubuntu/apps/libmodbus-3.1.10/tmp”目錄下安裝了Libmodbus。如果你的路徑不一樣,需要修改后續程序的Makefile。
把代碼上傳到Ubuntu。
然后,在Ubuntu下執行如下命令進行編譯:
$ source /opt/remi-sdk/environment-setup-aarch64-poky-linux$ make$ scp modbus_client root@192.168.5.9:/mnt
最后,在開發板上執行如下命令:
# ./modbus_client /dev/ttySC4 beep1 onmodbus_write_bit ok# ./modbus_client /dev/ttySC4 beep1 offmodbus_write_bit ok# ./modbus_client /dev/ttySC4 led1 onmodbus_write_bit ok# ./modbus_client /dev/ttySC4 led1 offmodbus_write_bit ok# ./modbus_client /dev/ttySC4 readTemprature = 32.0C, Humity = 39.2%Temprature = 31.9C, Humity = 39.2%
11.6 Modbus RTU服務器端編程與實驗
要把瑞米派當做一個Modbus服務器(傳感器)來使用,需要有另一個開發板作為客戶端。為了方便實驗,本課程使用同一個瑞米派開發板,它運行2個程序:一個模擬服務器,另一個模擬客戶端。
本節源碼位于如下目錄:

硬件框圖與連接如下所示。

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

實物連接圖如下:


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

“modbus_server.c”代碼解析如下。
1. 初始化與連接
代碼如下:
40 ctx = modbus_new_rtu(argv[1], 115200, 'N', 8, 1);41 if (ctx == NULL) {42 fprintf(stderr, "Unable to allocate libmodbus context\n");43 return -1;44 }4546 modbus_set_slave(ctx, SERVER_ID);4748 mb_mapping = modbus_mapping_new_start_address(0,49 NB_BITS, /* 5 個 DO 寄存器,對應 beep1,beep2,led1,led2,led3 */50 0,51 NB_INPUT_BITS,52 0,53 NB_REGISTERS,54 0,55 NB_INPUT_REGISTERS); /* 2 個 AI 寄存器,對應溫度和濕度 */56 memset(mb_mapping->tab_bits, 0, NB_BITS);57 memset(mb_mapping->tab_input_registers, 0, NB_INPUT_REGISTERS*2);5859 memset(old_bits, 0, NB_BITS);60 memset(old_regs, 0, NB_INPUT_REGISTERS*2);6162 if (modbus_connect(ctx) == -1) {63 fprintf(stderr, "Connection failed: %s\n", modbus_strerror(errno));64 modbus_free(ctx);65 return -1;66 }
第40行:分配一個modbus_t結構體。
第46行:設置自己的傳感器地址。
第48~55行:分配Modbus寄存器。
第56~57行:設置DO、AI寄存器初始值為0。
第59~60行:設置2個數組的值為0,這2個數組將用來跟Modbus寄存器進行比較,這樣才能知道Client程序有沒有修改這些值。
第62行:打開串口設備。
2. 等待Client程序發來請求
代碼如下:
68 while (1)69 {70 do {71 rc = modbus_receive(ctx, query);72 /* Filtered queries return 0 */73 } while (rc == 0);
第71行:讀取請求。
3. 模擬溫濕度傳感器
代碼如下:
82 /* 使用隨機數模擬溫度、濕度 */83 mb_mapping->tab_input_registers[0] = rand() % 1000; /* 溫度,單位:0.1C */84 mb_mapping->tab_input_registers[1] = rand() % 1000; /* 濕度,單位:0.1% */
4. 回復數據給Client
代碼如下:
86 rc = modbus_reply(ctx, query, rc, mb_mapping);87 if (rc == -1) {88 //break;89 }
如果Client發來的請求是讀取溫濕度值的話,那么第86行就會回復數據給它。
5. 模擬蜂鳴器和LED操作
代碼如下:
91 /* 根據 client 設置的數值,假裝操作蜂鳴器和 LED */92 if (mb_mapping->tab_bits[0] != old_bits[0])93 {94 printf("set beep1 %s\r\n", mb_mapping->tab_bits[0] ? "on" : "off");95 old_bits[0] = mb_mapping->tab_bits[0];96 }9798 if (mb_mapping->tab_bits[1] != old_bits[1])99 {100 printf("set beep2 %s\r\n", mb_mapping->tab_bits[1] ? "on" : "off");101 old_bits[1] = mb_mapping->tab_bits[1];102 }103104 if (mb_mapping->tab_bits[2] != old_bits[2])105 {106 printf("set led1 %s\r\n", mb_mapping->tab_bits[2] ? "on" : "off");107 old_bits[2] = mb_mapping->tab_bits[2];108 }109110 if (mb_mapping->tab_bits[3] != old_bits[4])111 {112 printf("set led2 %s\r\n", mb_mapping->tab_bits[4] ? "on" : "off");113 old_bits[3] = mb_mapping->tab_bits[4];114 }115116 if (mb_mapping->tab_bits[4] != old_bits[4])117 {118 printf("set led3 %s\r\n", mb_mapping->tab_bits[4] ? "on" : "off");119 old_bits[4] = mb_mapping->tab_bits[4];120 }
代碼比較簡單,不再贅述。
11.6.3 上機實驗
把代碼上傳到Ubuntu。
然后,在Ubuntu下執行如下命令進行編譯:
$ 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
最后,在開發板上執行如下命令(先執行 modbus_server):
# ./modbus_server /dev/ttySC2 &# ./modbus_client /dev/ttySC4 beep1 onmodbus_write_bit ok# ./modbus_client /dev/ttySC4 beep1 offmodbus_write_bit ok# ./modbus_client /dev/ttySC4 led1 onmodbus_write_bit ok# ./modbus_client /dev/ttySC4 led1 offmodbus_write_bit ok# ./modbus_client /dev/ttySC4 readTemprature = 64.9C, Humity = 42.1%Temprature = 36.2C, Humity = 2.7%Temprature = 69.0C, Humity = 5.9%


需要產品及方案支持
請掃碼登記
如您在使用瑞薩MCU/MPU產品中有任何問題,可識別下方二維碼或復制網址到瀏覽器中打開,進入瑞薩技術論壇尋找答案或獲取在線技術支持。
https://community-ja.renesas.com/zh/forums-groups/mcu-mpu/
未完待續
推薦閱讀
libmodbus情景分析 - RZ MPU工業控制教程連載(39)
主設備讀取回應與常用接口函數 - RZ MPU工業控制教程連載(40)
Modbus接口與數據處理 - RZ MPU工業控制教程連載(41)



需要產品及方案支持
請掃碼登記