序
没有学过C#,但不妨碍开发上位机,有C语言基础即可,过程较为简单~
常用控件
1.文本标签控件(Label)
显示文本,在代码中通过更改Text属性实现
2.下拉组合框控件(ComboBox)
存在一个下拉列表来存放可选的内容,在前台的属性中设置为DropDownList模式。
添加下拉选项的模式:
(1)在属性的Items中手动添加
(2)在代码中使用API进行添加
comboBox2.Items.Add( i.ToString() );
3.按钮控件(Button)
点击时触发一个事件,在代码中有一对应的事件响应函数。
4.文本框控件(TextBox)
用于显示发送数据或者接受数据,使用时需要将属性ScrollBars设置为Vertical,并设置Multiline为true(点击控件时右上方会出现图标,点击即可设置)
5.串口控件(SerialPort)
隐式控件,一般通过代码进行配置,使用系统的接口可以用来获取当前电脑的端口
//获取电脑当前可用的串口号并设置默认值
comboBox1.Items.AddRange( System.IO.Ports.SerialPort.GetPortNames() );
if ( comboBox1.Items.Count != 0 )
comboBox1.SelectedIndex = 0;
6.单选按钮控件(RadioButton)
用在多选一的情况下,例如选择接受数据通过ASCII或者HEX模式显示,这里注意要和容器控件(Panel)一起使用,几个选项中选一个就需要把这几个选项放到一个容器中去。
7.容器控件(Panel)
作用即上述,注意其不可见
整体前台效果如下:
后台逻辑控制
概述: GUI界面的开发几乎都是事件驱动型机制
事件源:控件
事件:对控件的一些操作
事件处理:当事件发生时,在后台对事件的处理
- 初始化工作
1.添加各下拉列表的下拉选项
2.获取电脑当前可用的串口号并设置默认值
3.手动添加串口接收中断函数
private void Form1_Load(object sender, EventArgs e)
{
//添加波特率下拉表
for (int i = 300; i <= 38400; i = i * 2) {
comboBox2.Items.Add(i.ToString());
}
string[] baud = { "43000", "56000", "57600", "115200", "128000", "230400", "256000", "460800" };
comboBox2.Items.AddRange( baud );
//添加数据位下拉表
string[] databit = { "8", "7", "9" };
comboBox3.Items.AddRange( databit );
//添加校验位下拉表
string[] judgebit = { "None", "odd", "Even", "Mard", "Space" };
comboBox4.Items.AddRange( judgebit );
//添加停止位下拉表
string[] stopbit = { "1", "1.5", "2" };
comboBox5.Items.AddRange( stopbit );
//获取电脑当前可用的串口号并设置默认值
comboBox1.Items.AddRange( System.IO.Ports.SerialPort.GetPortNames() );
if ( comboBox1.Items.Count != 0 )
comboBox1.SelectedIndex = 0;
//设置默认值
comboBox2.Text = "115200";
comboBox3.Text = "8";
comboBox4.Text = "None";
comboBox5.Text = "1";
//手动添加串口接收中断函数
serialPort1.DataReceived += new SerialDataReceivedEventHandler(port_DataReceived);
}
- 打开(关闭)串口控件事件
1.条件判断当前串口状态
2.如果串口当前是开启状态则对串口进行关闭,使能各个更改串口状态的comboBox控件,失能发送数据的button控件
3.如果串口当前是关闭状态则对串口进行开启(根据各comboBox的属性),失能各个更改串口状态的comboBox控件,使能发送数据的button控件
注:try…catch…的使用可以避免死机
private void button1_Click(object sender, EventArgs e)
{
try
{
//判断串口是否处于打开状态
if (serialPort1.IsOpen)
{
serialPort1.Close();
//表示串口此时处于关闭状态
button1.Text = "打开串口";
label6.Text = "串口已关闭";
label6.ForeColor = Color.Red;
//使能comboBox
comboBox1.Enabled = true;
comboBox2.Enabled = true;
comboBox3.Enabled = true;
comboBox4.Enabled = true;
comboBox5.Enabled = true;
//失能发送控件
button2.Enabled = false;
}
else
{
//此时串口处于打开状态
//失能comboBox
comboBox1.Enabled = false;
comboBox2.Enabled = false;
comboBox3.Enabled = false;
comboBox4.Enabled = false;
comboBox5.Enabled = false;
//配置串口的相关属性
serialPort1.PortName = comboBox1.Text;
serialPort1.BaudRate = Convert.ToInt32(comboBox2.Text);
serialPort1.DataBits = Convert.ToInt16(comboBox3.Text);
if (comboBox4.Text.Equals("None"))
serialPort1.Parity = System.IO.Ports.Parity.None;
else if (comboBox4.Text.Equals("Odd"))
serialPort1.Parity = System.IO.Ports.Parity.Odd;
else if (comboBox4.Text.Equals("Even"))
serialPort1.Parity = System.IO.Ports.Parity.Even;
else if (comboBox4.Text.Equals("Mark"))
serialPort1.Parity = System.IO.Ports.Parity.Mark;
else if (comboBox4.Text.Equals("Space"))
serialPort1.Parity = System.IO.Ports.Parity.Space;
if (comboBox5.Text.Equals("1"))
serialPort1.StopBits = System.IO.Ports.StopBits.One;
else if (comboBox5.Text.Equals("1.5"))
serialPort1.StopBits = System.IO.Ports.StopBits.OnePointFive;
else if (comboBox5.Text.Equals("2"))
serialPort1.StopBits = System.IO.Ports.StopBits.Two;
//打开串口
serialPort1.Open();
//表示此时串口处于打开状态
button1.Text = "关闭串口";
label6.Text = "串口已打开";
label6.ForeColor = Color.Red;
//使能发送控件
button2.Enabled = true;
}
}
catch
{
MessageBox.Show("端口错误,请检查串口", "错误");
}
}
- 发送数据
1.字符(ASCII)模式发送
直接利用函数接口发送文本框控件中的内容(因为是字符串形式),注意Write和Writeline的区别,后者多发送一个0x0A
2.16进制(HEX)模式发送
(1)首先取出文本框控件中的内容(字符串形式,每两个字符后有一个空格,用于划分两个16进制数)
(2)利用正则表达式对空格进行匹配然后替换为空字符
(3)每两个字符表示一个8bit的16进制数,将这两个字符转化为一个byte型变量,然后用一个byte型的数组存储(为了方便时用Write发送)
(4)使用Write发送刚刚得到的byte型的数组
private void button2_Click(object sender, EventArgs e)
{
byte[] temp = new byte[1];
try
{
if (radioButton4.Checked)
{
//串口处于开启状态,将发送区文本发送
//ASCII发送模式
serialPort1.Write(textBox2.Text);
}
else
{
//HEX发送模式
//用正则表达式去除空格
string buf = textBox2.Text;
string pattern = @"\s";
string replacement = "";
Regex rgx = new Regex(pattern);
string str_send = rgx.Replace(buf, replacement);
//发送数据
int num = (str_send.Length - str_send.Length % 2) / 2;
for (int i = 0; i < num; i ++)
{
temp[0] = Convert.ToByte(str_send.Substring(i*2, 2),16); //将两个发送字符转换为16进制的数
serialPort1.Write(temp, 0, 1);
}
//若还存在最后一位,截取1位并发送
if (str_send.Length%2 != 0)
{
temp[0] = Convert.ToByte(str_send.Substring(str_send.Length - 1, 1), 16);
serialPort1.Write(temp, 0, 1);
}
}
}
catch
{
MessageBox.Show("串口数据写入错误", "错误");
}
}
- 接收数据
1.字符(ASCII)模式接收
利用ReadExiting读取接收缓存区中的所有字节,然后采用委托的方式显示到文本框控件上(因为和main不是一个线程)
2.16进制(HEX)模式接收
(1)利用Read将接收到的字符存入一个byte型的数组中
(2)数组中每一个byte型的变量(8bit)转换为对应的用2个字符表示一个16进制的数的形式(2×8bit)
(3)将转换得到的2个字符送到文本框控件上去显示
private void port_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
if (radioButton1.Checked)
{
//接收到的用ASCII模式显示
string str = serialPort1.ReadExisting();
//采用委托的方式
this.Invoke(new EventHandler(delegate
{
textBox1.AppendText(str);
}));
}
else
{
//将接收到的字符存入数组中
int num = serialPort1.BytesToRead; //接收到的字节数
byte[] receive_buf = new byte[num];
serialPort1.Read(receive_buf, 0, num);
sb.Clear();
//接收到的用HEX模式显示
foreach (byte b in receive_buf)
{
sb.Append("0X"+b.ToString("X2")+" ");
}
this.Invoke(new EventHandler(delegate
{
textBox1.AppendText(sb.ToString());
}));
}
}
源码附上:
https://github.com/zyxstronger/SerialAssistant
Reference:
https://blog.csdn.net/mculover666/category_9375094.html
杜洋工作室视频:入门C#设计