C#串列埠通訊助手
阿新 • • 發佈:2018-12-21
簡介:
使用C#,開發平臺VS2010,功能是串列埠通訊。功能很簡單,僅供大家學習,效果如圖:
1.使用控制元件
控制元件型別 | 命名 | 用途 | 說明 |
ComboBox | cbSerival | 串列埠 | |
ComboBox | cbBuadRate | 波特率 | |
ComboBox | cbDataBits | 資料位 | |
ComboBox | cbStop | 停止位 | |
ComboBox | cbParity | 校驗位 | |
Button | btnOpen | 開啟 | |
Button | btnClear | 清除 | |
Button | btnSend | 傳送 | |
RadioButton | rbRecHEX | 接收格式:HEX | |
RadioButton | rbRecASCII | 接收格式:ASCII | |
RadioButton | rbSendHEX | 傳送格式:HEX | |
RadioButton | rbSendASCII | 傳送格式:ACSII | |
CheckBox | cbRTS | RTS | |
CheckBox | cbDTR | DTR | |
CheckBox | cbNewLine | 換行 | |
TextBox | tbRec | 接收編輯框 | ReadOnly:True,Multiline:True |
TextBox | tbSend | 傳送編輯框 | |
SerialPort | serialPort1 | 表示串列埠資源 | |
StatusStrip | statusStrip1 | 狀態列 | LayoutStyle:Table |
ToolStripStatusLabel | tsslDateTime | 時間 | BorderSiders:Right |
ToolStripStatusLabel | toolStripStatusLabel1 | 讓R和S在狀態列的右邊 | 緊跟tsslDateTime後邊,Spring:True |
ToolStripStatusLabel | toolStripStatusLabel2 | 傳送位元組統計 S: | BorderSiders:Left |
ToolStripStatusLabel | tsslSendCount | 傳送總位元組數 | BorderSiders:Right |
ToolStripStatusLabel | toolStripStatusLabel3 | 接收位元組統計 R: | |
ToolStripStatusLabel | tsslRecCount | 接收總位元組數 |
2.操作一波
(1)控制元件新增
要做到本介面的效果需要把上面控制元件全新增進去,StatusStrip下面的控制元件,是在StatusStrip中新增的,小白請勿發懵。
(2)初始化
說明:串列埠和控制元件初始化。
private void Form1_Load(object sender, EventArgs e)
{
//串列埠
string[] str = SerialPort.GetPortNames();
foreach (string port in str)
{
cbSerial.Items.Add(port);
}
cbSerial.SelectedIndex = 0;
//波特率
cbBuadRate.Items.Add("300");
cbBuadRate.Items.Add("1200");
cbBuadRate.Items.Add("2400");
cbBuadRate.Items.Add("4800");
cbBuadRate.Items.Add("9600");
cbBuadRate.Items.Add("19200");
cbBuadRate.Items.Add("38400");
cbBuadRate.Items.Add("43000");
cbBuadRate.Items.Add("56000");
cbBuadRate.Items.Add("115200");
cbBuadRate.SelectedIndex = 4;
//資料位
cbDataBits.Items.Add("5");
cbDataBits.Items.Add("6");
cbDataBits.Items.Add("7");
cbDataBits.Items.Add("8");
cbDataBits.SelectedIndex = 3;
//停止位
cbStop.Items.Add("0");
cbStop.Items.Add("1");
cbStop.Items.Add("1.5");
cbStop.Items.Add("2");
cbStop.SelectedIndex = 1;
//校驗位
cbParity.Items.Add("無");
cbParity.Items.Add("奇校驗");
cbParity.Items.Add("偶校驗");
cbParity.SelectedIndex = 0;
btnSend.Enabled = false;
rbRecASCII.Checked = true;
rbSendASCII.Checked = true;
//狀態控制元件
tsslDateTime.Text = DateTime.Now.ToString("yyyy-MM-dd hh:mm:ss");
tsslRecCount.Text = "0";
tsslSendCount.Text = "0";
}
(3)“開啟”按鈕
private void btnOpen_Click(object sender, EventArgs e)
{
if(cbSerial.Items.Count <= 0)
{
MessageBox.Show("當前無可用串列埠!");
return;
}
if (serialPort1.IsOpen == false)
{
serialPort1.PortName = cbSerial.SelectedItem.ToString();
serialPort1.BaudRate = Convert.ToInt32(cbBuadRate.SelectedItem.ToString());
serialPort1.DataBits = Convert.ToInt32(cbDataBits.SelectedItem.ToString());
serialPort1.StopBits = (StopBits)Convert.ToInt32(cbStop.SelectedItem.ToString());
serialPort1.Parity = (Parity)Convert.ToInt32(cbParity.SelectedIndex);
try
{
serialPort1.Open();
btnSend.Enabled = true;
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "開啟COM錯誤", MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}
btnOpen.Text = "關閉";
}
else
{
try
{
serialPort1.Close();
btnSend.Enabled = false;
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "關閉COM錯誤", MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}
btnOpen.Text = "開啟";
}
cbSerial.Enabled = !serialPort1.IsOpen;
cbBuadRate.Enabled = !serialPort1.IsOpen;
cbDataBits.Enabled = !serialPort1.IsOpen;
cbStop.Enabled = !serialPort1.IsOpen;
cbParity.Enabled = !serialPort1.IsOpen;
}
(4)“清除”按鈕
private void btnClear_Click(object sender, EventArgs e)
{
tbRec.Clear();
tbSend.Clear();
}
(5)“傳送”按鈕
private void btnSend_Click(object sender, EventArgs e)
{
byte[] sendData = null;
string strData = null;
if (cbNewLine.Checked)
{
strData = tbSend.Text.Trim() + "\r\n";
}
else
{
strData = tbSend.Text.Trim();
}
if (rbSendHEX.Checked)
{
sendData = strToHexByte(strData);
}
else if (rbSendASCII.Checked)
{
sendData = Encoding.ASCII.GetBytes(strData);
}
if (this.Send(sendData))
{
statusStrip1.Invoke(new MethodInvoker(delegate
{
if (tsslSendCount.Text == "0")
{
tsslSendCount.Text = tbSend.Text.Length.ToString();
}
else
{
try
{
tsslSendCount.Text = (int.Parse(tsslSendCount.Text) + tbSend.Text.Length).ToString();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "傳送位元組計數錯誤", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
}));
}
}
(6)格式切換
說明:rbSendHEX和rbSendASCII新增CheckedChanged事件,接收格式同理。
private void rbSendHEX_CheckedChanged(object sender, EventArgs e)
{
byte[] data = null;
data = System.Text.Encoding.Default.GetBytes(tbSend.Text.Trim());
if (rbSendHEX.Checked)
{
StringBuilder sb = new StringBuilder();
for (int i = 0; i < data.Length; i++)
{
sb.AppendFormat("{0:x2}" + " ", data[i]);
}
tbSend.Text = sb.ToString().ToUpper();
}
}
private void rbSendASCII_CheckedChanged(object sender, EventArgs e)
{
if (rbSendASCII.Checked)
{
byte[] data = null;
if (tbSend.Text == "")
{
return;
}
data = HexStringToByte(tbSend.Text.Trim());
tbSend.Text = new ASCIIEncoding().GetString(data);
}
}
3.資料型別轉換
(1) 16進位制轉位元組陣列
public static 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;
}
(2)字串轉換16進位制位元組陣列
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).Replace(" ", ""), 16);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "轉換成HEX錯誤", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
return returnBytes;
}
4.串列埠
(1)串列埠傳送
public bool Send(byte[] data)
{
if (serialPort1.IsOpen)
{
try
{
serialPort1.Write(data, 0, data.Length);
return true;
}
catch(Exception ex)
{
MessageBox.Show(ex.Message, "傳送資料錯誤", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
else
{
MessageBox.Show("未開啟串列埠", "錯誤", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
return false;
}
(2)串列埠接收
說明:新增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);
}));
}
5.疑難點
說明:在WinForm中使用多執行緒時,當在子執行緒中修改一個控制元件的值或者進行其它操作時,會出錯。不過此工程未使用子執行緒,可直接對控制元件控制,效果是等價的。
if (tsslRecCount.Text == "0")
{
tsslRecCount.Text = tbRec.Text.Length.ToString();
}
else
{
tsslRecCount.Text = (int.Parse(tsslRecCount.Text) + data.Length).ToString();
}
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);
}
}
}));
注意:BeginInvoke與Invoke一個是同步執行,一個是非同步執行。簡單的可以理解為,當使用Invoke時,當前執行緒(非UI執行緒)會阻塞然後UI執行緒執行Invoke裡傳入的方法,之後再繼續執行當前執行緒。而使用BeginInvoke時,當前執行緒不會阻塞,而是繼續執行,噹噹前執行緒執行完畢後,UI執行緒才會執行BeginInvoke傳入的方法。