<meter id="pryje"><nav id="pryje"><delect id="pryje"></delect></nav></meter>
          <label id="pryje"></label>

          新聞中心

          EEPW首頁(yè) > 嵌入式系統(tǒng) > 設(shè)計(jì)應(yīng)用 > Modbus協(xié)議完全資料與程序解析

          Modbus協(xié)議完全資料與程序解析

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

          評(píng)論


          技術(shù)專區(qū)

          關(guān)閉
          看屁屁www成人影院,亚洲人妻成人图片,亚洲精品成人午夜在线,日韩在线 欧美成人 (function(){ var bp = document.createElement('script'); var curProtocol = window.location.protocol.split(':')[0]; if (curProtocol === 'https') { bp.src = 'https://zz.bdstatic.com/linksubmit/push.js'; } else { bp.src = 'http://push.zhanzhang.baidu.com/push.js'; } var s = document.getElementsByTagName("script")[0]; s.parentNode.insertBefore(bp, s); })();