我們所說的 ASCII或 RTU方式,僅適用於標準的 Modbus網絡,它定義了在這些網絡上連續傳輸的消息段的每一位,以及決定怎樣將信息打包成消息域及如何解碼。
下表是ASCII協議和RTU協議進行的比較:
通過比較可以看到,ASCII 協議擁有開始和結束標記,因此在進行程序處理時能更加方便,傳輸的都是可見的ASCII字符,所以進行調試時就更加的直觀,它的 LRC校驗也比較容易。
但因傳輸的都是可見的ASCII字符,RTU傳輸的數據每一個字節 ASCII都要用兩個字節來傳輸,比如 RTU傳輸一個十六進制數 0xF9,ASCII 就需要傳輸’F’’9’的 ASCII碼 0x39和0x46兩個字節,這樣它的傳輸的效率就比較低。
所以一般來說,如果所需要傳輸的數據量較小可以考慮使用ASCII協議,如果所需傳輸的數據量比較大,最好能使用RTU協議。
ASCII 模式
當控制器設為在 Modbus網絡上以ASCII(美國標準信息交換代碼)模式通信,在消息中的每個 8Bit字節都作為兩個 ASCII字符發送。這種方式的主要優點是字符發送的時間間隔可達到1秒而不產生錯誤。
代碼系統:
· 十六進制,ASCII字符0...9,A...F
· 消息中的每個ASCII字符都是一個十六進制字符組成
每個字節的位:
· 1個起始位
· 7個數據位,最小的有效位先發送
· 1個奇偶校驗位,無校驗則無
LRC 域是一個包含一個8位二進制值的字節。LRC 值由傳輸設備來計算並放到消息幀中,接收設備在接收消息的過程中計算 LRC,並將它和接收到消息中 LRC域中的值比較,如果兩值不等,說明有錯誤。
LRC 校驗比較簡單,它在 ASCII協議中使用,檢測了消息域中除開始的冒號及結束的回車換行號外的內容。它僅僅是把每一個需要傳輸的數據按字節疊加後取反加1即可。
下面是它的VC代碼:
BYTE GetCheckCode(const char * pSendBuf, int nEnd)//獲得校驗碼
{
BYTE byLrc = 0;
char pBuf[4];
int nData = 0;
for(i=1; i { //每兩個需要發送的ASCII碼轉化為一個十六進制數 pBuf [0] = pSendBuf [i]; pBuf [1] = pSendBuf [i+1]; pBuf [2] = '/0'; sscanf(pBuf,"%x",& nData); byLrc += nData; } byLrc = ~ byLrc; byLrc ++; return byLrc; } CRC 校驗 CRC域是兩個字節,包含一16位的二進制值。它由傳輸設備計算後加入到消息中。接收設備重新計算收到消息的CRC,並與接收到的CRC域中的值比較,如果兩值不同,則有誤。 CRC添加到消息中時,低字節先加入,然後高字節。 編程方法如下: ①裝如一個16位寄存器,所有數位均為1。 ②該16位寄存器的高位字節與開始8位字節進行“異或”運算。運算結果放入這個16位寄存器。 ③把這個16寄存器向右移一位。 ④若向右(標記位)移出的數位是1,則生成多項式1010000000000001和這個寄存器進行“異或”運算;若向右移出的數位是0,則返回③。 ⑤重複③和④,直至移出8位。 ⑥另外8位與該十六位寄存器進行“異或”運算。 ⑦重複③~⑥,直至該報文所有字節均與16位寄存器進行“異或”運算,並移位8次。 ⑧這個16位寄存器的內容即2字節CRC錯誤校驗,被加到報文的最高有效位。 CRC添加到消息中時,低字節先加入,然後高字節。下面是它的VC代碼: WORD GetCheckCode(const char * pSendBuf, int nEnd)//獲得校驗碼 { WORD wCrc = WORD(0xFFFF);
for(int i=0; i { wCrc ^= WORD(BYTE(pSendBuf[i])); for(int j=0; j<8; j++) { if(wCrc & 1) { wCrc >>= 1; wCrc ^= 0xA001; } else { wCrc >>= 1; } } } return wCrc; }
對於一條RTU協議的命令可以簡單的通過以下的步驟轉化為ASCII協議的命令:
1、 把命令的CRC校驗去掉,並且計算出LRC校驗取代。
2、 把生成的命令串的每一個字節轉化成對應的兩個字節的ASCII碼,比如0x03轉化成0x30,0x33(0的ASCII碼和3的ASCII碼)。
3、 在命令的開頭加上起始標記“:”,它的ASCII碼為0x3A。
4、 在命令的尾部加上結束標記CR嗎,LF(0xD,0xA),此處的CR,LF表示回車和換行的ASCII碼。
閱讀更多 三旺通信 的文章