C#学习笔记5:简单上位机串口助手的实现
今日尝试使用C#进行 自己编写一款上位机串口助手:
文章提供源码、解释、测试效果、整体工程下载......
以下为串口助手的界面效果:
目录
1、功能设计与摆放控件:
2.遇到的报错解决与基本提示:
C#System.InvalidOperationException:“线程间操作无效: 从不是创建控件“textBox3”的线程访问它。
设置串口端口停止位波特率等时的数据强制类型转换规范:
串口接收触发异常:
串口对象的一些常用属性赋值实例:
串口发送信息:
串口接收信息:
3、实际功能展示截图:
4、在没有下位机情况下调试上位机串口的方法:
5、整体工程代码:
6、整体测试工程下载:
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的字符串
查阅资料网址:
C#实现串口通信解析_c#串口通讯-CSDN博客
3、实际功能展示截图:
主要是逻辑正确的弹窗提示,弹窗是调用函数实现的:
MessageBox.Show("当前串口有设备连接,串口已成功打开", "串口发送提示");
打开串口检测端口有无设备:
关闭串口:
串口接收测试:
使用单片机发送字符串测试接收功能 :
接收测试成功,效果成功在richTextBox组件打印:
勾选16进制显示设置:
是否被勾选的判断语句如下示例:
//如果不是16进制发送,就直接string形式发送if (!checkBox2.Checked)
清除接收区:
清除richTextBox的接收区可以直接调用函数:
richTextBox1.Clear();
4、在没有下位机情况下调试上位机串口的方法:
这里我使用虚拟串口软件,给电脑的COM3与COM4搭建了虚拟的串口连接:
软件下载地址如下:
https://download.csdn.net/download/qq_64257614/89044980
如图使用软件对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