一、工程创建
创建新项目,选择Windows窗体应用(.NET Framework),不选择Windows窗体应用,因为要使用.NET框架
二、创建布局
创建如下所示布局,选择左侧栏工具,里面有对应的控件,添加完后记得添加一个serialport控件,textbox框要显示下拉条则调整如图所示属性
布局优化,将各个控件的Text属性重命名成如下所示,新增了一个扫描按钮(Button5),comboBox复选框属性调整成不可修改,这样运行时就不能在框里面写内容只能选择框内有的内容。
三、代码编写
编写代码时,注意需要从控件界面双击控件,进入控件相应的函数体内编写,不要直接将代码复制粘贴进去,复制粘贴过去的函数在配置文件内没有定义,即使名字一样也无法关联到控件。各个函数的解释已经在代码中详细解释了,可一一查看,具体细节不懂,百度搜索函数名即可。
3.1 页面初始化函数Form1
在其中添加一个线程屏蔽函数,不要让程序运行时检查各个线程之间的冲突,因为打开一个新窗口就相当于创建了一个线程的子进程,子进程不能回头访问别的线程,会导致冲突。
3.2 初始化扫描端口号
双击页面布局中的窗口边框 ,进入窗体初始化函数,添加扫描串口函数,添加串口接收数据处理事件,禁用按钮3发送数据功能
随后编写串口扫描函数和串口接收数据处理函数
3.3 各个按钮的点击功能
双击各个按钮,进入按钮对应函数
扫描按钮:
关闭端口按钮:
打开端口按钮:
3.4 combomBox中添加波特率列表
在布局页面中,按下图所示点击,写入相应波特率即可
3.5 全部源码
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO.Ports;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace ISxyq
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
System.Windows.Forms.Control.CheckForIllegalCrossThreadCalls = false;//屏蔽线程检查
}
private void groupBox1_Enter(object sender, EventArgs e)
{
}
private void Form1_Load(object sender, EventArgs e)
{
//扫描当前哪个串口是打开状态,初始化扫描
SearchAndAddSerialToComboBox(serialPort1, comboBox1);
//手动添加串口接收数据处理事件
serialPort1.DataReceived += new System.IO.Ports.SerialDataReceivedEventHandler(serialPort1_DataReceived);
//禁用按钮3,因为初始化时消息内容为空,什么都发送不了
button3.Enabled = false;
}
private void serialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e)//串口接收数据处理方法
{
if (!radioButton3.Checked)//如果接受模式为字符模式,非数值模式
{
string str = serialPort1.ReadExisting();//字符串方式读取
textBox1.AppendText(str);//添加内容,相当于textBox1.Text = textBox1.Text+str;
}
else//如果接收模式为数值接收
{
byte data; //定义一个8位整型变量,每次数据传输时就是传8位,用不到什么第九位奇偶校验
data = (byte)serialPort1.ReadByte();//读取串口中的数据:读取到的是int类型的数据,需要进行一次转换。强转为byte类型,byte是8位,对应一个十六进制数,最终显示的也是十六进制数
String str = Convert.ToString(data, 16).ToUpper();//将8位变量转换成16进制数(Convert.ToString)大写的形式(.ToUpper()),并且赋值给一个字符串
textBox1.AppendText("0x" + (str.Length == 1 ? "0" + str : str) + " ");
}
}
private void SearchAndAddSerialToComboBox(SerialPort Port, ComboBox Box)//端口扫描函数
{
string Buffer; //创建缓存区,用于存储扫描到的串口数量
Box.Items.Clear(); //清空ComboBox内容,把上次扫描到的串口清除重新扫描
for (int i = 1; i < 20; i++)
{
try //核心原理是依靠try和catch完成遍历,因为这样for循环才不会报错退出
{
Buffer = "COM" + i.ToString();
Port.PortName = Buffer; //控件serialport的PortName属性
Port.Open(); //如果串口能打开,执行下一句,打不开,捕获异常,不执行下一句
Box.Items.Add(Buffer); //将当前串口写入ComboBox的Items中
Port.Close(); //关闭串口
}
catch{
}
}
}
private void button5_Click(object sender, EventArgs e)
{
SearchAndAddSerialToComboBox(serialPort1, comboBox1);//扫描串口
}
private void button4_Click(object sender, EventArgs e)
{
textBox1.Text = " ";//清除接收
}
private void button2_Click(object sender, EventArgs e)
{
try
{
serialPort1.Close();
button1.Enabled = true;
button2.Enabled = false;
}
catch
{
MessageBox.Show("串口关闭错误,请检查...", "错误");
}
}
private void button1_Click(object sender, EventArgs e)
{
try
{
serialPort1.Close();
serialPort1.PortName = comboBox1.Text;//端口名等于comboBox1中选中的端口
serialPort1.BaudRate = Convert.ToInt32(comboBox2.Text, 10);//波特率,十进制数据转换,将字符串类型的波特率转换成十进制数
serialPort1.Open();
button1.Enabled = false;
button2.Enabled = true;
}
catch
{
MessageBox.Show("端口错误,请检查串口", "错误");
}
}
private void button3_Click(object sender, EventArgs e)
{
byte[] Data = new byte[1]; //只存储一个字节的数组
if (serialPort1.IsOpen)//判断串口是否打开
{
if (textBox2.Text != "") //判断发送域是否有数据
{
if (!radioButton1.Checked)//以字符形式发送数据
{
try
{
serialPort1.WriteLine(textBox2.Text);//向串口中写入数据
}
catch (Exception)
{
MessageBox.Show("串口写入数据错误", "错误");//向串口写入数据发生错误
serialPort1.Close(); //关闭串口
button1.Enabled = true;//打开串口按钮开启
button2.Enabled = false;//关闭串口按钮关闭
}
}
else//以数值形式发送数据
{ //比如输入0550A ,前四位,05 50 最后一位, A
//防止用于输入的个数为奇数个,两个数字为一个十六进制数
for (int i = 0; i < (textBox2.Text.Length - textBox2.Text.Length % 2) / 2; i++)//处理前偶数个数字
{
Data[0] = Convert.ToByte(textBox2.Text.Substring(i * 2, 2), 16);//将字符串转换为16进制的数值
serialPort1.Write(Data, 0, 1);//向串口中写入数据
}
if (textBox2.Text.Length % 2 != 0)//单独处理最后一个数字
{
//
Data[0] = Convert.ToByte(textBox2.Text.Substring(textBox2.Text.Length - 1, 1), 16);//最后一位=长度-1;
//发送数据
serialPort1.Write(Data, 0, 1);
}
}
}
}
}
private void textBox1_TextChanged(object sender, EventArgs e)
{
textBox1.ScrollToCaret();//将文件内容滚动到当前输入位置
}
private void textBox2_TextChanged(object sender, EventArgs e)
{
if (textBox2.Text == "")//如果当前框内没有内容
{
button3.Enabled = false;//不允许发送数据
}
else
{
button3.Enabled = true;
}
}
}
}