Three steps to teach you Unity serial communication


Since I just changed my job, the new job is about serial ports. I have done several projects in the past few days, and I haven't seen any clear articles on the Internet during this period.
So today I will talk to friends who need to know about serial ports or who are interested in serial ports but have no way to start . What is a serial port? , how to carry out serial communication? .

1. Introduction to serial port

Serial interface (serial port) usually refers to COM interface, which is an extended interface using serial communication. The serial port sends and receives bytes in bits. Although slower than byte-wise parallel communication, a serial port can send data on one wire while receiving data on the other. Especially suitable for long-distance communication.

View the serial port: Right-click My Computer-Management-Device Manager-Port
open serial port
to select a port, double-click to view properties.
View serial port properties
Here through the serial port properties, you can know the following data:
Baud rate: This is a parameter to measure the symbol transmission rate.
Data Bits: This is a measure of the actual data bits in the communication.
Stop bit: Used to indicate the last bit of a single packet.
Parity check: A simple error detection method in serial communication.
For two ports to communicate, these parameters must match.

3. The principle of serial port communication:

The serial interface is an important data communication interface in the embedded system, and its essential function is as a code converter between the CPU and the serial device. When sending data, the data is converted from the CPU through the serial port, and the byte data is converted into serial bits; when receiving data, the serial bits are converted into byte data.

4. Commonly used protocols:

RS-232: Standard serial port, the most commonly used serial communication interface adopts unbalanced transmission mode, so-called single-ended communication, which is designed for point-to-point communication.
RS-422: Support point-to-many two-way communication. Separate sending and receiving channels are used, so there is no need to control the data direction, and any necessary signal exchange between devices can be realized by software (XON/XOFF handshake) or hardware (a pair of separate twisted-pair wires).
RS-485: Developed on the basis of RS-422, RS-485 can use two-wire and four-wire methods. Two-wire system can realize real multi-point two-way communication. It can realize point-to-multiple communication, but it is better than RS-422, no matter the four-wire or two-wire connection mode, 32 more devices can be connected to the bus.
Serial port interface standard specification 9-pin serial port:
insert image description here
pin function:
1. Data carrier detection (DCD)
2. Serial port receiving data (RXD)
3. Serial port sending data (TXD)
4. Data terminal ready (DTR)
5. Signal ground ( GND)
6. Data Send Ready (DSR)
7. Request to Send Data (RTS)
8. Clear to Send (CTS)
9. Ring Indicator (RI)

I am now using the CH340 chip for transmission
CH340

2. Use C# and Unity for serial port programming

When programming the serial port, we need to send commands to the serial port, and then we analyze the commands returned by the serial port. Starting from .NET Framework 2.0, C# provides the SerialPort class for serial port control. Namespace: System.IO.Ports. For details, please refer to (MSDN technical documentation)
1. Commonly used fields:
PortName: Get or set the communication port
BaudRate: Get or set the serial baud rate
DataBits: Get or set the standard data bit length of each byte
Parity: Get or Set the parity check protocol
StopBits: Get or set the standard stop bits of each byte
2. Common methods:
Close: Close the port connection, set the IsOpen property to false, and release the internal Stream object
GetPortNames: Get the serial port of the current computer Name array
Open: Open a new serial port connection
Read: Read from the SerialPort input buffer
Write: Write data to the serial port output buffer
3. Common events:
DataReceived: Indicates that the data receiving event of the SerialPort object will be processed The method
DisPosed: the Dispose method occurs when the component is released by calling (inherited from Component)
4. The serialport control use process
flow is to set the communication port number, baud rate, data bit, stop bit and parity bit, and then open the port connection and send Data, receive data, and finally close the port connection steps.

3. Problems encountered in programming

1. If the API platform of Unity3D is not switched to .NET2.0, Unity will report an error when writing the SerialPort class.
Solution: Switch the API platform of Unity3D to .NET2.0, switching method: "Edit–>project Setting–>Player–>Other Setting –>Api Compatibility level”. Here, switch ".NET2.0 Subset" to ".NET2.0"
2. If the target platform of Unity is not switched to Windows platform, it will prompt that the namespace does not support SystemIO, and prompt you to switch tools.
Solution: Switch the target platform to Windows platform, otherwise other platforms will report errors.
3. The information sent by the serial port cannot be parsed normally.
Solution: convert the message sent by the serial port into a byte stream. (Character stream conversion)
4. Missing information received by the serial port
(1) Received string (string): port.ReadLine()
data may be received incorrectly, data may be lost, and data cannot be received
(2) Receive byte array (byte[ ]): port.Read()
receives data faults, and will receive complete data twice
(3) Receive a single byte (byte): port.ReadByte()
combines the received data
5. The first time to send data Sometimes, the end of the data is often lost (summarized with the well-known boss, and it will be at the bottom of the article @大少)
For example, send: 64 64 80 89 The first received may be 64 80 89 0
Solution:

			//40405059 暂停
            if (paramByte[0] == (byte)64 && paramByte[1] == (byte)64 && paramByte[2] == (byte)80 && paramByte[3] == (byte)89)
            {
    
    
					Debug.Log("AA");
            }
			else if (paramByte[0] == (byte)64 && paramByte[1] == (byte)80 && paramByte[2] == (byte)89)
            {
    
    
					Debug.Log("AA");
            }

Through the above code, this pit can be perfectly avoided, and it will be normal the second time.

4. Source code sharing

After copying and pasting the following code, create a new empty object and hang it in the script to use it with the serial port assistant.

using UnityEngine;
using System.Collections;
using System.IO.Ports;
using System;
using System.Collections.Generic;
using System.Threading;
using System.Text;

public class PortControl : MonoBehaviour
{
    
    
    #region 定义串口属性
    public GUIText gui;
    //public GUIText Test;
    //定义基本信息
    public string portName = "COM3";//串口名
    public int baudRate = 9600;//波特率
    public Parity parity = Parity.None;//效验位
    public int dataBits = 8;//数据位
    public StopBits stopBits = StopBits.One;//停止位
    SerialPort sp = null;
    Thread dataReceiveThread;
    //发送的消息
    string message = "";
    public List<byte> listReceive = new List<byte>();
    char[] strchar = new char[100];//接收的字符信息转换为字符数组信息
    string str;
    #endregion
    void Start()
    {
    
    
        OpenPort();
        dataReceiveThread = new Thread(new ThreadStart(DataReceiveFunction));
        dataReceiveThread.Start();
    }
    void Update()
    {
    
    

    }

    #region 创建串口,并打开串口
    public void OpenPort()
    {
    
    
        //创建串口
        sp = new SerialPort(portName, baudRate, parity, dataBits, stopBits);
        sp.ReadTimeout = 400;
        try
        {
    
    
            sp.Open();
        }
        catch (Exception ex)
        {
    
    
            Debug.Log(ex.Message);
        }
    }
    #endregion



    #region 程序退出时关闭串口
    void OnApplicationQuit()
    {
    
    
        ClosePort();
    }
    public void ClosePort()
    {
    
    
        try
        {
    
    
            sp.Close();
            dataReceiveThread.Abort();
        }
        catch (Exception ex)
        {
    
    
            Debug.Log(ex.Message);
        }
    }
    #endregion


    /// <summary>
    /// 打印接收的信息
    /// </summary>
    void PrintData()
    {
    
    
        for (int i = 0; i < listReceive.Count; i++)
        {
    
    
            strchar[i] = (char)(listReceive[i]);
            str = new string(strchar);
        }
        Debug.Log(str);
    }

    #region 接收数据
    void DataReceiveFunction()
    {
    
    
        #region 按单个字节发送处理信息,不能接收中文
        //while (sp != null && sp.IsOpen)
        //{
    
    
        //    Thread.Sleep(1);
        //    try
        //    {
    
    
        //        byte addr = Convert.ToByte(sp.ReadByte());
        //        sp.DiscardInBuffer();
        //        listReceive.Add(addr);
        //        PrintData();
        //    }
        //    catch
        //    {
    
    
        //        //listReceive.Clear();
        //    }
        //}
        #endregion


        #region 按字节数组发送处理信息,信息缺失
        byte[] buffer = new byte[1024];
        int bytes = 0;
        while (true)
        {
    
    
            if (sp != null && sp.IsOpen)
            {
    
    
                try
                {
    
    
                    bytes = sp.Read(buffer, 0, buffer.Length);//接收字节
                    if (bytes == 0)
                    {
    
    
                        continue;
                    }
                    else
                    {
    
    
                        string strbytes = Encoding.Default.GetString(buffer);
                        Debug.Log(strbytes);
                    }
                }
                catch (Exception ex)
                {
    
    
                    if (ex.GetType() != typeof(ThreadAbortException))
                    {
    
    
                    }
                }
            }
            Thread.Sleep(10);
        }
        #endregion
    }
    #endregion



    #region 发送数据
    public void WriteData(string dataStr)
    {
    
    
        if (sp.IsOpen)
        {
    
    
            sp.Write(dataStr);
        }
    }
    void OnGUI()
    {
    
    
        message = GUILayout.TextField(message);
        if (GUILayout.Button("Send Input"))
        {
    
    
            WriteData(message);
        }
        string test = "AA BB 01 12345 01AB 0@ab 发送";//测试字符串
        if (GUILayout.Button("Send Test"))
        {
    
    
            WriteData(test);
        }
    }
    #endregion
}

5. Other issues

The serial port of each computer is different. For example, if you plug it in from computer A, the device manager shows COM 2, and the COM2 is defined in your program, so that communication can be realized.
If you change computer B, but now the serial port of computer B is COM10, and your code is still COM2, there is no way to complete the communication.
Solution 1: Set the COM port by reading the TXT file.

public static string portName = "";//串口名称
void Start()
    {
    
    
        string path = Application.streamingAssetsPath + "/config.txt";
        string[] strs = File.ReadAllLines(path);
        if (strs.Length > 0) portName = strs[0];
        Debug.Log(strs.Length);
    }


com
Solution 2: Dynamically set the COM port by reading the computer registry.

public string getPortName = "";//串口名称
void Start()
	{
    
    
		List<string> protReg = GetPortFromReg();

		if (protReg.Count > 0)
		{
    
    
			getPortName = protReg[2];//0是默认第一接口.
		}
		else
		{
    
    
			Debug.Log("获取不到端口");
		}
		Debug.Log("当前COM口配置为:"+getPortName);
	}

In this way, the COM port can be dynamically obtained, but this method still has limitations. If you want to be accurate, you still need to use a solution (via TXT text configuration).

Well, this article is over here, if you have any good suggestions and questions, welcome to leave a message!

Thank you for your help @静静的小魔龙https://blog.csdn.net/q764424567

Guess you like

Origin blog.csdn.net/weixin_45375968/article/details/121760710