订阅收费文章或资源:公众号“毛线杂货铺”,淘bao店铺ID:122344852,可搜索商铺“幸福的孩子yyx”或复制以下内容:
59《ZuboWnWzq1R《 https://m.tb.cn/h.5D3Od4wRAQzgQpH MF6563 我分享给你了一个超赞的内容,快来看看吧
或:
在简单的认识及使用串口通信之后,在实际应用中应该是配合硬件,和负责硬件通信的同事沟通好通信协议,来进行设备的控制及数据获取。
常用的串行通信协议有TTL电平(普通MCU芯片输出的串口电平)、RS232(工业上常用的串口标准)及RS485(串行总线标准,常用语通信距离为几十米到上千米时)等。
本文采用的是RS485,为半双工工作方式。下面是一个简单的获取设备信息的例子。
通信协议如下:
数据包格式:
包头(2byte) | 命令码(1byte) | 包长(2byte) | 数据/状态(Nbyte) | 异或校验(1byte) |
---|---|---|---|---|
发送数据/状态格式(24 bytes/每包,不足补0): | ||||
数据 | 说明 | |||
– | – | |||
设备编号 | 8byte | |||
系统时间 | 4byte | |||
接收设备返回的格式: | ||||
数据 | 说明 | |||
– | – | |||
设备编号 | 8byte | |||
设备电压温度 | 8byte,浮点数 | |||
增益 | 1byte | |||
4G状态 | 1byte | |||
存储容量 | 1byte | |||
时间戳 | 4byte 单位:秒 | |||
计数器 | 4byte | |||
控制类型 | 1byte 0x00-停止测量,0x01-开始测量,0x02-测量类型1,0x03-测量类型2,0x04-测量类型3 | |||
… | … |
发送获取数据的命令代码:
byte[] package = new byte[24];
int index=0;
package[index++] = 0x77;//帧头
package[index++] = 0xCC;
package[index++] = cmd;//命令码
package[index++] = 0;//数据长度高字节
package[index++] = 18;//数据长度低字节
//数据
var idbytes = Encoding.ASCII.GetBytes(id);
for (int i = 0; i < idbytes.Length; i++)
{
package[index++] = idbytes[i];//填充设备id
}
DateTime Now_Time = DateTime.Now;
int Time_Sec = GetTimeStamp(Now_Time);
package[index++] = (byte)(Time_Sec >> 24);
package[index++] = (byte)(Time_Sec >> 16);
package[index++] = (byte)(Time_Sec >> 8);
package[index++] = (byte)(Time_Sec);
//校验码
byte tmp = 0;
var length = package.Length - 1;
for (byte i = 0; i < length; i++)
tmp ^= package[i];
package[23] =tmp ;
serialPort.Write(package, 0, package.Length);
解析回复的数据(DataReceived事件):
Thread.Sleep(400);//延时,等待接收完数据 接收100个字节数据时间约为6ms
byte[] buffle = new byte[serialPort.BytesToRead];
serialPort.Read(buffle, 0, buffle.Length);//buffle为接收的数据
if (e.EventType != SerialData.Chars||serialPort == null)
{
return;
}
if (!serialPort.IsOpen)//串口在关闭时不接收数据 为了防止关闭串口时卡死的问题
{
serialPort.DiscardInBuffer();//丢弃接收缓冲区数据
return;
}
bool isAll = false;
if (DataBuffer[0] == 0x77 && DataBuffer[1] == 0xCC)//上次未接收完
{
var Length = DataBuffer.Length;
DataBuffer =RS485Helper. AddBytes(DataBuffer, buffle);
isAll = (Length == buffle.Length + bufferReadLength);
}
else//接收开始
{
if (buffle[0] == 0x77 && buffle[1] == 0xCC)
{
bufferReadLength = buffle.Length;
var length = (ushort)(buffle[3] << 8)+ (ushort)buffle[4]+6;//包长加包头包尾才是总长度
DataBuffer = new byte[length];
DataBuffer = RS485Helper.AddBytes(DataBuffer, buffle,false);//这个函数是将新增的byte[]添加到原有buffle后面
isAll = (length == buffle.Length);
}
}
if (isAll)
{
Analyse(DataBuffer.Clone() as byte[]);
DataBuffer = new byte[1000];
isAccept = false;
}
private void Analyse(byte[] buffle)
{
var gucCommand = buffle[2];
var devId = Encoding.Default.GetString(buffle.Skip(3).Take(8).ToArray());
object data=null;
switch (gucCommand)
{
case RS485Helper.DEV_INQUIRE_CMD:
Deal_DevInfo(buffle);
break; //更新连接标志
default: break;
}
if (OnComReceiveDataHandler != null)
{
OnComReceiveDataHandler(data, ComPortName, devId);//这里使用委托让UI界面去更新,注意现在是在子线程里面,使用
}
}
private void Deal_DevInfo(byte[] buffle)
{
ushort Data_Lenght = (ushort)((buffle[3] << 8) + buffle[4]);//接收字节的长度
string id= BitConverter.ToString(buffle, 5, 8);//仪器编号
var power = BitConverter.ToSingle(buffle, 13).ToString("f2");//电量
var Tem = BitConverter.ToSingle(buffle, 17).ToString("f2");//温度
float Gain_Value = 0;
switch (buffle[21])//增益
{
case 0: Gain_Value = 0.25f; break;
case 1: Gain_Value = 0.5f; break;
}
var Wireless_State = String.Format("{0:X}", buffle[22]);//4G状态
var Space = buffle[23].ToString();//剩余空间
int Time_Value = (buffle[24] << 24) + (buffle[25] << 16) + (buffle[26] << 8) + buffle[27];
var Col_Time = GetDateTime(Time_Value);//时间
//计数器
var Data_Count = (uint)((buffle[28] << 24) + (buffle[29] << 16) + (buffle[30] << 8) + buffle[31]);
byte Work_Mode = buffle[32];//工作模式
var workMode = "";
switch (Work_Mode)
{
case 0: workMode = "停止"; break;
case 1: workMode = "采集"; break;
case 2: workMode = "模式1"; break;
case 3: workMode = "模式2"; break;
case 4: workMode = "模式3"; break;
default: workMode = "停止"; break;
}
...
}