modbus之libmodbus

一、libmodbus簡(jiǎn)介

libmodbus是一個(gè)快速且可移植的Modbus庫宰衙,支持傳統(tǒng)的RS-232、RS-422睹欲、RS-485和以太網(wǎng)設(shè)備供炼。

二、安裝libmodbus

//進(jìn)入解壓目錄
cd libmodbus-3.1.6
//配置編譯選項(xiàng)(以ARM為例闸衫,--build為系統(tǒng)構(gòu)架 --host為編譯對(duì)應(yīng)系統(tǒng)工具鏈涛贯,--prefix為輸出目錄,選項(xiàng)均是可選的)
./configure --build=i686 --host=arm-linux --enable-static --prefix=[install path]/
//編譯安裝
make && make install

三蔚出、簡(jiǎn)單示例

  • RTU master
#include <stdio.h>
#include <stdlib.h>
#include <memory.h>
#include "modbus.h"

int main(void)
{ 
    int i = 0;
    int regs = 0;
    modbus_t *ctx = NULL;
    uint16_t tab_reg[64] = {0};

    //打開端口: 端口弟翘,波特率虫腋,校驗(yàn)位,數(shù)據(jù)位稀余,停止位
    ctx = modbus_new_rtu("/dev/ttyUSB0", 9600, 'N', 8, 1);
    //設(shè)置從機(jī)地址
    modbus_set_slave(ctx, 1);
    //設(shè)置串口模式(可選)
    modbus_rtu_set_serial_mode(ctx, MODBUS_RTU_RS485);
    //設(shè)置RTS(可選)
    modbus_rtu_set_rts(ctx, MODBUS_RTU_RTS_UP);
    //建立連接
    if (modbus_connect(ctx) == -1) {
        fprintf(stderr, "Connexion failed: %s\n", modbus_strerror(errno));
        modbus_free(ctx);
        return -1;
    }
    //設(shè)置應(yīng)答延時(shí)(可選)
    modbus_set_response_timeout(ctx, 0, 1000000);

    while (1)
    {
        memset(tab_reg, 0, sizeof(tab_reg));
        //讀寄存器設(shè)置:寄存器地址悦冀、數(shù)量、數(shù)據(jù)緩沖
        regs = modbus_read_registers(ctx, 0, 20, tab_reg);
        if (rc == -1) {
           fprintf(stderr, "%s\n", modbus_strerror(errno));
           continue;
        }
        printf("[%4d][read num = %d]", num++, regs);
        for (i = 0; i < 20; ++i)
        {
            printf("<%#x>", tab_reg[i]);
        }
        printf("\n");
        sleep(1);
    }
}
  • RTU-Master流程總結(jié):
  1. 初始化 modbus 指針
  2. 設(shè)置從站ID
  3. 建立連接
  4. 讀取保持寄存器/輸入寄存器/離散輸入/線圈輸入
  5. 寫單個(gè)寄存器/多個(gè)寄存器/多位數(shù)據(jù)
  6. 關(guān)閉連接
  • RTU slave
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <error.h>
#include <memory.h>
#include "modbus.h"

int main(void)
{ 
    int i = 0;
    int rc = 0;
    modbus_t *ctx = NULL;
    modbus_mapping_t *mb_mapping = NULL;
    uint8_t query[MODBUS_TCP_MAX_ADU_LENGTH];

    //打開端口: 端口睛琳,波特率盒蟆,校驗(yàn)位,數(shù)據(jù)位师骗,停止位
    ctx = modbus_new_rtu("/dev/ttyUSB0", 9600, 'N', 8, 1);
    //設(shè)置從機(jī)地址
    modbus_set_slave(ctx, 1);
    //設(shè)置串口模式
    //modbus_rtu_set_serial_mode(ctx, MODBUS_RTU_RS485);
    //設(shè)置RTS
    //modbus_rtu_set_rts(ctx, MODBUS_RTU_RTS_UP);
    //建立連接
    if (modbus_connect(ctx) == -1) {
        fprintf(stderr, "Connexion failed: %s\n", modbus_strerror(errno));
        modbus_free(ctx);
        return -1;
    }
    mb_mapping = modbus_mapping_new(MODBUS_MAX_READ_BITS, 0,
                                    MODBUS_MAX_READ_REGISTERS, 0);
    if (mb_mapping == NULL) {
        fprintf(stderr, "Failed to allocate the mapping: %s\n",
                modbus_strerror(errno));
        modbus_free(ctx);
        return -1;
    }

   //初始化幾個(gè)寄存器
   mb_mapping->tab_registers[0] = 1;
   mb_mapping->tab_registers[1] = 2;
   mb_mapping->tab_registers[2] = 3;
   mb_mapping->tab_registers[3] = 4;
   mb_mapping->tab_registers[4] = 5;
   mb_mapping->tab_registers[5] = 6;

    while (1)
    {
        memset(query, 0, sizeof(query));
        rc = modbus_receive(ctx, query);
        if (rc > 0) {
            modbus_reply(ctx, query, rc, mb_mapping);
        } else if (rc  == -1) {
            //Connection closed by the client or error
            break;
        }
    }

    printf("Quit the loop: %s\n", modbus_strerror(errno));

    modbus_mapping_free(mb_mapping);
    if (s != -1) {
        close(s);
    }
    modbus_close(ctx);
    modbus_free(ctx);
}

