Skip to content

Instantly share code, notes, and snippets.

@klkucan
Last active September 12, 2017 13:00
Show Gist options
  • Save klkucan/39b6b241b0f8082c388e8de9bac943be to your computer and use it in GitHub Desktop.
Save klkucan/39b6b241b0f8082c388e8de9bac943be to your computer and use it in GitHub Desktop.
Unity use ComPort
using System;
using System.Collections.Generic;
using System.IO.Ports;
using System.Text;
using System.Threading;
namespace ButflyCOM
{
public class ButflyCOMPort
{
SerialPort ComPort = new SerialPort();//声明一个串口
public string sStrMsg = "";
byte[] bReceiveByte;
public delegate void ReceiveCOMMsg(string str);
public ReceiveCOMMsg ReceiveCOMMessage;
public delegate void LogOut(string str);
public LogOut Log;
public TimeSpan ts1;// = new TimeSpan(DateTime.Now.Ticks);
public TimeSpan ts2;// = new TimeSpan(DateTime.Now.Ticks);
//public string sPortName;
public int iCOMNum = 1;
public bool bComOk = false;
private int m_speed;
/// <summary>
/// ctor
/// </summary>
/// <param name="log">为了让unity能够输出log而做的函数</param>
/// <param name="speed">骑马机速度</param>
/// <param name="iPort">骑马机COM号</param>
public ButflyCOMPort(LogOut log, int speed = 10, int iPort = 5)
{
m_speed = speed;
iCOMNum = iPort;
Log = log;
ComPort.ReadTimeout = 8000;//串口读超时8秒
ComPort.WriteTimeout = 8000;//串口写超时8秒,在1ms自动发送数据时拔掉串口,写超时5秒后,会自动停止发送,如果无超时设定,这时程序假死
ComPort.ReadBufferSize = 1024;//数据读缓存
ComPort.WriteBufferSize = 1024;//数据写缓存
OpenOntPort();
}
public void Close()
{
if (ComPort.IsOpen)
{
ComPort.Close();
}
}
/// <summary>
/// COM开启函数的包装器,包含3次尝试
/// </summary>
/// <returns></returns>
public bool OpenOntPort()
{
bool bOpen = false;
Log("OpenOntPort->打开COM" + iCOMNum.ToString());
int retry = 0;
while (!bOpen)
{
retry++;
if (retry > 3)
{
Log(string.Format("OpenOntPort->COM{0}打开失败", iCOMNum.ToString()));
return false;
}
bOpen = OpenPort("COM" + iCOMNum.ToString());
}
Log(string.Format("OpenOntPort->COM{0}已打开", iCOMNum.ToString()));
return true;
}
/// <summary>
/// 真正的开启COM的函数
/// </summary>
/// <param name="portName"></param>
/// <returns></returns>
private bool OpenPort(string portName)
{
try//尝试打开串口
{
ComPort.PortName = portName;//设置要打开的串口
ComPort.BaudRate = 115200;//设置当前波特率
ComPort.Parity = Parity.None;//设置当前校验位
ComPort.DataBits = 8;//设置当前数据位
ComPort.StopBits = StopBits.One;//设置当前停止位
ComPort.Open();//打开串口
return true;
}
catch (Exception e)//如果串口被其他占用,则无法打开
{
Console.WriteLine(e);
return false;//无法打开串口,提示后直接返回
}
}
/// <summary>
/// 发送数据,包含逻辑判断和数据拼装
/// </summary>
/// <param name="start"></param>
/// <returns></returns>
public int Send(bool start)
{
if (!ComPort.IsOpen)
{
Log("COM关闭,尝试重新打开");
if (OpenOntPort() == false)
return 0;
}
if (start)
{
Log("发送开始");
}
else
{
Log("发送停止");
}
string sStart = "65";
string sEnd = "42";
string str = "";
if (start)
{
str = sStart + m_speed.ToString() + "01" + sEnd;
}
else
{
str = sStart + m_speed.ToString() + "00" + sEnd;
}
if (Log != null) Log("comport send:" + str);
ts1 = new TimeSpan(DateTime.Now.Ticks);
ComSend(str);
return 1;
}
/// <summary>
/// 真正的发送功能
/// </summary>
/// <param name="str"></param>
private void ComSend(string str)//发送数据 普通方法,发送数据过程中UI会失去响应
{
byte[] sendBuffer = null;//发送数据缓冲区
string sendData = str;//复制发送数据,以免发送过程中数据被手动改变
try //尝试将发送的数据转为16进制Hex
{
sendData = sendData.Replace(" ", "");//去除16进制数据中所有空格
sendData = sendData.Replace("\r", "");//去除16进制数据中所有换行
sendData = sendData.Replace("\n", "");//去除16进制数据中所有换行
if (sendData.Length == 1)//数据长度为1的时候,在数据前补0
{
sendData = "0" + sendData;
}
else if (sendData.Length % 2 != 0)//数据长度为奇数位时,去除最后一位数据
{
sendData = sendData.Remove(sendData.Length - 1, 1);
}
List<string> sendData16 = new List<string>();//将发送的数据,2个合为1个,然后放在该缓存里 如:123456→12,34,56
for (int i = 0; i < sendData.Length; i += 2)
{
sendData16.Add(sendData.Substring(i, 2));
}
sendBuffer = new byte[sendData16.Count];//sendBuffer的长度设置为:发送的数据2合1后的字节数
for (int i = 0; i < sendData16.Count; i++)
{
sendBuffer[i] = (byte)(Convert.ToInt32(sendData16[i], 16));//发送数据改为16进制
}
}
catch //无法转为16进制时,出现异常
{
//MessageBox.Show("请输入正确的16进制数据");
return;//输入的16进制数据错误,无法发送,提示后返回
}
try//尝试发送数据
{//如果发送字节数大于1000,则每1000字节发送一次
int sendTimes = (sendBuffer.Length / 1000);//发送次数
for (int i = 0; i < sendTimes; i++)//每次发生1000Bytes
{
ComPort.Write(sendBuffer, i * 1000, 1000);//发送sendBuffer中从第i * 1000字节开始的1000Bytes
//sendCount.Text = (Convert.ToInt32(sendCount.Text) + 1000).ToString();//刷新发送字节数
}
if (sendBuffer.Length % 1000 != 0)
{
ComPort.Write(sendBuffer, sendTimes * 1000, sendBuffer.Length % 1000);//发送字节小于1000Bytes或上面发送剩余的数据
//sendCount.Text = (Convert.ToInt32(sendCount.Text) + sendBuffer.Length % 1000).ToString();//刷新发送字节数
}
}
catch//如果无法发送,产生异常
{
//MessageBox.Show("无法发送数据,原因未知!");
}
//sendScrol.ScrollToBottom();//发送数据区滚动到底部
}
public void ComReceive()//接收数据 数据在接收中断里面处理
{
bReceiveByte = new byte[40];//存储数据
if (ComPort == null) return;
if (!ComPort.IsOpen) return;
int bytesToRead = 0;//记录获取的数据长度
try
{
//通过read函数获取串口数据
bytesToRead = ComPort.Read(bReceiveByte, 0, bReceiveByte.Length);//接收数据缓存
sStrMsg = get16str(bReceiveByte);
ts2 = new TimeSpan(DateTime.Now.Ticks);
TimeSpan ts = ts2.Subtract(ts1).Duration(); //时间差的绝对值
String spanTime = ts.Milliseconds.ToString() + "毫秒"; //以X小时X分X秒的格式现实执行时间
if (ts.Milliseconds >= 35)
{
if (Log != null) Log("error spanTime:" + spanTime);
}
else
{
if (Log != null) Log(" spanTime:" + spanTime);
}
if (Log != null) Log("comport receive:" + sStrMsg);
}
catch (Exception ex)
{
}
}
public void ClearReceiveByte()
{
if (bReceiveByte == null) return;
for (int i = 0; i < bReceiveByte.Length; i++)
{
bReceiveByte[i] = 0;
}
}
private string get16str(byte[] recBuffer)
{
StringBuilder recBuffer16 = new StringBuilder();//定义16进制接收缓存
for (int i = 0; i < recBuffer.Length; i++)
{
recBuffer16.AppendFormat("{0:X2}" + " ", recBuffer[i]);//X2表示十六进制格式(大写),域宽2位,不足的左边填0。
}
return recBuffer16.ToString();
}
public int[] GetInputData()
{
int[] arrInput = new int[10] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
if (Convert.ToInt32(bReceiveByte[0]) != 136) return arrInput;
if (Convert.ToInt32(bReceiveByte[1]) != 153) return arrInput;
if (Convert.ToInt32(bReceiveByte[29]) != 221) return arrInput;
if (Convert.ToInt32(bReceiveByte[30]) != 238) return arrInput;
if (Convert.ToInt32(bReceiveByte[31]) != 255) return arrInput;
for (int i = 2; i < 12; i++)
{
arrInput[i - 2] = Convert.ToInt32(bReceiveByte[i]);
}
return arrInput;
}
public int[] GetInputData6()
{
int[] arrInput = new int[10] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
if (Convert.ToInt32(bReceiveByte[0]) != 136) return arrInput;
if (Convert.ToInt32(bReceiveByte[1]) != 153) return arrInput;
if (Convert.ToInt32(bReceiveByte[25]) != 221) return arrInput;
if (Convert.ToInt32(bReceiveByte[26]) != 238) return arrInput;
if (Convert.ToInt32(bReceiveByte[27]) != 255) return arrInput;
for (int i = 2; i < 8; i++)
{
arrInput[i - 2] = Convert.ToInt32(bReceiveByte[i]);
}
arrInput[6] = Convert.ToInt32(bReceiveByte[14]);
arrInput[7] = Convert.ToInt32(bReceiveByte[15]);
arrInput[8] = Convert.ToInt32(bReceiveByte[16]);
return arrInput;
}
public int GetDianweiNum()//big
{
int iNum = -1;
if (Convert.ToInt32(bReceiveByte[0]) != 136) return iNum;
if (Convert.ToInt32(bReceiveByte[1]) != 153) return iNum;
if (Convert.ToInt32(bReceiveByte[29]) != 221) return iNum;
if (Convert.ToInt32(bReceiveByte[30]) != 238) return iNum;
if (Convert.ToInt32(bReceiveByte[31]) != 255) return iNum;
string sStr16 = Convert.ToInt32(bReceiveByte[21]).ToString("X2") + Convert.ToInt32(bReceiveByte[22]).ToString("X2");
iNum = Convert.ToInt32(sStr16, 16);
return iNum;
}
public string Fill(string pStrSource)
{
switch (pStrSource.Length)
{
case 1: return "0000000" + pStrSource;
case 2: return "000000" + pStrSource;
case 3: return "00000" + pStrSource;
case 4: return "0000" + pStrSource;
case 5: return "000" + pStrSource;
case 6: return "00" + pStrSource;
case 7: return "0" + pStrSource;
default: return pStrSource;
}
}
#region MyRegion
/// <summary>
/// 从COM1-10轮询硬件,根据结果确定当前硬件是COM几
/// </summary>
public void ThreadProc()
{
int iLinkNum = 1; // 从COM1开始轮询
bool bOpen = false;
while (true)
{
Console.WriteLine("COM" + iLinkNum.ToString());
bOpen = OpenPort("COM" + iLinkNum.ToString());
iLinkNum++;
if (iLinkNum > 10)
{
iCOMNum = 10;
break;
}
if (!bOpen) continue;
Console.WriteLine("bOpen===open");
Thread.Sleep(200);
ComSend("");// FIXME 此处需要一个硬件能够接受的数据字符串
Thread.Sleep(400);
ClearReceiveByte();
ComReceive();
Console.WriteLine("bOpen===ComReceiveComReceiveComReceive");
if (Convert.ToInt32(bReceiveByte[0]) == 136 && Convert.ToInt32(bReceiveByte[1]) == 153)//理论上没有FC的
{
iCOMNum = iLinkNum - 1;
bComOk = true;
Console.WriteLine("--------------理论上没有FC的----------------");
Console.WriteLine(bOpen);
break;
}
else
{
ComPort.Close();
ClearReceiveByte();
continue;
}
}
}
#endregion
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment