工具
- 虚拟串口调试工具 Virtual Serial Port Driver 6.9
- 串口调试工具 sscom5.13.1
- 如果串口的数据包是字符串类型的,可以直接使用串口调试工具去转换。如果是double类型的数据包,需要自己去转一下,这里贴一个简易的代码
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;
public class double_convert_byte : MonoBehaviour {
double[] message = new double[3];
List<byte> listData = new List<byte>();
// Use this for initialization
void Start () {
message[0] =;
message[1] = ;
message[2] = ;
for(int i=0;i<3;i++)
{
listData.AddRange(BitConverter.GetBytes(message[i]));
}
var bytes = listData.ToArray();
var hex = BitConverter.ToString(bytes, 0).Replace("-", string.Empty).ToLower();
Debug.Log(hex);
}
// Update is called once per frame
void Update () {
}
}
串口读取及其解包
1.串口读取代码
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.IO.Ports;
using System.Threading;
using System;
using System.Text;
using System.Runtime.InteropServices;
namespace data_structure
{
public class PortControl : MonoBehaviour
{
[Header("串口名")] public string portName = "COM2";
[Header("波特率")] public int baudRate = 115200;
[Header("效验位")] public Parity parity = Parity.None;
[Header("数据位")] public int dataBits = 100;
[Header("停止位")] public StopBits stopBits = StopBits.One;
private SerialPort sp = null;
private Thread dataReceiveThread;
private byte[] datasBytes;
int i = 0;
private byte OneByte;
private byte[] OtherBytes;
ArrayList m_CmdRcv = new ArrayList(); //存放接收到的数据
//接收当前状态量数据
public Object_State_Struct data_state = new Object_State_Struct();
int cmdsize = 0;
byte firstHeader = 0x4A; //数据包帧头
byte secondHeader = 0x58;
private void Start()
{
OpenPortControl();
}
/// <summary>
/// 开启串口
/// </summary>
public void OpenPortControl()
{
sp = new SerialPort(portName, baudRate, parity, dataBits, stopBits);
//串口初始化
if (!sp.IsOpen)
{
sp.Open();
}
dataReceiveThread = new Thread(ReceiveData);//该线程用于接收串口数据
dataReceiveThread.Start();
}
/// <summary>
/// 关闭串口
/// </summary>
public void ClosePortControl()
{
if (sp != null && sp.IsOpen)
{
sp.Close();//关闭串口
sp.Dispose();//将串口从内存中释放掉
}
}
private void ReceiveData()
{
int bytesToRead = 0;
while (true)
{
if (sp != null && sp.IsOpen)
{
try
{
datasBytes = new byte[1024];
bytesToRead = sp.Read(datasBytes, 0, datasBytes.Length);//将串口中的数据插入到datasBytes中的第0位
//Debug.Log(bytesToRead);
if (bytesToRead == 0)
{
continue;
}
else
{
i++;
if (i == 1)
{
OneByte = datasBytes[0];
}
else if (i == 2)
{
List<byte> listData = new List<byte>();
listData.Add(OneByte);
listData.AddRange(datasBytes);//将串口数据组合成完整的包
OtherBytes = listData.ToArray();
i = 0;
Decode_data(OtherBytes, OtherBytes.Length);//解包程序
Debug.Log(OtherBytes);
}
//Debug.Log(strbytes);
}
}
catch (Exception e)
{
Debug.Log(e.Message);
}
}
Thread.Sleep(100);
}
}
/// <summary>
/// 数据解包
/// </summary>
public void Decode_data(byte[] receiveData, int recvLength)
{
addRange(receiveData, recvLength); //把接收到的数据暂存为m_CmdRcv
int fPz = m_CmdRcv.IndexOf((Byte)firstHeader); //查找消息头0x4A的位置;fPz=0,第一位;fPz>0,非第一位
bool flagofFramTip = false; //数据帧头查找标志位,初始化为false
cmdsize = Marshal.SizeOf(typeof(Object_State_Struct));
while (!flagofFramTip)
{
if (fPz < 0) { m_CmdRcv.Clear(); flagofFramTip = true; }
if (fPz > 0) { m_CmdRcv.RemoveRange(0, fPz); fPz = m_CmdRcv.IndexOf((Byte)firstHeader); }
if (fPz == 0)
{
if (m_CmdRcv.Count >= cmdsize)
{
if (secondHeader == (Byte)m_CmdRcv[fPz + 1])
{
//计算校验和
IntPtr pCmdRcv = Marshal.AllocHGlobal(cmdsize);
Byte check = 0;
ArrayList cmdData = new ArrayList();
for (int k = 0; k < cmdsize - 1; k++)
{
check += (Byte)m_CmdRcv[k];
cmdData.Add(m_CmdRcv[k]);
}
//判断校验和
if (check == (Byte)m_CmdRcv[cmdsize - 1])
{
// 认为此包正确
cmdData.Add(check);
//将cmdData的数据拷贝到pCmdRcv,方便后续的结构体直接赋值
Marshal.Copy((Byte[])cmdData.ToArray(typeof(Byte)), 0, pCmdRcv, cmdsize);
switch ((Byte)m_CmdRcv[fPz + 2])
{
case 0x41:
{
data_state = (Object_State_Struct)Marshal.PtrToStructure(pCmdRcv, typeof(Object_State_Struct));
}
break;
default:
break;
}
//移除检验完的帧长
m_CmdRcv.RemoveRange(0, cmdsize);
}
//校验和不匹配
else
{
m_CmdRcv.RemoveRange(0, 2);
}
}
//第二位识别帧不匹配
else
{
m_CmdRcv.RemoveRange(0, 1);
}
}
//识别帧小于识别帧长
else
{
flagofFramTip = true;
}
}
//帧头小于识别帧长
else { flagofFramTip = true; }
// 重新寻找帧头
fPz = m_CmdRcv.IndexOf((Byte)firstHeader);
}
}
/// <summary>
/// Byte数组转换为ArrayList
/// </summary>
/// <param name="receiveData">字符数组</param>
/// <param name="len">数组长度</param>
/// <returns></returns>
void addRange(Byte[] receiveData, int len)
{
for (int i = 0; i < len; i++)
{
m_CmdRcv.Add(receiveData[i]);
}
}
void OnApplicationQuit()
{
ClosePortControl();
}
}
}
结构体格式(应与协议一致)
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
namespace data_structure
{
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct Object_State_Struct
{
/// <summary>
/// 0.同步字节1
/// </summary>
public byte header1;
/// <summary>
/// 1.同步字节2
/// </summary>
public byte header2;
/// <summary>
/// 2.帧长(包含校验位)
/// </summary>
public byte len;
/// <summary>
/// 3.识别帧
/// </summary>
public byte ID;
public double posX;
/// 140.校验和
/// 0~139字节累加和
/// </summary>
public byte checksum;
}
}