RTU-Slave流程總結(jié):

  1. 初始化 modbus 指針;
  2. 設(shè)置從站ID;
  3. modbus_mapping_new初始化寄存器历等,返回一個(gè)modbus_mapping_t 指針;
  4. 建立連接;
  5. 調(diào)用 modbus_receive 函數(shù)判斷串口的接收數(shù)據(jù),負(fù)責(zé)接收處理及回復(fù)丧凤。
  • TCP master
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <error.h>
#include <memory.h>
#include <sys/socket.h>
#include "modbus.h"

void main(void)
{
    int i;
    int regs = 0;
    int num = 0;
    modbus_t *ctx = NULL;
    uint16_t tab_reg[64] = {0};
   
    ctx = modbus_new_tcp("127.0.0.1",8000);
    modbus_set_slave(ctx, 1);
    modbus_connect(ctx);
    modbus_set_response_timeout(ctx, 0, 1000000);
   
    while (1)
    {
        memset(tab_reg, 0, sizeof(tab_reg));
        regs = modbus_read_registers(ctx, 0, 20, tab_reg);
        printf("[%4d][read num = %d]", num++, regs);
        for (i = 0; i < 20; i++)
        {
            printf("<%#x>", tab_reg[i]);
        }
        printf("\n");
        sleep(1);
    }

    modbus_close(ctx);
    modbus_free(ctx);
}
  • TCP slave
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <error.h>
#include <memory.h>
#include <sys/socket.h>
#include "modbus.h"

int main(void)
{ 
    int i = 0;
    int rc = 0;
    modbus_t *ctx = NULL;
    modbus_mapping_t *mb_mapping = NULL;
    uint8_t query[MODBUS_TCP_MAX_ADU_LENGTH];

    //打開端口: ip, port
    ctx = modbus_new_tcp("127.0.0.1", 8000);
    //設(shè)置從機(jī)地址
    modbus_set_slave(ctx, 1);
    //建立連接
    if (modbus_connect(ctx) == -1) {
        fprintf(stderr, "Connexion failed: %s\n", modbus_strerror(errno));
        modbus_free(ctx);
        return -1;
    }
    mb_mapping = modbus_mapping_new(MODBUS_MAX_READ_BITS, 0,
                                    MODBUS_MAX_READ_REGISTERS, 0);
    if (mb_mapping == NULL) {
        fprintf(stderr, "Failed to allocate the mapping: %s\n",
                modbus_strerror(errno));
        modbus_free(ctx);
        return -1;
    }

   //初始化幾個(gè)寄存器
   mb_mapping->tab_registers[0] = 1;
   mb_mapping->tab_registers[1] = 2;
   mb_mapping->tab_registers[2] = 3;
   mb_mapping->tab_registers[3] = 4;
   mb_mapping->tab_registers[4] = 5;
   mb_mapping->tab_registers[5] = 6;

    while (1)
    {
        memset(query, 0, sizeof(query));
        rc = modbus_receive(ctx, query);
        if (rc > 0) {
            modbus_reply(ctx, query, rc, mb_mapping);
        } else if (rc  == -1) {
            //Connection closed by the client or error
            break;
        }
    }

    printf("Quit the loop: %s\n", modbus_strerror(errno));

    modbus_mapping_free(mb_mapping);
    if (s != -1) {
        close(s);
    }
    modbus_close(ctx);
    modbus_free(ctx);
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末募闲,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子愿待,更是在濱河造成了極大的恐慌浩螺,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,744評(píng)論 6 502
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件仍侥,死亡現(xiàn)場(chǎng)離奇詭異要出,居然都是意外死亡烙心,警方通過查閱死者的電腦和手機(jī)出革,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,505評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來霞掺,“玉大人砸紊,你說我怎么就攤上這事传于。” “怎么了醉顽?”我有些...
    開封第一講書人閱讀 163,105評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵沼溜,是天一觀的道長。 經(jīng)常有香客問我游添,道長系草,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,242評(píng)論 1 292
  • 正文 為了忘掉前任唆涝,我火速辦了婚禮找都,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘廊酣。我一直安慰自己能耻,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,269評(píng)論 6 389
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著嚎京,像睡著了一般嗡贺。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上鞍帝,一...
    開封第一講書人閱讀 51,215評(píng)論 1 299
  • 那天诫睬,我揣著相機(jī)與錄音,去河邊找鬼帕涌。 笑死摄凡,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的蚓曼。 我是一名探鬼主播亲澡,決...
    沈念sama閱讀 40,096評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼纫版!你這毒婦竟也來了床绪?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,939評(píng)論 0 274
  • 序言:老撾萬榮一對(duì)情侶失蹤其弊,失蹤者是張志新(化名)和其女友劉穎癞己,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體梭伐,經(jīng)...
    沈念sama閱讀 45,354評(píng)論 1 311
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡痹雅,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,573評(píng)論 2 333
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了糊识。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片绩社。...
    茶點(diǎn)故事閱讀 39,745評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖赂苗,靈堂內(nèi)的尸體忽然破棺而出愉耙,到底是詐尸還是另有隱情,我是刑警寧澤拌滋,帶...
    沈念sama閱讀 35,448評(píng)論 5 344
  • 正文 年R本政府宣布劲阎,位于F島的核電站,受9級(jí)特大地震影響鸠真,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜龄毡,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,048評(píng)論 3 327
  • 文/蒙蒙 一吠卷、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧沦零,春花似錦祭隔、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,683評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽千贯。三九已至,卻和暖如春搞坝,著一層夾襖步出監(jiān)牢的瞬間搔谴,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,838評(píng)論 1 269
  • 我被黑心中介騙來泰國打工桩撮, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留敦第,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,776評(píng)論 2 369
  • 正文 我出身青樓店量,卻偏偏與公主長得像芜果,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子融师,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,652評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容