串口调试助手应该都比较熟悉了,主要用于和下位机通信(如单片机),使用的通信协议就是串口通讯协议。首先先介绍下这个协议。
串口通信属于异步的串行通信,有如下几个特点。
1 . 物理上的连线至少三根,分别是tx数据发送线,rx数据接收线,GND共用的地线
2. 0与1的约定。RS232电平,约定﹣5V至﹣25V之间的电压信号为1,﹢5V至﹢25V之间的电压信号为0 。TTL电平,约定5V的电压信号为1,0V电压信号为0 。CMOS电平,约定3.3V的电压信号为1,0V电压信号为0 。其中,CMOS电平一般用于ARM芯片中。
3. 发送的顺序,串口是LSB->MSB
4. 波特率,收发双方共同约定的一个数据位(0或1)在数据传输线上维持的时间。也可理解为每秒可以传输的位数。常用的波特率有2400,9600,14400,19200,115200等。
5. 通信协议,串口通信分为起始位,数据位,校验位,停止位,时序如下图所示。
编程语言我使用的是C#,C#对这种桌面的图形化编程有着很好的支持,可以迅速编写一些桌面的小工具。
IDE使用visual studio 2015。
1.串口类的使用
串口的库C#已经为我们编写好了 我们可以直接使用,配置如下
serialPort1.BaudRate = Convert.ToInt32(comboBox2.Text);
serialPort1.PortName = comboBox1.Text;
serialPort1.StopBits = (StopBits)Convert.ToInt32(stopBox.Text);
serialPort1.DataBits = Convert.ToInt32(dataBox.Text);
serialPort1.Parity = (Parity)0;
//解决中文乱码的问题
serialPort1.Encoding = System.Text.Encoding.GetEncoding("GB2312");
serialPort1.Open();
设置串口通信的几个重点参数,如数据位,奇偶校验位,停止位,波特率等,同时设置
了串口的编码为GB2312,这样就能解决中文乱码的问题。
为了实时获取可用的端口号,可使用一个定时器,1s更新一次可用串口列表
string[] ports = SerialPort.GetPortNames();//获得可用串口列表
string selectCom = comboBox1.Text;
//更新可用串口列表
if (comboBox1.Items.Count > 0)
{
comboBox1.Items.Clear();
}
foreach (string port in ports)
{
comboBox1.Items.Add(port);
if (port.Equals(selectCom))
{
comboBox1.Text = selectCom;
}
}
配置好了后就可以添加数据接收事件,编写数据接收函数
serialPort1.DataReceived += new SerialDataReceivedEventHandler(serialPort1_DataReceived);
最简单的串口调试助手到此就完成了,不过我们可以再添加一些小功能。
串口调试助手都是和底层通信,那么经常使用的就是十六进制的数据,所以我们编写字符串转16进制和16进制转字符串这两个函数。
public static String stringToOxTool(String str)
{
StringBuilder sb = new StringBuilder();
Encoding gb = Encoding.GetEncoding("GB2312");
//按照GB2312的编码方式把字符串转换为byte型数据
byte[] values = gb.GetBytes(str);
foreach (byte item in values)
{
int value = Convert.ToInt32(item);
//对每个数据按照16进制去格式化
string newstr = String.Format("{0:X}", value) + " ";
sb.Append(newstr);
}
return sb.ToString();
}
public static String oxToStringTool(String str)
{
List<byte> list = new List<byte>();
StringBuilder sb = new StringBuilder();
String[] data= str.Split(' ');
Encoding gb = Encoding.GetEncoding("GB2312");
foreach (String item in data)
{
if (item == " ")
{
list.Add(0x20);
}
else if (item == "\r")
{
list.Add(0x0d);
}
else if (item == "\n")
{
list.Add(0x0a);
}
else
{
try
{
byte value = Convert.ToByte(item, 16);
list.Add(value);
}
catch
{
list.AddRange((gb.GetBytes(item)));
}
}
}
return gb.GetString(list.ToArray());
}
如果发送的过程是在主线程里运行的话,那么发送大文件时就会导致界面无法点击,所以数据的发送新建一个从线程,让数据在后台发送。
Thread t = new Thread(sendDataThread);
t.Start();
private void sendDataThread()
{
String str = sendDataBox.Text;
//如果数据是16进制格式的先转换为字符串格式
if (send_0x.Checked)
{
str = tool.oxToStringTool(sendDataBox.Text);
}
/*
按换行符去分割字符串,
即存在多行数据分行发送
*/
String[] data = str.Split('\n');
for (int i = 0; i < data.Length; i++)
{
//如果存在\r符,则得到它的位置并删除
int pos = data[i].LastIndexOf('\r');
if (pos != -1)
{
sendData(data[i].Remove(pos));
}
else
{
sendData(data[i]);
}
//发送间隔
Thread.Sleep(20);
}
}
一些发送的配置本来打算使用xml文件,不过搜索了下发现C#自己有一个设置文件,非常好用,而且配置方便。直接新建设置文件,然后配置就能在程序里使用了
//初始化时从设置文件中读取历史配置值
comboBox2.Text = config.Default.portBps;
sendDataBox.Text = config.Default.sendDataText;
stopBox.Text = config.Default.portStop;
dataBox.Text = config.Default.portData;
checkoutBox.Text = config.Default.portCheck;
comboBox1.Items.Add(config.Default.com);
comboBox1.Text = config.Default.com;
sendPeriodValue.Text = config.Default.periodValue.ToString();
sendNewLineBox.Checked = config.Default.sendNewLineFlag;
send_0x.Checked = config.Default.hexSendFlag;
hexShowBox.Checked = config.Default.hexSendFlag;
timeTickBox.Checked = config.Default.timeTickFlag;
checkBox2.Checked = config.Default.rxBoxBkColor;
//在窗口关闭事件中把配置数据保留下来
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
//保存数据
config.Default.Save();
}
代码托管地址: https://github.com/yuanluw/princomputer