php网站后台无法上传图片,什么网站可以做告白的网页,深圳戈麦斯网站开发,注册国际贸易公司需要多少钱1、协议
电表有个电力行业推荐标准《DLT645-2007多功能电能表通信协议》#xff0c;电表都支持#xff0c;通过该协议读取数据#xff0c;不同的电表不需要考虑编码格式、数据地址、高低位转换等复杂情况#xff0c;统一采集。
不方便的地方在于这个协议定义得有点小复杂…1、协议
电表有个电力行业推荐标准《DLT645-2007多功能电能表通信协议》电表都支持通过该协议读取数据不同的电表不需要考虑编码格式、数据地址、高低位转换等复杂情况统一采集。
不方便的地方在于这个协议定义得有点小复杂自己带有各种特殊性定义编程时一堆的坑。
不少电表可以同时支持DLT645-2007和MODBUS RTU协议但MODBUS协议在不同的电表中地址都是不同的需要查阅手册才能搞定。
DLT645不同的数据需要发送独立的请求而Modbus数据地址连接的可以一次读取各有所长和优势。
2、协议定义和报文 协议定义和报文在协议文档中有详细说明主要部分节选如下 3、数据域定义 协议中对每个数据都定义了明确的地址和解析格式如 比如 00 00 00 00表示组合有功总电能。同一组的可以使用FF通配表示读取整块的数据00 00 FF 00表示一次读取 00 00 00 00 ~ 00 00 3F 00的所有数据。 但需要注意的事不是所有电表都支持块数据读取。
4、编码验证 public class DLT645_2007{public enum CommandType{ReadData 0x11,WriteData 0x14,ReadAddress 0x13,WriteAddress 0x15}public class Dlt645Addr{public string dataIndentifier;public int dataLen;public float divisor 1.0f;public string unit;public string dataItemName;public string dataName;public string PascalType;public Dlt645Addr(string dataIndentifier, int dataLen, float divisor, string unit, string dataItemName, string dataName , string PascalType FLOAT){this.dataIndentifier dataIndentifier;this.dataLen dataLen;this.divisor divisor;this.unit unit;this.dataItemName dataItemName;this.dataName dataName;this.PascalType PascalType;}}public Dlt645Addr []addrList {//电能量new Dlt645Addr(00010000,4,100,V ,正向有功总电量,Forth_Have_Power_Total),// R4new Dlt645Addr(00010100,4,100,V ,正向有功尖电量,Forth_Have_Power_SPIKE),// R4 以上四个名称待核实new Dlt645Addr(00010200,4,100,V ,正向有功峰电量,Forth_Have_Power_PEAK),// R4new Dlt645Addr(00010300,4,100,V ,正向有功平电量,Forth_Have_Power_FLAT),// R4new Dlt645Addr(00010400,4,100,V ,正向有功谷电量,Forth_Have_Power_VALLEY),// R4//变量数据new Dlt645Addr(02010100,2, 10,V,A项电压,Phase_A_Volt),// R2new Dlt645Addr(02010200,2, 10,V,B项电压,Phase_B_Volt),// R2new Dlt645Addr(02010300,2, 10,V,C项电压,Phase_C_Volt),// R2new Dlt645Addr(02020100,3,1000,A,A项电流,Phase_A_Elec),// R3new Dlt645Addr(02020200,3,1000,A,B项电流,Phase_B_Elec),// R3new Dlt645Addr(02020300,3,1000,A,C项电流,Phase_C_Elec),// R3new Dlt645Addr(02030000,3,1000,kW,瞬时总有功率功率,Instant_Have_Power_Rate_Total),// R3new Dlt645Addr(02030000,3,1000,kW,瞬时A相有功率功率,Instant_Phase_A_Have_Power_Rate),// R3new Dlt645Addr(02030000,3,1000,kW,瞬时B相有功率功率,Instant_Phase_B_Have_Power_Rate),// R3new Dlt645Addr(02030000,3,1000,kW,瞬时C相有功率功率,Instant_Phase_C_Have_Power_Rate),// R3new Dlt645Addr(02040000,3,1000,kwar,瞬时总无功率功率,Instant_None_Power_Rate_Total),// R3new Dlt645Addr(02040000,3,1000,kwar,瞬时A相无功率功率,Instant_Phase_A_None_Power_Rate),// R3new Dlt645Addr(02040000,3,1000,kwar,瞬时B相无功率功率,Instant_Phase_B_None_Power_Rate),// R3new Dlt645Addr(02040000,3,1000,kwar,瞬时C相无功率功率,Instant_Phase_C_None_Power_Rate),// R3new Dlt645Addr(02050000,3,1000,kVA,瞬时总视在功率,Instant_Apparent_Power_Rate_Total),// R3new Dlt645Addr(02050000,3,1000,kVA,瞬时A相视在功率,Instant_Phase_A_Apparent_Power_Rate),// R3new Dlt645Addr(02050000,3,1000,kVA,瞬时B相视在功率,Instant_Phase_B_Apparent_Power_Rate),// R3new Dlt645Addr(02050000,3,1000,kVA,瞬时C相视在功率,Instant_Phase_C_Apparent_Power_Rate),// R3new Dlt645Addr(02060000,2,1000,,总功率因数,Power_Rate_Factor_Total),// R2new Dlt645Addr(02060100,2,1000,,A相功率因数,Phase_A_Power_Rate_Factor),// R2new Dlt645Addr(02060200,2,1000,,B相功率因数,Phase_B_Power_Rate_Factor),// R2new Dlt645Addr(02060300,2,1000,,C相功率因数,Phase_C_Power_Rate_Factor),// R2new Dlt645Addr(02070100,2, 10,V,A相相角,Phase_A_Angle),// R2new Dlt645Addr(02070200,2, 10,V,B相相角,Phase_B_Angle),// R2new Dlt645Addr(02070300,2, 10,V,C相相角,Phase_C_Angle),// R2new Dlt645Addr(02080100,2, 100,%,A相电压波形失真度,Phase_A_Volt_Waveform_Distortion),// R2new Dlt645Addr(02080200,2, 100,%,B相电压波形失真度,Phase_B_Volt_Waveform_Distortion),// R2new Dlt645Addr(02080300,2, 100,%,C相电压波形失真度,Phase_C_Volt_Waveform_Distortion),// R2new Dlt645Addr(02090100,2, 100,%,A相电流波形失真度,Phase_A_Elec_Waveform_Distortion),// R2new Dlt645Addr(02090200,2, 100,%,B相电流波形失真度,Phase_B_Elec_Waveform_Distortion),// R2new Dlt645Addr(02090300,2, 100,%,C相电流波形失真度,Phase_C_Elec_Waveform_Distortion)// R2//最大需量//事件记录数//负荷记录//参变量//安全认证};Dictionarystring,Dlt645Addr dictAddr new Dictionarystring, Dlt645Addr ();//是否需要唤醒 ,0xFEprivate bool isNeedWakeUp false;// 创建串口对象SerialPort serialPort null;int rxCount 0;byte[] rxdata new byte[512];Stopwatch swRead new Stopwatch ();public DLT645_2007(){foreach(var addr in addrList){dictAddr[addr.dataIndentifier] addr; }}//SerialPort(COM3, 9600, Parity.None, 8, StopBits.One);public bool OpenDevice(string portName, int baudRate 2400, Parity parity Parity.None, int dataBits8, StopBits stopBits StopBits.One){try{serialPort new SerialPort(portName, baudRate, parity, dataBits, stopBits);serialPort.Open();serialPort.ReadTimeout 500;serialPort.DataReceived SerialPort_DataReceived;return true;}catch(Exception ex){return false;}}private void SerialPort_DataReceived(object sender, SerialDataReceivedEventArgs e){byte[] rxTemp new byte[1024];int rdCount serialPort.Read(rxTemp, 0, rxTemp.Length);if (rdCount 0){for(int i 0; i rdCount; i){if (rxTemp[i] 0xfe)continue;rxdata[rxCount] rxTemp[i];if (rxTemp[i] 0x16){ParseData();}}}swRead.Stop();}public void ParseDataTest(string data){data data.Replace( , );rxCount data.Length;for(int i 0; i rxCount;i2){rxdata[i/2] Convert.ToByte(data.Substring(i, 2), 16);}ParseData();}private void ParseData(){//校验和标识检查if(rxCount 9 || rxdata[0] ! 0x68 || rxdata[7] ! 0x68){Console.WriteLine($校验和标识检查失败len:{rxCount},{rxdata[0]:X},{rxdata[7]:X});rxCount 0;return;}//响应命令检查if (rxdata[8] ! 0x91 rxdata[8] ! 0xB1 ){Console.WriteLine($响应命令检查失败{rxdata[8]:X});rxCount 0;return;}string addrT BitConverter.ToString(rxdata, 1, 6).Replace(-,);string addr addrT.Substring(8,2) addrT.Substring(6, 2) addrT.Substring(4, 2) addrT.Substring(2, 2) addrT.Substring(0, 2);string value ;int dataLen rxdata[9];for(int k 0; k dataLen; k){rxdata[10 k] - 0x33;value string.Format({0:X2}, rxdata[10 k]);}string index value.Substring(6, 2) value.Substring(4, 2) value.Substring(2, 2) value.Substring(0, 2);var dlt645 dictAddr[index];string value2 ;for(int k dlt645.dataLen-1; k 0; k --){value2 value.Substring(8 k * 2, 2);}float fv float.Parse(value2); Console.WriteLine($表号:{addr},{dlt645.dataItemName},{dlt645.dataIndentifier},{fv/dlt645.divisor} [{dlt645.unit}]);rxCount 0;}public void CloseDevice(){serialPort.Close();serialPort null;}public void Read(Liststring addrMeter, string data){if (isNeedWakeUp){byte[] reqHe { 0xFE, 0xFE };serialPort.Write(reqHe, 0, reqHe.Length);}byte []req BuildRequest(addrMeter[0], data, CommandType.ReadData);serialPort.Write(req,0,req.Length);swRead.Restart();}public byte[] BuildRequest(string addrMeter, string data, CommandType commandType){// 构建请求帧byte[] request new byte[12 4];int index 0;request[index] 0x68; // 帧起始符 68H//地址域 A0~A5地址域是用来表示电表地址低位在前高位在后request[index] Convert.ToByte(addrMeter.Substring(10, 2), 16); // 地址域 A0request[index] Convert.ToByte(addrMeter.Substring(8, 2), 16); // 地址域 A1request[index] Convert.ToByte(addrMeter.Substring(6, 2), 16); // 地址域 A2request[index] Convert.ToByte(addrMeter.Substring(4, 2), 16); // 地址域 A3request[index] Convert.ToByte(addrMeter.Substring(2, 2), 16); // 地址域 A4request[index] Convert.ToByte(addrMeter.Substring(0, 2), 16); // 地址域 A5request[index] 0x68; // 帧起始符request[index] 0x11; // 控制码request[index] (byte)(4);// Convert.ToByte((data.Count * 4).ToString(), 16); // 数据域长度for (int i 3;i 0; i --){string sV data.Substring(i*2, 2);if (sV.Equals(FF)){request[index] 0xff;}else{request[index] (byte)(Convert.ToByte(sV, 16) 0x33); // 数据}}byte crc GetCRC(request, 0, request.Length-2); // 校验码request[index] Convert.ToByte(crc.ToString(X), 16);request[index] 0x16; // 结束符return request;}private byte GetCRC(byte[] data, int start, int length){int I 0;for (int k 0; k length; k){I data[start k];}return (byte)(I % 256);}}