Winfrom实现串口通信工具
一、简介
要想实现该功能,需要对C#有一些基本的了解
二、实现步骤
2.1 实例化一个SerialPort 对象
SerialPort ComPort = new SerialPort();
2.2设置串口参数
ComPort.PortName = “COM3”;//串口号 ComPort.BaudRate = 9600;//波特率 ComPort.Parity = Parity.Even;//校验位 ComPort.DataBits = 8;//数据位长度 ComPort.StopBits = StopBits.One;//停止位
2.3打开串口
public void Open() { ComPort.Open(); ComPort.DataReceived += new SerialDataReceivedEventHandler(m_Serial_DataReceived); } public void m_Serial_DataReceived(object sender, SerialDataReceivedEventArgs e) { Thread.Sleep(100); try { byte[] byteRead = new byte[ComPort.BytesToRead]; ComPort.Read(byteRead, 0, byteRead.Length); } catch (System.Exception ex) { MessageBox.Show(ex.ToString()); } }
打开串口时,订阅DataReceived事件,当串口接收到数据时,就会调用方法 m_Serial_DataReceived(object sender, SerialDataReceivedEventArgs e),使用 SerialPort.Read(byte[] buffer, int offset, int count)将数据从缓存区中取出来;
2.4 发送数据 使用SerialPort.Write(string text)发送数据
public bool SendDate(string str) { try { if (ComPort.IsOpen) { ComPort.Write(str); } else { return false; } return true; } catch (Exception ex) { return false; } }
2.5 关闭串口 使用SerialPort.Close(),并且取消事件订阅
public void Close() { ComPort.Close(); ComPort.DataReceived -= new SerialDataReceivedEventHandler(m_Serial_DataReceived); }
三、使用Winfrom实现
3.1 界面实现
3.2 后台代码实现
3.2.1 新建类UsualCom,将SerialPort实习的收发等功能放在该类里实现
public class UsualCom { public SerialPort ComPort; static ReaderWriterLockSlim LogWriteLock = new ReaderWriterLockSlim(); public UI m_ui = null; public UsualCom(UI ui) { ComPort = new SerialPort(); ComPort.WriteBufferSize = 1024; m_ui = ui; } public bool IsOpen { get { return ComPort.IsOpen; } } public string PortName { get { return ComPort.PortName; } set { ComPort.PortName = value; } } public int BaudRate { get { return ComPort.BaudRate; } set { ComPort.BaudRate = value; } } public Parity Parity { get { return ComPort.Parity; } set { ComPort.Parity = value; } } public int DataBits { get { return ComPort.DataBits; } set { ComPort.DataBits = value; } } public int ReadTimeout { get { return ComPort.ReadTimeout; } set { ComPort.ReadTimeout = value; } } public int WriteTimeout { get { return ComPort.WriteTimeout; } set { ComPort.WriteTimeout = value; } } public StopBits StopBits { get { return ComPort.StopBits; } set { ComPort.StopBits = value; } } /// <summary> /// 串口发送 /// </summary> public bool SendDate(byte[] Buff, int nplace) { try { if (ComPort.IsOpen) { ComPort.Write(Buff, 0, nplace); } else { return false;// Open(); } return true; } catch (Exception ex) { return false; } } public bool SendDate(string str) { try { if (ComPort.IsOpen) { ComPort.Write(str); } else { return false; } return true; } catch (Exception ex) { return false; } } public void Open() { ComPort.Open(); ComPort.DataReceived += new SerialDataReceivedEventHandler(m_Serial_DataReceived); } public void Close() { ComPort.Close(); ComPort.DataReceived -= new SerialDataReceivedEventHandler(m_Serial_DataReceived); } /// <summary> /// 初始化打开串口 /// </summary> public bool InitOpenPort() { if (IsOpen) { Close(); } try { Open(); } catch (Exception e) { Close(); return false; } return true; } /// <summary> /// 关闭串口 /// </summary> public bool CloseOpenPort() { try { if (IsOpen) { Close(); } } catch (Exception e) { return false; } return true; } /// <summary> /// 串口接收 /// </summary> public void m_Serial_DataReceived(object sender, SerialDataReceivedEventArgs e) { Thread.Sleep(100); try { byte[] byteRead = new byte[ComPort.BytesToRead]; ComPort.Read(byteRead, 0, byteRead.Length); string msg = ""; msg = System.Text.Encoding.ASCII.GetString(byteRead); msg = ByteArray2String(byteRead) + "\r\n"; putlog(msg); } catch (System.Exception ex) { MessageBox.Show(ex.ToString()); } } /// <summary> /// 实现界面信息打印 /// </summary> /// <param name="msg"></param> public void putlog(string msg) { string s = ""; s = DateTime.Now.ToString("[yyyy-MM-dd HH:mm:ss fff]") + " " + msg + s + "\r\n"; m_ui.ShowMsgToFormMain(s); WriteLog(s); } /// <summary> /// 日志打印 /// </summary> /// <param name="logstr"></param> private static void WriteLog(string logstr) { try { LogWriteLock.EnterReadLock(); string sFilePath = Directory.GetCurrentDirectory() + "\\log\\" + DateTime.Now.ToString("yyyyMM"); string sFileName = DateTime.Now.ToString("yyyyMMdd") + ".log"; sFileName = sFilePath + "\\" + sFileName; //文件的绝对路径 if (!Directory.Exists(sFilePath))//验证路径是否存在 { Directory.CreateDirectory(sFilePath); //不存在则创建 } FileStream fs; StreamWriter sw; if (File.Exists(sFileName)) { fs = new FileStream(sFileName, FileMode.Append, FileAccess.Write); } else { fs = new FileStream(sFileName, FileMode.Create, FileAccess.Write); } sw = new StreamWriter(fs); sw.Write(logstr); sw.Close(); fs.Close(); } catch { } } public string ByteArray2String(byte[] buff) { string s = ""; for (int i = 0; i < buff.Length; i++) { s += buff[i].ToString("X2") + " "; } return s; } public byte[] string2ByteL(string value) { string send = value.Replace(" ", ""); int length = send.Length / 2; byte[] rtu = new byte[length]; for (int i = 0; i < length; i++) { rtu[i] = Bin2BCD(send.Substring(i * 2, 2)); } return rtu; } public byte Bin2BCD(string binValue) { int Value = Convert.ToInt32(binValue, 16); return (byte)Value; } public string ByteArray2Ascii(byte[] value) { string s = ""; for (int i = 0; i < value.Length; i++) { s += Encoding.ASCII.GetString(value); } return s; } }
3.2.2 将需要通知到UI线程的委托事件也放置在UI类里面
public class UI { public delegate void ShowMsg(string msg); public event ShowMsg OnShowMsg; public void ShowMsgToFormMain(string msg) { OnShowMsg(msg); } }
3.2.3 窗体后台代码
public partial class MainForm : Form { public delegate void ShowData(string msg); private UI m_UI = null; private UsualCom gzComport = null; public MainForm() { InitializeComponent(); Initcontrol(); } private void Initcontrol() { string[] str = System.IO.Ports.SerialPort.GetPortNames(); foreach (string s in str) { cboxPort.Items.Add(s); } int[] Bps = { 9600, 57600, 115200, 256000, 512000, 921600, 1228800 }; List<int> listBps = new List<int>(Bps); foreach (int T in listBps) { cboxBandRate.Items.Add(T); } float[] Spb = { 1, 2 }; foreach (float B in Spb) { cboxStopBit.Items.Add(B); } string[] strParity = { "无校验", "奇校验", "偶校验" }; foreach (string st in strParity) { cboxParity.Items.Add(st); } cboxStopBit.SelectedIndex = Settings.Default.cboxStopBit; cboxBandRate.SelectedIndex = Settings.Default.cboxBandRate; cboxPort.SelectedIndex = Settings.Default.cboxPort; cboxParity.SelectedIndex = Settings.Default.cboxParity; rbtnHexModeS1.Checked = Settings.Default.rbtnHexModeS1; rbtnHexModeS2.Checked = Settings.Default.rbtnHexModeS2; rbtnHexModeS3.Checked = Settings.Default.rbtnHexModeS3; rbtnTextModeS1.Checked = Settings.Default.rbtnTextModeS1; rbtnTextModeS2.Checked = Settings.Default.rbtnTextModeS2; rbtnTextModeS3.Checked = Settings.Default.rbtnTextModeS3; rbtnHexModeR.Checked = Settings.Default.rbtnHexModeR; rbtnTextModeR.Checked = Settings.Default.rbtnTextModeR; m_UI = new UI(); gzComport = new UsualCom(m_UI); m_UI.OnShowMsg += ShowMsgInvoke; } /// <summary> /// 保存参数 /// </summary> public void Save() { Settings.Default.cboxPort = cboxPort.SelectedIndex; Settings.Default.cboxBandRate = cboxBandRate.SelectedIndex; Settings.Default.cboxParity = cboxParity.SelectedIndex; Settings.Default.cboxParity = cboxParity.SelectedIndex; Settings.Default.rbtnHexModeS1 = rbtnHexModeS1.Checked; Settings.Default.rbtnHexModeS2 = rbtnHexModeS2.Checked; Settings.Default.rbtnHexModeS3 = rbtnHexModeS3.Checked; Settings.Default.rbtnTextModeS1 = rbtnTextModeS1.Checked; Settings.Default.rbtnTextModeS2 = rbtnTextModeS2.Checked; Settings.Default.rbtnTextModeS3 = rbtnTextModeS3.Checked; Settings.Default.Save(); } private void btnOpen_Click(object sender, EventArgs e) { if (cboxPort.Items.Count <= 0) { MessageBox.Show("没有发现串口,请检查端口!"); return; } if (btnOpen.Text == "打开串口") { gzComport.PortName = cboxPort.SelectedItem.ToString(); gzComport.BaudRate = Convert.ToInt32(cboxBandRate.SelectedItem); gzComport.DataBits = 8; switch (cboxParity.SelectedIndex) { case 0: gzComport.Parity = Parity.None; break; case 1: gzComport.Parity = Parity.Odd; break; case 2: gzComport.Parity = Parity.Even; break; default: break; } switch (cboxStopBit.SelectedIndex) { case 0: gzComport.StopBits = StopBits.One; break; case 1: gzComport.StopBits = StopBits.Two; break; case 2: gzComport.StopBits = StopBits.OnePointFive; break; case 3: gzComport.StopBits = StopBits.Two; break; default: break; } gzComport.ReadTimeout = 1000; gzComport.WriteTimeout = 1000; if (gzComport.InitOpenPort()) { gzComport.putlog("打开串口成功"); } else { gzComport.putlog("打开串口失败"); } cboxPort.Enabled = false; cboxBandRate.Enabled = false; cboxStopBit.Enabled = false; cboxParity.Enabled = false; btnOpen.Text = "关闭串口"; } else if (btnOpen.Text == "关闭串口") { if (gzComport.CloseOpenPort()) { gzComport.putlog("串口关闭成功"); } cboxPort.Enabled = true; cboxBandRate.Enabled = true; cboxStopBit.Enabled = true; cboxParity.Enabled = true; btnOpen.Text = "打开串口"; } Save();//保存参数 } /// <summary> /// 数据发送 /// </summary> /// <param name="cmd"> 命令</param> /// <param name="check"> 模式</param> public void SendData(string cmd, bool mode) { if (cmd == "" || cmd == string.Empty) { return; } gzComport.putlog(cmd + "\r\n"); if (mode) { gzComport.SendDate(cmd); } else { gzComport.SendDate(gzComport.string2ByteL(cmd), gzComport.string2ByteL(cmd).Length); } } private void btnSend1_Click(object sender, EventArgs e) { string cmd = rtbDataSend1.Text.Trim(); SendData(cmd, rbtnTextModeS1.Checked); } private void btnSend2_Click(object sender, EventArgs e) { string cmd = rtbDataSend2.Text.Trim(); SendData(cmd, rbtnTextModeS2.Checked); } private void btnSend3_Click(object sender, EventArgs e) { string cmd = rtbDataSend3.Text.Trim(); SendData(cmd, rbtnTextModeS3.Checked); } public void ShowMsgInvoke(string msg) { if (this.rtbDataR.InvokeRequired) { ShowData show = new ShowData(ShowMsgInvoke); this.rtbDataR.Invoke(show, new object[] { msg }); } else { this.rtbDataR.AppendText(msg); this.rtbDataR.SelectionStart = rtbDataR.Text.Length; this.rtbDataR.SelectionLength = 0; this.rtbDataR.ScrollToCaret(); } } private void btnClear1_Click(object sender, EventArgs e) { rtbDataSend1.Clear(); } private void btnClear2_Click(object sender, EventArgs e) { rtbDataSend2.Clear(); } private void btnClear3_Click(object sender, EventArgs e) { rtbDataSend3.Clear(); } private void btnRecClear_Click(object sender, EventArgs e) { rtbDataR.Clear(); } }
四、实现效果 (界面上的功能并非全部实现)