串口通信

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.IO.Ports;
using System.Text.RegularExpressions;
using System.Threading;

namespace Serial_T
{
    public partial class Form1 : Form
    {
        private SerialPort comm = new SerialPort();
        private StringBuilder builder = new StringBuilder();//避免在事件处理方法中反复的创建,定义到外面。  
        private long received_count = 0;//接收计数  
        private long send_count = 0;//发送计数
        private System.Timers.Timer timer = new System.Timers.Timer();

        public Form1()
        {
            InitializeComponent();
            Init();
            //添加事件注册  
            comm.DataReceived += comm_DataReceived; 
        }

        /// <summary>
        /// 打开/关闭当前串口
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void buttonOpenClose_Click(object sender, EventArgs e)
        {
            //根据当前串口对象,来判断操作  
            if (comm.IsOpen)
            {
                //打开时点击,则关闭串口  
                comm.Close();
            }
            else
            {
                OpenPort();
            }
            //设置按钮的状态  
            BthStatus();
        }

        /// <summary>
        /// 初始化系统
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnInit_Click(object sender, EventArgs e)
        {
            Init();
        }

        /// <summary>
        /// 应用端口配置
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnSetPort_Click(object sender, EventArgs e)
        {
            SetPort();
        }

        /// <summary>
        /// 发送消息
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void buttonSend_Click(object sender, EventArgs e)
        {
            string sendData = txSend.Text;

            // 循环发送
            if (cirSend.Checked)
            {
                int _interval = 0;
                if (int.TryParse(txInterval.Text.Trim(), out _interval))
                {
                    buttonSend.Invoke(new MethodInvoker(delegate
                    {
                        if (buttonSend.Text.Trim() == "发送")
                        {
                            buttonSend.Text = "停止";
                        }
                        else
                        {
                            buttonSend.Text = "发送";
                        }
                    }));

                    timer.Enabled = true;
                    timer.Interval = _interval;
                    timer.AutoReset = true;
                    timer.Elapsed += new System.Timers.ElapsedEventHandler((s, erg) => comm_DataSend(s, erg, sendData));
                    timer.Start();
                }
                else
                {
                    MessageBox.Show("请填入正确间隔时间!");
                }
            }
            else
            {
                comm_DataSend(sendData);
            }
        }

        /// <summary>
        /// 清空
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void clearData_Click(object sender, EventArgs e)
        {
            //复位接受和发送的字节数计数器并更新界面。   
            send_count = received_count = 0;
            NumReceive.Text = "接收量:0";
            NumSend.Text = "发送量:0";
            txReceive.Text = "";
            txSend.Text = "";
        }

        /// <summary>
        /// 接收文本换行状态改变
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void checkBoxNewlineGet_CheckedChanged(object sender, EventArgs e)
        {
            txReceive.WordWrap = checkBoxNewlineGet.Checked;
        }

        /// <summary>
        /// 十六进制发送状态改变
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void checkBoxHexSend_CheckedChanged(object sender, EventArgs e)
        {
            if (checkBoxHexSend.Checked)
            {
                checkBoxNewlineSend.Checked = false;
                checkBoxNewlineSend.Enabled = false;
            }
            else
            {
                checkBoxNewlineSend.Enabled = true;
            }
        }

        /// <summary>
        /// 初始化系统
        /// </summary>
        private void Init()
        {
            //关闭当前串口   
            if (comm.IsOpen)
            {
                comm.Close();
            }

            //初始化下拉串口名称列表框  
            string[] ports = SerialPort.GetPortNames();
            Array.Sort(ports);
            comboPortName.Items.Clear();
            comboPortName.Items.AddRange(ports);
            comboPortName.SelectedIndex = comboPortName.Items.Count > 0 ? 0 : -1;
            comboBaudrate.SelectedIndex = comboBaudrate.Items.IndexOf("9600");
            dataBits.SelectedIndex = dataBits.Items.IndexOf("8");
            StopBits.SelectedIndex = StopBits.Items.IndexOf("1");
            ParityBits.SelectedIndex = ParityBits.Items.IndexOf("None");

            //初始化SerialPort对象  
            comm.NewLine = "/r/n";
            comm.RtsEnable = true;//根据实际情况吧。  

            //复位接受和发送的字节数计数器并更新界面。
            checkBoxNewlineGet.Checked = false;
            hexReceive.Checked = false;
            cirSend.Checked = false;
            checkBoxHexSend.Checked = false;
            checkBoxNewlineSend.Checked = false;
            txReceive.Text = "";
            txSend.Text = "";
            send_count = received_count = 0;
            NumReceive.Text = "接收量:0";
            NumSend.Text = "发送量:0";
            BthStatus();
        }

        /// <summary>
        /// 串口数据接收事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void comm_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {
            int n = comm.BytesToRead;//先记录下来,避免某种原因,人为的原因,操作几次之间时间长,缓存不一致  
            byte[] buf = new byte[n];//声明一个临时数组存储当前来的串口数据  
            received_count += n;//增加接收计数  
            comm.Read(buf, 0, n);//读取缓冲数据  
            builder.Clear();//清除字符串构造器的内容
            //因为要访问ui资源,所以需要使用invoke方式同步ui。
            this.Invoke((EventHandler)(delegate
            {
                //判断是否是显示为16禁止  
                if (hexReceive.Checked)
                {
                    //依次的拼接出16进制字符串
                    foreach (byte b in buf)
                    {
                        builder.Append(b.ToString("X2") + " ");
                    }
                }
                else
                {
                    //直接按ASCII规则转换成字符串  
                    builder.Append(Encoding.ASCII.GetString(buf));
                }
                //追加的形式添加到文本框末端,并滚动到最后。  
                this.txReceive.AppendText(builder.ToString());
                //修改接收计数  
                NumReceive.Text = "接收量:" + received_count.ToString();
            }));
        }

