c#串口调试助手、上位机
简介:
此串口调试助手是在windows下开发的,工具是 Visual Studio 2017开发的,串口调试助手支持 600115200波特率,端口号是 CMO1CMO9,支持数据位、停止位、奇偶位,支持数据的接收与发送,接收方式十六进制、字符的选择,对接收端数据的清空,并能对温度传感器数据进行接收与绘折线图,并且能设置正常温度现实的区间,及时判断温度是否显示正常与否,并能对曲线的显示进行刷新重新绘制。
效果图片:
源码文件名:Csha_demo-master
想要源代码的可以关注公众号回复:上位机
串口参数介绍
简介:
典型地,串口用于ASCII码字符的传输。通信使用3根线完成:(1)地线,(2)发送,(3)接收。由于串口通信是异步的,端口能够在一根线上发送数据同时在另一根线上接收数据。
波特率:
这是一个衡量符号传输速率的参数。它表示每秒钟传送的符号的个数。例如300波特表示每秒钟发送300个符号。当我们提到时钟周期时,我们就是指波特率,例如如果协议需要4800波特率,那么时钟是4800Hz。这意味着串口通信在数据线上的采样率为4800Hz。通常电话线的波特率为14400,28800和36600。波特率可以远远大于这些值,但是波特率和距离成反比。高波特率常常用于放置的很近的仪器间的通信,典型的例子就是GPIB设备的通信。
数据位:
数据位表示一组数据实际包含的数据位数。数据位紧跟在起始位之后,是通信中的真正有效信息。数据位的位数由通信双方共同约定,一般可以是6位、7位或8位,比如标准的ASCII码是0—127(7位),扩展的ASCII码是0—255(8位)。传输数据时先传送字符的低位,后传送字符的高位,即低位(LSB)在前,高位(MSB)在后。
奇偶位:
奇偶校验通常用在数据通信中来保证数据的有效性。奇偶校验位是一个表示给定位数的二进制数中 1 的个数是奇数还是偶数的二进制数。奇偶校验位是最简单的错误检测码。
停止位:
用于表示单个包的最后一位。典型的值为1,1.5和2位。由于数据是在传输线上定时的,并且每一个设备有其自己的时钟,很可能在通信中两台设备间出现了小小的不同步。因此停止位不仅仅是表示传输的结束,并且提供计算机校正时钟同步的机会。适用于停止位的位数越多,不同时钟同步的容忍程度越大,但是数据传输率同时也越慢。
串口通信模块(SerialPort)
- 配置IO文件
1 2
| using System.IO; using System.IO.Ports;
|
- 图标
属性 |
介绍 |
BaudRate |
波特率 |
DataBits |
数据位 |
Parity |
奇偶校验位 |
PortName |
端口号 |
StopBits |
停止位 |
ByteToRead |
获取输入缓冲区的 |
IsOpen |
获取是否开启串口 |
在这里我们只用到DataReceived串口接收函数,如需了解另外两个请自己查阅
事件 |
介绍 |
DataReceived |
串口接收函数 |
ErrorReceived |
串口数据接收错误 |
PinChanged |
串口号发生改变 |
串口窗口介绍
由图可以看出正常温度区间设置的是20-25度之间,测试温度的过程中温度曲线黄色的为正常的曲线,红色的曲线为温度异常。温度刷新,温度曲线重新读取画线
在窗体上添加4个Groupbox控件:
- 第一个:串口设置
- 第二的:接收数据
- 第三个:发送数据
- 第四个:温度曲线显示
代码编写
串口初始化函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61
| private void button_open_Click(object sender, EventArgs e) { if (!serialPort1.IsOpen) { serialPort1.PortName = comboBox1.Text; serialPort1.BaudRate = Convert.ToInt32(comboBox2.Text, 10); float f = Convert.ToSingle(comboBox3.Text.Trim()); if (f == 0) serialPort1.StopBits = StopBits.None; else if (f == 1.5) serialPort1.StopBits = StopBits.OnePointFive; else if (f == 1) serialPort1.StopBits = StopBits.One; else if (f == 2) serialPort1.StopBits = StopBits.Two; else serialPort1.StopBits = StopBits.One; serialPort1.DataBits = Convert.ToInt32(comboBox4.Text.Trim()); string s = comboBox5.Text.Trim(); if (s.CompareTo("无") == 0) serialPort1.Parity = Parity.None; else if (s.CompareTo("奇校验") == 0) serialPort1.Parity = Parity.Odd; else if (s.CompareTo("偶校验") == 0) serialPort1.Parity = Parity.Even; else serialPort1.Parity = Parity.None; try { serialPort1.Open(); button_open.Text = "关闭串口"; comboBox1.Enabled = false; comboBox2.Enabled = false; comboBox3.Enabled = false; comboBox4.Enabled = false; comboBox5.Enabled = false; comboBox6.Enabled = false; comboBox7.Enabled = false; } catch { MessageBox.Show("串口打开失败!"); } } else { serialPort1.Close(); button_open.Text = "打开串口"; comboBox1.Enabled = true; comboBox2.Enabled = true; comboBox3.Enabled = true; comboBox4.Enabled = true; comboBox5.Enabled = true; comboBox6.Enabled = true; comboBox7.Enabled = true; }
}
|
画坐标图
画坐标时用到头文件:
1 2
| using System.Drawing; using System.Drawing.Drawing2D;
|
画线时用到类graphics
graphics是抽象函数不能实例化,并且画线的时候编辑器是以左上角为坐标原点画的,想要把它改成左下角,只能自己计算坐标点,根据自己的需求把它画成称自己想要的,如上图我把(50,218)这个坐标表示成原点
注意:Graphics是在控件Groupbox控件下事件Paint下写的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| private void groupBox4_Paint(object sender, PaintEventArgs e) { FontFamily family = new FontFamily("Arial"); int fontstyle = (int)FontStyle.Italic; GraphicsPath gp = new GraphicsPath(); string Str; for (int i = 0; i <= 14; i++) { e.Graphics.DrawLine(TablePen, StartPrint + i * Unit_length, StartPrint - 32, StartPrint + i * Unit_length, 10 * Unit_length + 18); gp.AddString((i * 10).ToString(), family, fontstyle, 8, new RectangleF(StartPrint + i * Unit_length - 7, 10 * Unit_length + 18 + 4, 400, 50), null); } gp.AddString("时间(s)", family, fontstyle, 12, new RectangleF(groupBox4.ClientRectangle.Width / 2 , 9 * Unit_length + 55, 400, 50), null); Draw X 横向轴绘制 for (int i = 0; i <= 10; i++) { e.Graphics.DrawLine(TablePen, StartPrint, i * Unit_length + 18, StartPrint + 14 * Unit_length, i * Unit_length + 18); Str = Convert.ToString((10 - i) * 5); if (i == 0) Str = "50"; if (i == 10) break; gp.AddString(Str, family, fontstyle, 8, new RectangleF(20, i * Unit_length +16, 400, 50), null); } gp.AddString("温", family, fontstyle, 12, new RectangleF(0, groupBox4.ClientRectangle.Height / 2 - StartPrint, 400, 50), null); gp.AddString("度", family, fontstyle, 12, new RectangleF(0, groupBox4.ClientRectangle.Height / 2 + 18 - StartPrint, 400, 50), null); gp.AddString("°C", family, fontstyle, 12, new RectangleF(0, groupBox4.ClientRectangle.Height / 2 + 32 - StartPrint, 400, 50), null); e.Graphics.DrawPath(Pens.White, gp); }
|
方法介绍
DrawLine(Pen pen, int x1, int y1, int x2, int y2);
pen:定义线条的宽度、颜色、样式
画线由(x1,y1)向(x2,y2)画
public void AddString(string s, FontFamily family, int style, float emSize, RectangleF layoutRect, StringFormat format);
s:绘制的字符
family:绘制的字体类型
style:字体的样式
emsize:方形块的高度
layoutRect:文本的矩形
format:文本格式设置信息
c#延时函数
1 2 3 4 5 6 7 8
| public static void Delay(int milliSecond) { int start = Environment.TickCount; while (Math.Abs(Environment.TickCount - start) < milliSecond) { Application.DoEvents(); } }
|
关于Math.Abs():
Environment.TickCount,内部API是用DWORD GetTickCount()来实现的,该属性的值从系统计时器派生,并以 32 位有符号整数的形式存储。因此,如果系统连续运行,TickCount 将在约 24.9 天内从零递增至 Int32. MaxValue ,然后跳至 Int32. MinValue (这是一个负数),再在接下来的 24.9 天内递增至零。DWORD是无符号的,而 Environment.TickCount属性返回的值是有符号的,所以有一半的值用负数表示!
串口写函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| private void button_send_Click(object sender, EventArgs e) { if(serialPort1.IsOpen) { if (textBox_send.Text.Trim() != "") { serialPort1.Write(textBox_send.Text.Trim()); } else { MessageBox.Show("发送框没有数据"); } } else { MessageBox.Show("串口未打开"); } }
|
串口读函数(如果是温度传感器并选择温度传感器画温度曲线)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52
| private void post_DataReceived(object sender, SerialDataReceivedEventArgs e) { float Up, Dw,t; Graphics graphics = groupBox4.CreateGraphics(); if (!radioButton1.Checked) { string str = serialPort1.ReadExisting(); if(!radioButton3.Checked) { string result = System.Text.RegularExpressions.Regex.Replace(str, @"[^0-9]+", ""); Console.WriteLine(result); Dw = Convert.ToSingle(comboBox6.Text); Up = Convert.ToSingle(comboBox7.Text); if(Dw<Up) { t = Dw; Dw = Up; Up = t; } dstr2 = Convert.ToSingle(result); textBox_T.Text = result + "度"; textBox_receive.AppendText(str); if(dstr2>=Up&&dstr2<=Dw) { graphics.DrawLine(LinesPen, Origin_x + i * Unit_length, dstr1, Origin_x + (i+0.1f) * Unit_length, Origin_y - dstr2 * 4); } else { graphics.DrawLine(LinesEpen, Origin_x + i * Unit_length, dstr1, Origin_x + (i + 0.1f) * Unit_length, Origin_y - dstr2 * 4); } i += 0.1f; dstr1 = Origin_y - dstr2 * 4; Delay(1000); } else { textBox_receive.AppendText(str); } } else { byte data; data = (byte)serialPort1.ReadByte(); string str = Convert.ToString(data, 16).ToUpper(); textBox_receive.AppendText("0x" + (str.Length == 1 ? "0" + str : str) + " ");
} }
|
相关链接
- c#串口调试助手温度曲线的显示-上位机的开发-串口参数介绍
=================我是分割线=================
欢迎到公众号来唠嗑: