C# Unity 與COM口設(shè)備通信 Part2

  • Part1 中講了幾個比較棘手的問題,這部分給出一些解決思路,這種思路肯定不是最優(yōu)解,但至少解決了現(xiàn)有問題,而且成功避開了一些麻煩,如果各位看官又更好的思路,還希望留言討論
  1. 因為Unity中沒有 SerialDataReceivedEventHandler,所以我果斷選擇了用C#控制臺來接收和發(fā)送數(shù)據(jù),這樣更加方便,而且開多個線程也不會造成莫名其妙的無響應(yīng)。
  2. 至于怎么將數(shù)據(jù)傳給Unity?各位看官肯定有思路??!所以我選擇socket!各位看官又更好的思路歡迎討論……

Tip:SerialDataReceivedEventHandler 是一個委托,當(dāng)COM設(shè)備向控制臺發(fā)送數(shù)據(jù)時,該委托掛載的方法便會執(zhí)行

  • OK,接下來上代碼
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO.Ports;
using System.Net.Sockets;
using System.Net;
using System.Threading;

//向COM端發(fā)送數(shù)據(jù) DD,其實是byte的221
//COM端接收到正確的數(shù)據(jù)后,會向控制臺發(fā)送回數(shù)據(jù)
//數(shù)據(jù)格式類似于 255 255 171 0 34 136 42 12 171
//前兩位,即使255,255 無實際作用,表示數(shù)據(jù)開始
//中間兩位,表示實際數(shù)據(jù)部分,具體處理方法見 ProcessingData
//最后4位,CRC32驗證,驗證前面4位是否正確(該功能未完成)

namespace COM_Socket_Server
{
    class Program
    {
        //COM端口的各類設(shè)置
        //COM口
        private static SerialPort ComDevice = new SerialPort();
        //用于存儲8個BYTE
        static List<byte> AllDatas = new List<byte>();

        //公共參數(shù)部分
        //存儲COM設(shè)備返回并處理完成的角度值,用于傳遞給unity
        private static string toClientMessage = null;

        static void Main(string[] args)
        {
            //COM端口初始化
            COM_Init();

            //單獨開啟一個線程檢測COM狀態(tài)
            Thread COMThread = new Thread(SendMsgToCOM);
            COMThread.Start();
        }

        //COM初始化方法
        private static void COM_Init()
        {
            //定義串口初始化參數(shù)
            ComDevice.PortName = "COM3"; //COM口名稱
            ComDevice.BaudRate = 9600; //波特率

            //開打串口
            ComDevice.Open();

            //串口打開后掛載回調(diào)事件
            if (ComDevice.IsOpen)
            {
                ComDevice.DataReceived += new SerialDataReceivedEventHandler(ComDevice_DataReceived);
                Console.WriteLine("COM端口已經(jīng)打開");
            }
            else
            {
                Console.WriteLine("error");
            }
        }

        //循環(huán)向COM設(shè)備發(fā)送信息
        private static void SendMsgToCOM()
        {
            while (true)
            {
                //向COM設(shè)備發(fā)送221,其實是字符串“DD”
                //發(fā)送后COM設(shè)備會被觸發(fā)
                byte[] byt = new byte[1];
                byt[0] = 221;

                ComDevice.Write(byt,0,1);

                這里將Sleep的值設(shè)置的略長,為了能在第二次“DD”發(fā)送之前,分好幾次完全接收了COM設(shè)備發(fā)送的信息
                Thread.Sleep(500);
            }
        }

        //回調(diào)方法,在收到COM設(shè)備發(fā)送的消息后調(diào)用
        private static void ComDevice_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {
            //聲明一個 byte數(shù)組 用來存儲接收到的數(shù)據(jù)
            byte[] ReDatas = new byte[ComDevice.BytesToRead];

            //讀取數(shù)據(jù)
            ComDevice.Read(ReDatas, 0, ReDatas.Length);

            //由于COM設(shè)備的特性,8個byte并不是一次全部傳輸過來,而是分多次
            //所以將多次接收的結(jié)果先都存儲在一個list中
            foreach (var item in ReDatas)
            {
                AllDatas.Add(item);
            }

            //驗證list的長度
            //如果長度為8,則開始用后4位的CRC32驗證前面4位的正確性(缺少此步驟)
            if (AllDatas.Count == 8)
            {
                //Console.WriteLine("數(shù)據(jù)長度正確,長度為8");
                 
                ProcessingData(AllDatas[2], AllDatas[3]);

                //所又步驟完成后清空list,下次接收時所有又從0開始
                AllDatas.Clear();

                //此處還應(yīng)該用最后2位做CRC校驗
            }
            else
            {
                Console.WriteLine("數(shù)據(jù)長度出錯!");
                //此處并不能只單純的驗證list的長度,而應(yīng)該先驗證整個list的開頭是否位兩個255,然后再看實際數(shù)據(jù)位是否完整
                //AllDatas.Clear();
            }
        }

        //處理數(shù)據(jù)位
        private static void ProcessingData(byte b1, byte b2)
        {
            //將數(shù)據(jù)放入一個byte數(shù)組中,轉(zhuǎn)換成int16格式
            byte[] bb = new byte[2];
            bb[0] = b1;
            bb[1] = b2;

            Int16 i16 = BitConverter.ToInt16(bb, 0);

            //這里將轉(zhuǎn)換出來的數(shù)值進行一次運算才能變?yōu)樾枰慕嵌戎?            int i2 = Convert.ToInt32(i16);
            float angel = 360 * (i2 * 1.0f / 1023.0f);

            Console.WriteLine(angel.ToString());

            toClientMessage = angel.ToString();
            
        }
    }
}
以上就是COM通信的全部代碼了,其實看代碼并沒有多難,就大家手頭項目來說,不同的地方只是數(shù)據(jù)發(fā)送和接收到之后的處理部分,其他地方應(yīng)該差異不大
里面應(yīng)該還有很多需要改正的地方,這里只是初步實現(xiàn)了“運行起來沒問題”。
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

推薦閱讀更多精彩內(nèi)容