今日尝试使用C#进行 自己编写一款上位机串口助手:
文章提供源码、解释、测试效果、整体工程下载......
以下为串口助手的界面效果:
目录
C#System.InvalidOperationException:“线程间操作无效: 从不是创建控件“textBox3”的线程访问它。
1、功能设计与摆放控件:
与之前的串口发送不同,我们此次做的是兼顾接收与发送的串口助手,预设功能如下:
1、串口选择
2、波特率
3、接收显示窗口
4、切换十六进制发送接收功能
5、清除接收区
6、必要的交互按钮
最大的接收区我使用的组件是:richTextBox
清除接收区、打开关闭串口、发送等按键使用的组件是:button
16进制显示、发送我使用了可以框选和不选的组件:checkBox
单条发送后的文本输入区我使用的组件是:textBox(相比richTextBox只有一行)
2.遇到的报错解决与基本提示:
C#System.InvalidOperationException:“线程间操作无效: 从不是创建控件“textBox3”的线程访问它。
这项报错是我 试图 将串口接收到的信息打印在richTextBox1组件时遇到的
解决方案 是在创建窗体时增加代码 禁止编译器对跨线程访问做检查:
Control.CheckForIllegalCrossThreadCalls = false;
查阅资料网址:
C#System.InvalidOperationException:“线程间操作无效: 从不是创建控件“textBox3”的线程访问它。” - 知乎
设置串口端口停止位波特率等时的数据强制类型转换规范:
串口接收触发异常:
在串口部分,每个属性的数据类型不太相同,所以赋值时需要注意一下
我们一般将combox下拉框中的text属性作为设置的相应值赋值给seriesport的某些属性,但数据类型不一定对应,所以赋值的时候需要作对应的强制类型转换:
对于停止位设置进入串口服务事件函数的相关问题,在以下代码注释中有所说明:
serialPort1.PortName = comboBox1.Text;//设置端口号
serialPort1.BaudRate = Convert.ToInt32(comboBox2.Text);//设置端口波特率
serialPort1.StopBits = (StopBits)Convert.ToInt32(comboBox3.Text);//设置停止位
serialPort1.DataBits = Convert.ToInt32(comboBox4.Text);//设置数据位
/* 一定要加上下面这句话。
* 意思是接收缓冲区其中假设有一个字节的话就出发接收函数。
假设不加上这句话,
那就有时候触发接收都发了好多次了也设有触发接收,有时候延时现象等等
*/
serialPort1.ReceivedBytesThreshold = 1;
serialPort1.DataReceived += new SerialDataReceivedEventHandler(serialPort1_DataReceived);
serialPort1.Open(); //打开串口
串口对象的一些常用属性赋值实例:
这也是我查阅网上资料获取的笔记摘录,为的是
SerialPort mySerialPort = new SerialPort("COM2");//端口
mySerialPort.BaudRate = 9600;//波特率
mySerialPort.Parity = Parity.None;//校验位
mySerialPort.StopBits = StopBits.One;//停止位
mySerialPort.DataBits = 8;//数据位
mySerialPort.Handshake = Handshake.Non;
mySerialPort.ReadTimeout = 1500;
mySerialPort.DtrEnable = true;//启用数据终端就绪信息
mySerialPort.Encoding = Encoding.UTF8;
mySerialPort.ReceivedBytesThreshold = 1;//DataReceived触发前内部输入缓冲器的字节数
mySerialPort.DataReceived += new SerialDataReceivedEvenHandler(DataReceive_Method);
mySerialPort.Open();//打开串口
串口发送信息:
Write(Byte[], Int32, Int32) :将指定数量的字节写入串行端口
Write(Char[], Int32, Int32) :将指定数量的字符写入串行端口
Write(String) :将指定的字符串写入串行端口
WriteLine(String) :将指定的字符串和NewLine值写入输出缓冲区
// Write a string
port.Write("Hello World");
// Write a set of bytes
port.Write(new byte[] { 0x0A, 0xE2, 0xFF }, 0, 3);
// Close the port关闭串口
port.Close();
串口接收信息:
Read(Byte[], Int32, Int32):从SerialPort输入缓冲区读取一些字节,并将那些字节写入字节数组中指定的偏移量处
ReadByte():从SerialPort输入缓冲区中同步读取一个字节
ReadChar(): 从SerialPort输入缓冲区中同步读取一个字符
ReadExisting() :在编码的基础上,读取SerialPort对象的流和输入缓冲区中所有立即可用的字节
ReadLine() :一直读取到输入缓冲区中的NewLine值
ReadTo(String) :一直读取到输入缓冲区中的指定value的字符串
查阅资料网址:
3、实际功能展示截图:
主要是逻辑正确的弹窗提示,弹窗是调用函数实现的:
MessageBox.Show("当前串口有设备连接,串口已成功打开", "串口发送提示");
打开串口检测端口有无设备:
关闭串口:
串口接收测试:
使用单片机发送字符串测试接收功能 :
接收测试成功,效果成功在richTextBox组件打印:
勾选16进制显示设置:
是否被勾选的判断语句如下示例:
//如果不是16进制发送,就直接string形式发送
if (!checkBox2.Checked)
清除接收区:
清除richTextBox的接收区可以直接调用函数:
richTextBox1.Clear();
4、在没有下位机情况下调试上位机串口的方法:
这里我使用虚拟串口软件,给电脑的COM3与COM4搭建了虚拟的串口连接:
软件下载地址如下:
如图使用软件对COM3与COM4进行虚拟连接:
使用SSCOM串口助手软件成功检测到COM3与COM4的虚拟连接:
发送测试:
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;
using System.Threading.Tasks;
using System.Windows.Forms;
using static System.Windows.Forms.VisualStyles.VisualStyleElement;
using static System.Windows.Forms.VisualStyles.VisualStyleElement.Button;
namespace Serial_Assistant_YZH
{
public partial class Form1 : Form
{
int CXk1 = 0;//蔡徐坤图片计数器
public Form1()
{
InitializeComponent();
serialPort1.Encoding = Encoding.GetEncoding("GB2312"); //串口接收编码
Control.CheckForIllegalCrossThreadCalls = false;
}
private void Form1_Load(object sender, EventArgs e)
{
for(int i=1;i<10;i++)//初始化串口号下拉框内容
{
comboBox1.Items.Add("COM" + i.ToString()); //添加串口
}
for (int H = 0; H < 5; H++)//初始化串口波特率下拉框内容
{
switch (H)
{
case 0: comboBox2.Items.Add("2400"); break;
case 1: comboBox2.Items.Add("4800"); break;
case 2: comboBox2.Items.Add("9600"); break;
case 3: comboBox2.Items.Add("115200"); break;
}
}
for(int j=0;j<3;j++)
{
switch (j)
{
case 0: comboBox3.Items.Add("1"); break;
case 1: comboBox3.Items.Add("1.5"); break;
case 2: comboBox3.Items.Add("2"); break;
}
}
comboBox1.Text = "COM1";//端口下拉框初始值
comboBox2.Text = "9600";//波特率下拉框初始值
comboBox3.Text = "1";//停止位
comboBox4.Text = "8";//数据位
serialPort1.Close(); //关闭串行端口连接
}
//数据接收显示
private void richTextBox1_TextChanged(object sender, EventArgs e){}
//打开串口
private void button1_Click(object sender, EventArgs e)
{
try
{
serialPort1.PortName = comboBox1.Text;//设置端口号
serialPort1.BaudRate = Convert.ToInt32(comboBox2.Text);//设置端口波特率
serialPort1.StopBits = (StopBits)Convert.ToInt32(comboBox3.Text);//设置停止位
serialPort1.DataBits = Convert.ToInt32(comboBox4.Text);//设置数据位
/* 一定要加上下面这句话。
* 意思是接收缓冲区其中假设有一个字节的话就出发接收函数。
假设不加上这句话,
那就有时候触发接收都发了好多次了也设有触发接收,有时候延时现象等等
*/
serialPort1.ReceivedBytesThreshold = 1;
serialPort1.DataReceived += new SerialDataReceivedEventHandler(serialPort1_DataReceived);
serialPort1.Open(); //打开串口
MessageBox.Show("当前串口有设备连接,串口已成功打开", "串口发送提示");
//按键状态置位
button1.Enabled = false;
button2.Enabled = true;
}
catch
{
MessageBox.Show("端口无设备连接", "错误警告");
}
}
//关闭串口
private void button2_Click(object sender, EventArgs e)
{
try
{
serialPort1.Close(); //关闭串口
//按键状态置位
button1.Enabled = true;
button2.Enabled = false;
MessageBox.Show("已关闭串口", "串口发送提示");
}
catch{}
}
private void label3_Click(object sender, EventArgs e){}
//单条发送数据
private void button3_Click(object sender, EventArgs e)
{
byte[] Data = new byte[1]; //单字节发数据
if (serialPort1.IsOpen)
{
if (textBox1.Text != "")
{
//如果不是16进制发送,就直接string形式发送
if (!checkBox2.Checked)
{
try
{
serialPort1.Write(textBox1.Text);
//serialPort1.WriteLine(); //字符串写入
}
catch
{
MessageBox.Show("串口数据写入错误", "错误");
}
}
else //数据模式
{
try //如果此时用户输入字符串中含有非法字符(字母,汉字,符号等等,try,catch块可以捕捉并提示)
{
for (int i = 0; i < (textBox1.Text.Length - textBox1.Text.Length % 2) / 2; i++)//转换偶数个
{
Data[0] = Convert.ToByte(textBox1.Text.Substring(i * 2, 2), 16); //转换
serialPort1.Write(Data, 0, 1);
}
if (textBox1.Text.Length % 2 != 0)
{
//单独处理最后一个字符
Data[0] = Convert.ToByte(textBox1.Text.Substring(textBox1.Text.Length - 1, 1), 16);
serialPort1.Write(Data, 0, 1);//写入
}
//Data = Convert.ToByte(textBox2.Text.Substring(textBox2.Text.Length - 1, 1), 16);
}
catch
{
MessageBox.Show("数据转换错误,请输入数字。", "错误");
}
}
}
}
}
//单条发送输入文本框
private void textBox1_TextChanged(object sender, EventArgs e)
{
}
//串口接收
//一个接收数据事件获取串口发送来的数据
private void serialPort1_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
{
//处理事件这块可以加上延时确保不定数的数据可以全部收到缓冲后,才去读缓冲内容--单位: 毫秒
Thread.Sleep(50);
//如果16进制转换没被勾选
if (!checkBox1.Checked)
{
richTextBox1.AppendText(serialPort1.ReadExisting()); //串口类会自动处理汉字,所以不需要特别转换
}
//如果16进制转换被勾选了
else
{
try
{
//定义缓冲区数组大小为串口缓冲区数据的字节数
//因为串口事件触发时有可能收到不止一个字节
byte[] data = new byte[serialPort1.BytesToRead];
serialPort1.Read(data, 0, data.Length);
foreach (byte Member in data) //遍历用法
{
string str = Convert.ToString(Member, 16).ToUpper();
richTextBox1.AppendText("0x" + (str.Length == 1 ? "0" + str : str) + " ");
}
}
catch { }
}
}
//蔡徐坤图片
private void pictureBox1_Click(object sender, EventArgs e)
{
int CXK = 0;
CXk1++;
CXK = CXk1 % 5;
switch(CXK)
{
case 0: MessageBox.Show("你干嘛~哎呦!", "蔡徐坤");label6.Text = "哎呦!"; break;
case 1: MessageBox.Show("唱跳、RAP、篮球、Music!", "蔡徐坤"); label6.Text = "篮球"; break;
case 2: MessageBox.Show("鸡你太美~Baby", "蔡徐坤"); label6.Text = "鸡你太美!"; break;
case 3: MessageBox.Show("练习时长两年半", "蔡徐坤"); label6.Text = "两年半!"; break;
case 4: MessageBox.Show("别点了,认真学习", "蔡徐坤"); label6.Text = "认真学习!"; break;
}
}
//清除接收区
private void button4_Click(object sender, EventArgs e)
{
richTextBox1.Clear();
MessageBox.Show("已清除接收区", "清除接收区");
}
//停止位
private void comboBox3_SelectedIndexChanged(object sender, EventArgs e){}
//数据位
private void comboBox4_SelectedIndexChanged(object sender, EventArgs e){}
//串口选择
private void comboBox1_SelectedIndexChanged(object sender, EventArgs e){}
//波特率选择
private void comboBox2_SelectedIndexChanged(object sender, EventArgs e){}
//
private void checkBox1_CheckedChanged(object sender, EventArgs e){}
//16进制发送按钮
private void checkBox2_CheckedChanged(object sender, EventArgs e){}
}
}
6、整体测试工程下载:
https://download.csdn.net/download/qq_64257614/89044991?spm=1001.2014.3001.5503