unity中想发送16进制给串口 这是16进制的内容: 01 03 00 00 00 01 84 0A 但是串口收到的变成01 03 00 00 00 01 04 0A
using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Ports;
using System.Text;
using System.Threading;
using UnityEngine;
using System.Linq;
using Microsoft.Win32;
namespace HSJFramework
{
public enum ReceiveDataType
{
EventHandler,
NewThread
}
public class SeriaPortManager : MonoBehaviour
{
#region 定义串口属性
//定义基本信息
public string portName ;//串口名
public int baudRate = 9600;//波特率
public int dataBits = 8;//数据位
public Parity parity = Parity.None;//效验位
public StopBits stopBits = StopBits.One;//停止位
SerialPort sp = null;//声明的串口对象
Thread dataReceiveThread;//监听串口消息的线程
//接收消息方式
public ReceiveDataType receiveDataType = ReceiveDataType.NewThread;
/// <summary>
/// 缓存消息列表
/// </summary>
List<byte> bufferList = new List<byte>();
/// <summary>
/// 一条消息的长度(消息为16进制)
/// </summary>
int messageLen = 15;
#endregion
void Start()
{
ScanSeria();
//本地配置数据加载
if (File.Exists(Application.streamingAssetsPath + "/SeriaPortConfig.txt"))
{
Debug.Log("加载串口配置数据");
string path = Application.streamingAssetsPath + "/SeriaPortConfig.txt";
string[] strs = File.ReadAllLines(path);
portName = strs[0];
}
OpenPort();
}
/// <summary>
/// 创建打开串口
/// </summary>
public void OpenPort()
{
Debug.Log("打开串口"+portName);
sp = new SerialPort(portName, baudRate, parity, dataBits, stopBits);
sp.ReadTimeout = 4000;
sp.WriteTimeout = 4000;
sp.Open();
if (receiveDataType == ReceiveDataType.NewThread)
{
dataReceiveThread = new Thread(DataReceiveFunction);
dataReceiveThread.Start();
}
//经测试无效
else if (receiveDataType == ReceiveDataType.EventHandler)
{
sp.DataReceived += new SerialDataReceivedEventHandler(DataReceived);
}
}
private void DataReceived(object sender, SerialDataReceivedEventArgs e)
{
ReceiveData();
}
/// <summary>
/// 写入发送数据
/// </summary>
/// <param name="dataStr"></param>
public void WriteData()
{
string dataStr= "01 03 00 00 00 01 84 0A";
if (sp.IsOpen)
{
Debug.Log("发送指令:"+dataStr);
//方式一
var bd = StringToHexBytes(dataStr);//转16进制字节数组写入
sp.Write(bd, 0, bd.Length);
//方式二
sp.Write(CheckModul(), 0, CheckModul().Length);//拼接16进制字节数组
}
}
//测试发送串口指令—拼接
public byte[] CheckModul()
{
return new byte[] { 0x01, 0x03, 0x00, 0x00, 0x00, 0x84, 0x0A };
}
/// <summary>
/// 接收数据的线程方法,在.Net一般使用回调函数DataReceived处理,unity里面会有异常故使用开启新线程的方式
/// </summary>
void DataReceiveFunction()
{
while (sp != null && sp.IsOpen)
{
try
{
Thread.Sleep(100);
//单字节接收,只接收单帧数据的第一个字节,不考虑数据的异常情况(一般使用在测试或者协议简单,功能单一的场景)
ReceiveChar();
//接收单帧的所有数据,可能缺失也能粘包
ReceiveData();
}
catch (Exception ex)
{
Debug.Log(ex.Message);
}
}
}
private void ReceiveChar()
{
List<byte> listReceive = new List<byte>();
char[] strchar = new char[100];//接收的字符信息转换为字符数组信息
byte addr = Convert.ToByte(sp.ReadByte());
sp.DiscardInBuffer();
listReceive.Add(addr);
string str = "";
for (int i = 0; i < listReceive.Count; i++)
{
strchar[i] = (char)(listReceive[i]);
str = new string(strchar);
}
Debug.Log(str);
listReceive.Clear();
}
/// <summary>
/// 接收读取并处理消息
/// </summary>
private void ReceiveData()
{
//待读字节个数
int n = sp.BytesToRead;
Debug.Log(n);
//创建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] == 85 && bufferList[1] == 170)
{
//如果小于则说明数据区尚未接收完整,
if (bufferList.Count < messageLen)
{
//跳出接收函数后之后继续接收数据
break;
}
Debug.Log(bufferList.Count);
//得到一帧完整的数据,进行处理,在此之前可以使用校验位保证此帧数据完整性
byte[] processingByteArray = new byte[messageLen];
//从缓存池中拷贝到处理数组
bufferList.CopyTo(0, processingByteArray, 0, messageLen);
//处理一帧数据
DataAnalysis(processingByteArray);
//从缓存池移除处理完的这帧
bufferList.RemoveRange(0, messageLen);
}
else
{
//帧头不正确时,清除第一个字节,继续检测下一个。
bufferList.RemoveAt(0);
}
}
}
/// <summary>
/// 数据解析处理 具体的处理解析方案跟下位机一同制定协商
/// </summary>
private void DataAnalysis(byte[] dataBytes)
{
List<byte> allDB= dataBytes.ToList();
byte[] b1 =new byte[2];
allDB.CopyTo(0, b1, 0, 2);
Debug.Log("消息头:" + byteToHexStr(b1));
byte[] b2 = new byte[4];
allDB.CopyTo(b1.Length, b2, 0, 4);
Debug.Log("幅度:" + byteToHexStr(b2)+"/"+ + HexBufToFloat(b2, 0));
byte[] b3 = new byte[4];
allDB.CopyTo(b1.Length+b2.Length, b3, 0, 4);
Debug.Log("载频:" + byteToHexStr(b3)+"/"+ HexBufToFloat(b3, 0));
byte[] b4 = new byte[4];
allDB.CopyTo(b1.Length + b2.Length+b3.Length, b4, 0, 4);
Debug.Log("低频:" + byteToHexStr(b4)+"/" + HexBufToFloat(b4, 0));
byte[] b5 = new byte[1];
allDB.CopyTo(allDB.Count-1, b5, 0, 1);
Debug.Log("消息尾:" + byteToHexStr(b5));
}
/// <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 += "-";
}
returnStr = returnStr.Remove(returnStr.Length - 1);
}
return returnStr;
}
/// <summary>
/// 关闭串口
/// </summary>
public void ClosePort()
{
if (sp!=null)
{
sp.Close();
if (dataReceiveThread!=null)
{
dataReceiveThread.Abort();
}
}
}
private void OnDestroy()
{
ClosePort();
}
/// <summary>
/// 字符串转16进制字符串
/// </summary>
/// <param name="input">要转格式的字符串</param>
/// <returns>转化为16进制的字符串</returns>
private string StringToHexStr(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;
}
//字符串转16进制字节数组
public byte[] StringToHexBytes(string hs)
{
string[] strArr = hs.Trim().Split(' ');
byte[] b = new byte[strArr.Length];
//逐个字符变为16进制字节数据
for (int i = 0; i < strArr.Length; i++)
{
b[i] = Convert.ToByte(strArr[i], 16);
}
//按照指定编码将字节数组变为字符串
return b;
}
public char[] StringToHexChar(string hs)
{
string[]strArr = hs.Trim().Split(' ');
char[] b = new char[strArr.Length*2];
//逐个字符变为16进制字节数据
for (int i = 0; i < strArr.Length; i++)
{
b[i*2] = strArr[i].ToCharArray()[0];
b[i * 2+1] = strArr[i].ToCharArray()[1];
}
//按照指定编码将字节数组变为字符串
return b;
}
/// <summary>
/// 16进制字符串转回正常字符串
/// </summary>
/// <param name="input">16进制</param>
/// <returns>转回的字符串</returns>
private string HexStrToStr(string input)
{
string[] hexvaluesplit = input.Split('-');
string end = string.Empty;
foreach (string hex in hexvaluesplit)
{
if (hex != "")
{
int value = Convert.ToInt32(hex, 16);
string stringvalue = char.ConvertFromUtf32(value);
char charValue = (char)value;
end += charValue;
}
}
return end;
}
//16进制字节数据转Float数据,offset默认为0根据消息协议设定设置
private float HexBufToFloat(byte[] buf, int offset)
{
float f = 0;
UInt32 num = HexBufToU32(buf, offset);
byte[] bs = BitConverter.GetBytes(num);
f = BitConverter.ToSingle(bs, 0);
return f;
}
//16进制字节数据转Int数据
private UInt32 HexBufToU32(byte[] buf, int offset)
{
UInt32 val = 0;
if ((offset + 4) > buf.Length)
{
return 0;
}
val |= (UInt32)buf[offset + 0] << 24;
val |= (UInt32)buf[offset + 1] << 16;
val |= (UInt32)buf[offset + 2] << 8;
val |= (UInt32)buf[offset + 3] << 0;
return val;
}
//扫描本机所有端口
private void ScanSeria()
{
string[] portList = SerialPort.GetPortNames();
foreach (var item in portList)
{
Debug.Log(item);
}
}
//使用注册表信息扫描
private string[] ScanPorts_Regedit()
{
RegistryKey keyCom = Registry.LocalMachine.OpenSubKey("Hardware\\DeviceMap\\SerialComm");
string[] SubKeys = keyCom.GetValueNames();
string[] portList = new string[SubKeys.Length];
for (int i = 0; i < SubKeys.Length; i++)
{
portList[i] = (string)keyCom.GetValue(SubKeys[i]);
}
return portList;
}
public byte[] hexStringToBytes(string hexString)
{
if ((hexString == null) || (hexString.Equals("")))
{
return null;
}
hexString = hexString.ToUpper();
int length = hexString.Length / 2;
char[] hexChars = hexString.ToCharArray();
byte[] d = new byte[length];
for (int i = 0; i < length; i++)
{
int pos = i * 2;
d[i] = ((byte)(charToByte(hexChars[pos]) << 4 | charToByte(hexChars[pos + 1])));
}
return d;
}
private sbyte charToByte(char c)
{
return (byte)"0123456789ABCDEF".IndexOf(c);
}
public byte[] getObject(string obj)
{
string[] arr = obj.Split(' ');
byte[] b = new byte[arr.Length];
for (int i = 0; i < arr.Length; i++)
{
b[i] = hexStringToBytes(arr[i])[0];
}
return b;
}
}
}
不管用方法1还是方法2,
最后还使用了getObject的方法去转
得到的结果还是一样的。而getObject的方法是通过java同事的脚本改写过来的,java里面这样写是没有任何问题的。且发现出错的84在他们那边转换之后得到的值其实是-124,而我们这边转换的值132。后面把byte改用sbyte,虽然转换的值可以得到-124.但是write()方法之后在串口助手里得到的值仍然是04.
有人可以解惑吗?