新聞中心

        EEPW首頁 > 嵌入式系統 > 設計應用 > Modbus協議完全資料與程序解析

        Modbus協議完全資料與程序解析

        作者: 時間:2016-12-01 來源:網絡 收藏
        switch(Modbus_mode) //通過判斷模式來進行對響應的發送
        {
        case Modbus_read_coil:
        read_coil_proc();
        break;
        ……
        default:
        return;
        break;
        }
        這樣的做的話,就可以吧解析函數,執行函數和具體的實施函數分開來弄,層次多多少少要清晰一些
        下面就是針對01,02,03,04,05,06,15,16幾個功能碼的執行及返回進行說明
        在說明各功能函數之前,先說說響應。
        上面說的那兩個函數只不過是對一幀的外圍進行解析與判斷,至于具體的參數,還需要功能函數去解析與返回,功能函數要做的事情有3個,1個是參數的解析,2是執行,3是返回響應。
        先說響應,響應是有特點的,第一個字節肯定是自己的本機地址,第二個字節肯定是功能碼,最后兩個字節肯定是crc校驗,所以說,在發送緩沖中,基本上4個字節已經定死了
        Modbus_send_buf[0] = Modbus_addr;
        Modbus_send_buf[1] = Modbus_read_input_reg; //相應的功能碼,每個功能寒暑都不一樣
        再經過執行函數最后算crc
        modbus_crc = crc16(Modbus_send_buf,temp); //計算發送crc數據
        Modbus_send_buf[temp] = modbus_crc >> 8; //計算
        temp++;
        Modbus_send_buf[temp] = modbus_crc & 0xff; //return num 高位
        5.1 01 讀線圈狀態
        #define Modbus_read_coil 0x01
        其實表面上挺難理解的,啥線圈啥的,但你仔細看看就可以了解,就是讀輸出數字量,如果你寫下位機的話,其實就是控制讀取輸出io,說白了,就是把目前的io輸出狀態返回給主機。這些io連接的可能是繼電器,也可能是一些開關之類的東西,也就是些數字信號。讀數字輸出信號。
        計算機發送命令:[設備地址] [命令號01] [起始寄存器地址高8位] [低8位] [讀取的寄存器數高8位] [低8位]
        設備響應:[設備地址] [命令號01] [返回的字節個數][數據1][數據2]...[數據n][CRC校驗的低8位] [CRC校驗的高8位]
        簡單的說就是返回所有的輸出io的值,放在一個或者幾個字節里,可以用判斷的方法來實現,當然,也可以用與或的方式實現。
        if(P1_0 == 1)
        {
        temp |= (1<<8);
        }
        else
        {
        temp &= (1<<8);
        }
        將temp的值放入第四個緩沖區,當然這根據設備的io口,編程時就已經確定了的。接下來就可以進行crc計算了。最后發送即可。
        Modbus_send_buf[3] = temp;
        modbus_crc = crc16(Modbus_send_buf,4);
        Modbus_send_buf[4] = modbus_crc >> 8;
        Modbus_send_buf[5] = modbus_crc & 0xff; //return num 高位
        5.2 02 讀只可讀數字量寄存器(輸入狀態)
        基本上和01意思差不多,只不過這個功能碼返回的數據是輸入io的數據,和01的區別是01可讀可改,而02只可讀不可改。也就是輸入的狀態。數據不可由設備本身控制。程序方面和01程序一樣。
        5.3 03讀可讀寫模擬量寄存器(保持寄存器)
        說簡單點就是讀da,da屬于模擬量,也可以輸出,但是以模擬量的方式來進行傳輸的
        計算機發送命令:[設備地址] [命令號03] [起始寄存器地址高8位] [低8位] [讀取的寄存器數高8位] [低8位] [CRC校驗的低8位] [CRC校驗的高8位]
        設備響應:[設備地址] [命令號03] [返回的字節個數][數據1][數據2]...[數據n][CRC校驗的低8位] [CRC校驗的高8位]
        其中返回字節個數,為讀取寄存器數乘2
        寫程序時,首先要注意數據個數,temp = Modbus_recevie_buf[5];一般寄存器個數不會超過255,個數取讀取寄存器個數的低八位即可。返回即乘2,temp = temp << 1;,下面要做的就是一個循環for(i = 0;i < temp ; i += 2),把需要的數據放入發送數組。其內容是
        Modbus_send_buf[i+3]=(data_v&0xff00)>>8;
        Modbus_send_buf[i+4]=data_v&0x0ff;
        由于幀的前面3個是地址,功能碼,和返回字節個數,所以循環從第四個數據開始存放。data_v為讀取的數據,在程序中還需要其他語句配合。比如:data_v = updateValue();
        循環后就可以進入crc校驗了可以利用返回字節數來確定crc的校驗個數temp = temp + 3;,最后計算發送字節的個數
        send_cnt = Modbus_recevie_buf[5]*2 + 5 ; //數據發送個數 數據+地址+命令+返回數據個數+crc低+crc高
        最后將數據發送出去即可。
        5.4 04讀只可讀模擬量寄存器(輸入寄存器)
        和03的區別是04就是讀ad,ad輸入輸入模擬兩,只能讀,不能改,同樣也是以模擬兩的方式來進行傳輸的。其程序 與03類似
        5.5 05寫數字量(線圈狀態)
        05則是修改io口輸出狀態,數字量輸出。
        計算機發送命令:[設備地址] [命令號05] [需下置的寄存器地址高8位] [低8位] [下置的數據高8位] [低8位] [CRC校驗的低8位] [CRC校驗的高8位]
        設備響應:若執行成功,則原樣返回
        寫程序時,首先確定需要修改的io口,然后根據0xff00或0x0000來置位或清零該數據位。執行完成后,將接收到的數據重新發送即可 Uart0_senddata(Modbus_recevie_buf,8);
        5.6 06寫單個模擬量寄存器(保持寄存器)
        06為修改設備da數據,模擬量傳輸數據。
        計算機發送命令:[設備地址] [命令號06] [需下置的寄存器地址高8位] [低8位] [下置的數據高8位] [低8位] [CRC校驗的低8位] [CRC校驗的高8位]
        設備響應:若執行成功,原樣返回即可
        5.7 16主機設置寄存器
        簡單的說,就是一次設置多個da,以一個偏移量為準,一次設置多個輸出模擬里量
        計算機發送命令:[設備地址] [命令號10] [開始地址高8位] [低8位] [寄存器個數高8位] [低8位] [第一個寄存器數據高][第一個寄存器數據低][第二個寄存器數據高][第二個寄存器數據低]……[CRC校驗的低8位] [CRC校驗的高8位]
        命令響應:功能碼[0x10],寄存器起始地址高字節,低字節,要寫的寄存器數量的高字節,低字節,CRC校驗低字節,高字節
        在程序中,首先要獲取寄存器個數
        num = Modbus_recevie_buf[6] - 2;
        然后進入循環,一次把寄存器數據提取出來for(i = 0; i < num; i = i + 2)
        在循環的內部提取數據temp = (((unsigned int)(Modbus_recevie_buf[i+7])<<8)|(Modbus_recevie_buf[i+8]));
        以上就是我在項目中涉及到的一點modbus的通訊的下位機程序,不全,但總體的思路,接收數據并解析,解析后提取數據在設備上加載或采集,然后再按照響應的方式發送回去。
        下回改進的方向,1,增加功能碼2,增加宏定義及編譯定義,3增加單片主機的程序,和pc主從機的程序。4,增加ascii的程序,和rtu同時設置。Pc機程序,采用c#號編寫。
        完整的程序請參考:http://www.51hei.com/bbs/dpj-23230-1.html
        上一頁 1 2 下一頁

        評論


        技術專區

        關閉
        主站蜘蛛池模板: 浦北县| 平顺县| 沙雅县| 无极县| 临城县| 新余市| 泾源县| 松江区| 安义县| 怀化市| 铜川市| 红河县| 甘肃省| 隆德县| 锦屏县| 三门峡市| 双峰县| 奉贤区| 尉犁县| 永川市| 新巴尔虎右旗| 永昌县| 如皋市| 庆城县| 天门市| 阿克陶县| 栾川县| 内丘县| 扶沟县| 孟连| 恩平市| 共和县| 桐城市| 丹棱县| 固阳县| 永新县| 太康县| 濮阳县| 常宁市| 泸州市| 临桂县|