天天看点

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;
            }
        }
    }
}