C#上位机之—WinForm实现串口通信示例

2021-03-19 17:27

阅读:734

标签:构造   sop   指正   iso   校验位   rgs   text   nop   thread   

上位机开发常用到串口通信来控制设备,串口通信的主要参数:COM口,波特率(9600),停止位(One),数据位(8),校验位(None),括号中的是常用值,具体意思我也不太懂,会用能实现功能就行哈哈;

开发工具:VS2012;   开发前需要添加以下服务引用:

.......
using System.IO.Ports;

窗体搭建,因为没有串口设备供调试 ,所以我用虚拟串口即两个串口互相连接来实现通信,窗体分为上下两部分,对应两个串口区,上图为虚拟串口设置,下图为Winform样式:

 技术图片                   技术图片

首先创建一个baseCom类:

1.声明变量,构造函数:

技术图片技术图片
        public delegate void delegateOnShowMsg(comType type,string msg);
        public delegate void delegateOnOpenCom(comType type, bool onOff);
        public event delegateOnShowMsg OnShow;
        public event delegateOnOpenCom OnOpen;
        comType type;
        string baudRate = string.Empty;
        string parity = string.Empty;
        string stopBits = string.Empty;
        string dataBits = string.Empty;
        string portName = string.Empty;
        public System.IO.Ports.SerialPort comPort = new System.IO.Ports.SerialPort();
        public baseCom(string portName, string baudRate, string stopBits, string dataBits, string parity,comType type)
        {
            this.portName = portName;
            this.baudRate = baudRate;
            this.stopBits = stopBits;
            this.dataBits = dataBits;
            this.parity = parity;
            this.type = type;
        }
View Code

2.打开串口和关闭串口函数:

技术图片技术图片
        public void OpenPort()
        {
            try
            {
                if (comPort.IsOpen)
                    comPort.Close();
                comPort.BaudRate = int.Parse(baudRate);
                comPort.StopBits = (StopBits)Enum.Parse(typeof(StopBits), stopBits);
                comPort.DataBits = int.Parse(dataBits);
                comPort.Parity = (Parity)Enum.Parse(typeof(Parity), parity);
                comPort.PortName = portName;
                comPort.Handshake = Handshake.None;
                comPort.Open();
                if (comPort.IsOpen)
                {
                    showOnoff(true);
                    comPort.Handshake = Handshake.None;
                    comPort.DataReceived += comPort_DataReceived;
                }
                showMsg(portName + " Open Success");
            }
            catch (Exception ex)
            {
                showMsg("Unable to Open " + portName);
                showMsg(ex.Message);
                showOnoff(false);
            }
        }
        public void ClosePort()
        {
            if (comPort.IsOpen)
            {
                comPort.Close();
                comPort.Dispose();
                showOnoff(false);
                showMsg(portName + " Close Success");
            }
        }
View Code

3.接受数据和发送数据函数:

技术图片技术图片
        public void comPort_DataReceived(object sender,SerialDataReceivedEventArgs e)
        {
            try
            {
                int n = comPort.BytesToRead;
                if (n == 0)
                    return;
                byte[] buffer = new byte[n];
                comPort.Read(buffer, 0, n);
                string rcv = Encoding.Default.GetString(buffer, 0, buffer.Length);
                showMsg("RECV:" + rcv);
            }
            catch (Exception ex)
            {
                ClosePort();
                showMsg("Com Closed:" + ex.Message);
            }
        }
        public void comPort_SendData(string msg)
        {
            if (msg == "")
            {
                showMsg("CAN Not EMPTY");
                return;
            }
            if (comPort == null)
            {
                showMsg("First Open Port");
                return;
            }
            if (!comPort.IsOpen)
            {
                showMsg("COM Not Open");
                return;
            }
            byte[] data = Encoding.Default.GetBytes(msg);
            comPort.Write(data, 0, data.Length);
            showMsg("SEND:" + msg);
        }
View Code

4.显示信息,显示状态函数:

技术图片技术图片
        public void showMsg(string msg)
        {
            if (OnShow != null)
                OnShow(type, msg);
        }
        public void showOnoff(bool flag)
        {
            if (OnOpen != null)
                OnOpen(type, flag);
        }
        public enum comType
        {
            _up,
            _down
        }
View Code

OK,baseCOM类已定义完成,现在编写窗体各控件的功能函数:

1.初始化控件,主要是下拉菜单的Item的添加,初始值,初始状态:

