天天看點

C# 通過Com端口和單片機通訊(232/485/USB)

首先呢,這個代碼我工作中也在用,而且一般公司代碼不能外發,隻不過呢,這個是在我入職之前就寫着玩的,應該無所謂咯。

1、首先呢,運作起來是這樣的,一直在收取單片機的資料

C# 通過Com端口和單片機通訊(232/485/USB)

2、對應單片機呢,是這樣發的(大學的時候買的STM32F1的卡,很久沒接觸單片機了),裡面的printf函數輸出,通過USB線傳回給電腦。

C# 通過Com端口和單片機通訊(232/485/USB)

3、對應C#裡面的幾個關鍵點

(1)使用Serialport對象,結合微軟官方執行個體程式使用:SerialPort serialPort = new SerialPort();

(2)讀取目前有哪些接線的端口号(還有設定通訊速度,校驗位什麼的):

// 查詢更新已有端口
IList<string> list = new List<string>();
// 讀取目前有哪些COM口
foreach (string s in SerialPort.GetPortNames())
{
    list.Add(s);
}
port_m.DataSource = list;
           

(3)接收到資料後的事件觸發

serialPort.DataReceived += new SerialDataReceivedEventHandler(DataReceivedHandler);
           

(4)事件觸發中,中英文都傳送,需要如下格式轉換:

通訊時,string轉換成byte,用于發送(包含中文)

Byte[] data = System.Text.Encoding.Default.GetBytes(textBox1.Text); 
serialPort.Write(data, 0, data.Length);
           

通訊時,byte轉換成string,用于接收(包含中文)

int dataLength = serialPort.BytesToRead; 
byte[] buffer = new byte[1024]; 
sp.Read(buffer, 0, dataLength); 
string indata = System.Text.Encoding.Default.GetString(buffer, 0, dataLength);
           

(5)事件觸發呢是這樣的

void DataReceivedHandler(
                        object sender,
                        SerialDataReceivedEventArgs e)
        {
            if (waitTimes == 0)
            {
                SerialPort sp = (SerialPort)sender;

                Thread.Sleep(10);           // 計算需要多長時間延時後再發送

                int dataLength = serialPort.BytesToRead;
                byte[] buffer = new byte[1024];
                sp.Read(buffer, 0, dataLength);
                string indata = System.Text.Encoding.Default.GetString(buffer, 0, dataLength);
                //indata += sp.ReadExisting();                           // 讀取緩沖區全部内容
                // String to store the response ASCII representation.
                //ASCIIEncoding ASCll = new ASCIIEncoding();
                //indata += ASCll.GetString(bt) + "\r\n";
                //indata += Convert.ToString(sp.BytesToRead) + "\r\n";
                haveRead = true;
                // 需要觸發更新界面
                this.BeginInvoke(new ReadDelegate(Read), new object[] { indata });
            }
        }
        private delegate void ReadDelegate(string str);
        private void Read(string str)
        {
            this.textBox2.Text += str; 
            this.textBox2.SelectionStart = this.textBox2.Text.Length;
            this.textBox2.ScrollToCaret();  // 滾動到目前選中位置
        }
           

4、好啦,差不多了,于是看下我整體代碼有些什麼

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

using System.Timers;                    // 用于系統定時重新整理
using System.IO.Ports;
using System.Threading;
using System.Runtime.CompilerServices;

namespace Com
{
    public partial class Form1 : Form
    {
        //系統定時器
        System.Timers.Timer timer;
        public static int waitTimes = 0;    // 端口發送後等待回收時間
        static bool haveRead = false;       // 已經讀取到資料
        static bool timerOut = false;       // 讀取等待逾時
        static SerialPort serialPort = new SerialPort();
        StringComparer stringComparer = StringComparer.OrdinalIgnoreCase;
        //Thread readThread = new Thread(Read);

        public Form1()
        {
            InitializeComponent();
            InitParameter();

            serialPort.ReadTimeout = 500;
            serialPort.WriteTimeout = 500;
        }

        private void send_Click(object sender, EventArgs e)
        {
            Byte[] data = System.Text.Encoding.Default.GetBytes(textBox1.Text);
            if (receive_mode.Text == "發送後延時") {
                if (serialPort.IsOpen)
                    serialPort.Write(data, 0, data.Length);
                Thread.Sleep(waitTimes);
                string indata;
                int dataLength = serialPort.BytesToRead;
                if (dataLength > 0)
                {
                    byte[] buffer = new byte[1024];
                    serialPort.Read(buffer, 0, dataLength);
                    indata = System.Text.Encoding.Default.GetString(buffer, 0, dataLength);
                }
                else
                    indata = "逾時未收到\r\n";

                // 需要觸發更新界面
                this.BeginInvoke(new ReadDelegate(Read), new object[] { indata });
            }
            else
            {
                if (serialPort.IsOpen)
                    serialPort.Write(data, 0, data.Length);

                TimerInit(250);
                while (!timerOut && !haveRead) ;
                if (timerOut == true) // 需要觸發更新界面
                    this.BeginInvoke(new ReadDelegate(Read), new object[] { "逾時未收到\r\n" });
                timerOut = false;
                haveRead = false;
                timer.Stop();
            }
        }

