帖子目的
Modbus RTU是工業控制現場經典的控制協議,本貼結合市場一線實際工作經驗,總結上位機通過ModbusRTU控制SV660P的注意事項,希望對大家有所幫助
1.Modbus協議說明
Modbus通信的底層為RS485信號,采用雙絞線進行聯接就可以了,因此傳輸距離較遠,可達1000米,抗干擾性能比較好,且成本低,在工業控制設備的通信中被廣泛使用,現在眾多廠家的變頻器、控制器都采用了該協議。
傳送數據格式有HEX碼數據和ASCII碼兩種,分別稱為Modbus-RTU和Modbus-ASC 協議。
前者為數據直接傳送,而后者需將數據變換為ASCII碼后傳送,因此Modbus-RTU協議的通信效率較高,處理簡單,使用得更多。
Modbus為單主多從通信方式,采用的是主問從答方式,每次通信都是由主站首先發起,從站被動應答。因此,如變頻器之類的被控設備,一般內置的是從站協議,而PLC之類的控制設備,則需具有主站協議、從站協議。
2.常用Modbus 功能碼及數據編址
SV660P作為Modbus從站時,支持Modbus協議功能碼0x03, 0x06, 0x10;
Modbus通信主機在訪問(讀取或改寫) 伺服從機的內部變量時,必須遵循如下的通信命令幀定義,以及變量地址索引方法,才能進行正常的通信操作
功能碼 0x03(03):讀寄存器

功能碼 0x10(16):寫多個寄存器

3.錯誤響應幀



4.接線&SV660P參數設置




注:如線束制作不便,可直接購買 USB-S6-L-T00-3.0 數據線使用


5.通訊例子
5.1 寫動作H31-00
5.1.1 伺服使能,H31-00的bit0設置為1
Send->
01 10 31 00 00 01 02 00 01 47 53
Recv<-
01 10 31 00 00 01 0F 35
5.1.2 伺服斷使能,H31-00的bit0設置為0
Send->
01 10 31 00 00 01 02 00 00 86 93
5.1.3 正點動,H31-00的bit1設置為1
Send->
01 10 31 00 00 01 02 00 03 C6 92
5.1.4 反點動,H31-00的bit2設置為1
Send->
01 10 31 00 00 01 02 00 05 46 90
5.1.5 絕對定位,H31-00的bit3設置為1
Send->
01 10 31 00 00 01 02 00 01 47 53 (先寫0)
Send->
01 10 31 00 00 01 02 00 09 46 95 (再寫1)
5.1.6 原點回歸使能,H31-00的bit4設置為1
Send->
01 10 31 00 00 01 02 00 01 47 53(先寫0)
Send->
01 10 31 00 00 01 02 00 11 46 9F(再寫1)
5.1.7 VDI急停,H31-00的bit5設置為1
Send->
01 10 31 00 00 01 02 00 21 46 8B (先寫1,觸發急停,面板報Er.900)
Send->
01 10 31 00 00 01 02 00 01 47 53 (再寫0,解除急停)
5.1.8 報警復位,H31-00的bit6設置為1
Send->
01 10 31 00 00 01 02 00 41 46 A3 (先寫1,報警復位)
Send->
01 10 31 00 00 01 02 00 01 47 53 (再寫0)
5.2 寫參數
注意:參數掉電保持H0C-13=1,且參數設置好后,斷電重啟,然后必須關閉H0C-13=0,保護EEPROM。
5.2.1 寫目標位置H11-0C=10000(假設寫入ABCD數據,格式為CDAB)
Send->
01 10 11 0C 00 02 04 27 10 00 00 38 DB
Recv->
01 10 11 0C 00 02 84 F7
5.2.2 寫點動速度H06-04=32rpm
Send->
01 10 06 04 00 01 02 00 20 C0 0C
Recv->
01 10 06 04 00 01 40 80
5.2.3 功能碼急停,斷使能,面板不報Er.900,H0D-05=1
Send->
01 10 0D 05 00 01 02 00 01 BB 05 (先寫1,觸發急停)
Send->
01 10 0D 05 00 01 02 00 00 7A C5(再寫1,解除急停)
Recv->
01 10 0D 05 00 01 13 64
5.2.4 驅動重啟H0D-00=1
Send->
01 10 31 00 00 01 02 00 00 86 93(伺服斷使能,重啟后自動恢復為0)
Send->
01 10 0D 00 00 01 02 00 01 BB 50(驅動重啟)
Recv->
01 10 0D 00 00 01 03 65 (正確返回)
Recv->
01 90 04 4D C3 (從站設備故障,請先斷使能)
5.3 讀參數
5.3.1 讀實際位置H0B-07(假設讀取格式為CDAB,實際數據為ABCD)
Send->
01 03 0B 07 00 02 77 EE
Recv->
01 03 04 09 B2 00 00 59 88(當前位置為0x09B2=2482)
5.3.2 讀故障代碼H0B-34
Send->
01 03 0B 22 00 01 26 24
Recv->
01 03 02 07 40 BB 84 (Er.740編碼器故障)
Recv->
01 03 02 E9 39 37 C6(Er.939動力線斷線)

5.3.3 讀物理DO信號H0B-05
Send->
01 03 0B 05 00 01 96 2F
Recv->
01 03 02 00 1A 39 8F(上電默認,bit0-伺服准備好,bit2-零速信號)
Recv->
01 03 02 00 18 B8 4E(定位完成,bit1-定位完成,保持信號)
Recv->
01 03 02 00 08 B9 82(回原完成,bit4-原點回零完成,保持信號)

5.3.4 以當前位置為零點(位置=0)H05-30=6
Send->
01 10 05 1E 00 01 02 00 06 70 EC
Recv->
01 10 05 1E 00 01 61 03
6.CRC16計算方法
以C++為例,可參考以下代碼:[i]
#include <cstdio> #include <iostream> using namespace std; uint16_t CRC16(uint8_t* arr_buff, int len) { uint16_t crc = 0xFFFF; uint16_t i, j, Data; for (j = 0; j<len; j++) { crc = crc ^*arr_buff++; for (i = 0; i<8; i++) { if ((crc & 0x0001) >0) { crc = crc >> 1; crc = crc ^ 0xa001; } else crc = crc >> 1; } } return (crc); } void main() { uint8_t dataIn[9] = { 0x01,0x10,0x31,0x00,0x00,0x01,0x02,0x00,0x01 }; cout << "dataIn[" << sizeof(dataIn) << "]" << "= { "; for (int i = 0; i < sizeof(dataIn); i++) { printf("%02x ", dataIn[i]); } cout << "};" << endl; uint16_t Result = CRC16(dataIn, sizeof(dataIn)); cout << "CRC16 Result : " << hex << Result%0x100 << " " << hex << Result/0x100 << endl; system("Pause"); }
[i]運行結果如下:

