MODBUS通訊協定及RS485介面通訊程式
一.檔案列表
RS485.pdf | 電路圖 |
RS485.C | C的原始程式 |
RS485.asm | 由C轉成的組合語言檔 |
RS485.hex | 燒錄檔 |
二.MODBUS介紹
MODBUS通訊協定本来是MODICON公司為自己所生產的PLC(可程式邏輯控制器)所開發的通訊協定,後來廣泛為工業界所运用,它是一對多的方法來通訊,现在他是採開放的方法不需付出任何費用,任何人皆可開發,所以现在許多PLC、人機介面及圖控軟體都有援助。
现在modbus通訊協定可分為ModbusASCII及ModbusRTU兩種傳送方法,ModbusASCII顧名思義便是以ASCII碼的方法來傳輸,而ModbusRTU是以Binary的方法來傳輸,二者以RTU的方法最快,所以我介紹RTU的方法,它傳送資料是從低位元開始傳送,下面的表格是Modbus通訊協定的功用表,其间384、484、584、884、M84及984為Modicon公司所生產的PLC型號。
Code | Name | 384 | 484 | 584 | 884 | M84 | 984 |
01 | ReadCoilStatus | Y | Y | Y | Y | Y | Y |
02 | ReadInputStatus | Y | Y | Y | Y | Y | Y |
03 | ReadHoldingRegisters | Y | Y | Y | Y | Y | Y |
04 | ReadInputRegisters | Y | Y | Y | Y | Y | Y |
05 | ForceSingleCoil | Y | Y | Y | Y | Y | Y |
06 | PresetSingleRegister | Y | Y | Y | Y | Y | Y |
07 | ReadExceptionStatus | Y | Y | Y | Y | Y | Y |
08 | Diagnostics | (seeModiconModbusProtocolReferenceGuideChapter3) | |||||
09 | Program484 | N | Y | N | N | N | N |
10 | Poll484 | N | Y | N | N | N | N |
11 | FetchComm.Event | Ctr. | Y | N | Y | N | N |
12 | FetchComm.Event | Log | Y | N | Y | N | N |
13 | ProgramController | Y | N | Y | N | N | Y |
14 | PollController | Y | N | Y | N | N | Y |
15 | ForceMultipleCoils | Y | Y | Y | Y | Y | Y |
16 | PresetMultipleRegisters | Y | Y | Y | Y | Y | Y |
17 | ReportSlave | ID | Y | Y | Y | Y | Y |
18 | Program884/M84 | N | N | N | Y | Y | N |
19 | ResetComm.Link | N | N | N | Y | Y | N |
20 | ReadGeneralReference | N | N | Y | N | N | Y |
21 | WriteGeneralReference | N | N | Y | N | N | Y |
22 | MaskWrite4XRegister | N | N | N | N | N | (1) |
23 | Read/Write4XRegisters | N | N | N | N | N | (1) |
24 | ReadFIFOQueue | N | N | N | N | N | (1) |
Notes:
(1)Functionissupportedin984–785only.
此次的範例我們只用了Function3(ReadHoldingRegisters)及Function6(PresetSingleRegister)的功用,所以以下針對這兩個Function做一說明
Function03(ReadHoldingRegisters)
讀取SlaveHoldingRegisters的內容(二進制碼)從PLC4X的參考方位,我以範例來說明
QUERYExample
FieldName (Hex)
——————————–
SlaveAddress 11
Function 03
StartingAddressHi 00
StartingAddressLo 6B
No.ofPointsHi 00
No.ofPointsLo 03
ErrorCheck(LRCorCRC) ––
SlaveAddress從0-7E(Hex),Functioncode為03,讀取暫存器的开始方位從40108-40110,其间108為6C,但因通訊的暫存器方位從0開始,所以108需減一,也便是6B,108-110總共三個暫存器(No.ofPoints),ErrorCheck有分LRC及CRC,LRC為ModbusASCIIMode的錯誤檢查碼,RTUMode运用的是CRC的檢查方法,CRC的檢查方法在程式說明的章節再說明。织梦内容管理体系
RESPONSEExample
FieldName (Hex)
——————————–
SlaveAddress 11
Function 03
ByteCount 06
DataHi(Register40108) 02
DataLo(Register40108) 2B
DataHi(Register40109) 00
DataLo(Register40109) 00
DataHi(Register40110) 00
DataLo(Register40110) 64
ErrorCheck(LRCorCRC) ––
此回應是從Slave傳至Master,前頭的Address及Function都與Master傳過來的一樣,ByteCount為要回傳至Master的byte數,因為Master要求讀取3個暫存器的資料,一個暫存器有兩個bytes,所以總共6個bytes,再來便是顺次傳回40108-10110的內容,最後再CRC檢查碼。
Function06(PresetSingleRegister)
將資料寫入HoldingRegister,且一次只寫入一個暫存器
QUERYExample
FieldName (Hex)
——————————–
SlaveAddress 11
Function 06
RegisterAddressHi 00
RegisterAddressLo 01
PresetDataHi 00
PresetDataLo 03
ErrorCheck(LRCorCRC) ––
將資料03寫入SlaveAddress11暫存器40002的方位。
RESPONSEExample
FieldName (Hex)
——————————–
SlaveAddress 11
Function 06
RegisterAddressHi 00
RegisterAddressLo 01
PresetDataHi 00
PresetDataLo 03
ErrorCheck(LRCorCRC) ––
Slave的回應很簡單,只需從Master傳來的資料無誤,也通過CRC的檢查,將本来收到的資料傳回給Master即可。
三.程式說明
程式裡頭最主要的是CRCcheck,在這裡針對CRCcheck做一說明,程式裡有一個副程式uns16crc16(uns8*puchMsg,uns8crc_count),我針對其參數做一說明:
uns16à傳回16bits的無號數資料
uns8*puchMsgà傳入字串位址,其字串的資料型態為無號數的八位元
uns8crc_countà無號數的八位元,其代表傳入字串的長度
針對crc16副程式做一說明:
先宣告三個暫存器uindex,uchCRCHi及uchCRCLo,且將ff(Hex)的值丟入uchCRCHi及uchCRCLo。
1.檢查crc_count是否為零,若為零則到步驟5,否則繼續。
2.將uchCRCHi與字串的榜首個byte做ExclusiveOR(互斥或),將結果送到uindex暫存器,將指標移到字串的下一個字元。织梦内容管理体系
3.运用uindex當索引去查auchCRCHi的表格相對應的值,再將它與uchCRCLo做ExclusiveOR(互斥或),將結果送入uchCRCLo中。
4.將crc_count減一,跳至步驟一。
5.將uchCRCHi往左移8bit再與uchCRCLo做OR,然後將此16bits的資料傳回。
這套C語言是由BKnudsenData所開發,其網站為http://www.bknd.com/cc5x/index.shtml,相對其他公司,這套CCompiler較為廉价,所以較契合經濟效益,以下針對主程式做一說明:
此程式是當Modbus的Slave,其位址為11(Hex),它只要設定頻率(set_hz)及設定啟動(set_run)這兩組暫存器需求設定罢了,而需讀取的資料有設定頻率(40001)、設定啟動(40086)、现在運轉的頻率(40079)、现在運轉的電流(40080)、现在運轉的狀態(40085)及现在的錯誤訊息(40087)。
從第205-266列為Slave從Master接纳到資料之後所做的相關處理及回應,第207列是做從Master接纳的資料再一次做CRC的檢查,看計算的CRC檢查碼與Master傳過來的檢查碼有無一樣,若一樣則傳回該回應的值。dedecms.com
從第267-282列為將要傳送到Master的值,透過串列埠傳出去,且將LTC485的IC設為傳送形式;第283-284列為若TRMT(TransmitShiftRegisterStatusbit)為空的話,這表明一切資料已傳送完畢,則將LTC485設為接纳形式。
第112-113列為若接纳資料間隔超過8ms,則需從新開始接纳字串。