查看: 1525|回复: 0

[.NET源码] C.Net串口工具源码 串口调试工具 支持16进制发送 可以定时自动发送

发表于 2018-3-23 08:00:05
软件功能:

使用C#实现PC串口通讯

支持定时发送

支持16进制(hex) ASCII UTF-8 Unicode 四种编码格式

支持配置文件的保存和读取

可以可以显示发送历史

可以统计总的发送字节数和接受字节数

软件界面:

Screen Shot 2018-03-17 at 17.47.04 PM.png

C#源码:
  1. using System;
  2. using System.Collections.Generic;
  3. using System.ComponentModel;
  4. using System.Data;
  5. using System.Drawing;
  6. using System.Linq;
  7. using System.Text;
  8. using System.Windows.Forms;
  9. using System.IO;
  10. using System.IO.Ports;
  11. using System.Threading;
  12. using System.IO;
  13. using System.Xml.Serialization;
  14. namespace 串口调试工具
  15. {
  16. public partial class Form1 : Form
  17. {
  18. private SerialPort sp = new SerialPort();//链接对象
  19. Config config = new Config();//配置文件
  20. public Form1()
  21. {
  22. InitializeComponent();
  23. }
  24. private void Form1_Load(object sender, EventArgs e)
  25. {
  26. //获取串口列表
  27. string[] comList = SerialPort.GetPortNames();
  28. if (comList.Length == 0)
  29. {
  30. MessageBox.Show("无可用串口");
  31. return;
  32. }
  33. foreach (var com in comList)
  34. {
  35. cmbComList.Items.Add(com);
  36. }
  37. //添加波特率
  38. int[] baudRate = { 300, 600, 1200, 2400, 4800, 9600, 19200, 38400, 43000, 56000, 57600, 115200 };
  39. foreach (var br in baudRate)
  40. {
  41. cmbBautRade.Items.Add(br);
  42. }
  43. //添加数据位
  44. int[] dataBits = { 8, 7, 6, 5 };
  45. foreach (var db in dataBits)
  46. {
  47. cmbDataBits.Items.Add(db);
  48. }
  49. //添加停止位
  50. int[] stopBits = { 1, 2, 3 };
  51. foreach (var sb in stopBits)
  52. {
  53. cmbStopBits.Items.Add(sb);
  54. }
  55. //添加检验方式
  56. string[] parity = { "None", "Even", "Mark", "Odd", "Space" };
  57. foreach (var p in parity)
  58. {
  59. cmbParity.Items.Add(p);
  60. }
  61. //添加常用编码
  62. string[] encode = { "ASCII","UTF-8","Unicode","Hex"};
  63. foreach (var en in encode)
  64. {
  65. cmbEncodeSend.Items.Add(en);
  66. cmbEncodeRec.Items.Add(en);
  67. }
  68. //加载配置文件
  69. LoadConfig();
  70. }
  71. private void LoadConfig()
  72. {
  73. //把配置信息赋值给控件默认值
  74. cmbComList.SelectedItem = config.PortName;
  75. if (cmbComList.SelectedIndex == -1) cmbComList.SelectedIndex = 0;
  76. cmbBautRade.SelectedItem = config.BautRade;
  77. cmbDataBits.SelectedItem = config.DataBits;
  78. cmbStopBits.SelectedItem = config.StopBits;
  79. cmbParity.SelectedItem = config.Parity;
  80. cmbEncodeRec.SelectedItem = config.EncodeRec;
  81. cmbEncodeSend.SelectedItem = config.EncodeSend;
  82. //激活打开按钮
  83. this.btnOpen.Enabled = true;
  84. }
  85. private void btnOpen_Click(object sender, EventArgs e)
  86. {
  87. if (((Button)sender).Text == "打开串口")
  88. {
  89. //赋值给串口
  90. sp.PortName = cmbComList.SelectedItem.ToString();
  91. sp.Parity=(Parity)Enum.Parse(typeof(Parity),cmbParity.SelectedItem.ToString());
  92. sp.BaudRate = Convert.ToInt32(cmbBautRade.SelectedItem.ToString());
  93. sp.StopBits = (StopBits)Convert.ToInt32(cmbStopBits.SelectedItem.ToString());
  94. sp.DataBits = Convert.ToInt32(cmbDataBits.SelectedItem.ToString());
  95. try
  96. {
  97. sp.Open();
  98. //修改控件状态
  99. this.btnOpen.Text = "关闭串口";
  100. foreach (Control ctr in groupBox1.Controls)
  101. {
  102. //把下拉框全部禁用
  103. ctr.Enabled = false;
  104. }
  105. //开启新线程,监听收取内容
  106. Thread thread = new Thread(receive);
  107. thread.Start();
  108. }
  109. catch (Exception ex)
  110. {
  111. MessageBox.Show(ex.Message);
  112. }
  113. }
  114. else
  115. {
  116. if (this.btnAutoSend.Text == "停止发送")
  117. {
  118. MessageBox.Show("当前定时发送中,请先停止定时发送任务.");
  119. return;
  120. }
  121. sp.Close();
  122. //修改控件状态
  123. this.btnOpen.Text = "打开串口";
  124. foreach (Control ctr in this.groupBox1.Controls)
  125. {
  126. ctr.Enabled = true;
  127. }
  128. }
  129. }
  130. private void Form1_FormClosed(object sender, FormClosedEventArgs e)
  131. {
  132. //窗体关闭时关闭端口
  133. sp.Close();
  134. }
  135. private void btnSend_Click(object sender, EventArgs e)
  136. {
  137. Send();
  138. }
  139. private void btnAutoSend_Click(object sender, EventArgs e)
  140. {
  141. if (this.btnAutoSend.Text == "定时发送")
  142. {
  143. //根据打开按钮状态初步检查端口是否已经打开
  144. if (this.btnOpen.Text == "打开串口") return;
  145. System.Text.RegularExpressions.Regex reg1 = new System.Text.RegularExpressions.Regex(@"^[0-9]\d*$");
  146. if (reg1.IsMatch(txtTime.Text.ToString()))
  147. {
  148. //激活Timer定时器
  149. this.timer1.Interval = Convert.ToInt32(txtTime.Text.ToString());
  150. this.timer1.Start();
  151. //修改控件状态
  152. this.btnAutoSend.Text = "停止发送";
  153. this.btnSend.Enabled = false;
  154. }
  155. else
  156. {
  157. MessageBox.Show("发送间隔应为正整数");
  158. txtTime.Text = "1000";
  159. }
  160. }
  161. else
  162. {
  163. this.btnAutoSend.Text = "定时发送";
  164. this.btnSend.Enabled = true;
  165. this.timer1.Stop();
  166. }
  167. }
  168. private void Send()
  169. {
  170. if (sp.IsOpen)
  171. {
  172. //获取字节
  173. byte[] buffer = Encode();
  174. if (buffer.Length == 0) return;
  175. try
  176. {
  177. sp.Write(buffer, 0, buffer.Length);
  178. }
  179. catch (Exception ex)
  180. {
  181. MessageBox.Show(ex.Message);
  182. }
  183. //添加发送历史
  184. this.txtHistory.AppendText(string.Format("[{0}] 小贝 \r\n", DateTime.Now.ToString("HH:mm:ss.ff"), txtSend.Text));
  185. //统计发送字节
  186. this.labSendCount.Text = (Convert.ToInt32(labSendCount.Text) + buffer.Length).ToString();
  187. }
  188. else
  189. {
  190. this.timer1.Stop();
  191. MessageBox.Show("串口尚未打开");
  192. this.btnAutoSend.Text = "定时发送";
  193. }
  194. }
  195. private void timer1_Tick(object sender, EventArgs e)
  196. {
  197. //定时发送
  198. Send();
  199. }
  200. //字节反编码
  201. private byte[] Encode()
  202. {
  203. byte[] buffer = null;
  204. switch (this.cmbEncodeSend.SelectedItem.ToString())
  205. {
  206. case "Unicode":
  207. buffer = Encoding.Unicode.GetBytes(txtSend.Text);
  208. break;
  209. case "UTF-8":
  210. buffer = Encoding.UTF8.GetBytes(txtSend.Text);
  211. break;
  212. case "ASCII":
  213. buffer = Encoding.ASCII.GetBytes(txtSend.Text);
  214. break;
  215. case "Hex":
  216. buffer = strToToHexByte(txtSend.Text);
  217. break;
  218. }
  219. return buffer;
  220. }
  221. //编码
  222. private string UnEncode(byte[] buffer)
  223. {
  224. string str = string.Empty;
  225. switch (this.cmbEncodeSend.SelectedItem.ToString())
  226. {
  227. case "Unicode":
  228. str = new UnicodeEncoding().GetString(buffer);
  229. break;
  230. case "UTF-8":
  231. str = new UTF8Encoding().GetString(buffer);
  232. break;
  233. case "ASCII":
  234. str = new ASCIIEncoding().GetString(buffer);
  235. break;
  236. case "Hex":
  237. str = byteToHexStr(buffer);
  238. break;
  239. }
  240. return str;
  241. }
  242. /// <summary>
  243. /// 字节数组转16进制字符串
  244. /// </summary>
  245. /// <param name="bytes"></param>
  246. /// <returns></returns>
  247. public static string byteToHexStr(byte[] bytes)
  248. {
  249. string returnStr = "";
  250. if (bytes != null)
  251. {
  252. for (int i = 0; i < bytes.Length; i++)
  253. {
  254. returnStr += bytes[i].ToString("X2");
  255. }
  256. }
  257. return returnStr;
  258. }
  259. /// <summary>
  260. /// 字符串转16进制字节数组
  261. /// </summary>
  262. /// <param name="hexString"></param>
  263. /// <returns></returns>
  264. private static byte[] strToToHexByte(string hexString)
  265. {
  266. hexString = hexString.Replace(" ", "");
  267. if ((hexString.Length % 2) != 0)
  268. hexString += " ";
  269. byte[] returnBytes = new byte[hexString.Length / 2];
  270. for (int i = 0; i < returnBytes.Length; i++)
  271. returnBytes[i] = Convert.ToByte(hexString.Substring(i * 2, 2), 16);
  272. return returnBytes;
  273. }
  274. private void receive()
  275. {
  276. //接收信息 先判断是否为打开状态
  277. while (sp.IsOpen)
  278. {
  279. if (sp.BytesToRead == 0) continue;
  280. //准备接收
  281. byte[] buffer = new byte[sp.BytesToRead];
  282. try
  283. {
  284. //接受动作
  285. sp.Read(buffer, 0, buffer.Length);
  286. }
  287. catch (Exception ex)
  288. {
  289. MessageBox.Show(ex.Message);
  290. }
  291. //更新UI信息
  292. this.Invoke((Action)delegate
  293. {
  294. this.txtRec.AppendText(UnEncode(buffer));
  295. //是否自动换行
  296. if(cbLine.Checked)
  297. this.txtRec.AppendText("\r\n");
  298. //接收统计信息
  299. this.labRecCount.Text = (Convert.ToInt32(this.labRecCount.Text) + buffer.Length).ToString();
  300. });
  301. }
  302. }
  303. private void button1_Click(object sender, EventArgs e)
  304. {
  305. //清空发送历史
  306. this.txtHistory.Clear();
  307. }
  308. private void button2_Click(object sender, EventArgs e)
  309. {
  310. //清空接收
  311. this.txtRec.Clear();
  312. }
  313. private void btnLoad_Click(object sender, EventArgs e)
  314. {
  315. //读取xml文件 序列化对象
  316. OpenFileDialog ofd = new OpenFileDialog();
  317. ofd.Filter = "XML(*.xml)|";
  318. if (ofd.ShowDialog() == DialogResult.OK)
  319. {
  320. string filePath = ofd.FileName;
  321. if (File.Exists(filePath))
  322. {
  323. try
  324. {
  325. var mySerializer = new XmlSerializer(typeof(Config));
  326. using (var sr = new StreamReader(new FileStream(filePath, FileMode.Open, FileAccess.Read)))
  327. {
  328. config = (Config)mySerializer.Deserialize(sr);
  329. }
  330. LoadConfig();
  331. }
  332. catch (Exception ee)
  333. {
  334. MessageBox.Show(ee.Message);
  335. }
  336. }
  337. else
  338. {
  339. MessageBox.Show("文件不存在");
  340. }
  341. }
  342. }
  343. private void btnSave_Click(object sender, EventArgs e)
  344. {
  345. FolderBrowserDialog fbd = new FolderBrowserDialog();
  346. if (fbd.ShowDialog() == DialogResult.OK)
  347. {
  348. //给对象赋值并序列化保存
  349. config.PortName = cmbComList.SelectedItem.ToString();
  350. config.Parity = cmbParity.SelectedItem.ToString();
  351. config.BautRade = Convert.ToInt32(cmbBautRade.SelectedItem.ToString());
  352. config.StopBits = Convert.ToInt32(cmbStopBits.SelectedItem.ToString());
  353. config.DataBits = Convert.ToInt32(cmbDataBits.SelectedItem.ToString());
  354. XmlSerializer xmlFormat=new XmlSerializer(typeof(Config));
  355. string filePath = fbd.SelectedPath + "\\PortConfig.xml";
  356. using (Stream stream = new FileStream(filePath, FileMode.Create, FileAccess.Write, FileShare.None))
  357. {
  358. xmlFormat.Serialize(stream, config);
  359. }
  360. MessageBox.Show("成功保存到路径:"+filePath);
  361. }
  362. }
  363. private void linkLabel1_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
  364. {
  365. System.Diagnostics.Process.Start("http://www.chengchenxu.com");
  366. }
  367. }
  368. }
复制代码

软件下载:

串口调试工具.rar

源码工程文件:

串口调试工具.rar

虚拟端口软件下载:

VirtualSerialPortDriver.rar

未实现的功能:

16进制校验功能,即发送16进制格式的时候检查输入值是否为正确的16进制数字

接受文件的完整性校验功能,有时候一条信息会分两次接受完整

本文为博主原创,转载请保留出处:
http://www.chengchenxu.com/Article/30/



回复

使用道具 举报