Modbus簡介
參考:Modbus協議深入講解 https://www.ni.com/zh-cn/innovations/white-papers/14/the-modbus-protocol-in-depth.html
http://www.sohu.com/a/230628953_315598
官方文檔:http://www.modbus.org/docs/Modbus_Application_Protocol_V1_1b3.pdf
Modbus協議包括ASCII、RTU、TCP等,並沒有規定物理層。此協議定義了控制器能夠認識和使用的消息結構,而不管它們是經過何種網絡進行通信的。標准的Modicon控制器使用RS232C實現串行的Modbus。Modbus的ASCII、RTU協議規定了消息、數據的結構、命令和就答的方式,數據通訊采用Maser/Slave方式,Master端發出數據請求消息,Slave端接收到正確消息后就可以發送數據到Master端以響應請求;Master端也可以直接發消息修改Slave端的數據,實現雙向讀寫。
其通信協議理解也比較簡單,其幀結構如下

地址碼 + 功能碼 + 數據區 + 錯誤校驗
常用功能碼

最常使用的讀寫功能碼如下;
01 讀取單個/多個線圈狀態(類似DO:數字輸出)
02 讀取單個/多個離散輸入(類似DI:數字輸入)
03 讀取單個/多個保存寄存器
04 讀取單個/多個輸入寄存器(類似AI:模擬輸入)
05 寫單個線圈狀態
06 寫單個保存寄存器
15 寫多個線圈
16 寫多個保存寄存器
FreeModbus簡析
FreeMODBUS 提供了RTU/ASCII 傳輸模式及TCP協議支持。
FreeModbus協議對硬件的需求非常少——基本上任何具有串行接口,並且有一些能夠容納modbus數據幀的RAM的微控制器都足夠了。
現支持如下功能碼:
- Read Input Register (0x04)
- Read Holding Registers (0x03)
- Write Single Register (0x06)
- Write Multiple Registers (0x10)
- Read/Write Multiple Registers (0x17)
- Read Coils (0x01)
- Write Single Coil (0x05)
- Write Multiple Coils (0x0F)
- Read Discrete Inputs (0x02)
- Report Slave ID (0x11)
FreeModbus源碼解析
參考:https://blog.csdn.net/u014748120/article/details/80313215
待續。。。
Modbus通信實現
本文測試主機為 arm-linux,可以使用 libmodbus 靜態庫實現modbus通信,為追求可移植性,本文主要使用 freemodbus 來實現。
1. libmodbus使用
ubuntu系統使用libmodbus可以使用以下命令安裝
sudo apt-get install libmodbus-dev # 或者 sudo apt-get install libmodbus5
使用文檔參考:https://libmodbus.org/documentation/
庫參考手冊:https://libmodbus.org/docs/v3.1.4/
移植到arm的話則需下載源碼進行交叉編譯 http://libmodbus.org/releases/libmodbus-3.1.4.tar.gz
解壓安裝
tar -xzvf libmodbus-3.1.4.tar.gz cd libmodbus-3.1.4 # 新建安裝文件夾 mkdir -p install chmod 777 install ./configure --prefix=$(pwd)/install --host=arm-linux --enable-static ac_cv_func_malloc_0_nonnull=yes CC=arm-fsl-linux-gnueabi-gcc
make
make install
在我的應用程序工程里面新建一個 libmodbus 文件夾,將上面安裝 install目錄下的 include和lib文件夾拷貝過來

我的工程總體結構如下所示

在 mys_src 里面添加 modbus 主機測試程序 modbus_test.c
makefile編寫如下所示:
#編譯配置,使能為1 CONFIG_MODBUS_BUILD = 1 #當前路徑 CUR_DIR := $(shell pwd) #libmodbus目錄 LIBMODBUS_DIR := $(CUR_DIR)/../libmodbus # 頭文件路徑 INCLUDE := INCLUDE += -I$(CUR_DIR)/../include/ ifeq ($(CONFIG_MODBUS_BUILD), 1) INCLUDE += -I$(LIBMODBUS_DIR)/include/modbus/ endif #C編譯器的選項 CFLAGS := CFLAGS += -g -Wall CFLAGS += -std=gnu99 CFLAGS += $(INCLUDE) #庫文件參數 LDFLAGS := #libmodbus共享庫鏈接 #LDFLAGS += -L$(LIBMODBUS_DIR)/lib #libmodbus靜態庫鏈接 ifeq ($(CONFIG_MODBUS_BUILD), 1) LDFLAGS += $(LIBMODBUS_DIR)/lib/libmodbus.a endif SRCS += modbus_test.c OBJS += modbus_test.o BINS += modbus_test all:$(OBJS) $(BINS) $(OBJS):%.o:%.c $(CC) -c $(CFLAGS) $^ -o $(OBJ_DIR)/$@ $(BINS):$(OBJS) $(CC) -o $(BIN_DIR)/$@ $(OBJ_DIR)/$^ $(LDFLAGS)
modbus_test.c
#include <stdio.h> #include <unistd.h> #include <string.h> #include <stdlib.h> #include <errno.h> #include <modbus.h> #define MODBUS_DEV_NAME "/dev/ttymxc3" ///< 串口設備 int main(void) { modbus_t *ctx =NULL; // 以串口的方式創建libmobus實例,並設置參數 ctx = modbus_new_rtu(MODBUS_DEV_NAME, 115200, 'N', 8, 1); if (ctx == NULL) //使用UART4,對應的設備描述符為ttymxc3 { fprintf(stderr, "Unable to allocate libmodbus contex\n"); return -1; } // 使用RS485時需考慮設置串口模式、RTS引腳等 // modbus_rtu_set_serial_mode(MODBUS_RTU_RS485); //設置串口模式 modbus_set_debug(ctx, 1); //設置1可看到調試信息 modbus_set_slave(ctx, 1); //設置slave ID if (modbus_connect(ctx) == -1) //等待連接設備 { fprintf(stderr, "Connection failed:%s\n", modbus_strerror(errno)); return -1; } int i,rc; uint16_t tab_reg[64] = {0}; //定義存放數據的數組 while (1) { printf("\n----------------\n"); //讀取保持寄存器的值,可讀取多個連續輸入保持寄存器 rc = modbus_read_registers(ctx, 0, 10, tab_reg); if (rc == -1) { fprintf(stderr,"%s\n", modbus_strerror(errno)); return -1; } for (i=0; i<10; i++) { printf("reg[%d] = %d(0x%x)\n", i, tab_reg[i], tab_reg[i]); } usleep(5000000); } modbus_close(ctx); //關閉modbus連接 modbus_free(ctx); //釋放modbus資源,使用完libmodbus需要釋放掉 return 0; }
編譯之后可通過nfs掛載進行測試
modbus從機模擬
Modbus slave測試工具可以用來做modbus從機設備,從而實現arm控制板通過串口與PC端模擬的modbus從機進行通信測試。
Modbus slave下載地址:https://www.modbustools.com/download/ModbusSlaveSetup64Bit.exe

然后設置 setup->slave definition 從機ID、設置為保存寄存器,10條

同時我們也給寄存器設置一些值

開發板運行測試程序后,成功讀取modbus從機寄存器值

2.freemodbus在linux上的使用
待續。。。