技术图片技术图片
        public string[] baudRates = { "2400", "4800", "9600", "19200", "39400", "43000", "56000" };
        public string[] paritys = { "None", "ODD", "Even" };
        public string[] dataBits = { "5", "6", "7", "8" };
        public string[] stopBits = { "None", "One", "Two", "OnePointFive" } ;
        public void InitControls()
        {
            comboBox_com.Items.Clear();
            comboBox_baudRate.Items.Clear();
            comboBox_dataBits.Items.Clear();
            comboBox_parity.Items.Clear();
            comboBox_StopBit.Items.Clear();
            comboBox_com2.Items.Clear();
            foreach (var v in baudRates)
                comboBox_baudRate.Items.Add(v);
            foreach (var v in stopBits)
                comboBox_StopBit.Items.Add(v);
            foreach (var v in paritys)
                comboBox_parity.Items.Add(v);
            foreach (var v in dataBits)
                comboBox_dataBits.Items.Add(v);
            foreach (var v in System.IO.Ports.SerialPort.GetPortNames())
            {
                comboBox_com.Items.Add(v);
                comboBox_com2.Items.Add(v);
            }
            comboBox_com.SelectedIndex = 0;
            comboBox_baudRate.SelectedIndex = 2;
            comboBox_dataBits.SelectedIndex = 3;
            comboBox_parity.SelectedIndex = 0;
            comboBox_StopBit.SelectedIndex = 1;
            comboBox_com2.SelectedIndex = 0;
        }
View Code

2.声明两个COM类,comUp和comDown:

public delegate void delegateOnOff(comType type,bool onoff);//定义两个委托
public delegate void delegateShow(comType type,string msg);//为了防止报错“从不是创建控件的线程控制它”
baseCom comUp;    // 定义上串口COM
baseCom comDown;   //定义下串口COM
Image imgOn, imgOff; //指示灯
Thread th;        //线程用来实现自动发送

3.编写打开(关闭)串口按钮点击事件(打开comUp和打开comDown代码一样,只贴出comUp):

技术图片技术图片
        private void button_OpenCom_Click(object sender, EventArgs e)
        {
            string cmd = ((Button)sender).Text.Split( )[0];
            if (comUp != null)
                comUp.ClosePort();
            if (cmd == "Close")
                return;
            string s1 = comboBox_com.SelectedItem.ToString();
            string s2 = comboBox_baudRate.SelectedItem.ToString();
            string s3 = comboBox_StopBit.SelectedItem.ToString();
            string s4 = comboBox_dataBits.SelectedItem.ToString();
            string s5 = comboBox_parity.SelectedItem.ToString();
            comUp = new baseCom(s1, s2, s3, s4, s5,comType._up);
            comUp.OnOpen += SignalState;
            comUp.OnShow += ShowMsg;
            comUp.OpenPort();
        }
View Code

4.编写发送数据按钮点击事件:

private void button_Send_Click(object sender, EventArgs e)
{
     if (comUp != null)
       comUp.comPort_SendData(textBox_ComSend.Text);
}

5.编写数据接受发送显示到文本框及状态指示灯变化函数:

技术图片技术图片
        public void SignalState(comType type,bool onoff)
        {
            if (this.InvokeRequired)
            {
                delegateOnOff d = new delegateOnOff(SignalState);
                this.Invoke(d,new object[]{type,onoff});
            }
            else
            {
                if (type == comType._up)
                {
                    pictureBox_ComSignal.Image = onoff ? imgOn : imgOff;
                    button_OpenCom.Text = onoff ? "Close COM" : "Open COM";
                }
                else
                {
                    pictureBox_Com2.Image = onoff ? imgOn : imgOff;
                    button_OpenCom2.Text = onoff ? "Close COM" : "Open COM";
                }
            }
        }
        public void ShowMsg(comType type, string msg)
        {
            if (this.InvokeRequired)
            {
                delegateShow d = new delegateShow(ShowMsg);
                this.Invoke(d, new object[] { type, msg });
            }
            else
            {
                string date = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:fff") + "\r\n";
                if (type == comType._up)
                {
                    textBox_serialPort.Text += (date + msg + "\r\n");
                }
                else
                {
                    textBox_serialPort2.Text += (date + msg + "\r\n");
                }
            }
        }
View Code

6.Monitor函数,即线程函数,用来实现数据自动发送(没有进行准确定时,大概设了个间隔):

技术图片技术图片
        public void Monitor()
        {
            double i =0;
            while (i++10000000000)
            {
                if (i == 1000000000)
                {
                    i = 0;
                    if (checkBox_AutoSend.Checked)
                    {
                        if (comUp != null)
                            comUp.comPort_SendData(textBox_ComSend.Text);
                    }
                    if (checkBox_AutoSend2.Checked)
                    {
                        if (comDown != null)
                            comDown.comPort_SendData(textBox_comSend2.Text);
                    }
                }
            }
        }
View Code

至此,串口通信功能已基本实现,可在此框架上进行实际应用开发,编码新手,欢迎大家批评指正!看下效果图(COM1和COM11虚拟连接):

技术图片

C#上位机之—WinForm实现串口通信示例

标签:构造   sop   指正   iso   校验位   rgs   text   nop   thread   

原文地址:https://www.cnblogs.com/cfsl/p/12327095.html


评论


亲,登录后才可以留言!