上次说到了协议的大致结构,这次我们来说说怎么去实现制动连接串口(当你把设备连上来之后,怎么去让软件自动去识别是否为目标设备,当然这需要上位机与下位机共同完成,这里我们只讨论上位机部分)
先上协议:
帧头(3)+设备号(1)+指令类型(2)+数据长度(2)+载荷+CRC(2)
需要在下位机上实现的部分:
接收到一帧数据(帧头为53 5A 59,设备号01,类型为02,载荷无)53 59 A2 01 02 00 00 00 CRC
后,会返回(帧头为53 5A 59,设备号01,类型为02,载荷为"6F 6B")53 5A 59 01 02 00 02 00 6F 6B CRC
则表示指令接收成功。
下面说我的思路,在软件界面打开后,开一个自动连接线程处理连接部分。具体步骤是:
- 获取计算机所有串口。
- 尝试发送指定数据到每个可用串口。
- 尝试从串口接收数据并检查是否为约定数据,若是则绑定该端口,完成连接。不是则换到下一个。循环。
好了,让我们简单点,下面直接上代码:
bool IsConnected=false;
private void AutoConcted()
{
while (true)//循环
{
while (!IsConnected)//未连接
{
string[] strPorNnames = SerialPort.GetPortNames();//获取所有可用串口名
foreach (string portName in strPorNnames)//遍历串口
{
try
{
SPort.PortName = portName;
SPort.Open();
SPort.DiscardOutBuffer();
byte[] bytSend = new byte[] {0x53,0x59,0xA2,0x01,0x02, 0x00,0x00,0x00,CRC};//自行去CRC去
SPort.Write(bytSend, 0, bytSend.Length);
Thread.Sleep(100);//确保数据发送及解析时间
int n = SPort.BytesToRead;
byte[] bytRec = new byte[n];
SPort.Read(bytRec, 0, n);
if (IsHertJump(bytRec))//判断返回是否为指定数据
{
IsConnected = true;
break;//是则跳出循环
}
else
{ SPort.Close(); }
}
catch (Exception)
{ SPort.Close(); }
}
Thread.Sleep(400);
}
}
}
是的,自动连接应该可以实现了,然而又有了新问题,这种自动连接貌似只能连一次,中途拔掉一下就不行了,因为连接上之后进程就自己销毁了。而且拔掉之后(串口断开)软件并不会有任何的状态提示,之后你所有的数据都会往一个不知道的地方去了。所以,我们还要加一个检测断开的机制。由于两者不会同时需要,所以可以写到一个线程里去,没连上就自动去连,连上了就检测是否断开。
修改后的代码:(完善后的自动连接线程)
private void AutoConcted()
{
while (true)
{
while (!IsConnected)
{
string[] strPorNnames = SerialPort.GetPortNames();
foreach (string portName in strPorNnames)
{
try
{
SPort.PortName = portName;
SPort.Open();
SPort.DiscardOutBuffer();
byte[] bytSend = new byte[] {0x53,0x59,0xA2,0x01,0x02, 0x00,0x00,0x00,CRC};//自行去CRC去
SPort.Write(bytSend, 0, bytSend.Length);
Thread.Sleep(100);
int n = SPort.BytesToRead;
byte[] bytRec = new byte[n];
SPort.Read(bytRec, 0, n);
if (IsHertJump(bytRec))
{
IsConnected = true;
break;
}
else
{
SPort.Close();
}
}
catch (Exception)
{
SPort.Close();
}
}
Thread.Sleep(400);
}
while (IsConnected)
{
if (!SPort.IsOpen)//检查是否断开
{
SPort.Close();
IsConnected = false;
}
Thread.Sleep(1000);
}
}
}