        void DataReceivedHandler(
                        object sender,
                        SerialDataReceivedEventArgs e)
        {
            if (waitTimes == 0)
            {
                SerialPort sp = (SerialPort)sender;

                Thread.Sleep(10);           // 計算需要多長時間延時後再發送

                int dataLength = serialPort.BytesToRead;
                byte[] buffer = new byte[1024];
                sp.Read(buffer, 0, dataLength);
                string indata = System.Text.Encoding.Default.GetString(buffer, 0, dataLength);
                //indata += sp.ReadExisting();                           // 讀取緩沖區全部内容
                // String to store the response ASCII representation.
                //ASCIIEncoding ASCll = new ASCIIEncoding();
                //indata += ASCll.GetString(bt) + "\r\n";
                //indata += Convert.ToString(sp.BytesToRead) + "\r\n";
                haveRead = true;
                // 需要觸發更新界面
                this.BeginInvoke(new ReadDelegate(Read), new object[] { indata });
            }
        }
        private delegate void ReadDelegate(string str);
        private void Read(string str)
        {
            this.textBox2.Text += str; 
            this.textBox2.SelectionStart = this.textBox2.Text.Length;
            this.textBox2.ScrollToCaret();  // 滾動到目前選中位置
        }
        
        private void port_m_SelectedIndexChanged(object sender, EventArgs e)
        {
            
        }

        private void receive_Click(object sender, EventArgs e)
        {
            if(!serialPort.IsOpen)
            {
                connect.Text = "關閉";
                try
                {
                    object myPort;
                    myPort = port_m.SelectedItem;
                    serialPort.PortName = Convert.ToString(myPort);

                    object mySpeed;
                    mySpeed = speed.SelectedItem;
                    serialPort.BaudRate = Convert.ToInt32(mySpeed);

                    object myParity;
                    myParity = odd_even.SelectedItem;
                    serialPort.Parity = (Parity)Enum.Parse(typeof(Parity), Convert.ToString(myParity), true);

                    serialPort.DataBits = 8;

                    object myStop;
                    myStop = receive_mode.SelectedItem;
                    serialPort.StopBits = (StopBits)Enum.Parse(typeof(StopBits), Convert.ToString(myStop), true);
                }
                catch (Exception ex) { }

                serialPort.Open();
                // 連接配接後開始執行讀取線程
                Task.Run(() => {
                    while (false)
                    {
                        if (haveRead)
                        {
                            TimerInit(100);
                            while (haveRead) ;
                        }
                    }
                });
            }
            else
            {
                connect.Text = "連接配接";
                serialPort.Close();
            }
        }
        void TimerInit(int time)
        {
            //高重新整理定時器初始化
            timer = new System.Timers.Timer();
            timer.Interval = time;              // 機關:毫秒
            timer.Elapsed += OnTimedEvent;
            timer.AutoReset = true;
            timer.Enabled = true;
            timer.Start();
            //timer.Stop();
        }
        /* 定時器Timer觸發事件
         */
        public void OnTimedEvent(object source, ElapsedEventArgs e)
        {
            timerOut = true;
        }


        private void InitParameter()
        {
            serialPort.DataReceived += new SerialDataReceivedEventHandler(DataReceivedHandler);

            //comboBox1.Items.Add(textBox1.Text);

            // 查詢更新已有端口
            IList<string> list = new List<string>();
            // 讀取目前有哪些COM口
            foreach (string s in SerialPort.GetPortNames())
            {
                list.Add(s);
            }
            port_m.DataSource = list;

            // 傳輸速度
            int[] speed_data = new int[] { 9600, 19200, 38400, 115200 };
            speed.DataSource = speed_data;

            // 奇偶校驗
            IList<string> list1 = new List<string>();
            list1.Clear();
            list1.Add("None");
            list1.Add("奇校驗");
            list1.Add("偶校驗");
            odd_even.DataSource = list1;

            // 停止位
            string[] stop = { "1", "2" };
            stop_num.DataSource = stop;

            //list.Clear();
            string[] str = { "事件", "發送後延時" };
            receive_mode.DataSource = str;             // StopBits

            // 觸發事件
            this.port_m.SelectedValueChanged += new System.EventHandler(this.port_m_SelectedIndexChanged);
        }
        // 接收方式發生改變時
        void receive_mode_changed(object ob, EventArgs e) 
        {
            if(receive_mode.Text == "發送後延時")
            {
                DelayTime delayTime = new DelayTime();
                delayTime.Show();
            }
            else
            {
                waitTimes = 0;
            }
        }
    }
}