C#写一个串口助手

tech2024-10-15  1

最近一段时间开始学C#,可看的书再多也还是需要自己动手实践,才能夯实基础,于是就从基本的串口助手开始。用零零散散的时间,从零到整的做了个串口助手。以下是对串口建立到完成的一个回顾总结,加深印象。界面大致效果如下

我用的接收控件是RichTextBox   其他的大都是TextBox  CheckBox  CheckListBox  以及 menStrip  statusStrip Button  Timer

定时器我用了三个  一个是刷新下方标签的   一个是定时发送的     还有一个用来接收完整数据包(下面会有说明)

获取串口号

string[] str = SerialPort.GetPortNames(); if (str.Length == 0) { MessageBox.Show("当前未检测到串口"); return; } else { foreach(string s in System.IO.Ports.SerialPort.GetPortNames()) //遍历本机串口,加到下拉框 { cbSerial.Items.Add(s); } cbSerial.SelectedIndex = 0; //默认选择第一个 } //在窗体加载中执行,也可以另外使用按键或定时刷新执行这段代码

串口的其他参数

如 数据位 停止位 奇偶校验位 波特率 以及串口的一些超时之类的,可以在设计界面直接指定也可,或者程序运行再执行也可,不

再过多赘述了

 发送数据格式

十六进制发和ascii字符模式  字符串模式可以直接用文本框内容 通过发送指令发送出去。十六进制模式需要将文本框内容进行适当的转化

public class GlbNum { public static Form1 frm1; public enum jiaoyan //校验的枚举 { none=0, crc16 }; public static byte[] htb(string s) //字符转十六进制方法 { s = s.Replace(" ", ""); //丢弃空格和换行 s = s.Replace("\r\n", ""); byte[] buffer = new byte[s.Length / 2]; if (s.Length % 2 == 0) //字符串成偶数情况下 { for (int i = 0; i < s.Length; i += 2) buffer[i / 2] = (byte)Convert.ToByte(s.Substring(i, 2), 16); } else //奇数情况下需要丢弃最后一个字符 { for (int i = 0; i < s.Length-1; i += 2) buffer[i / 2] = (byte)Convert.ToByte(s.Substring(i, 2), 16); } return buffer; } }

我的全局变量,方便下面程序的阅读

bool isOpen = false; //串口状态标志位 long sendDataCnt = 0; //发送数据量 long receiveDataCnt = 0; //接收数据量 string timeMs; //时间戳的字符串 byte[] sendArr; //十六进制发送数组 会配合局部变量sendArr2 -》校验后的数组 byte[] a1 = new byte[2]; //modbus 校验位 char[] cc; //字符串发送数组 StringBuilder dataReceive = new StringBuilder(); //两个stringbuiler 用来在时间戳接收发送用,用以显示分包数据 StringBuilder dataSend = new StringBuilder(); GlbNum.jiaoyan cmpBit = GlbNum.jiaoyan.none; //校验状态 初始化为0 int cmPar = 0; //前一次的接收数据量,用以下次比较 来获得完整数据

串口发送(HEX)

sendArr = GlbNum.htb(tbSend.Text.ToString()); try { serialPort1.Write(sendArr2, 0, sendArr2.Length); } //这里就很简单了,将文本转化为十六进制,然后通过serialport的 Write方法发送 //还有writeline发送 这个会多发送一个换行 视情况而定 使用任意方法; catch(Exception ex) { MessageBox.Show(ex.Message.ToString()); sendtimer.Enabled = false; cbtime.Checked = false; serialPort1.Close(); btnOpen.Text = "打开串口"; return; } //异常里就是输出下异常信息,并复位下串口的一些变量之类的

串口发送文本的话,就直接发送文本框的字符串即可。

cc = tbSend.Text.ToCharArray(); serialPort1.Write(cc, 0, cc.Length);

串口接收(接收完整的数据包)

我在调试时,用的是个串口模块将其 txd与rxd短接,调试接收数据,都是完整的没问题,可实际接到别的串口设备,接收通讯的时候就出现了,在时间戳开启模式下,我发现数据收过来是被分割显示了的,即串口接收中断产生了,可是接收还未完成,你就已经执行了接收中断里的数据分析了,才会导致这类问题。

在这里我采用了定时器查询的方法。  接收中断产生,先读当前采集数据量,并打开定时器,等待一段时间后,在定时器tick事件里再读一次数据量,两者比较 ,如果不一致则代表,数据接收未完成,一致则代表完成 ,然后开始处理,串口接收到的数据。

串口接收中断事件 private void serialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e) { cmPar = serialPort1.BytesToRead; //先取一次值 timer2.Enabled = true; timer2.Start(); //开启定时器 判断数据接收 } 定时器2的tick事件 private void timer2_Tick(object sender, EventArgs e) { if (isOpen) { int temp = serialPort1.BytesToRead; //再次读取数据量 if (temp == 0) return; else { if (temp == cmPar) //非0则与第一次比较 一致则进入 { //添加用户处理代码 } } } }

数据接收     分为16进制接收和字符串接收     使用方法  toString(“X2")

if (cbHexreceive.Checked) //十六进制显示 { foreach (byte b in rcArr) { dataReceive.Append(b.ToString("X2")); dataReceive.Append(b.ToString(" ")); //便于阅读添加 空格 } rtbReceive.AppendText(dataReceive.ToString()); //显示到接收框 } else //ascii显示 { foreach (byte b in rcArr) { dataReceive.Append((char)b); } rtbReceive.AppendText(dataReceive.ToString()); }

至此,一个简单的串口发送接收就可以实现了。我这边还加了时间戳和一个modbus的校验以及接收数据的保存,代码就不贴了。

在串口程序里,最好放置一些捕获异常的语句,来消除硬件上改变带来的程序的影响。可以大大提供的程序运行的效率。

 

最新回复(0)