使用C#,开发环境VS2012,功能是串口调试助手。功能很简单,仅供大家学习。如果对其中的控件不熟悉的,可以在本人博客或专栏中查看相应控件的介绍。
代码下载链接:https://download.csdn.net/download/c_gyl/10878545。
命名 | 功能 |
---|---|
cbxSerial | 串口号 |
cbxBuadRate | 波特率 |
cbxDataBits | 数据位 |
cbxStop | 停止位 |
cbxParity | 校验位 |
btnOpen | 打开或关闭 |
btnSend | 发送数据 |
tbxRec | 接收显示 |
tbxSend | 发送显示 |
添加控件。设置对应的属性。
在窗体的Load事件中,初始化窗体。
private void Form1_Load(object sender, EventArgs e)
{
//串口
string[] str = SerialPort.GetPortNames();
foreach (string port in str)
{
cbxSerial.Items.Add(port);
}
cbxSerial.SelectedIndex = 0;
//波特率
cbxBuadRate.Items.Add("300");
cbxBuadRate.Items.Add("1200");
cbxBuadRate.Items.Add("2400");
cbxBuadRate.Items.Add("4800");
cbxBuadRate.Items.Add("9600");
cbxBuadRate.Items.Add("19200");
cbxBuadRate.Items.Add("38400");
cbxBuadRate.Items.Add("43000");
cbxBuadRate.Items.Add("56000");
cbxBuadRate.Items.Add("115200");
cbxBuadRate.SelectedIndex = 4;
//数据位
cbxDataBits.Items.Add("5");
cbxDataBits.Items.Add("6");
cbxDataBits.Items.Add("7");
cbxDataBits.Items.Add("8");
cbxDataBits.SelectedIndex = 3;
//停止位
cbxStop.Items.Add("0");
cbxStop.Items.Add("1");
cbxStop.Items.Add("1.5");
cbxStop.Items.Add("2");
cbxStop.SelectedIndex = 1;
//校验位
cbxParity.Items.Add("无");
cbxParity.Items.Add("奇校验");
cbxParity.Items.Add("偶校验");
cbxParity.SelectedIndex = 0;
//格式
rbnRecASCII.Checked = true;
rbnSendASCII.Checked = true;
//发送按钮
btnSend.Enabled = false;
}
按钮的Click事件中,设置串口。
private void btnOpen_Click(object sender, EventArgs e)
{
try
{
if (!serialPort1.IsOpen)
{
serialPort1.PortName = cbxSerial.SelectedItem.ToString();
serialPort1.BaudRate = Convert.ToInt32(cbxBuadRate.SelectedItem.ToString());
serialPort1.DataBits = Convert.ToInt32(cbxDataBits.SelectedItem.ToString());
serialPort1.StopBits = (StopBits)Convert.ToInt32(cbxStop.SelectedItem.ToString());
serialPort1.Parity = (Parity)Convert.ToInt32(cbxParity.SelectedIndex);
serialPort1.ReadTimeout = 1000;
serialPort1.WriteTimeout = 1000;
serialPort1.DataReceived += new SerialDataReceivedEventHandler(serialPort1_DataReceived);
serialPort1.Open();
if (serialPort1.IsOpen)
{
btnSend.Enabled = true;
}
btnOpen.Text = "关闭";
}
else
{
serialPort1.DataReceived -= new SerialDataReceivedEventHandler(serialPort1_DataReceived);
serialPort1.Close();
btnSend.Enabled = false;
btnOpen.Text = "打开";
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "操作串口错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}
}
通过右键菜单,关联接收编辑框。
private void 清除ToolStripMenuItem_Click(object sender, EventArgs e)
{
tbxRec.Clear();
}
通过发送按钮的Click事件。
private void btnSend_Click(object sender, EventArgs e)
{
byte[] sendData = null;
string strData = null;
strData = tbxSend.Text.Trim();
if (rbnSendHEX.Checked)
{
sendData = strToHexByte(strData);
}
else if (rbnSendASCII.Checked)
{
sendData = Encoding.ASCII.GetBytes(strData);
}
if (Send(sendData))
{
tsslSendCount.Text = (int.Parse(tsslSendCount.Text) + tbxSend.Text.Length).ToString();
}
}
接收和发送格式,通过CheckedChanged事件,判断格式。
private void rbSendASCII_CheckedChanged(object sender, EventArgs e)
{
if (rbnSendASCII.Checked)
{
byte[] data = null;
if (tbxSend.Text == "")
{
return;
}
data = HexStringToByte(tbxSend.Text.Trim());
tbxSend.Text = new ASCIIEncoding().GetString(data);
}
}
private void rbSendHEX_CheckedChanged(object sender, EventArgs e)
{
if (rbnSendHEX.Checked)
{
byte[] data = null;
data = System.Text.Encoding.Default.GetBytes(tbxSend.Text.Trim());
StringBuilder sb = new StringBuilder();
for (int i = 0; i < data.Length; i++)
{
sb.AppendFormat("{0:x2}" + " ", data[i]);
}
tbxSend.Text = sb.ToString().ToUpper();
}
}
private void rbRecASCII_CheckedChanged(object sender, EventArgs e)
{
if (rbnRecASCII.Checked)
{
byte[] data = null;
if (string.IsNullOrEmpty(tbxRec.Text))
{
return;
}
data = HexStringToByte(tbxRec.Text.Trim());
tbxRec.Text = new ASCIIEncoding().GetString(data);
}
}
private void rbRecHEX_CheckedChanged(object sender, EventArgs e)
{
if (rbnRecHEX.Checked)
{
byte[] data = null;
data = System.Text.Encoding.Default.GetBytes(tbxRec.Text.Trim());
StringBuilder sb = new StringBuilder();
for (int i = 0; i < data.Length; i++)
{
sb.AppendFormat("{0:x2}" + " ", data[i]);
}
tbxRec.Text = sb.ToString().ToUpper();
}
}
private byte[] HexStringToByte(string hexstring)
{
string[] tmpary = hexstring.Trim().Split(' ');
byte[] buff = new byte[tmpary.Length];
for (int i = 0; i < buff.Length; i++)
{
buff[i] = Convert.ToByte(tmpary[i], 16);
}
return buff;
}
private byte[] strToHexByte(string hexString)
{
hexString = hexString.Replace(" ", "");
if ((hexString.Length % 2) != 0)
hexString += " ";
byte[] returnBytes = new byte[hexString.Length / 2];
try
{
for (int i = 0; i < returnBytes.Length; i++)
returnBytes[i] = Convert.ToByte(hexString.Substring(i * 2, 2), 16);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "转换成HEX错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
return returnBytes;
}
private bool Send(byte[] data)
{
if (serialPort1.IsOpen)
{
try
{
serialPort1.Write(data, 0, data.Length);
Thread.Sleep(10);
serialPort1.WriteLine("\r\n");
return true;
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "发送数据错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
else
{
MessageBox.Show("未打开串口", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
return false;
}
添加serialPort1的DataReceived事件
private void serialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
byte[] ReDatas = new byte[serialPort1.BytesToRead];
serialPort1.Read(ReDatas, 0, ReDatas.Length);
this.AddData(ReDatas);
}
public void AddData(byte[] data)
{
if (rbRecHEX.Checked)
{
StringBuilder sb = new StringBuilder();
for (int i = 0; i < data.Length; i ++ )
{
sb.AppendFormat("{0:x2}" + " ", data[i]);
}
AddContent(sb.ToString().ToUpper());
}
else if (rbRecASCII.Checked)
{
AddContent(new ASCIIEncoding().GetString(data));
}
statusStrip1.Invoke(new MethodInvoker(delegate
{
if (tsslRecCount.Text == "0")
{
tsslRecCount.Text = tbRec.Text.Length.ToString();
}
else
{
try
{
tsslRecCount.Text = (int.Parse(tsslRecCount.Text) + data.Length).ToString();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "接收字节计数错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
}));
}
private void AddContent(string content)
{
this.BeginInvoke(new MethodInvoker(delegate
{
tbRec.AppendText(content);
}));
}
statusStrip1.Invoke(new MethodInvoker(delegate
{
if (tsslRecCount.Text == "0")
{
tsslRecCount.Text = tbxRec.Text.Length.ToString();
}
else
{
try
{
tsslRecCount.Text = (int.Parse(tsslRecCount.Text) + data.Length).ToString();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "接收字节计数错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
}));
在Winform中不能直接跨线程操作控件,一般通过Invoke,在拥有此控件的基础窗口句柄的线程上执行委托。
从 SerialPort 对象接收数据时,将在辅助线程上引发 DataReceived 事件。 由于此事件在辅助线程而非主线程上引发,因此尝试修改主线程中的一些元素(如 UI 元素)时会引发线程异常。 如果有必要修改主 Form 或 Control 中的元素,请使用 Invoke 回发更改请求,这将在正确的线程上执行。
BeginInvoke与Invoke一个是同步执行,一个是异步执行。简单的可以理解为,当使用Invoke时,当前线程(非UI线程)会阻塞然后UI线程执行Invoke里传入的方法,之后再继续执行当前线程。而使用BeginInvoke时,当前线程不会阻塞,而是继续执行,当当前线程执行完毕后,UI线程才会执行BeginInvoke传入的方法。
借助虚拟串口软件,把机台可用的其中两个COM关联起来。
VSPD下载链接:https://download.csdn.net/download/c_gyl/10878572。