使用libmodbus讀傳感器流程

【1.項目描

手上有一個溫溼度傳感器,基於modbus RTU協議,採用RS485串口和Tiny6410通信,把採集到的溫溼度顯示在Tiny6410的界面程序上。這裏簡要給出使用libmodbus第三方工具讀取溫溼度的程序流程。關於libmodbus在嵌入式LINUX上的使用方法,參考上一篇博客:http://blog.chinaunix.net/uid-11829250-id-5750595.html

【2.關於libmodbus

libmodbus是一個免費開源的第三方modbus協議庫,可工作在多種平臺下。libmodbus支持RTU方式和TCP/IP方式。這裏傳感器使用的是modbus RTU方式。在modbus RTU方式中,對client/master和server/slave的是這樣定義的:
The Modbus RTU framing calls a slave, a device/service which handle Modbus requests, and a master, a client which send requests. The communication is always initiated by the master.
從這個定義中可以看出,構造RTU數據幀,並且響應modbus請求的一方是server/slave,而發出請求的一方是client/master,並且雙方通信總是由client/master一方發起。因此本項目中,溫溼度傳感器是server/slave一方,Tiny6410是client/master一方。

【3.溫溼度傳感器Modbus RTU協議

查看溫溼度傳感器手冊,採用RS485通信,採用串口參數爲波特率9600,數據位8,停止位1,無校驗位。若要讀取溫溼度數值,則Tiny6410要往溫溼度傳感器發送的請求幀爲:01 03 00 00 00 02 c4 0b,這裏都是十六進制表示。01表示溫溼度傳感器的從站地址;03是modbus功能碼,表示讀取保持寄存器的值;00 00是保持寄存器的地址;00 02是讀取寄存器的長度;c4 0b是CRC校驗位。正常情況下,溫溼度傳感器會返回給Tiny6410 TRU幀爲01 03 04 01 0F 02 16 CRCHCRCL。01爲從站地址;03爲modbus功能碼;04爲讀取的數據字節長度;010F爲溫度數據,換算成十進制後除以10,得到真實的溫度值;0216爲溼度數據,換算成十進制後除以10,得到真實的溼度值。

【4.libmods編寫讀傳感器溫溼度程序流程】

使用libmodbus讀取傳感器數值,一般要經過這樣幾個步驟(採用modbus RTU方式):
1.創建一個modbus_t類型的context,用來打開串口
modbus_t  *ctx;
ctx = modbus_new_rtu("/dev/ttySAC3",9600,'N',8,1);
這裏打開的串口是Tiny6410的串口3,波特率9600,無校驗,數據位是8,停止位是1。
2.建立連接
modbus_connect(ctx);//建立和傳感器的連接
3.設置超時時間:
    struct timeval t;
    t.tv_sec = 0;
    t.tv_usec = 1000000;//1000ms
    modbus_set_response_timeout(ctx,&t);
libmodbus中對 modbus_set_response_timeout的定義如下:
The modbus_set_response_timeout() function shall set the timeout interval used to wait for a response. If the waiting before receiving the response is longer than the given timeout, an error will be raised.
意思是如果在超時時間內還沒有收到響應,那麼就會發出一個錯誤碼。
4.設置slave地址
modbus_set_slave(ctx, 0x01);//溫溼度傳感器的modbus站地址爲0x01;
5.讀保持寄存器的值。
使用int modbus_read_registers(modbus_t *ctx, int addr, int nb, uint16_t *dest)讀取保持寄存器的值。對該函數的描述是:

The modbus_read_registers() function shall read the content of the nb holding registers to the address addr of the remote device. The result of reading is stored in dest array as word values (16 bits).

You must take care to allocate enough memory to store the results in dest (at least nb * sizeof(uint16_t)).

The function uses the Modbus function code 0x03 (read holding registers).

該函數用來讀保持寄存器的值,使用的功能碼是0x03,其中寄存器的起始地址放入addr參數,讀寄存器的個數放入nb參數,讀出的值放入dest。若讀取正確,返回值爲讀取的寄存器數,若讀取錯誤,返回值爲-1。針對本例,應使用的函數爲:
uint16_t tab_reg[2];
int regs=modbus_read_registers(ctx,0,2,tab_reg);
讀取溫溼度的請求幀爲:01 03 00 00 00 02 c4 0b,即寄存器地址爲0,要讀的寄存器個數爲2。若讀取成功,溫度數值置於tab_regp[0],溼度數值置於tab_reg[1],分別除以10,就得到正確的溫溼度數值。
5.釋放並關閉modbus
modbus_close(ctx); 
modbus_free(ctx);

此外,當有多個從站時,需要仔細設置 response timeout。這是摘錄libmodbus v3.1.2幫助文檔裏的一段話
The libmodbus implementation of RTU isn’t time based as stated in original Modbus specification, instead all bytes are sent as fast as possible and a response or an indication is considered complete when all expected characters have been received. This implementation offers very fast communication but you must take care to set a response timeout of slaves less than response timeout of master (ortherwise other slaves may ignore master requests when one of the slave is not responding).
這段話的意思是說,從站設置的response timeout應小於主站的response timeout,因此爲了防止出現某些從站因爲response timeout設置不恰當而不能響應的問題,建議把主站的response timeout設置的儘可能大一些。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章