C#-DL/T 645—2007协议
作者:互联网
前面一篇写了97版的协议,今天就来看下07版的DL/T 645协议,总的来说,差别不是很大,也是就是数据项标识的不同。
1. 帧格式
帧格式是和之前97的一版是一样的,
注意:
(1)97一版忘了说,地址域是BCD码,若电表地址是112233445566,那么传输的字节就是0x66 0x55 0x44 0x33 0x22 0x11,即小端传输;
(2)数据标识项与97的有差别,97的是两个字节,07的是4个字节,如图所示DI3 DI2 DI2 DI0;
(3)依然要发送4个字节的FEH,来唤醒对方;
(4)传输+-0x33的如图更加详细,即发送方+0x33后发送,接收方收到数据后-0x33进行处理;
2. 数据项标识
这次数据项标识采用发送请求块的方式进行请求数据,比如ABC相电压,只发送一次请求即可返回三相电压。
如图所示可以请求00 01 FF 00正向有功电能数据块的数据,对方会把包含的所有数据都会返回,文档上写的是63个电能,实际上大多数电表是没有的,所以不用太计较那么多的数据,一般就是尖峰平谷4段。
3. 数据库表,依然采用初始化数据表配置的方式进行处理(其实是先写的07版的协议...)
DROP TABLE IF EXISTS `protocol_DLT645_07package`; CREATE TABLE `protocol_DLT645_07package` ( `id` int(11) NOT NULL AUTO_INCREMENT, `devicetype` int(11) NOT NULL, -- 设备类型 `blockaddr` int(11) NOT NULL, -- 块地址 `blockname` varchar(50) NOT NULL, -- 块名称 `blockcontent` varchar(50) NOT NULL, -- 块内容 `visible` int(11) NOT NULL, -- 是否请求;0不请求;1请求; PRIMARY KEY (`id`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8; INSERT INTO `protocol_DLT645_07package` VALUES (null, -1, '130816', '正向有功总电能数据块', '65536, 65792, 66048, 66304, 66560', '1'); --0001FF00 INSERT INTO `protocol_DLT645_07package` VALUES (null, -1, '196352', '反向有功总电能数据块', '131072, 131328, 131584, 131840, 132096', '1'); --0002FF00 INSERT INTO `protocol_DLT645_07package` VALUES (null, -1, '33685248', 'ABC相电压数据块', '33620224, 33620480, 33620736', '1'); --0201FF00 INSERT INTO `protocol_DLT645_07package` VALUES (null, -1, '33750784', 'ABC相电流数据块', '33685760, 33686016, 33686272', '1'); --0202FF00 INSERT INTO `protocol_DLT645_07package` VALUES (null, -1, '33816320', '瞬时总有功功率数据块', '33751040, 33751296, 33751552, 33751808', '1'); --0203FF00 INSERT INTO `protocol_DLT645_07package` VALUES (null, -1, '33881856', '瞬时总无功功率数据块', '33816576, 33816832, 33817088, 33817344', '1'); --0204FF00 INSERT INTO `protocol_DLT645_07package` VALUES (null, -1, '33947392', '瞬时总视在功率数据块', '33882112, 33882368, 33882624, 33882880', '1'); --0205FF00 INSERT INTO `protocol_DLT645_07package` VALUES (null, -1, '34012928', '总功率因数数据块', '33947648, 33947904, 33948160, 33948416', '1'); --0206FF00 INSERT INTO `protocol_DLT645_07package` VALUES (null, -1, '41943042', '电网频率数据', '41943042', '1'); --02800002 INSERT INTO `protocol_DLT645_07package` VALUES (null, -1, '41943048', '时钟电池电压', '41943048', '1'); --02800008 DROP TABLE IF EXISTS `protocol_DLT645_07signal`; CREATE TABLE `protocol_DLT645_07signal` ( `id` int(11) NOT NULL AUTO_INCREMENT, `devicetype` int(11) NOT NULL, -- 设备类型 `signaladdr` int(11) NOT NULL, -- 信号地址 `signalname` varchar(50) NOT NULL, -- 信号名称 `signalid` int(11) NOT NULL, -- 信号ID `datalength` int(11) NOT NULL, -- 数据长度,所占字节数 `ratio` float NOT NULL, -- 变比 `ismultiplifct` int(11) NOT NULL, -- 是否乘于互感器变比,变比在协议中配置 `visible` int(11) NOT NULL, -- 是否需要解析;0不解析;1解析; PRIMARY KEY (`id`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8; INSERT INTO `protocol_DLT645_07signal` VALUES (null, -1, '65536', '正向有功总电能', '-1', '4', '0.01', '1', '1' ); INSERT INTO `protocol_DLT645_07signal` VALUES (null, -1, '65792', '(当前)正向有功费率1电量', '-1', '4', '0.01', '1', '1' ); INSERT INTO `protocol_DLT645_07signal` VALUES (null, -1, '66048', '(当前)正向有功费率2电量', '-1', '4', '0.01', '1', '1' ); INSERT INTO `protocol_DLT645_07signal` VALUES (null, -1, '66304', '(当前)正向有功费率3电量', '-1', '4', '0.01', '1', '1' ); INSERT INTO `protocol_DLT645_07signal` VALUES (null, -1, '66560', '(当前)正向有功费率4电量', '-1', '4', '0.01', '1', '1' ); INSERT INTO `protocol_DLT645_07signal` VALUES (null, -1, '131072', '反向有功总电能', '-1', '4', '0.01', '1', '1' ); INSERT INTO `protocol_DLT645_07signal` VALUES (null, -1, '131328', '(当前)反向有功费率1电量', '-1', '4', '0.01', '1', '1' ); INSERT INTO `protocol_DLT645_07signal` VALUES (null, -1, '131584', '(当前)反向有功费率2电量', '-1', '4', '0.01', '1', '1' ); INSERT INTO `protocol_DLT645_07signal` VALUES (null, -1, '131840', '(当前)反向有功费率3电量', '-1', '4', '0.01', '1', '1' ); INSERT INTO `protocol_DLT645_07signal` VALUES (null, -1, '132096', '(当前)反向有功费率4电量', '-1', '4', '0.01', '1', '1' ); INSERT INTO `protocol_DLT645_07signal` VALUES (null, -1, '33620224', 'A相电压', '-1', '2', '0.1', '0', '1' ); INSERT INTO `protocol_DLT645_07signal` VALUES (null, -1, '33620480', 'B相电压', '-1', '2', '0.1', '0', '1' ); INSERT INTO `protocol_DLT645_07signal` VALUES (null, -1, '33620736', 'C相电压', '-1', '2', '0.1', '0', '1' ); INSERT INTO `protocol_DLT645_07signal` VALUES (null, -1, '33685760', 'A相电流', '-1', '3', '0.001', '1', '1' ); INSERT INTO `protocol_DLT645_07signal` VALUES (null, -1, '33686016', 'B相电流', '-1', '3', '0.001', '1', '1' ); INSERT INTO `protocol_DLT645_07signal` VALUES (null, -1, '33686272', 'C相电流', '-1', '3', '0.001', '1', '1' ); INSERT INTO `protocol_DLT645_07signal` VALUES (null, -1, '33751040', '瞬时总有功功率', '-1', '3', '0.0001', '1', '1' ); INSERT INTO `protocol_DLT645_07signal` VALUES (null, -1, '33751296', '瞬时A相有功功率', '-1', '3', '0.0001', '1', '1' ); INSERT INTO `protocol_DLT645_07signal` VALUES (null, -1, '33751552', '瞬时B相有功功率', '-1', '3', '0.0001', '1', '1' ); INSERT INTO `protocol_DLT645_07signal` VALUES (null, -1, '33751808', '瞬时C相有功功率', '-1', '3', '0.0001', '1', '1' ); INSERT INTO `protocol_DLT645_07signal` VALUES (null, -1, '33816576', '瞬时总无功功率', '-1', '3', '0.0001', '0', '1' ); INSERT INTO `protocol_DLT645_07signal` VALUES (null, -1, '33816832', '瞬时A相无功功率', '-1', '3', '0.0001', '0', '1' ); INSERT INTO `protocol_DLT645_07signal` VALUES (null, -1, '33817088', '瞬时B相无功功率', '-1', '3', '0.0001', '0', '1' ); INSERT INTO `protocol_DLT645_07signal` VALUES (null, -1, '33817344', '瞬时C相无功功率', '-1', '3', '0.0001', '0', '1' ); INSERT INTO `protocol_DLT645_07signal` VALUES (null, -1, '33882112', '瞬时总视在功率', '-1', '3', '0.0001', '1', '1' ); INSERT INTO `protocol_DLT645_07signal` VALUES (null, -1, '33882368', '瞬时A相视在功率', '-1', '3', '0.0001', '1', '1' ); INSERT INTO `protocol_DLT645_07signal` VALUES (null, -1, '33882624', '瞬时B相视在功率', '-1', '3', '0.0001', '1', '1' ); INSERT INTO `protocol_DLT645_07signal` VALUES (null, -1, '33882880', '瞬时C相视在功率', '-1', '3', '0.0001', '1', '1' ); INSERT INTO `protocol_DLT645_07signal` VALUES (null, -1, '33947648', '总功率因数', '-1', '2', '0.001', '0', '1' ); INSERT INTO `protocol_DLT645_07signal` VALUES (null, -1, '33947904', 'A相功率因数', '-1', '2', '0.001', '0', '1' ); INSERT INTO `protocol_DLT645_07signal` VALUES (null, -1, '33948160', 'B相功率因数', '-1', '2', '0.001', '0', '1' ); INSERT INTO `protocol_DLT645_07signal` VALUES (null, -1, '33948416', 'C相功率因数', '-1', '2', '0.001', '0', '1' ); INSERT INTO `protocol_DLT645_07signal` VALUES (null, -1, '41943042', '电网频率', '-1', '2', '0.01', '0', '1' ); INSERT INTO `protocol_DLT645_07signal` VALUES (null, -1, '41943048', '时钟电池电压', '-1', '2', '0.01', '0', '1' );View Code
protocol_DLT645_07package表示请求的数据块表,主要是对应了请求块和应答包之间的关系。用的是十进制,只把请求块的内容又转换成了十六进制,可以对照协议文档进行查找;
另外,07版的我是取用的+0x33之后的数据,07版本我是取用的原有数据的标识,可能会更加清晰;
4. 上代码,环境和97版的是一样的,
初始化配置项:
/// <summary> /// 电表物理地址 /// </summary> public byte[] MeterPhysicalAddr { set; get; } /// <summary> /// 请求实时数据,块 /// </summary> public Dictionary<int, int[]> RequestRealDataDic { set; get; } /// <summary> /// 信号ID MAP /// </summary> public Dictionary<int, Signal> SignalIdMap { set; get; }View Code
初始化请求包:
/// <summary> /// 初始化请求实时数据,块 /// </summary> private void InitRequestRealDataDic() { RequestRealDataDic = new Dictionary<int, int[]>(); List<protocol_dlt645package> pcakageS = DbHelp.GetList<protocol_dlt645package>(). Where(s => s.visible == (int)EnumYesOrNo.Yes). Where(s => s.devicetype == this.DeviceType).ToList(); if(pcakageS == null || pcakageS.Any() == false) { return; } foreach(protocol_dlt645package package in pcakageS) { string[] siganlAddrS = package.blockcontent.Split(' ', ',', ',').Where(s => !string.IsNullOrEmpty(s)).ToArray(); int[] signalAddrList = Array.ConvertAll(siganlAddrS, int.Parse); if (signalAddrList != null && signalAddrList.Count() != 0) { RequestRealDataDic.Add(package.blockaddr, signalAddrList); } } }View Code
初始化解析数据包:
/// <summary> /// 初始化信号ID MAP /// </summary> private void InitSignalIdMap() { SignalIdMap = new Dictionary<int, Signal>(); List<protocol_dlt645signal> signalList = DbHelp.GetList<protocol_dlt645signal>().Where(x => x.devicetype == this.DeviceType).ToList(); if (signalList == null || signalList.Any() == false) { return; } foreach(protocol_dlt645signal dlt645signal in signalList) { Signal signal = new Signal { SignalID = dlt645signal.signalid, SignalName = dlt645signal.signalname, DataLength = dlt645signal.datalength, Visible = dlt645signal.visible, Ratio = dlt645signal.ismultiplifct == (int)EnumYesOrNo.Yes ? dlt645signal.ratio*ConstValue.FCT : dlt645signal.ratio, }; SignalIdMap.Add(dlt645signal.signaladdr, signal); } }View Code
初始化电表地址等:
/// <summary> /// 初始化属性 /// </summary> private void InitAttribute() { try { MeterPhysicalAddr = new byte[6]; var addr = ConfigurationManager.AppSettings["MeterPhysicalAddr"]; if (addr != null) { string[] strList = addr.Split('|'); for (int i = 0; i < 6; i++) { MeterPhysicalAddr[i] = BCD_to_HEX(byte.Parse(strList[5 - i])); } } } catch(Exception ex) { LogEvent.Loger.Fatal(ex.ToString()); } }View Code
两个线程一发一收,我们这里用到了redis当做消息队列处理,收发都是经过redis进行处理的,可以理解为当前的发送不是直接到设备的,而是经过一层统一处理放到redis的消息队列当中,相当于收发都取redis的,这个不重要,和直连是一样的。
发送请求实时数据线程:
/// <summary> /// 按块请求实时数据 /// </summary> private void RequestBlockThread() { while (true) { Thread.Sleep(RealDataInterval); try { foreach (int dataFlag in RequestRealDataDic.Keys) { Thread.Sleep(RealDataInterval); // 发送实时数据请求 SendDataRequest(dataFlag); // 有功功率请求频繁 //Thread.Sleep(RealDataInterval); //SendDataRequest(ConstValue.ActivePowerFlag); } } catch (Exception ex) { LogEvent.Loger.Fatal(ex.ToString()); } } } /// <summary> /// 发送实时数据请求 /// </summary> /// <param name="dataFlag"></param> private void SendDataRequest(int dataFlag) { MessageInfo sendMessage = new MessageInfo { MessageHead = ConstValue.MessageHead, Addr = MeterPhysicalAddr, // 改为自动获取或 StartHead = ConstValue.MessageHead, ControlCode = ConstValue.ControlCode, DataLength = ConstValue.DataFlagLength, DataFlag = ConvertDataFlag(dataFlag, EnumAddDataFlag.Add), EndFrame = ConstValue.MessageEndFrame }; SaveSendMessage(sendMessage); } /// <summary> /// 转换数据标识,-+0x33 /// </summary> /// <param name="dataFlag"></param> /// <param name="addFlag"></param> /// <returns></returns> private int ConvertDataFlag(int dataFlag, EnumAddDataFlag addFlag) { byte[] dataS = new byte[4]; ConvertIntToByteArray(dataFlag, ref dataS); if (addFlag == EnumAddDataFlag.Add) { for (int i = 0; i < 4; i++) { dataS[i] += ConstValue.DataFlagDeviation; } } else { for (int i = 0; i < 4; i++) { dataS[i] -= ConstValue.DataFlagDeviation; } } int index = 0; return DataCopy.GetINT(dataS, ref index); } /// <summary> /// 发送数据 /// </summary> /// <param name="message"></param> private void SaveSendMessage(MessageInfo message) { try { byte[] SendData = message.ObjectToByte(); LogEvent.LogInfo.FatalFormat("发送:\r\n{0}", DataCopy.ToHexString(SendData)); RedisHelper redisclient = new RedisHelper((int)EnumUserRedisNum.Protocol); string sessionId = redisclient.HashGetString(ConstValue.DeviceCodeSessionKey, string.Format("{0}|{1}", StationID, CanID)); SendMessage sendMessage = new SendMessage(); sendMessage.SessionID = sessionId; sendMessage.SendData = SendData; redisclient.ListRightPush(String.Format("{0}|发送", ProtocolMeterHelp.ProtocolID), sendMessage); } catch (Exception ex) { LogEvent.Loger.Fatal(ex.ToString()); } }View Code
接收实时数据应答线程:
/// <summary> /// 获取消息线程 /// </summary> private void GetMessageTh() { RedisHelper redisclient = new RedisHelper((int)EnumUserRedisNum.Protocol); string key = String.Format("{0}|接收", ProtocolID); ProtocolMeter ProtocolMeter = ProtocolMeter.GetInstance(); while (true) { Thread.Sleep(RequestInterval * 100); try { if (Work == false) { continue; } ReviceMessage message = redisclient.ListLeftPop<ReviceMessage>(key); if (message == null) { continue; } ProtocolMeter = ProtocolMeter.GetInstance(); ProtocolMeter.ParseProtocol(message); } catch(Exception ex) { LogEvent.Loger.Fatal(ex.ToString()); } } } /// <summary> /// 解析数据包 /// </summary> /// <param name="rMsg"></param> public void ParseProtocol(ReviceMessage rMsg) { try { SaveClientStatus(rMsg); if (rMsg.Key == EnumSocektKeyType.连接.ToString()) { LogEvent.LogInfo.Debug("**************************客户端连接**************************"); // 保存设备、局站、协议等、 StationLogin(rMsg.SessionID); return; } // LogEvent.LogInfo.DebugFormat("接收:\r\n{0}", DataCopy.ToHexString(rMsg.ReviceData)); MessageInfo messageInfo = new MessageInfo(rMsg); if (!messageInfo.Valid) { MessageRecord.SaveInvalidMessage(rMsg.ReviceData); //记录非法数据包 return; } // 数据解析 ReviceRealData(messageInfo.Data, messageInfo.DataFlag); } catch (Exception ex) { LogEvent.Loger.Fatal(ex.ToString()); } } /// <summary> /// 接收到实时数据 /// </summary> /// <param name="data">数据域</param> /// <param name="dataFlag">数据标识</param> private void ReviceRealData(byte[] data, int dataFlag) { int flag = ConvertDataFlag(dataFlag, EnumAddDataFlag.Reduce); // 减0x33 SaveRealData(flag, data); } /// <summary> /// 保存实时数据 /// </summary> /// <param name="dataFlag"></param> /// <param name="data"></param> private void SaveRealData(int dataFlag, byte[] data) { List<RealDataInfo> realList = new List<RealDataInfo>(); Dictionary<int, byte[]> dataByteDic = new Dictionary<int, byte[]>(); int index = 0; int[] dataFlagS = RequestRealDataDic[dataFlag]; foreach(int flag in dataFlagS) { int dstOffset = 0; byte[] bS = new byte[SignalIdMap[flag].DataLength]; DataCopy.ByteCopy(data, index, bS, ref dstOffset, data.Length, SignalIdMap[flag].DataLength); index += SignalIdMap[flag].DataLength; dataByteDic.Add(flag, bS); } LogEvent.LogInfo.FatalFormat("dataByteDic---{0}", dataByteDic.Keys.Count); foreach (int flag in dataByteDic.Keys) { if(SignalIdMap[flag].Visible == (int)EnumYesOrNo.No) { continue; } int count = dataByteDic[flag].Length; double value = 0; int minus_flag = 0; if((((dataByteDic[flag][count-1] - ConstValue.DataFlagDeviation) >> 7) & 0x01) == 1) { minus_flag = 1; } value += HEX_to_BCD((byte)((dataByteDic[flag][count - 1] - ConstValue.DataFlagDeviation) & 0x7F)) * Math.Pow(10, (count - 1) * 2); for (int i = 0; i < count - 1; i++) { value += HEX_to_BCD((byte)(dataByteDic[flag][i] - ConstValue.DataFlagDeviation)) * Math.Pow(10, i * 2); } if(minus_flag == 1) { value = -value; } realList.Add(new RealDataInfo { DeviceCode = string.Format("{0}|{1}", StationID, CanID), SignalID = SignalIdMap[flag].SignalID, Value = value * SignalIdMap[flag].Ratio, StringValue = "", DataStatus = 0, UpdateTime = DateTime.Now }); LogEvent.LogInfo.DebugFormat($"{Convert.ToString(flag, 16)}|{DataCopy.ToHexString(dataByteDic[flag])}|{value * SignalIdMap[flag].Ratio}"); } //保存实时数据 RedisHelper redis = new RedisHelper((int)EnumUserRedisNum.RealData); redis.ListRightPush(ConstValue.SetRealData, realList); }View Code
接收到实时数据解析处理就好了。
其他的一些数据类得定义:
namespace Protocol_Meter_DLT645_07 { public class MessageInfo { #region 属性 /// <summary> /// 帧起始符,68H /// </summary> public byte MessageHead { set; get; } /// <summary> /// 地址域,6字节 /// </summary> public byte[] Addr { set; get; } /// <summary> /// 帧起始符,68H /// </summary> public byte StartHead { set; get; } /// <summary> /// 控制码 /// </summary> public byte ControlCode { set; get; } /// <summary> /// 数据域长度 /// </summary> public byte DataLength { set; get; } /// <summary> /// 数据标识 /// </summary> public int DataFlag { set; get; } /// <summary> /// 数据域 /// </summary> public byte[] Data { set; get; } /// <summary> /// 校验域 /// </summary> public byte CheckSum { set; get; } /// <summary> /// 结束帧,16H /// </summary> public byte EndFrame { set; get; } /// <summary> /// 发送数据的SOCKET /// </summary> public string SessionID { set; get; } /// <summary> /// 原始包 /// </summary> public byte[] MessageData { set; get; } /// <summary> /// 消息包是否有效 /// </summary> public bool Valid { set; get; } #endregion #region 构造 public MessageInfo() { } /// <summary> /// 通过接收的数据构造函数 /// </summary> /// <param name="message"></param> public MessageInfo(ReviceMessage message) { try { MessageData = new byte[message.ReviceData.Length]; Buffer.BlockCopy(message.ReviceData, 0, MessageData, 0, message.ReviceData.Length); int index = 0; int dstOffset = 0; // FE FE FE FE 68 22 52 88 00 00 00 68 91 07 33 33 37 35 33 33 33 CF 16 index += ConstValue.FE_Length; // 帧起始符 MessageHead = DataCopy.GetByte(message.ReviceData, ref index); // 地址域,6字节 Addr = new byte[6]; DataCopy.ByteCopy(message.ReviceData, index, Addr, ref dstOffset, message.ReviceData.Length, 6); index += 6; // 帧起始符 StartHead = DataCopy.GetByte(message.ReviceData, ref index); // 控制码 ControlCode = DataCopy.GetByte(message.ReviceData, ref index); // 数据域长度 DataLength = DataCopy.GetByte(message.ReviceData, ref index); // 数据标识 DataFlag = DataCopy.GetINT(message.ReviceData, ref index); // 数据域 int dataLength = message.ReviceData.Length - ConstValue.MessageLengthWithoutData - ConstValue.FE_Length + 4; dstOffset = 0; if (dataLength > 0) { Data = new byte[dataLength]; DataCopy.ByteCopy(message.ReviceData, index, Data, ref dstOffset, message.ReviceData.Length, dataLength); index += dataLength; } // 校验码 CheckSum = DataCopy.GetByte(message.ReviceData, ref index); // 结束符 EndFrame = DataCopy.GetByte(message.ReviceData, ref index); SessionID = message.SessionID; Valid = true; } catch (Exception ex) { LogEvent.Loger.Fatal(ex.ToString()); Valid = false; } } #endregion #region 方法 /// <summary> /// 将对象转化为二进制 /// </summary> /// <returns></returns> public byte[] ObjectToByte() { int messageLength = ConstValue.MessageLengthWithoutData; if (Data != null) messageLength += Data.Length; int index = 0; byte[] result = new byte[messageLength]; try { DataCopy.ByteCopy(ConstValue.FE_Head, 0, result, ref index, ConstValue.FE_Head.Length, messageLength); // 包头 DataCopy.ByteCopy(MessageHead, result, ref index); // 地址域 if (Addr != null) DataCopy.ByteCopy(Addr, 0, result, ref index, Addr.Length, messageLength); // 帧起始符 DataCopy.ByteCopy(StartHead, result, ref index); // 控制码 DataCopy.ByteCopy(ControlCode, result, ref index); // 数据域长度 DataCopy.ByteCopy(DataLength, result, ref index); // 数据标识 DataCopy.ByteCopy(DataFlag, result, ref index); // 消息包 if (Data != null) DataCopy.ByteCopy(Data, 0, result, ref index, Data.Length, messageLength); // 校验码 CheckSum = CheckSumHelp.AddCheckSum(result, 4, index); DataCopy.ByteCopy(CheckSum, result, ref index); // 数据标识 DataCopy.ByteCopy(EndFrame, result, ref index); } catch (Exception ex) { LogEvent.LogInfo.Fatal(ex.ToString()); return null; } return result; } #endregion } }View Code
数据转换(十六进制和BCD的转换):
/// <summary> /// BCD转16进制 /// </summary> /// <param name="data"></param> /// <returns></returns> private byte HEX_to_BCD(byte data) { int temp; temp = ((data >> 4) * 10 + (data & 0x0f)); return (byte)temp; } /// <summary> /// 16进制转BCD /// </summary> /// <param name="data"></param> /// <returns></returns> private byte BCD_to_HEX(byte data) { int temp; temp = (((data / 10) << 4) + (data % 10)); return (byte)temp; }View Code
校验和的处理:
namespace Protocol_Meter_DLT645_07 { /// <summary> /// 报文校验 /// </summary> public class CheckSumHelp { /// <summary> /// 校验和,左闭右开 /// </summary> /// <param name="pchMsg"></param> /// <param name="startByte"></param> /// <param name="endByte"></param> /// <returns></returns> public static byte AddCheckSum(byte[] pchMsg, int startByte, int endByte) { try { int sum = 0; for (int i = startByte; i < endByte; i++) { sum += pchMsg[i]; sum %= 256; } return (byte)sum; } catch(Exception ex) { LogEvent.Loger.Fatal(ex.ToString()); return 0; } } } }View Code
解析完之后实时数据就可以做业务处理了,监控运行、历史数据统计等等...总的来说和97版本的协议差别不大。
标签:DL,protocol,C#,INTO,DLT645,int,645,VALUES,null 来源: https://www.cnblogs.com/7haihai/p/14032374.html