11.3libmodbus情景分析
以“modbus_write_bits”函數為例,分析下圖的執行流程:
11.3.1
初始化
1. 主設備初始化
主設備程序先調用“modbus_new_rtu”函數,僅僅是分配一個modbus結構體,在里面記錄要使用的串口設備、參數:
左右滑動查看完整內容
modbus_t * modbus_new_rtu(const char *device, int baud, char parity, int data_bit, int stop_bi t);
再調用“modbus_set_slave”,是設置“要訪問哪個從設備”。每當訪問不同地址的設備之前,都應該調用這個函數。
最后調用“modbus_connect”函數,這個函數只是打開串口、設置串口參數,并沒有跟從設備進行數據交互。
2. 從設備初始化
從設備的初始化,跟主設備類似,不過多了使用“modbus_mapping_new_start_address”函數創建寄存器 buffer。
modbus_mapping_t結構體如下定義:
左右滑動查看完整內容
typedef struct _modbus_mapping_t { int nb_bits; int start_bits; int nb_input_bits; int start_input_bits; int nb_input_registers; int start_input_registers; int nb_registers; int start_registers; uint8_t *tab_bits; uint8_t *tab_input_bits; uint16_t *tab_input_registers; uint16_t *tab_registers; } modbus_mapping_t;
它被用來描述DI、DO、AI、AO四類寄存器。以DO寄存器為例,這個結構體里有3個成員:
①nb_bits:DO寄存器個數。
②start_bits:DO寄存器起始寄存器地址。
③tab_bits:指向一個“uint8_t”類型的數組,里面每個數組項表示一個DO寄存器,這個數組大小為nb_bits。數組中第0項,對應第“start_bits”個DO寄存器。
“modbus_mapping_new_start_address”函數原型
如下:
左右滑動查看完整內容
/* Allocates 4 arrays to store bits, input bits, registers and inputs registers. The pointers are stored in modbus_mapping structure. The modbus_mapping_new_start_address() function shall return the new allocated structure if successful. Otherwise it shall return NULL and set errno to ENOMEM. */ modbus_mapping_t *modbus_mapping_new_start_address(unsigned int start_bits, unsigned int nb_bits, unsigned int start_input_bits, unsigned int nb_input_bits, unsigned int start_registers, unsigned int nb_registers, unsigned int start_input_registers, unsigned int nb_input_registers);
假設從設備執行了如下代碼:
左右滑動查看完整內容
modbus_mapping_t *mb_mapping; mb_mapping = modbus_mapping_new_start_address(0, 4, /* DO, 4 個寄存器 */ 0, 3, /* DI, 3 個寄存器 */ 0, 2, /* AO, 2 個寄存器 */ 0, 1; /* AI, 1 個寄存器 */
將會分配出如下結構體:
modbus傳輸的本質,就是讀寫上圖中4個數組。
11.3.2
主設備發送請求
主設備調用“modbus_write_bits”函數,想寫若干個DO寄存器,比如:
左右滑動查看完整內容
01 uint8_t buf[2] = {1, 0}; 02 int rc = modbus_write_bits(ctx, 0, 2, buf);
根據Modbus RTU協議,它必定執行如下操作:
①構造數據包
②通過串口發送數據包
③等待、讀取回復
對于上述代碼,數據包的內容如下:
1. 先構造包頭
函數調用關系如下:
2. 再構造數據
代碼如下:
3. 計算檢驗碼
在發送數據包的函數里,先計算檢驗碼,代碼如下:
4. 發送數據包
前面構造好了數據包,發送就比較簡單:調用write函數進行發送即可。代碼如下:
11.3.3
從設備接收請求
從設備的程序一直在等待主機發來的消息,示例代碼如下:
“modbus_receive”函數內部實現為:
①使用select機制,逐個讀取字符
②根據讀到的字符,分辨還需要讀多少數據
1. 讀取單個字符
函數調用關系如下:
2. 判斷還需要讀取多少數據
從設備讀取主設備發來的請求包時,步驟為:
①先讀取“功能碼”
②再根據功能碼判斷后續要的包頭數據還剩多少,讀取包頭
③最后根據包頭數據解析要讀多少數據,讀取數據。
流程如下圖所示:
確定第1個階段數據長度的代碼如下:
讀到功能碼后,根據功能碼計算剩下的包頭的數據:
讀到完整的包頭后,計算剩下的數據長度:
3. 判斷數據完整性
就是根據校驗碼判斷數據是否有錯誤,代碼如下:
11.3.4
從設備回應
從設備接收到請求后,調用如下函數進行處理、回應:
在“modbus_reply”函數內部,它會:
①對于寫請求:把請求包中的數據解析出入,填入 mb_mapping中對應的寄存器buffer;
②對于讀請求:從mb_mapping中對應的寄存器buffer取出數據;
③構造回復包,發送給主設備。
本情景分析中,主設備調用“modbus_write_bits”函數,想寫兩個DO寄存器,比如:
左右滑動查看完整內容
01 uint8_t buf[2] = {1, 0}; 02 int rc = modbus_write_bits(ctx, 0, 2, buf);
從設備使用“modbus_reply”函數處理。
1. 根據請求包設置寄存器buffer
代碼如下:
2. 構造回復包
對于“寫多個DO寄存器”的請求,它的回復包格式如下:
下面的代碼,構造的回復包里含有上圖1、2的信息(在發送回復包時才構造校驗碼):
3. 發送回復包
最后,從設備發送回復包:
-
MODBUS
+關注
關注
28文章
1819瀏覽量
77200 -
MPU
+關注
關注
0文章
374瀏覽量
48882 -
函數
+關注
關注
3文章
4344瀏覽量
62855 -
LibModbus
+關注
關注
0文章
10瀏覽量
7265
原文標題:libmodbus情景分析 - RZ MPU工業控制教程連載(39)
文章出處:【微信號:瑞薩MCU小百科,微信公眾號:瑞薩MCU小百科】歡迎添加關注!文章轉載請注明出處。
發布評論請先 登錄
相關推薦
評論