基於C#實現串口通訊:c#串口通訊類

工控機通常都帶有很多串口(10個),而且可以通過Moxa卡擴展串口. 但Moxa的串口和電腦自帶的串口還是有點區別 C#裡面沒區別, 但之前VB6的MSComm控件有時就會有不一樣的地方.

支持串口通訊的儀錶,通常通訊指令分2種,一種是文本格式的,另一種是16進制格式的.
文本格式的,比如說有些儀器,查版本號發 *IDN? 就會返迴文本格式的結果,例如 XXX 8905,502-H19-1449,V1.38.02.18A2

16進制通訊的,比如青智的電流表,查詢電流用的命令格式 01是儀錶地址, 03是讀取的命令.1000是寄存器開始地址,000A是讀取長度, C10D是CRC校驗碼(多數使用CRC,也有儀器使用和校驗的)C#工控上位機系列(2)- 串口通信/監控工具

青智

還有一種儀器是自帶MCU,就是一打開串口就自動上傳數據給上位機, 這種就不需要命令了.只需要定時讀取串口緩衝區的內容,按照報文的格式,分析出哪一段數據才是你需要的.

我常用的串口通訊工具有下面2個

在Github下載一個ComDBG的工具,這個是C#寫的,可以自己根據代碼擴展需要的功能,比如歷史發送記錄

C#工控上位機系列(2)- 串口通信/監控工具

另外可以用一個監控工具,串口監控精靈, 這個對於那些沒有代碼的exe(比如一些儀錶自帶有一些小軟件), 我們直接監控某個串口的收發信息.就知道對應的命令是什麼了.

C#工控上位機系列(2)- 串口通信/監控工具

我通常把串口通訊做成一個基類, 把打開/關閉串口,文本命令,16進制命令,CRC校驗,和校驗都寫到基類了,方便調用

C#工控上位機系列(2)- 串口通信/監控工具

下面是部分方法的代碼

public bool InitCom(int portNum,int BaudRate =9600)
        {
            //端口打開時無法設置“PortName”
            if (!sp.IsOpen)
                sp.PortName = "COM" + portNum.ToString();
            else
            {
                if (sp.PortName != "COM" + portNum.ToString())
                {
                    sp.Close();
                    sp.PortName = "COM" + portNum.ToString();
                }

            }
            sp.BaudRate = BaudRate;//波特率
            sp.Parity = Parity.None;//無奇偶校驗位
            sp.StopBits = StopBits.One;//兩個停止位
            sp.Handshake = Handshake.None;//控制協議
            sp.WriteTimeout = 1000; /*Write time out*/
            sp.ReceivedBytesThreshold = 1;//設置 DataReceived 事件發生前內部輸入緩衝區中的字節數
            return true;
        }
//把一串命令,默認是文本string命令, 也可能是十六進制的數(空格分開),發到串口
        protected bool SerialPortCmd(string command,ref string recvMsg, 
            int iDelay = 100, int RecvMsgLenParm= 2,bool IsCmdText =true)
        {

            DelaySec = iDelay;
            RecvMsgLen = RecvMsgLenParm; 

            if (!openCom())
                return false;
            try
            {
                byte[] bytes;
                if (IsCmdText)
                    bytes = Encoding.Default.GetBytes(command);
                else
                    bytes = HexStringToBytes(command);
                sp.Write(bytes, 0, bytes.Length);
            }
            catch (Exception ex)
            {
                Debug.Write(ex.ToString());
                return false;   //write failed
            }

            return DataReceived(IsCmdText, ref recvMsg);
               

        }
private bool DataReceived(bool IsResultText,ref string result)
        {
            //Thread Safety explain in MSDN:
            // Any public static (Shared in Visual Basic) members of this type are thread safe. 
            // Any instance members are not guaranteed to be thread safe.
            // So, we need to synchronize I/O

            lock (thisLock)
            {


                string RecvMsgBuffer;
                int len = sp.BytesToRead;
          
                if (len >= RecvMsgLen) //返回長度足夠了.
                {

                    Byte[] data = new Byte[len];
                    try
                    {
                        sp.Read(data, 0, len);

                    }
                    catch (Exception ex)
                    {
                        throw ex;
                    }
                    if (IsResultText)
                        RecvMsgBuffer = Encoding.Default.GetString(data);
                    else
                        RecvMsgBuffer = BytesToHexString(data);
  

                    result = RecvMsgBuffer;
                    return true;
                }
                else
                    return false;

            }

        }

原創文章,作者:投稿專員,如若轉載,請註明出處:https://www.506064.com/zh-hant/n/223438.html

(0)
打賞 微信掃一掃 微信掃一掃 支付寶掃一掃 支付寶掃一掃
投稿專員的頭像投稿專員
上一篇 2024-12-09 14:20
下一篇 2024-12-09 14:20

相關推薦

發表回復

登錄後才能評論