C#3串口调试助手
這個是簡單的小串口調(diào)試助手,主要是數(shù)據(jù)接收和數(shù)據(jù)發(fā)送,有些地方我也不懂,剛學C#.請大家多多指教
數(shù)據(jù)的收發(fā)都可以實現(xiàn),好像十六進制顯示和收發(fā)不太好,如果大家有改進的歡迎討論。謝謝。
當時第一次做的時候,好多控件都不能用,那是因為我沒綁定事件,請剛學的小伙伴們不要犯一樣的錯誤哦。
事件就是這個了。
下面貼上代碼:
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; using System.IO.Ports; using System.IO; using System.Reflection; using System.Threading;namespace serialport {public partial class Form1 : Form{#region 變量及委托聲明// 關閉標志,表示串口正在關閉private bool closing = false;//監(jiān)聽標志, 用于安全關閉串口private bool listening = false;//累計接收字節(jié)private long receiveCount = 0;//累計發(fā)送字節(jié)private long sendCount = 0;//委托,用于跨線程調(diào)用delegate void InvokeTextPaly(string text);//List,用于二進制數(shù)據(jù)包的緩存,也可用數(shù)組緩存private List<byte> bufferRead = new List<byte>(4096);//數(shù)組,用于緩存一個長度完整的數(shù)據(jù)包byte[] dataCatchedArry = new byte[9];#endregion#region CRC16校驗碼索引數(shù)組private byte[] crcHiArry = { 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40 };private byte[] crcLoArry = { 0x00, 0xC0, 0xC1, 0x01, 0xC3, 0x03, 0x02, 0xC2, 0xC6, 0x06, 0x07, 0xC7, 0x05, 0xC5, 0xC4,0x04, 0xCC, 0x0C, 0x0D, 0xCD, 0x0F, 0xCF, 0xCE, 0x0E, 0x0A, 0xCA, 0xCB, 0x0B, 0xC9, 0x09,0x08, 0xC8, 0xD8, 0x18, 0x19, 0xD9, 0x1B, 0xDB, 0xDA, 0x1A, 0x1E, 0xDE, 0xDF, 0x1F, 0xDD,0x1D, 0x1C, 0xDC, 0x14, 0xD4, 0xD5, 0x15, 0xD7, 0x17, 0x16, 0xD6, 0xD2, 0x12, 0x13, 0xD3,0x11, 0xD1, 0xD0, 0x10, 0xF0, 0x30, 0x31, 0xF1, 0x33, 0xF3, 0xF2, 0x32, 0x36, 0xF6, 0xF7,0x37, 0xF5, 0x35, 0x34, 0xF4, 0x3C, 0xFC, 0xFD, 0x3D, 0xFF, 0x3F, 0x3E, 0xFE, 0xFA, 0x3A,0x3B, 0xFB, 0x39, 0xF9, 0xF8, 0x38, 0x28, 0xE8, 0xE9, 0x29, 0xEB, 0x2B, 0x2A, 0xEA, 0xEE,0x2E, 0x2F, 0xEF, 0x2D, 0xED, 0xEC, 0x2C, 0xE4, 0x24, 0x25, 0xE5, 0x27, 0xE7, 0xE6, 0x26,0x22, 0xE2, 0xE3, 0x23, 0xE1, 0x21, 0x20, 0xE0, 0xA0, 0x60, 0x61, 0xA1, 0x63, 0xA3, 0xA2,0x62, 0x66, 0xA6, 0xA7, 0x67, 0xA5, 0x65, 0x64, 0xA4, 0x6C, 0xAC, 0xAD, 0x6D, 0xAF, 0x6F,0x6E, 0xAE, 0xAA, 0x6A, 0x6B, 0xAB, 0x69, 0xA9, 0xA8, 0x68, 0x78, 0xB8, 0xB9, 0x79, 0xBB,0x7B, 0x7A, 0xBA, 0xBE, 0x7E, 0x7F, 0xBF, 0x7D, 0xBD, 0xBC, 0x7C, 0xB4, 0x74, 0x75, 0xB5,0x77, 0xB7, 0xB6, 0x76, 0x72, 0xB2, 0xB3, 0x73, 0xB1, 0x71, 0x70, 0xB0, 0x50, 0x90, 0x91,0x51, 0x93, 0x53, 0x52, 0x92, 0x96, 0x56, 0x57, 0x97, 0x55, 0x95, 0x94, 0x54, 0x9C, 0x5C,0x5D, 0x9D, 0x5F, 0x9F, 0x9E, 0x5E, 0x5A, 0x9A, 0x9B, 0x5B, 0x99, 0x59, 0x58, 0x98, 0x88,0x48, 0x49, 0x89, 0x4B, 0x8B, 0x8A, 0x4A, 0x4E, 0x8E, 0x8F, 0x4F, 0x8D, 0x4D, 0x4C, 0x8C,0x44, 0x84, 0x85, 0x45, 0x87, 0x47, 0x46, 0x86 , 0x82, 0x42, 0x43, 0x83, 0x41, 0x81, 0x80,0x40};#endregion#region 窗口函數(shù)public Form1(){InitializeComponent();}private void Form1_Load(object sender, EventArgs e){GetPortName();if (comboBox_portName.Text == "")comboBox_portName.Text = "COM1";if (comboBox_dataBits.Text == "")comboBox_dataBits.Text = "8";if (comboBox_stopBits.Text == "")comboBox_stopBits.Text = "1";if (comboBox_rate.Text == "")comboBox_rate.Text = "9600";if (comboBox_paity.Text == "")comboBox_paity.Text = "None";OpenSerialPort();checkBox_hexSend_CheckedChanged(null, null); //加載默認設置并配置checkBox_autoSend_CheckedChanged(null, null);//checkBox_wrap_CheckedChanged(null, null);}#endregion#region 初始化打開串口//獲取當前串口名private void GetPortName(){comboBox_portName.Items.Clear();string[] portNames = SerialPort.GetPortNames();foreach (string name in portNames){if (name != "")comboBox_portName.Items.Add(name);}comboBox_portName.Text = global ::serialport.Properties.Settings.Default.PortName; }//打開串口private void OpenSerialPort(){if (serialPort1.IsOpen){return;}try{CheckConfig();serialPort1.Open();if (serialPort1.IsOpen){button_openClosePort.Text = "關閉串口";label_powerLed.ForeColor = Color.Lime;Label_mainMessage.ForeColor = Color.Green;Label_mainMessage.Text = serialPort1.PortName + "已打開";}}catch{Label_mainMessage.ForeColor = Color.Red;Label_mainMessage.Text = "串口打開失敗!";}}//關閉串口private void CloseSerialPort(){if (!serialPort1.IsOpen){return;}try{closing = true;while (listening)Application.DoEvents();serialPort1.Close();closing = false;if (!serialPort1.IsOpen){button_openClosePort.Text = "打開串口";label_powerLed.ForeColor = Color.DarkGray;Label_mainMessage.ForeColor = Color.Green;Label_mainMessage.Text = serialPort1.PortName + "已關閉";}}catch{Label_mainMessage.ForeColor = Color.Red;Label_mainMessage.Text = "串口關閉失敗!";}}//每次打開串口前需要重新檢測參數(shù)并配置private void CheckConfig(){comboBox_portName_TextChanged(null, null);comboBox_rate_TextChanged(null, null);comboBox_dataBits_TextChanged(null, null);comboBox_stopBits_TextChanged(null, null);comboBox_paity_TextChanged(null, null);// checkBox_RTS_CheckedChanged(null, null);// checkBox_DTR_CheckedChanged(null, null);}//用于刷新端口名稱private void comboBox_portName_MouseDown(object sender, MouseEventArgs e){GetPortName();}private void comboBox_portName_TextChanged(object sender, EventArgs e){try{if (serialPort1.IsOpen){CloseSerialPort();CheckConfig();// serialPort1.PortName = comboBox_portName.Text;OpenSerialPort();}else{serialPort1.PortName = comboBox_portName.Text;}}catch{//Label_mainMessage.ForeColor = Color.Red;//Label_mainMessage.Text = "串口號配置錯誤!";}}private void comboBox_rate_TextChanged(object sender, EventArgs e){try{serialPort1.BaudRate = Convert.ToInt32(comboBox_rate.Text);}catch{Label_mainMessage.Text = "波特率配置錯誤!";}}private void comboBox_dataBits_TextChanged(object sender, EventArgs e){try{serialPort1.DataBits = Convert.ToInt32(comboBox_dataBits.Text);}catch{Label_mainMessage.Text = "數(shù)據(jù)位配置錯誤!";}}private void comboBox_stopBits_TextChanged(object sender, EventArgs e){try{if (comboBox_stopBits.Text == "1")serialPort1.StopBits = StopBits.One;else if (comboBox_stopBits.Text == "1.5")serialPort1.StopBits = StopBits.OnePointFive;else if (comboBox_stopBits.Text == "2")serialPort1.StopBits = StopBits.Two;}catch{Label_mainMessage.Text = "停止位配置錯誤!";}}private void comboBox_paity_TextChanged(object sender, EventArgs e){try{switch (comboBox_paity.Text){case "None":serialPort1.Parity = Parity.None; break;case "Odd":serialPort1.Parity = Parity.Odd; break;case "Even":serialPort1.Parity = Parity.Even; break;case "Mark":serialPort1.Parity = Parity.Mark; break;case "Space":serialPort1.Parity = Parity.Space; break;}}catch{Label_mainMessage.Text = "校驗位配置錯誤!";}}/* private void checkBox_RTS_CheckedChanged(object sender, EventArgs e){serialPort1.DtrEnable = checkBox_DTR.Checked;}private void checkBox_DTR_CheckedChanged(object sender, EventArgs e){serialPort1.RtsEnable = checkBox_RTS.Checked;}*///串口開關按鈕 Click事件private void button_openClosePort_Click(object sender, EventArgs e){if (button_openClosePort.Text == "打開串口")OpenSerialPort();elseCloseSerialPort();}//點擊help,彈出新窗口private void label_help_Click(object sender, EventArgs e){}#endregion#region 數(shù)據(jù)接收//跨線程更新控件,用于顯示串口接收到的數(shù)據(jù) private void AppenTextBox(string text){if (textBox_receive.InvokeRequired){InvokeTextPaly d = new InvokeTextPaly(AppenTextBox); //聲明并初始化委托this.Invoke(d, new object[] { text });}else{Label_receiveCount.Text = receiveCount.ToString();if (button_stopOn.Text == "恢復顯示") //表示當前暫停顯示,窗口不再更新數(shù)據(jù)return;if (checkBox_wrap.Checked) //每次獲得的數(shù)據(jù)之間是否換行textBox_receive.AppendText(text + "\r\n");elsetextBox_receive.AppendText(text);}}//串口接收中斷事件//清除窗口private void button_clear_Click(object sender, EventArgs e){textBox_receive.Clear();receiveCount = sendCount = 0;Label_receiveCount.Text = Label_sendCount.Text = "0";}//顯示格式 CheckedChang事件private void check_hexPlay_CheckedChanged(object sender, EventArgs e){//PS:太亂了,嘗試更簡單有效的代碼StringBuilder buildHexPlay = new StringBuilder();if (textBox_receive.Text.Length == 0) //窗口為空,不需要轉(zhuǎn)換return;if (check_hexPlay.Checked) //將字符轉(zhuǎn)換為HEX格式顯示{char[] bufString = new char[textBox_receive.Text.Length];bufString = textBox_receive.Text.ToArray();foreach (char c in bufString){if (c == '\r' || c == '\n')continue; //過濾自動換行添加的回車符號,BUG:同時會把有效的回車符號也過濾掉buildHexPlay.Append(Convert.ToString(Convert.ToByte(c), 16) + " ");}textBox_receive.Text = buildHexPlay.ToString().ToUpper();}else //將HEX轉(zhuǎn)為字符顯示{string[] bufString = new string[textBox_receive.Text.Length];char[] split = { ' ', '\n', '\r' }; //將空格,回車符過濾,BUF:可能存在bufString = textBox_receive.Text.Trim().Split(split);foreach (string ss in bufString){if (ss != "") //由于有回車符"\r\n"存在,所以得到的SS可能為""buildHexPlay.Append(Convert.ToChar(Convert.ToByte(ss, 16)));}textBox_receive.Text = buildHexPlay.ToString();}}#endregion#region 數(shù)據(jù)發(fā)送//添加CRC16校驗碼private void addCRC16(ref List<byte> sendhex){byte crcHi = 0xff;byte crcLo = 0xff;byte index = 0;for (int i = 0; i < sendhex.Count; i++){index = Convert.ToByte(sendhex[i] ^ crcLo);crcLo = Convert.ToByte(crcHi ^ crcHiArry[index]);crcHi = crcLoArry[index];}sendhex.Add(crcLo);sendhex.Add(crcHi);//return Convert.ToUInt16((crcHi << 8 | crcLo));}//發(fā)送按鈕 Click事件private void button_send_Click(object sender, EventArgs e){if (!serialPort1.IsOpen){Label_mainMessage.ForeColor = Color.Red;Label_mainMessage.Text = "串口未打開!";return;}StringBuilder buildSend = new StringBuilder();// buildSend.Clear(); int count = 0; //發(fā)送字符的長度try{if (checkBox_hexSend.Checked) //發(fā)送16進制{List<byte> bufferSend = new List<byte>();// buildSend.Clear(); string sendSting = textBox_sendString.Text.Trim(); //刪去前導和后置空格符string s = "";while (sendSting.Length > 1) //奇數(shù)個16進制數(shù)據(jù)最后一個被拋棄{s = sendSting.Substring(0, 2);buildSend.Append(s + " ");bufferSend.Add(Convert.ToByte(s, 16)); //將字符s 如“1A” 轉(zhuǎn)化為字節(jié)31,送入字節(jié)列表BufferSendsendSting = sendSting.Remove(0, 2);sendSting = sendSting.Trim(); //刪去前導空格符}textBox_sendString.Text = buildSend.ToString().ToUpper(); //格式化顯示發(fā)送的數(shù)據(jù)if (checkBox_CRC16.Checked) //加上了CRC16校驗碼,并將完整的報文顯示在另一個TEXTBOX上{addCRC16(ref bufferSend);// buildSend.Clear();foreach (byte b in bufferSend.ToArray()){buildSend.Append(b.ToString("X2") + " ");}// textBox_dataCatched.Text = buildSend.ToString().ToUpper();}serialPort1.Write(bufferSend.ToArray(), 0, bufferSend.ToArray().Length);count = bufferSend.Count;}else //asc編碼直接發(fā)送,發(fā)送字符{/* if (checkBox_sendNewLine.Checked) //發(fā)送新行{serialPort1.WriteLine(textBox_sendString.Text);count = textBox_sendString.Text.Length + 2;}else{*/serialPort1.Write(textBox_sendString.Text);count = textBox_sendString.Text.Length;// }}sendCount += count;Label_sendCount.Text = sendCount.ToString();//也可直接使用用LABEL.TEXT的值來表示,少一個全局變量,其實LABEL.TEXT對于主窗口就是一個全局變量//Label_sendCount.Text = Convert .ToString ( Convert.ToInt64(Label_sendCount.Text) + count ); //原來長度加上新發(fā)送的長度}catch{MessageBox.Show("發(fā)送失敗,請檢查發(fā)送數(shù)據(jù)是否正確!", "提示");}}//16進制發(fā)送 CheckedChanged事件private void checkBox_hexSend_CheckedChanged(object sender, EventArgs e){}//自動發(fā)送 CheckedChanged事件private void checkBox_autoSend_CheckedChanged(object sender, EventArgs e){if (checkBox_autoSend.Checked){numericUpDown_period.Enabled = false;timer1.Interval = (int)numericUpDown_period.Value;timer1.Start();}else{numericUpDown_period.Enabled = true;timer1.Stop();}}//定時器1觸發(fā)事件,用于自動發(fā)送private void timer1_Tick(object sender, EventArgs e){if (serialPort1.IsOpen)button_send_Click(null, null);timer1.Interval = (int)numericUpDown_period.Value;}//按鍵檢測,用于檢測16進制輸入數(shù)據(jù)是否有效private void textBox_sendString_KeyPress(object sender, KeyPressEventArgs e){if (checkBox_hexSend.Checked){}else{}}//暫停顯示按鈕 Click事件private void button_stopOn_Click(object sender, EventArgs e){button_stopOn.Text = (button_stopOn.Text == "暫停顯示") ? "恢復顯示" : "暫停顯示";}#endregion} } PS:這個代碼是在師兄給我代碼的基礎上實現(xiàn)的,如果師兄看見了請不要拍我
總結(jié)
- 上一篇: 《CentOS中使用sl(跑火车)命令》
- 下一篇: c# char unsigned_dll