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