注意:
1.上述窗体用到了按钮、Radio、Panel、GroupBox、TextBox、SerialPorts、ComboBox等控件,组件。
2.对于Panel、GroupBox控件,需要先插入。再插入其他控件。其中Panel一般是为了将Radio进行组合而使用。GroupBox是为了更明显的显示界面给用户。
3.其中TextBox一般只能横向拉伸,不能纵向拉伸,选择TsxtBox框上的黑色三角符号,然后勾选“MultiLine”之后,即可进行上下左右拉伸。其中为了让其出现滚动条可以在属性中选择“ScrollBars”。
2.窗体函数事件
2.1 窗体函数中直接进行初始化和设置
//窗体事件
private void Form1_Load(object sender, EventArgs e)
{
//对端口进行设置
for (int i = 1; i < 20; i++)
{
comboBox1.Items.Add("COM"+ i.ToString());
}
//对串口号、波特率进行默认值设置
comboBox1.Text = "COM1";
comboBox2.Text = "4800";
radioButton1.Checked = true; //函数中选择发送模式 为“数值”发送模式。 radioButton1为单选按钮属性(name)名字
radioButton3.Checked = true; //函数中选择接收模式 为“数值”接收模式。 radioButton3为单选按钮属性(name)名字
button1.Text = "打开串口"; //确保 “打开串口”按键文本属性为 “打开串口”
button2.Text = "关闭串口"; //确保 “关闭串口”按键文本属性为 “关闭串口”
}
主要是进行窗体初始化设置,下拉框设置,选择发送模式 和接收模式设置为“数值”模式。
2.2 在窗体函数中,只进行初始化,其他工作封装在一个函数中。
//窗体事件
private void Form1_Load(object sender, EventArgs e)
{
Updata_Serialport_Name(comboBox1); //调用更新可用串口函数,comboBox1为 端口 组合框名字
/*//对端口进行设置
for (int i = 1; i < 20; i++)
{
comboBox1.Items.Add("COM"+ i.ToString());
}*/
//对串口号、波特率进行默认值设置
comboBox1.Text = "COM1";
comboBox2.Text = "4800";
radioButton1.Checked = true; //函数中选择发送模式 为“数值”发送模式。 radioButton1为单选按钮属性(name)名字
radioButton3.Checked = true; //函数中选择接收模式 为“数值”接收模式。 radioButton3为单选按钮属性(name)名字
button1.Text = "打开串口"; //确保 “打开串口”按键文本属性为 “打开串口”
button2.Text = "关闭串口"; //确保 “关闭串口”按键文本属性为 “关闭串口”
//必须手动添加处理串口数据接收
//serialPort1.DataReceived += new EventHandler(this.Port_DataReceived);//SerialDataReceived
}
/*用户自定义更新可用串口函数*/
private void Updata_Serialport_Name(ComboBox MycomboBox)
{
//System.IO.Ports.SerialPort.GetPortNames()函数功能为获取计算机所有可用串口,以字符串数组形式输出
string[] ArryPort = System.IO.Ports.SerialPort.GetPortNames(); //定义字符串数组,数组名为 ArryPort,将可用的串口信息存放在字符串中
MycomboBox.Items.Clear(); //清除当前组合框下拉菜单内容
for (int i = 0; i < ArryPort.Length; i++)
{
MycomboBox.Items.Add(ArryPort[i]); //将所有的可用串口号添加到端口对应的组合框中
}
}
注意:
1.System.IO.Ports.SerialPort.GetPortNames()函数功能为获取计算机所有可用串口,以字符串数组形式输出。可简写为SerialPort.GetPortNames()。但要加using System.IO.Ports;命名空间
2.MycomboBox.Items.Add()在MycomboBox控件下添加下拉信息。
3.Updata_Serialport_Name()该函数类似于串口扫描函数。
//串口数据信息接收
private void Port_DataReceived(object sender, SerialDataReceivedEventArgs e)//SerialDataReceived
{
//接收方式为字符模式,字符方式读
//Checked:获取或设置一个值,该值指示是否已选中控件。
if (!radioButton3.Checked)
{
//字符串方式读缓冲区中的数据
string str = serialPort1.ReadExisting();
//把读取的数据添加至接收区。AppendText():向文本框的当前文本追加文本。
textBox2.AppendText(str);
}
//接收方式为数值模式,数值方式读
else
{
byte data;
//ReadByte()从 System.IO.Ports.SerialPort 输入缓冲区中同步读取一个字节。返回:强制转换为 System.Int32 的字节;或者,如果已读取到流的末尾,则为 -1。
//因为函数ReadByte()的返回值为int,因此要转换强制转换为byte。
data = (byte)serialPort1.ReadByte();
//Convert.ToString() 将 8 位无符号整数的值转换为其等效的指定基数的字符串表示形式。
// 参数:
// value:要转换的 8 位无符号整数。
// toBase:返回值的基数,必须是 2、8、10 或 16。
// 返回结果: 以 toBase 为基数的 value 的字符串表示形式。
//转换为大写十六进制字符串
string str = Convert.ToString(data, 16).ToUpper();
//对单个值,进行补0
textBox2.AppendText("0x" + ((str.Length == 1) ? "0" + str : str));
/*
if (str.Length == 1)
{
str = "0" + str;
}
else
{
str = str;
}
textBox2.AppendText("0x" + str);
*/
}
注意:
1.Checked:获取或设置一个值,该值指示是否已选中控件。
2.AppendText():向文本框的当前文本追加文本。
3.ReadByte()从 System.IO.Ports.SerialPort 输入缓冲区中同步读取一个字节。返回:强制转换为 System.Int32 的字节;或者,如果已读取到流的末尾,则为 -1。
4.Convert.ToString() 将 8 位无符号整数的值转换为其等效的指定基数的字符串表示形式。
参数:
4.1 value:要转换的 8 位无符号整数。
4.2 toBase:返回值的基数,必须是 2、8、10 或 16。
返回结果:
以 toBase 为基数的 value 的字符串表示形式。
4.打开按钮
private void button1_Click(object sender, EventArgs e)
{
try
{
//在打开串口之前获取串口号和波特率
serialPort1.PortName = comboBox1.Text;
//转换为10进制,10可省略
serialPort1.BaudRate = Convert.ToInt32(comboBox2.Text,10);
//打开串口
serialPort1.Open();
//打开串口按钮不可用,变成灰色
button1.Enabled = false;
//关闭串口按钮可用。
button2.Enabled = true;
}
catch
{
MessageBox.Show("端口错误,请检查串口","打开串口错误");
}
}
打开按钮后,打开按钮图标变灰色,不可用。关闭按钮图标可用。
5.关闭按钮
private void button2_Click(object sender, EventArgs e)
{
try
{
//关闭串口
serialPort1.Close();
//打开串口按钮可用
button1.Enabled = true;
//关闭串口按钮不可用,变成灰色
button2.Enabled = false;
}
catch
{
//一般关闭串口不出错,此处对程序不进行处理
}
}
6.发送按钮,实现串口的发送功能,从字符和数值两个模式进行撰写。
private void button3_Click(object sender, EventArgs e)
{
byte[] data = new byte[1];
// IsOpen :获取一个值,该值指示 System.IO.Ports.SerialPort 对象的打开或关闭状态。
// 返回结果: 如果串行端口已打开,则为 true;否则为 false。 默认值为 false。
if (serialPort1.IsOpen)//串口打开
{
//发送框不能为空
if (textBox1.Text != "")
{
//发送模式为字符模式
if (!radioButton1.Checked)
{
try
{
//将发送的数据存在于缓冲区
serialPort1.WriteLine(textBox1.Text);
}
catch(Exception err)
{
MessageBox.Show("串口数据写入错误", "发送错误");
}
}
//发送模式为数值模式
else
{
try
{
//文本数据长度
int dataLength = textBox1.Text.Length;
//判断本本个数是奇数还是偶数
int dataRemain = textBox1.Text.Length % 2;
//(dataLength - dataRemain)/2 十六进制发送时,看有几个字节。
//处理前length-1个数据
for (int i = 0; i < (dataLength - dataRemain)/2; i++)
{
// Substring():
// 从此实例检索子字符串。 子字符串从指定的字符位置开始且具有指定的长度。
// 参数:
// startIndex:
// 此实例中子字符串的起始字符位置(从零开始)。
// length:
// 子字符串中的字符数。
// 返回结果:
// 与此实例中在 startIndex 处开头、长度为 length 的子字符串等效的一个字符串,如果 startIndex 等于此实例的长度且 length
// 为零,则为 System.String.Empty。
data[0] = Convert.ToByte(textBox1.Text.Substring(i*2,2),16);//将获取的数值转换为十六进制每两位两位存入data[0]这个字节中
//Convert.ToByte():
//将指定基数的数字的字符串表示形式转换为等效的 8 位无符号整数。
// 参数:
// value:
// 包含要转换的数字的字符串。
// fromBase:
// value 中数字的基数,它必须是 2、8、10 或 16。
// 返回结果:
// 与 value 中数字等效的 8 位无符号整数,如果 value 为 null,则为 0(零)。
serialPort1.Write(data, 0, 1);//循环发送每一个字节,如abc则发0xab
// Write(data, 0, 1):
// 使用缓冲区的数据将指定数量的字节写入串行端口。
// 参数:
// buffer:
// 包含要写入端口的数据的字节数组。
// offset:
// buffer 参数中从零开始的字节偏移量,从此处开始将字节复制到端口。
// count:
// 要写入的字节数。
}
//处理奇数个数据的最后一位
if(textBox1.Text.Length % 2 != 0)
{
//将最后一位转换为十六进制数据存入data中。
data[0] = Convert.ToByte(textBox1.Text.Substring(textBox1.Text.Length-1, 1),16);
//发送最后一位
serialPort1.Write(data, 0, 1);
}
}
catch (Exception err)
{
MessageBox.Show("发送数据错误", "发送错误");
}
}
}
}
}
注意:
- Substring():
从此实例检索子字符串。 子字符串从指定的字符位置开始且具有指定的长度。
参数:
startIndex:此实例中子字符串的起始字符位置(从零开始)。
length:子字符串中的字符数。
返回结果:
与此实例中在 startIndex 处开头、长度为 length 的子字符串等效的一个字符串,如果 startIndex 等于此实例的长度且 length为零,则为 System.String.Empty。
2.Convert.ToByte():
将指定基数的数字的字符串表示形式转换为等效的 8 位无符号整数。
参数:
value:包含要转换的数字的字符串。
fromBase:value 中数字的基数,它必须是 2、8、10 或 16。
返回结果:
与 value 中数字等效的 8 位无符号整数,如果 value 为 null,则为 0(零)。
3.Write(data, 0, 1):
使用缓冲区的数据将指定数量的字节写入串行端口。
参数:
buffer:包含要写入端口的数据的字节数组。
offset:buffer 参数中从零开始的字节偏移量,从此处开始将字节复制到端口。
count:要写入的字节数。
4.IsOpen :
获取一个值,该值指示 System.IO.Ports.SerialPort 对象的打开或关闭状态。
返回结果:
如果串行端口已打开,则为 true;否则为 false。 默认值为 false。
7.文本框,将滚动条调整至当前位置
private void textBox1_TextChanged(object sender, EventArgs e)
{
//将滚动条调整至当前位置。
textBox1.ScrollToCaret();
}
private void textBox2_TextChanged(object sender, EventArgs e)
{
textBox2.ScrollToCaret();
}
8.清空接收文本
private void button4_Click(object sender, EventArgs e)
{
textBox2.Text = "";
}
1.C#上位机(简单实现串口发送).
2.C#上位机(定时器计数).