使用Unity开发应用的需要使用到串口通讯,便研究了两天的Unity串口通讯,使用C#编写SerialPort类实现串口编程。编程时遇到的问题和一些解决方法和思路进行的总结。
一、串口简介
串行接口(串口)通常指COM接口,是采用串行通信方式的扩展接口。串口按位(bit)发送和接收字节。尽管比按字节(byte)的并行通信慢,但是串口可以在使用一根线发送数据的同时用另一根线接收数据。特别适用于远距离通信。
1、查看串口:右键 我的电脑-管理-设备管理器-端口,选择一个端口,双击查看属性。
2、 串口属性:从上图中可以看到串口属性,串口通信最重要的属性参数是波特率、数据位、停止位和奇偶校验。对于两个进行通信的端口,这些参数必须匹配。
(1)波特率:这是一个衡量符号传输速率的参数。指的是信号被调制以后在单位时间内的变化,即单位时间内载波参数变化的次数,如每秒钟传送960个字符,而每个字符格式包含10位(1个起始位,1个停止位,8个数据位),这时的波特率为960Bd,比特率为10位*960个/秒=9600bps。
(2)数据位:这是衡量通信中实际数据位的参数。当计算机发送一个信息包,实际的数据往往不会是8位的,标准的值是6、7和8位。标准的ASCII码是0~127(7位),扩展的ASCII码是0~255(8位)。
(3)停止位:用于表示单个包的最后几位。典型的值为1,1.5和2位。由于数据是在传输线上定时的,并且每一个设备有其自己的时钟,很可能在通信中两台设备间出现了小小的不同步。因此停止位不仅仅是表示传输的结束,并且提供计算机校正时钟同步的机会。
(4)校验位:在串口通信中一种简单的检错方式。有四种检错方式:偶、奇、高和低。当然没有校验位也是可以的。
3、串口通信原理:
串行接口在嵌入式系统中是一种重要的数据通信接口,其本质功能是作为CPU和串行设备间的编码转换器。在发送数据时,数据从CPU经串行端口,字节数据转换为串行的位;在接收数据时,串行的位转换为字节数据。
4、常用的协议:
RS-232: 标准串口,最常用的一种串行通讯接口采取不平衡传输方式,即所谓单端通讯, 是为点对点通讯而设计的。
RS-422: 支持点对多的双向通信。采用单独的发送和接收通道,因此不必控制数据方向,各装置之间任何必须的信号交换均可以按软件方式(XON/XOFF握手)或硬件方式(一对单独的双绞线)实现。
RS-485: 从RS-422基础上发展而来的, RS-485可以采用二线与四线方式,二线制可实现真正的多点双向通信,而采用四线连接时,与RS-422一样只能实现点对多的通信,但它比RS-422有改进,无论四线还是二线连接方式总线上可多接到32个设备。
串口的接口标准规范9针串口:
针脚功能:
1、数据载波检测(DCD)
2、串口接收数据(RXD)
3、串口发出数据(TXD)
4、数据终端就绪(DTR)
5、信号地线(GND)
6、数据发送就绪(DSR)
7、发送数据请求(RTS)
8、清除发送(CTS)
9、铃声指示(RI)
二、使用C#和Unity进行串口编程
在对串口进行编程时候,我们要向串口发送指令,然后我们解析串口返回的指令。从.NET Framework 2.0开始,C#提供了SerialPort类用于实现串口控制。命名空间:System.IO.Ports。详细信息可以参看( MSDN技术文档)
1、 常用的字段:
PortName:获取或设置通信端口
BaudRate:获取或设置串行波特率
DataBits:获取或设置每个字节的标准数据位长度
Parity:获取或设置奇偶效验检查协议
StopBits:获取或设置每个字节的标准停止位数
2、 常用方法:
Close:关闭端口连接,将IsOpen属性设置false,并释放内部Stream对象
GetPortNames:获取当前计算机的串行端口名称数组
Open:打开一个新的串行端口连接
Read:从SerialPort输入缓冲区中读取
Write:将数据写入串行端口输出缓冲区
3、常用事件:
DataReceived:表示将处理SerialPort对象的数据接收事件的方法
DisPosed:通过调用释放组件时发生Dispose方法(继承自Component)
4、SerialPort 控件使用流程
流程是设置通信端口号及波特率、数据位、停止位和校验位,再打开端口连接、发送数据、接收数据,最后关闭端口连接步骤。
三、编程遇到的问题
1、没有将Unity3D的API平台切换成.NET2.0,这时Unity编写SerialPort类会报错。
解决方法:将Unity3D的API平台切换成.NET2.0,切换方法: “Edit–>project Setting–>Player–>Other Setting –>Api Compatibility level”。在这里将“.NET2.0 Subset”切换为“.NET2.0”
2、Unity的目标平台没有切换为Windows平台,会提示该命名空间不支持SystemIO,提示你切换工具。
解决方法:把目标平台切换为Windows平台,否则是其他平台会报错误。
3、串口发送的信息不能正常解析
解决方法:把串口发送的消息使用字节流进行转换。(字符流转换)
4、串口接收信息的缺失问题
1)接收字符串(string):port.ReadLine()
数据接收可能错误,数据丢失,数据接收不到
2)接收字节数组(byte[]):port.Read()
接收数据断层,会分两次接收完整数据
3)接收单个字节(byte):port.ReadByte()
将接收到的数据进行组合
登录后复制
1 using UnityEngine;
2 using System.Collections;
3 using System.IO.Ports;
4 using System;
5 using System.Collections.Generic;
6 using System.Threading;
7 using System.Text;
8
9 public class PortControl : MonoBehaviour
10 {
11 #region 定义串口属性
12 public GUIText gui;
13 //public GUIText Test;
14 //定义基本信息
15 public string portName = "COM3";//串口名
16 public int baudRate = 9600;//波特率
17 public Parity parity = Parity.None;//效验位
18 public int dataBits = 8;//数据位
19 public StopBits stopBits = StopBits.One;//停止位
20 SerialPort sp = null;
21 Thread dataReceiveThread;
22 //发送的消息
23 string message = "";
24 public List<byte> listReceive = new List<byte>();
25 char[] strchar = new char[100];//接收的字符信息转换为字符数组信息
26 string str;
27 #endregion
28 void Start()
29 {
30 OpenPort();
31 dataReceiveThread = new Thread(new ThreadStart(DataReceiveFunction));
32 dataReceiveThread.Start();
33 }
34 void Update()
35 {
36
37 }
38
39 #region 创建串口,并打开串口
40 public void OpenPort()
41 {
42 //创建串口
43 sp = new SerialPort(portName, baudRate, parity, dataBits, stopBits);
44 sp.ReadTimeout = 400;
45 try
46 {
47 sp.Open();
48 }
49 catch (Exception ex)
50 {
51 Debug.Log(ex.Message);
52 }
53 }
54 #endregion
55
56
57
58 #region 程序退出时关闭串口
59 void OnApplicationQuit()
60 {
61 ClosePort();
62 }
63 public void ClosePort()
64 {
65 try
66 {
67 sp.Close();
68 dataReceiveThread.Abort();
69 }
70 catch (Exception ex)
71 {
72 Debug.Log(ex.Message);
73 }
74 }
75 #endregion
76
77
78 /// <summary>
79 /// 打印接收的信息
80 /// </summary>
81 void PrintData()
82 {
83 for (int i = 0; i < listReceive.Count; i++)
84 {
85 strchar[i] = (char)(listReceive[i]);
86 str = new string(strchar);
87 }
88 Debug.Log(str);
89 }
90
91 #region 接收数据
92 void DataReceiveFunction()
93 {
94 #region 按单个字节发送处理信息,不能接收中文
95 //while (sp != null && sp.IsOpen)
96 //{
97 // Thread.Sleep(1);
98 // try
99 // {
100 // byte addr = Convert.ToByte(sp.ReadByte());
101 // sp.DiscardInBuffer();
102 // listReceive.Add(addr);
103 // PrintData();
104 // }
105 // catch
106 // {
107 // //listReceive.Clear();
108 // }
109 //}
110 #endregion
111
112
113 #region 按字节数组发送处理信息,信息缺失
114 byte[] buffer = new byte[1024];
115 int bytes = 0;
116 while (true)
117 {
118 if (sp != null && sp.IsOpen)
119 {
120 try
121 {
122 bytes = sp.Read(buffer, 0, buffer.Length);//接收字节
123 if (bytes == 0)
124 {
125 continue;
126 }
127 else
128 {
129 string strbytes = Encoding.Default.GetString(buffer);
130 Debug.Log(strbytes);
131 }
132 }
133 catch (Exception ex)
134 {
135 if (ex.GetType() != typeof(ThreadAbortException))
136 {
137 }
138 }
139 }
140 Thread.Sleep(10);
141 }
142 #endregion
143 }
144 #endregion
145
146
147
148 #region 发送数据
149 public void WriteData(string dataStr)
150 {
151 if (sp.IsOpen)
152 {
153 sp.Write(dataStr);
154 }
155 }
156 void OnGUI()
157 {
158 message = GUILayout.TextField(message);
159 if (GUILayout.Button("Send Input"))
160 {
161 WriteData(message);
162 }
163 string test = "AA BB 01 12345 01AB 0@ab 发送";//测试字符串
164 if (GUILayout.Button("Send Test"))
165 {
166 WriteData(test);
167 }
168 }
169 #endregion
170 }
免责声明:本文系网络转载或改编,未找到原创作者,版权归原作者所有。如涉及版权,请联系删