C#上位機使用Modbus RTU協議控制變頻器
一、RTU報文格式示例
通信命令碼:
03H:讀從機參數
06H:寫從機參數
10H:寫多個參數
上位機寫單個寄存器:【從機地址】1字節+【命令碼】1字節+【寄存器地址高-低】2字節+【數據值高-低】2字節+【CRC校驗值低-高】2字節,總共8字節。
上位機讀寄存器:【從機地址】1字節+【命令碼】1字節+【寄存器地址高-低】2字節+【讀取寄存器數量高-低】2字節+【CRC校驗值低-高】2字節,總共8字節。
二、生成CRC校驗值的方法
private byte[] CalculateCrc(byte[] data){ushort crc = 0xFFFF;for (int i = 0; i < data.Length; i++){crc ^= (ushort)data[i];for (int j = 0; j < 8; j++){if ((crc & 0x0001) != 0){crc >>= 1;crc ^= 0xA001;}else{crc >>= 1;}}}byte[] crcBytes = new byte[2];//CRC低位crcBytes[0] = (byte)(crc & 0xFF);//CRC高位crcBytes[1] = (byte)(crc >> 8);return crcBytes;}
三、對變頻器進行讀寫
這個方法是將傳入的不帶CRC校驗的字節數組計算CRC校驗值之后組成完整的報文并下發。
public void WriteMessage(byte[] data){try{//計算CRC校驗值byte[] crc = this.CalculateCrc(data);//把CRC校驗值組合進去,組成完整的報文byte[] sendDataCRC = data.Concat(crc).ToArray();//將加了CRC校驗值的報文轉換成16進制的字符串string str = this.serialPortHelper.AlgorithmHelperObject.BytesTo16(sendDataCRC, Enum16Hex.Blank);this.SendData(str);}catch (Exception ex){MessageBox.Show("主站設備下發報文錯誤:" + ex.Message);}}
當通道有數據傳回時,通過串口的DataReceived事件直接觸發接收數據方法,并將報文顯示到界面上。
this.serialPortHelper.SerialPortObject.DataReceived += new SerialDataReceivedEventHandler(this.SerialPort_DataReceived);private void SerialPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
{try{string data = string.Empty;byte[] temp = this.serialPortHelper.ReceiveData();if (temp.Length != 0){foreach (var item in temp){data += item.ToString("X2") + " ";}}this.txtReceiveData.Invoke(new Action<string>(s =>{ this.txtReceiveData.Text += "【" + DateTime.Now.ToLongTimeString() + "】" + s + "\r\n"; }), data);}catch (Exception ex){MessageBox.Show("接收數據出現錯誤:" + ex.Message);}
}public byte[] ReceiveData()
{//定義一個接收數組,獲取結束緩沖區數據的字節數byte[] byteData = new byte[this.serialPort.BytesToRead];//讀取數據this.serialPort.Read(byteData, 0, serialPort.BytesToRead);return byteData;
}
1、設定變頻器運行頻率
變頻器頻率設置地址為1E01H。
private void btnSetHz_Click(object sender, EventArgs e){//從機地址【0X01】//命令碼【0X03】,讀從機參數//起始地址【0X0000】,對應PLC的40001//寄存器數量【0X0001】//byte[] sendData = new byte[6] {0X01, 0X03, 0X00, 0X00, 0X00, 0X01};//將寫入的數據轉換為字節數組,最大頻率設置為5000,即50.00Hzbyte[] value = new byte[2];if (Convert.ToInt32(this.txtSetHz.Text.Trim()) > 5000){value = BitConverter.GetBytes(5000);}else{value = BitConverter.GetBytes(Convert.ToInt16(this.txtSetHz.Text.Trim()));}//報文格式:從機地址【1字節】——通信命令碼【1字節】——參數地址【2字節,高-低位】——參數值【2字節,高-低位】——CRC【2字節,低-高位】//除了CRC之后的報文,從機地址:0X01,命令碼:0X06(寫入單個寄存器),寄存器地址:0X1E01,寫入的數據:writeData[]。byte[] sendData = new byte[6] { 0X01, 0X06, 0X1E, 0X01, value[1], value[0] };WriteMessage(sendData);}
2、啟動/停止變頻器運行
變頻器操作命令字地址為1E00H。
private void btnOperateCode_Click(object sender, EventArgs e)
{byte[] value = new byte[2];value = BitConverter.GetBytes(Convert.ToInt16(this.cboxOperateCode.Text));byte[] sendData = new byte[6] { 0X01, 0X06, 0X1E, 0X00, value[1], value[0] };WriteMessage(sendData);
}
3、監控變頻器狀態
變頻器狀態地址為1E02H。
private void btnMonitorUuivertorState_Click(object sender, EventArgs e){isMonitor = true;if (thread == null){thread = new Thread(ReadUuivertorState);thread.IsBackground = true;thread.Start();}}private void ReadUuivertorState(){while (isMonitor){//byte[] value = new byte[2];//value = BitConverter.GetBytes(Convert.ToInt16(this.cboxOperateCode.Text));//報文格式:從機地址【1字節】——通信命令碼【1字節】——參數地址【2字節,高-低位】——參數個數【2字節,高-低位】——CRC【2字節,低-高位】//除了CRC之后的報文,從機地址:0X01,命令碼:0X03(讀單個或多個寄存器),寄存器地址:0X1E02,參數個數:0X0001。byte[] sendData = new byte[6] { 0X01, 0X03, 0X1E, 0X02, 0X00, 0X01 };WriteMessage(sendData);Thread.Sleep(1000);}}