Modbus addresses are normally written as 5 or 6 character values. Sometimes the leading zero is not present.
//Modbus地址經(jīng)常寫作5或6位字符的形式,有時候開頭的0沒有寫出。
//下面的地址是當S7-200為modbus從站時S7-200內(nèi)部的點和modbus地址的對應關系。
000001 - 00xxxx are discrete outputs mapped to Q0.0 - Q15.7
//000001 - 00xxxx 表示離散量輸出映射到 Q0.0 - Q15.7
010001 - 01xxxx are discrete inputs mapped to I0.0 - I15.7
//010001 - 01xxxx 表示離散量輸入映射到 I0.0 - I15.7
030001 - 03xxxx are input registers
040001 - 04xxxx are output (holding) registers
The first two characters determine which function the master uses to access the data type. The last four characters of the address select the proper value within the data type.
//modubs地址的前兩個字符(如果地址形式為6位)或前一個字符(如果地址形式為5位)決定了modbus主站訪問數(shù)據(jù)類型的功能代碼,后四位字符指定了指定數(shù)據(jù)類型的正確數(shù)據(jù)的地址。
Addresses 00xxxx utilize functions 1, 5 and 15. //地址 00xxxx 使用功能碼1, 5 and 15.
Addresses 01xxxx utilize function 2. //地址 01xxxx 使用功能碼 2.
Addresses 03xxxx utilize function 4. //地址 03xxxx 使用功能碼 4.
Addresses 04xxxx utilize functions 3, 6 and 16. //地址 04xxxx 使用功能碼 3, 6 and 16.
Function 5 is a single bit write and function 15 is a multiple bit write. //功能碼 5 表示寫單個位,而功能碼15 則是寫多個位.
Function 6 is a single word write and function 16 is a multiple word write.//功能碼6表示寫一個字,而功能碼16表示寫多個字
All Modbus addresses are 1 based, that is, the first holding register is addressed as 040001, but Modbus is zero based on the wire (seems strange, doesn't it?).
//所有的Modbus地址是從1開始的,第一個保持寄存器的地址是040001,但是在modbus總線上地址卻是從0開始的(是不是很奇怪,為什么?)
We need to check to be sure that the address is not zero (for any given data type).
//我們需要檢查以確保對任意給定的類型地址不能是0
//下面是部分代碼和代碼的注釋
//取modbus的數(shù)據(jù)的地址,注意:這里給定的modbus數(shù)據(jù)地址是雙字32位而不是單字16位,表明modbus數(shù)據(jù)地址范圍可能會超過//65535,后面的分析也表明了確實可以超過,而且達到了40多萬,但只是對某些數(shù)據(jù)類型而言
LD SM0.0
MOVD #Addr:LD3, AC0 // get a copy of Addr
If the Address input is greater than 0 and less than 10000 then the data type is for discrete outputs.
//如果輸入的地址在0-10000之間則訪問的數(shù)據(jù)則數(shù)據(jù)類型為離散量輸出。
If the request is to read then we will use modbus function 1. If this is a write and the count is 1 then we will use Modbus function 5. If this is a multibit write then we must use modbus function 15 for the write.
//如果是讀數(shù)據(jù),則使用modbus功能碼1,如果是寫1個數(shù)據(jù),則使用功能碼5,如果是寫多個位則使用功能碼15
NOTE: The boadcast address (0) cannot be used if this is a read request.
//主要廣播地址(指從站的地址為0時)不能用于讀數(shù)據(jù)。
NOTE: There is an override to force the use of function 15 for single bit writes in the case where the slave does not support
Modbus Function 5.
//注意:如果從站不支持寫1個離散量輸出位時的功能碼5,我們將強制使用功能碼15.
If the Address input is greater than 10000 and less than 20000 then the data type is for discrete inputs.
//如果地址在10000-20000直接則數(shù)據(jù)類型為離散量輸入
The only thing we can do with discrete inputs is to read them via modbus function 2.
//對于離散量輸入唯一要做的就是通過功能碼2去讀取數(shù)據(jù)
If the Address input is greater than 30000 and less than 40000 then the data type is for analog inputs.
//如果地址范圍在30000-40000之間,則數(shù)據(jù)類型為模擬量輸入
The only thing we can do with analog inputs is to read them via modbus function 4.
//對離散量輸入數(shù)據(jù)唯一可以做的事情就是用功能碼4去讀取數(shù)據(jù)。
If the Address input is greater than 40000 and less than 50000 then the data type is for holding registers.
//如果地址范圍在40000-50000之間,則數(shù)據(jù)類型為保持寄存器
If the request is to read then we will use modbus function 3. If this is a write and the count is 1 then we will use Modbus function 6. If this is a multibit write then we must use modbus function 16 for the write.
//如果是讀取保持寄存器,則使用功能碼3,如果是寫1個保持寄存器則使用功能碼6,如果是寫多個保持寄存器則使用功能碼16
NOTE: There is an override to force the use of function 16 for single word writes in the case where the slave does not support
Modbus Function 6.
//注意:如果從站不支持寫1個保持寄存器的功能碼6,我們將強制使用功能碼16.
NOTE: We have added a check for the address range for 400,001 to 465,536 so that users can address holding register
numbers greater than 9999. This allows use of the full address range for the "advanced" users but still keeps it
simple for the "normal" users.
//我們增加了對地址范圍400001-465536的檢查,以便用戶能夠訪問地址大于9999(modbus地址剔除掉功能碼后的地址數(shù)據(jù))的保持寄存器,這將允許"高級"用戶使用全部地址范圍而對"正常"用戶來說仍然是簡單的。
Address error...
//modbus地址檢查出錯處理...
The address is outside of the expected ranges (we did not match any of the range checks above) so show an error and return. We will also reach here if there was, for example, a write to discrete inputs or analog inputs. In either case there is an error so abort the message.
If this is a broadcast (address = 0) and the function is a read function (1, 2, 3 and 4) then show an error and abort. If this is a write request (functions 5, 6, 15 and 16) then set a flag so that we can terminate the message after it has transmitted.
//如果是modbus廣播,則對于讀功能1,2,3,4,則顯示錯誤并且取消掉當前操作,如果是寫數(shù)據(jù)(功能碼為5,6,15,16)時則設置1個標志以便當我們發(fā)送結束后就終止當前消息
LDB= #Slave:LB1, 0 // if (slave address == 0)
LPS
AB<= mModbusFunction:VB255, 4 // if (function <= 4)
MOVB mRequestError:4, AC0 // error = request error
JMP 250 // return
LPP
S mModbusBroadcast:V250.1, 1 // set the broadcast flag
LD SM0.0
MOVW 16#FFFF, AC0 // initialize the CRC 初始化crc的值為16#FFFF
BTI mModbusBufr:VB0, #count:LW2 // get the byte count from the buffer
MOVD &mModbusBufr:&VB0, #ptr:LD4 // get buffer address for CRC check
INCD #ptr:LD4 // point to first message byte
FOR AC2, +1, #count:LW2 // for all bytes in msg 外循壞,對所有字節(jié)進行計算
XORB *#ptr:*LD4, AC0 // XOR byte with current CRC LSByte
FOR AC1, +1, +8 //內(nèi)循壞,對單個字節(jié)進行計算,每個字節(jié)共8位,這里沒有使用常用的
//算法,而是對每個字節(jié)的每個位逐一計算,常規(guī)算法是對每個字節(jié)對應的結果保存在一個數(shù)組里,然
//后將該字節(jié)的數(shù)值做為數(shù)組下標索引而直接從數(shù)組中取得結果,這樣能減少計算時間,提高計算速度
SRW AC0, 1 // shift the CRC
LD SM1.1 // if (LSBit was 1)
XORW 16#A001, AC0 // XOR the CRC polynomial
NEXT // next bit
LD SM0.0
INCD #ptr:LD4 // point to the next message byte //修改數(shù)據(jù)指針,以便對下一個字節(jié)進行處理
NEXT // next message byte
LD SM0.0 // when the CRC is complete...
SWAP AC0 // swap CRC bytes
MOVW AC0, #crc:LW0 // write the output
MOVW AC0, *#ptr:*LD4 // write CRC into buffer