        /// <summary>
        /// 串口发送数据
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void comm_DataSend(string str)
        {
            str =localName.Text.Trim() +  str;
            //定义一个变量,记录发送了几个字节  
            int n = 0;
            //16进制发送  
            if (checkBoxHexSend.Checked)
            {
                //我们不管规则了。如果写错了一些,我们允许的,只用正则得到有效的十六进制数  
                MatchCollection mc = Regex.Matches(str, @"[0-9a-fA-F]{2}");
                List<byte> buf = new List<byte>();//填充到这个临时列表中  
                //依次添加到列表中  
                foreach (Match m in mc)
                {
                    buf.Add(Convert.ToByte(m.ToString(), 16));
                }
                //转换列表为数组后发送  
                comm.Write(buf.ToArray(), 0, buf.Count);
                //记录发送的字节数
                n = buf.Count;
            }
            else//ascii编码直接发送  
            {
                //包含换行符  
                if (checkBoxNewlineSend.Checked)
                {
                    comm.WriteLine(str);
                    n = txSend.Text.Length + 2;
                }
                else//不包含换行符  
                {
                    comm.Write(str);
                    n = txSend.Text.Length;
                }
            }
            send_count += n;//累加发送字节数  
            NumSend.Text = "发送量:" + send_count.ToString();//更新界面
        }

        /// <summary>
        /// 串口发送数据(定时)
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void comm_DataSend(object sender, System.Timers.ElapsedEventArgs e, string str)
        {
            if (cirSend.Checked && comm.IsOpen && (buttonSend.Text == "停止"))
            {
                //定义一个变量,记录发送了几个字节  
                int n = 0;
                //16进制发送  
                if (checkBoxHexSend.Checked)
                {
                    //我们不管规则了。如果写错了一些,我们允许的,只用正则得到有效的十六进制数  
                    MatchCollection mc = Regex.Matches(str, @"[0-9a-fA-F]{2}");
                    List<byte> buf = new List<byte>();//填充到这个临时列表中  
                    //依次添加到列表中  
                    foreach (Match m in mc)
                    {
                        buf.Add(Convert.ToByte(m.ToString(), 16));
                    }
                    //转换列表为数组后发送  
                    comm.Write(buf.ToArray(), 0, buf.Count);
                    //记录发送的字节数
                    n = buf.Count;
                }
                else//ascii编码直接发送  
                {
                    //包含换行符  
                    if (checkBoxNewlineSend.Checked)
                    {
                        comm.WriteLine(str);
                        n = txSend.Text.Length + 2;
                    }
                    else//不包含换行符  
                    {
                        comm.Write(str);
                        n = txSend.Text.Length;
                    }
                }
                send_count += n;//累加发送字节数  
                NumSend.Invoke(new MethodInvoker(delegate { NumSend.Text = "发送量:" + send_count.ToString(); }));
                //NumSend.Text = "发送量:" + send_count.ToString();//更新界面
            }
            else
            {
                timer.Stop();
            }
            
        }

        /// <summary>
        /// 同步按钮状态
        /// </summary>
        private void BthStatus()
        {
            //设置按钮的状态  
            buttonOpenClose.Text = comm.IsOpen ? "关闭串口" : "启动串口";
            buttonSend.Enabled = comm.IsOpen;  
        }

        /// <summary>
        /// 打开串口
        /// </summary>
        /// <returns>返回BOOL型,True为成功,False为失败</returns>
        public void OpenPort()
        {
            if (!comm.IsOpen)
            {
                SetPort();
                try
                {
                    comm.Open();
                }
                catch (Exception ex)
                {
                    //捕获到异常信息,创建一个新的comm对象,之前的不能用了。  
                    comm = new SerialPort();
                    //添加事件注册  
                    comm.DataReceived += comm_DataReceived; 
                    //现实异常信息给客户。  
                    MessageBox.Show(ex.Message);
                }
            }
        }

        /// <summary>
        /// 应用串口配置
        /// </summary>
        /// <returns>返回BOOL型,True为成功,False为失败</returns>
        public void SetPort()
        {
            if (string.IsNullOrEmpty(comboPortName.Text.Trim()))
            {
                MessageBox.Show("串口号不能为空!");
            }
            else
            {
                //关闭当前串口   
                if (comm.IsOpen)
                {
                    comm.Close();
                }
                comm.PortName = comboPortName.Text;
                comm.BaudRate = int.Parse(comboBaudrate.Text);
                comm.DataBits = int.Parse(dataBits.Text);
                //comm.Parity = Parity.None;
                //comm.StopBits = new StopBits();
                BthStatus();
            }
        }

        private void cirSend_CheckedChanged(object sender, EventArgs e)
        {
            if (!cirSend.Checked && buttonSend.Text.Trim() == "停止")
            {
                buttonSend.Text = "发送";
            }
        }
    }
}

 

posted @ 2016-09-14 13:10  Ariter  阅读(228)  评论(0)    收藏  举报