最近和别人一起研究了一下串口通讯,通过硬件控制Unity开发的程序,感觉还他那个好用的,就是有好多常理无法解释的骑怕问题。不啰嗦。直接上代码,都有注释,相信大家都能看的懂。下面的代码中接收的数据必须是“[***********]”这种形式。通过“[]”能更好的判断数据的准确性,防止发生数据丢失的情况。注:如果使用USB串口通讯的话,使用同一条数据线完成接收和发送消息会出现丢失数据的情况,具体怎么解决木钱还没想到更好的方法,如果大家有好的解决方法欢迎前来指教。
using System.Collections.Generic;
using UnityEngine;
using System.IO.Ports;
using System.Threading;
using System;
using System.Text;
public class MainProt: MonoBehaviour
{
//COM口
public string portName = "COM3";
//波特率
public int baudrate = 115200;
//校验位
public Parity parite = Parity.None;
//数据位
public int dataBits = 8;
//停止位
public StopBits stopbits = StopBits.One;
SerialPort port;
Thread portRev, portDeal;
Queue<string> dataQueue;
string outStr = string.Empty;
//判断是否开始整合数据
private bool isStart = false;
//记录整合的数据
StringBuilder receiveStr = new StringBuilder();
//用来记录接收的完整的数据,后面好处理
Queue<string> inputStr = new Queue<string>();
//计时用的变量
private float cutDownTime = 0;
// Use this for initialization
void Start()
{
dataQueue = new Queue<string>();
port = new SerialPort(portName, baudrate, parite, dataBits, stopbits);
port.ReadTimeout = 400;
try
{
port.Open();
Debug.Log("串口打开成功!");
portRev = new Thread(PortReceivedThread);
portRev.IsBackground = true;
portRev.Start();
portDeal = new Thread(DealData);
portDeal.Start();
}
catch (System.Exception ex)
{
Debug.Log(ex.Message);
}
}
// Update is called once per frame
void Update()
{
if (!portRev.IsAlive)
{
portRev = new Thread(PortReceivedThread);
portRev.IsBackground = true;
portRev.Start();
}
if (!portDeal.IsAlive)
{
portDeal = new Thread(DealData);
portDeal.Start();
}
//发送数据,这里的发送数据是定时向硬件方面发送数据,如不需要直接删除就好
//cutDownTime += Time.deltaTime;
//if (cutDownTime >= 0.5f)
//{
// //将string转换为byte[]
// byte[] decBytes = System.Text.Encoding.UTF8.GetBytes("ABC");
// SendData(decBytes);
// Debug.Log("已发送");
// cutDownTime = 0;
//}
//退出
if (Input.GetKeyDown(KeyCode.Escape))
{
Application.Quit();
}
}
/// <summary>
/// 接收
/// </summary>
void PortReceivedThread()
{
try
{
byte[] buf = new byte[1];
string resStr = string.Empty;
if (port.IsOpen)
{
port.Read(buf, 0, 1);
}
if (buf.Length == 0)
{
return;
}
if (buf != null)
{
for (int i = 0; i < buf.Length; i++)
{
resStr += buf[i].ToString("X2");
dataQueue.Enqueue(resStr);
}
}
}
catch (System.Exception ex)
{
Debug.Log(ex.Message);
}
}
/// <summary>
/// 处理
/// </summary>
void DealData()
{
while (dataQueue.Count != 0)
{
for (int i = 0; i < dataQueue.Count; i++)
{
outStr += dataQueue.Dequeue();
if (outStr.Length == 2)
{
//数据开头“[”
if (outStr == "5B")
{
isStart = true;
}
//将所有数据从开始拼接到一起
if (isStart)
{
//接收的是十六进制的数据,要完成一下转化
receiveStr.Append(ToMyString(outStr));
}
else
{
Debug.Log("错误数据: "+ receiveStr);
}
//数据结尾“]”
if (outStr == "5D")
{
isStart = false;
//将接收的完整的数据添加到队列。待加
Debug.Log(receiveStr);
//开头和结尾都对了才能够加入队列中处理
inputStr.Enqueue(receiveStr.ToString());
//清空接收的数据
receiveStr.Remove(0, receiveStr.Length);
}
outStr = string.Empty;
}
}
}
}
/// <summary>
/// 发送
/// </summary>
/// <param name="msg"></param>
void SendData(byte[] msg)
{
//这里要检测一下msg
if (port.IsOpen)
{
port.Write(msg, 0, msg.Length);
}
}
/// <summary>
/// 退出
/// </summary>
void OnApplicationQuit()
{
Debug.Log("退出!");
if (portRev.IsAlive)
{
portRev.Abort();
}
if (portDeal.IsAlive)
{
portDeal.Abort();
}
//退出程序的时候,一定要关闭串口
port.Close();
}
/// <summary>
/// 字符串转16进制
/// </summary>
/// <param name="input">要转格式的字符串</param>
/// <returns>转化为16进制的字符串</returns>
private string ToSixteen(string input)
{
char[] values = input.ToCharArray();
string end = string.Empty;
foreach (char letter in values)
{
int value = Convert.ToInt32(letter);
string hexoutput = string.Format("{0:X}", value); //0 表示占位符 x或X表示十六进制
end += hexoutput + "_";
}
end = end.Remove(end.Length - 1);
return end;
}
/// <summary>
/// 16进制转回字符串
/// </summary>
/// <param name="input">16进制</param>
/// <returns>转回的字符串</returns>
private string ToMyString(string input)
{
string[] hexvaluesplit = input.Split('_');
string end = string.Empty;
foreach (string hex in hexvaluesplit)
{
int value = Convert.ToInt32(hex, 16);
string stringvalue = char.ConvertFromUtf32(value);
char charValue = (char)value;
end += charValue;
}
return end;
}
}