Last active
September 12, 2017 13:00
-
-
Save klkucan/39b6b241b0f8082c388e8de9bac943be to your computer and use it in GitHub Desktop.
Unity use ComPort
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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