最近研究了一下MODBUS通信,在STC12C5A60S2單片機上實現了MODBUS協議的部分功能,方便上位機從單片機系統上獲取數據,比如由單片機獲取的溫度、濕度、或者控制信號的狀態等。有了MODBUS協議后,上位機的開發就很方便了,可以使用C#等高級語言通過串口通信,或者使用組態王直接通過串口通信而不需要寫代碼,這些都歸功於MODBUS協議的開放性,很多的組態軟件都能提供對他的支持。甚至通過PLC直接可以和單片機通信,比如在PLC系統上沒有AD時,可以使用單片也來進行AD,然后通過MODBUS返回給PLC進行相應的控制。
通過MODBUS協議可以實現主機和多個從機進行通謝,而每個從機有唯一的地址,主機就靠這個地址和從機進行通信。每一幀數據都要通過CRC進行校驗,保證通信的正確性。
在進行多機通信時只需要把每個從機的串口並到一起即可,見后面的圖。
單片機中3號功能的核心代碼如下:
unsigned char createRespond_M(unsigned char *respondMessage,unsigned char* _messageReceived ,unsigned int* _registerData) { unsigned char i,j; unsigned char numberOfPoints = 0; unsigned char _slaveAddress = 0 ; unsigned char bytesToSend = 0; unsigned char startAddress=0; unsigned char crcCalculation[]={0,0,0}; unsigned int CntHi = _messageReceived[4]; //將其轉換為int型,然后放到高8位。 CntHi = CntHi<<8; numberOfPoints = CntHi| _messageReceived[5]; if(numberOfPoints > MaxnumberOfPoints) { return 0; } bytesToSend = 2 * numberOfPoints +5; _slaveAddress = _messageReceived[0]; respondMessage[0] = _slaveAddress; respondMessage[1] = 3; respondMessage[2] =2 * numberOfPoints; startAddress = (((unsigned int)(_messageReceived[2])) << 8) | _messageReceived[3]; j= 0; for (i = 0; i < numberOfPoints; i++) { respondMessage[i + j + 3] = ((_registerData[startAddress + i] >> 8) & 0xff); respondMessage[i + j + 4] =(_registerData[startAddress + i] & 0xff); j++; } calculateCRC(respondMessage, bytesToSend - 2,crcCalculation); respondMessage[bytesToSend - 2] = crcCalculation[0]; respondMessage[bytesToSend - 1] = crcCalculation[1]; return bytesToSend; } //對接收的數據進行CRC檢驗,同時判斷是否為Address所指定的從機地址和是否為function3功能。 bit CheckRecData(unsigned char * RecData,unsigned char Address) { if(RecData[0] == Address && RecData[1] == 3) //地址為自己的地址,同時功能碼為3(function 3) { if(checkCRC(RecData,8)) { return 1; } } return 0; }
本例中每個從機返回80個字節的數據,1號機返回i+1, 2號機返回2*i+1 ,當然在實際運用中只要自己定義所返回的數據的含義即可。比如1,2字節代表溫度,3,4字節代表濕度,接下來的4個字節代表P0,P1,P2,P3端口的狀態等。可以自由定義,很方便。
具體效果見下圖:

把兩塊板的串口通過杜綁線連在一起。


在TEXTBOX中輸入從機的地址,返回相應的數據

如果輸入的地址從機不存在,那么通信將會超時,就會提示通信故障。這個是根據通信超時來判斷的。
