Unity 读取串口数据并确保数据完整

12 篇文章 0 订阅

Unity 读取串口数据并确保数据完整

前言

STM32下位机发送串口数据到Unity,Unity使用的是C#,读取串口数据的函数只有两种,一个是Read另一个是ReadLine,下位机持续发数,需要有一个数据缓存池缓存,否则数据包会错乱,并且当数据包出现缺省时,数据接收会有延迟等问题。
Read每次会读取不定长度的值,ReadLine会以 " \n " 为消息结尾,持续不断的等待接收数据,下位机将数据转化为Char有些不方便,所以使用Read方法不断读取。

实现代码

  1. 缓存数据
  2. 完整性判断
  3. 解析数据
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO.Ports;
using UnityEngine;

public class RecPortScript : MonoBehaviour
{
    #region 串口参数,主要修改串口名与波特率
    /// <summary>
    /// 串口名
    /// </summary>
    string getPortName;
	/// <summary>
	/// 波特率
	/// </summary>
	int baudRate = 115200;
	private Parity parity = Parity.None;
	private int dataBits = 8;
	private StopBits stopBits = StopBits.One;
	SerialPort sp = null;
    #endregion

    #region 消息处理相关
    /// <summary>
    /// 缓存消息列表
    /// </summary>
    List<byte> bufferList = new List<byte>();
	/// <summary>
	/// 一条消息的长度
	/// </summary>
	int messageLen = 24;
    #endregion
    // Start is called before the first frame update
    void Start()
    {
		getPortName = "COM4";
		baudRate = 115200;

		OpenPort(getPortName, baudRate);
		StartCoroutine(DataReceiveFunction());
	}
	IEnumerator DataReceiveFunction()
	{

		while (true)
        {
			if (sp != null && sp.IsOpen) {
				try
				{
					RecAndProcessingFunction();
				}
				catch (Exception ex)
				{
					Debug.LogError(ex);
				}
			}
			yield return new WaitForSeconds(Time.deltaTime);
		}
	}

	/// <summary>
	/// 读取并处理消息
	/// </summary>
	private void RecAndProcessingFunction()
    {
		//待读字节个数
		int n = sp.BytesToRead;
		//创建n个字节的缓存
		byte[] buf = new byte[n];
		//读到在数据存储到buf
		sp.Read(buf, 0, n);
		//1.缓存数据 不断地将接收到的数据加入到buffer链表中
		bufferList.AddRange(buf);
		//2.完整性判断 至少包含帧头(1字节)、类型(1字节)、功能位(22字节) 根据设计不同而不同
		while (bufferList.Count >= 2)
        {
			//2.1 查找数据头 根据帧头和类型
			if (bufferList[0] == 170 && bufferList[1] == 85)
            {
				//如果小于则说明数据区尚未接收完整,
				if (bufferList.Count < messageLen) 
				{
					//跳出接收函数后之后继续接收数据
					break;
				}
				//得到一帧完整的数据,进行处理,在此之前可以使用校验位保证此帧数据完整性
				byte[] processingByteArray = new byte[messageLen];
				//从缓存池中拷贝到处理数组
				bufferList.CopyTo(0, processingByteArray, 0, messageLen);
				//处理一帧数据
				DataProcessingFunction(processingByteArray);
				//从缓存池移除处理完的这帧
				bufferList.RemoveRange(0, messageLen);
			}
			else
			{
				//帧头不正确时,清除第一个字节,继续检测下一个。
				bufferList.RemoveAt(0);
			}
		}
	}
	/// <summary>
	/// 数据处理
	/// </summary>
	private void DataProcessingFunction(byte[] dataBytes)
    {
		Debug.Log(byteToHexStr(dataBytes));
	}
	/// <summary>
	/// 字节数组转16进制字符串
	/// </summary>
	/// <param name="bytes"></param>
	/// <returns></returns>
	public static string byteToHexStr(byte[] bytes)
	{
		string returnStr = "";
		if (bytes != null)
		{
			for (int i = 0; i < bytes.Length; i++)
			{
				returnStr += bytes[i].ToString("X2");
				returnStr += "-";
			}
		}
		return returnStr;
	}

	#region 串口开启关闭相关
	//打开串口
	public void OpenPort(string DefaultPortName,int DefaultBaudRate)
	{
		sp = new SerialPort(DefaultPortName, DefaultBaudRate, parity, dataBits, stopBits);
		sp.ReadTimeout = 10;
		try
		{
			if (!sp.IsOpen)
			{
				sp.Open();
			}
		}

		catch (Exception ex)
		{
			Debug.Log(ex.Message);
		}
	}
	
	//关闭串口
	public void ClosePort()
	{
		try
		{
			sp.Close();
		}
		catch (Exception ex)
		{
			Debug.Log(ex.Message);
		}
	}
    #endregion
    
    #region Unity
    private void OnApplicationQuit()
    {
        ClosePort();
    }
    private void OnDisable()
    {
        ClosePort();
    }
    #endregion
}

最后加上一个字符串转16进制、16进制转回字符串的C#代码

	/// <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;
    }

参考: c#中,确保数据接收完整的 串口处理程序

评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值