1、UI设计
用到的控件如下:textbox,label,button,自定义控件(圆形状的灯),checkbox,serialport。UI布局如下。
2、逻辑设计
2.1串口参数初始化设计
在讲程序编写之前,需要先说明一下串口通讯的参数分为哪几个。串口参数一般有端口号,波特率,校验位,数据位,停止位这几种。
端口号,端口号指的是硬件的USB或者DB9的硬件接口接入到你电脑上后,电脑设备管理器显示的COMX。
波特率,波特率简单的说就指的是串口字节发送的速率,一般来讲,最好两个串口之间的波特率设定值设成一样是最好的。
校验位,校验位的作用是让数据在远距离传输的时候,排查干扰用的。近距离传输或者干扰小的情况下,可以不用。一般来讲,外面的串口助手,校验位有三个选项,无,奇校验,偶校验。
无:不用校验位
奇偶校验:在发送完一个字节后,会再多发送一个位,这个校验位分高电平或者低电平。如果是奇校验,则这个校验位是1,同时你前面发送的一个字节里面包含的1的个数加上这个校验位要为奇数,否则不通过。偶校验则是不包含校验位,只算发送的一个字节里面的1的个数是否为偶数。
PS:我是与雷赛电机通讯的,我需要用到的是CRC校验,这个你们能去网上找现成的CRC转化工具,或者自己去搜索相关原理。
数据位:数据位指的是你发送的数据是以多少位去发送的。
停止位:停止位指的是你发送完数据后,需要间隔多少位的时间在发送下一个。
下面就来看看串口参数初始化模块的代码是怎么样的。
关于串口初始化的设置我是把它放在Serial页面加载的事件中的。前三行代码你们也可以不写,这个主要是为了获取当前电脑已经连接的物理或者虚拟串口端口号用的。
private void Serial_Load(object sender, EventArgs e)
{
//获取当前电脑所拥有的端口号
string[] ports = System.IO.Ports.SerialPort.GetPortNames();
//AddRange() 是ComboBox控件添加集合的一个函数
comboBox_PortNum.Items.AddRange(ports);
//SelectedIndex当前索引的值,如果没有选择则是负数,如果combobox的当前选择索引值是负数,那它就空白的。
comboBox_PortNum.SelectedIndex = comboBox_PortNum.Items.Count > 0 ? 0 : -1;
//串口设置初始化
comboBox_bitflow.Text = "38400";
comboBox_databit.Text = "8";
comboBox_stopbit.Text = "1";
comboBox_checkbit.Text = "无";
}
2.2串口打开或者关闭功能
下面是我对这个按钮绑定世界编写的程序
private void btn_OpenOrClose_Click(object sender, EventArgs e)
{
if (btn_OpenOrClose.Text=="打开串口")
{
try
{
serialPort1.PortName = comboBox_PortNum.SelectedItem.ToString();//端口号赋值
serialPort1.BaudRate = int.Parse(comboBox_bitflow.SelectedItem.ToString());//波特率赋值
serialPort1.DataBits = int.Parse(comboBox_databit.SelectedItem.ToString());//数据位赋值
switch (comboBox_stopbit.ToString())
{
case "1":
serialPort1.StopBits = StopBits.One;
break;
case "1.5":
serialPort1.StopBits = StopBits.OnePointFive;
break;
case "2":
serialPort1.StopBits = StopBits.Two;
break;
default:
break;
}
switch (comboBox_checkbit.ToString())
{
case "无":
serialPort1.Parity = Parity.None;
break;
case "奇校验":
serialPort1.Parity = Parity.Odd;
break;
case "偶校验":
serialPort1.Parity = Parity.Even;
break;
default:
break;
}
serialPort1.Open();//串口连接函数
btn_OpenOrClose.Text = "关闭串口";
//串口灯
circle1.Color = Color.Green;//自定义控件(灯)
circle1.Invalidate();
}
catch (Exception err)
{
MessageBox.Show("串口打开失败"+err.ToString(),"提示");
}
}
else
{
try
{
serialPort1.Close();//串口关闭函数
btn_OpenOrClose.Text = "打开串口";
circle1.Color = Color.Red;
circle1.Invalidate();
}
catch (Exception)
{
throw;
}
}
}
PS:经过对比各类串口助手后的出来的结果:
串口通讯的时候,各个串口软件都是互发ASCII码(十进制),比如说textbox里面填写的是"a",那么串口助手就会发送字符a对应的ASCII码(十进制)给对方,但是串口软件如果勾选了16进制发送,那么它就会把TextBox里面的内容直接换算成十六进制发送出去,比如说文本框里面写的是"16",那它就会发送\u0016出去.但是如果没有勾选十六进制,它则是发送1 和6 这两个字符对应的ASCII出去
2.3串口发送函数(16进制发送或者字符发送)
2.3.1发送按钮绑定的事件函数的程序内容
private void btn_Send_Click(object sender, EventArgs e)
{
try
{
if (checkbox_HEXSend.Checked)//勾选了十六进制的情况下执行
{
string[] s = textBox_serialSend.Text.Split(' ');//以字符串里面空格为模板截取字符串数组
byte[] b = new byte[s.Length];
for (int i = 0; i < s.Length; i++)
{
b[i] = byte.Parse(s[i],System.Globalization.NumberStyles.HexNumber);//把字符串按照指定样式转化为byte。
}
else//不勾选了十六进制的情况下执行
{
serialPort1.Write(b,0,b.Length);//发送字节
return;
}
}
serialPort1.Write(textBox_serialSend.Text);//发送字节
textBox_showTNum.Text = "TX:"+(++txNum);
}
catch (Exception e1)
{
MessageBox.Show(e1.ToString());
}
}
2.3串口助手接收数据部分
十六进制显示选项
接收文本显示框
接收部分的代码如下
private void serialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
int SerialByteLenth = serialPort1.BytesToRead;//获取此次接收缓冲区收到的字节数量
byte[] SerialData = new byte[SerialByteLenth];//创建对应长度的字节数组
serialPort1.Read(SerialData,0,SerialByteLenth);//读到的是十进制的ASCII
string SerialStr=Encoding.Default.GetString(SerialData);//转为16进制的字符串编码如1就转为\u0001
if (checkbox_Hexshow.Checked)//如果勾选了十六进制显示则执行下面的
{
string s = ByteToHex(SerialData);//把十进制的数值转化为16进制,比如11就变成A,12就变成B
Invoke(new Action(() => { textBox_serialRecive.AppendText(s); textBox4_showRNum.Text = "RX:" + (++rxNum); }));
return;
}
Invoke(new Action(() => { textBox_serialRecive.AppendText(SerialStr); textBox4_showRNum.Text = "RX:" + (++rxNum); }));serialport这个控件是在子线程,要访问主线程控件需要这么写。
}
//把字节里面的数值转化为十六进制
private string ByteToHex(byte[] b)
{
string returnStr = string.Empty;
try
{
if (b != null)
{
foreach (byte item in b)
{
if (item <16)
{
returnStr += "0";
returnStr += item.ToString("X");//把byte以十六进制显示,比如11就变成A
returnStr += ' ';
continue;
}
returnStr += item.ToString("X");//把byte以十六进制显示
returnStr += ' ';
}
}
}
catch (Exception )
{
return returnStr;
}
return returnStr;
}
PS:显示字符接收和发生数量的功能暂未完善,就先不写上去了。
还要一点在编写的过程中要注意,C#的char类型是有符号类型的,及其所能存储的数字最大是7f,所以我们在发送的时候尽量不要用char去存储。
2.4接收区清零按钮
代码如下
private void btn_RecDataZero_Click(object sender, EventArgs e)
{
textBox_serialRecive.Text = "";
}
2.5发送/接收字符数量区域清零按钮(未完善)
代码如下
private void bnt_Zero_Click(object sender, EventArgs e)
{
txNum = 0;
rxNum = 0;
textBox4_showRNum.Text = "RX:0";
textBox_showTNum.Text = "TX:0";
}
未完待续......