一、界面设计
在做软件之前使用“软件界面设计工具”先设计并绘制出软件界面,方便在写代码之前确认“功能需求”以及“交互流程”。
这里使用的软件是:“Axure RP”
二、新建工程与绘制界面
- 新建工程:
使用任意一个Visual studio即可,这里使用Visual studio2017作为开发环境(安装的时候选择.net桌面开发)。新建工程选择“c# winform类型的工程,然后填写工程名字即可完成工程创建”。如下图所示:
- 绘制图形界面:
鼠标单击打开“From1.cs”文件,会出现界面绘制界面。点击软件左侧栏的“工具栏”弹出界面控件列表,选择要绘制的控件拖动到软件绘制界面,并调整控件位置,直到达到设计图所设计的样子。如下图所示:
- 添加按钮按下相应函数:
选中按钮并使用右键点击“属性”,从而打开这个按钮的属性配置窗口,在窗口里可以设置很多属性,切换到事件配置页面(闪电图标)即可编辑与此控件相关的事件。在“事件配置页面”即可给按钮添加点击事件响应函数,如下图所示:
三、用到的库函数说明
用到了.net的类为:“SerialPort”。这个类中常用的函数说明如下:
“SerialPort”类的官方文档:https://docs.microsoft.com/zh-cn/dotnet/api/system.io.ports.serialport?view=netframework-4.8
- 公有成员函数
Open();//打开串口设备
Close();//关闭串口设备
int Write (byte[] buffer, int offset, int count);//给串口写数据
int Read (byte[] buffer, int offset, int count);//从串口读数据 - 公有成员变量
IsOpen //串口设备是否打开
ComDevice.PortName //设置或读取串口名称
ComDevice.BaudRate //设置或读取波特率
ComDevice.DataBits //设置或读取数据位
ComDevice.Parity //设置或读取校验位
ComDevice.StopBits //设置或读取停止位
四、核心编写逻辑代码
.net提供了串口编程函数类,为了避免把逻辑代码和界面代码混合编写。这里给串口相关操作函数做了二次封装。界面代码只要调用二次封装的类,即可完成串口通信。
- 逻辑代码
二次封装需要新定义一个类,使用Visual Studio添加自定义类方法如下图所示:
填写类名字:
新建完类后,在类中编写如下代码(简化展示,详情查看源代码):
namespace winform_serial_port_gui_tool
{
public delegate void RecvListener(byte[] data, int length); //定义一个委托
class SerialComm
{
private SerialPort ComDevice;
private static SerialComm mInstance = null;
private RecvListener recvListener = null;
public SerialComm()
{
ComDevice = new SerialPort();
}
public void SetRecvListener(RecvListener listener)
{
recvListener = listener;
}
public bool Open()
{
try
{
Console.WriteLine("##### open serial port");
ComDevice.DataReceived += new SerialDataReceivedEventHandler(Com_DataReceived);
ComDevice.Open();
if (ComDevice.IsOpen == true)
{
return true;
}
}
catch (Exception ex)
{
Console.WriteLine("未能成功开启串口" + ex.Message);
}
return false;
}
public void Close()
{
try
{
if (ComDevice.IsOpen)
{
ComDevice.DataReceived -= new SerialDataReceivedEventHandler(Com_DataReceived);
ComDevice.Dispose();
ComDevice.Close();
}
}
catch (Exception ex)
{
Console.WriteLine("串口关闭错误" + ex.Message);
}
}
public bool IsOpen() {
return ComDevice.IsOpen;
}
public bool Send(char[] data)
{
if (ComDevice.IsOpen)
{
try
{
ComDevice.Write(data, 0, data.Length);
return true;
}
catch (Exception ex)
{
Console.WriteLine("发送失败" + ex.Message);
}
}
else
{
Console.WriteLine("串口未开启");
}
return false;
}
private void Com_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
int length = ComDevice.BytesToRead;
byte[] ReDatas = new byte[length];
ComDevice.Read(ReDatas, 0, ReDatas.Length);
if (recvListener != null)
{
recvListener(ReDatas, length);
}
}
//*********** serial property settings *****************/
public void SetSerialPortName(string portName) {
ComDevice.PortName = portName;
}
public void SetSerialBaudRate(int rate) {
ComDevice.BaudRate = rate;
}
public void SetSerialDataBits(int dataBits) {
ComDevice.DataBits = dataBits;
}
public void SetSerialParity(Parity parity) {
ComDevice.Parity = parity;
}
public void SetSerialStopBits(StopBits stopBits) {
ComDevice.StopBits = stopBits;
}
}
}
- 界面代码
在工程文件中,选中“Form1”然后点击右键“查看代码”,进入到界面代码编辑页面。如下图所示:
在界面代码文件中编写如下代码:
namespace winform_serial_port_gui_tool
{
public partial class Form1 : Form
{
private SerialComm serialComm;
private string recvCache = "";
public Form1()
{
InitializeComponent();
serialComm = new SerialComm();
serialComm.SetRecvListener(RecvListener);
InitUI();
}
private void InitUI() {
comboBoxSerialPort.Items.AddRange(serialComm.GetSerialDeviceStrList());
comboBoxSerialBaud.Items.AddRange(serialComm.GetSerialBaudRateStrList());
comboBoxSerialDataBits.Items.AddRange(serialComm.GetSerialDataBitsStrList());
comboBoxSerialParity.Items.AddRange(serialComm.GetSerialParityStrList());
comboBoxSerialStopBits.Items.AddRange(serialComm.GetSerialStopBitsStrList());
if (comboBoxSerialPort.Items.Count > 0) {
comboBoxSerialPort.SelectedIndex = 0;
}
comboBoxSerialBaud.SelectedIndex = 3;
comboBoxSerialDataBits.SelectedIndex = 3;
comboBoxSerialParity.SelectedIndex = 0;
comboBoxSerialStopBits.SelectedIndex = 1;
}
private void DisableSettingsUI() {
comboBoxSerialPort.Enabled = false;
comboBoxSerialBaud.Enabled = false;
comboBoxSerialDataBits.Enabled = false;
comboBoxSerialParity.Enabled = false;
comboBoxSerialStopBits.Enabled = false;
}
private void EnableSettingsUI() {
comboBoxSerialPort.Enabled = true;
comboBoxSerialBaud.Enabled = true;
comboBoxSerialDataBits.Enabled = true;
comboBoxSerialParity.Enabled = true;
comboBoxSerialStopBits.Enabled = true;
}
private void SetSerialSettings() {
serialComm.SetSerialPortName(comboBoxSerialPort.Text);
serialComm.SetSerialBaudRate(SerialComm.GetBaudRateByIndex(comboBoxSerialBaud.SelectedIndex));
serialComm.SetSerialDataBits(SerialComm.GetDataBitsByIndex(comboBoxSerialDataBits.SelectedIndex));
serialComm.SetSerialParity(SerialComm.GetParityByIndex(comboBoxSerialParity.SelectedIndex));
serialComm.SetSerialStopBits(SerialComm.GetStopBitsByIndex(comboBoxSerialStopBits.SelectedIndex));
}
private void buttonSerialOpen_Click(object sender, EventArgs e)
{
if (serialComm.IsOpen())
{
//do close
serialComm.Close();
EnableSettingsUI();
buttonSerialOpen.Text = "open";
}
else
{
//do open
SetSerialSettings();
serialComm.Open();
DisableSettingsUI();
buttonSerialOpen.Text = "close";
}
}
private void buttonSerialSend_Click(object sender, EventArgs e)
{
if (!serialComm.IsOpen()) {
MessageBox.Show("Please open the serial port first !");
return;
}
char[] data = textBoxSerialSend.Text.ToString().ToCharArray();
serialComm.Send(data);
textBoxSerialSend.Clear();
}
private void RecvListener(byte[] data, int length) {
this.Invoke( (MethodInvoker)delegate ()
{
String temp = System.Text.Encoding.UTF8.GetString(data);
Console.Out.WriteLine(temp);
recvCache += temp;
textBoxSerialRecv.Text = recvCache;
});
}
}
}