一、winform页面设计
toolStripStatusLabel共添加了7个,“初始化正常”命名为state_tssl、“0”分别命名为:sencount_tssl、recivecount_tssl
二、功能实现
2.1 串口设置
在页面初始化时,加载串口信息,将打开串口和关闭串口放在同一个按钮中实现
private void Form1_Load(object sender, EventArgs e)
{
SerialLoad();
}
private void SerialLoad()
{
EncodingInfo[] encodingInfos = Encoding.GetEncodings();
RegistryKey keyCom = Registry.LocalMachine.OpenSubKey(@"Hardware\DeviceMap\SerialComm");
string[] sSubKeys = keyCom.GetValueNames();
port_cbb.Items.Clear();
foreach (var sValue in sSubKeys)
{
string portName = (string)keyCom.GetValue(sValue);
port_cbb.Items.Add(portName);
}
this.port_cbb.SelectedIndex = 0;
this.baud_cbb.SelectedIndex = 1;
this.check_cbb.SelectedIndex = 0;
this.databit_cbb.SelectedIndex = 3;
this.stopbit_cbb.SelectedIndex = 0;
}
private bool Comconnect = false;
private void open_btn_Click(object sender, EventArgs e)
{
try
{
if (serialPort1.IsOpen == false)
{
serialPort1.PortName = port_cbb.Text;
serialPort1.BaudRate = Convert.ToInt32(baud_cbb.Text);
serialPort1.DataBits = Convert.ToInt32(databit_cbb.Text);
switch (check_cbb.SelectedIndex)
{ // none odd even
case 0:
serialPort1.Parity = Parity.None;
break;
case 1:
serialPort1.Parity = Parity.Odd;
break;
case 2:
serialPort1.Parity = Parity.Even;
break;
default:
serialPort1.Parity = Parity.None;
break;
}
switch (stopbit_cbb.SelectedIndex)
{ // 1 1.5 2
case 0:
serialPort1.StopBits = StopBits.One;
break;
case 1:
serialPort1.StopBits = StopBits.OnePointFive;
break;
case 2:
serialPort1.StopBits = StopBits.Two;
break;
default:
serialPort1.StopBits = StopBits.One;
break;
}
serialPort1.Open();
state_tssl.Text = $"{serialPort1.PortName}已打开!";
Comconnect = true;
Open_btn.Text = "关闭串口";
Open_btn.ForeColor = Color.Red;
}
else
{
serialPort1.Close();
Comconnect = false;
Open_btn.Text = "打开串口";
state_tssl.Text = $"{serialPort1.PortName}已断开!";
Open_btn.ForeColor = Color.Green;
}
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString() + serialPort1.PortName.ToString());
}
}
2.2 接收设置
声明两个只读的List<byte>
,用于存储在网络通信过程中接收和发送的数据。List<byte>
是一个可以存储多个字节类型数据的集合是可以存储多个字节类型数据的集合。
private readonly List<byte> reciveBuffer = new List<byte>();
private readonly List<byte> sendBuffer = new List<byte>();
两个整数,用以收发计数
private int reciveCount = 0;
private int sendCount = 0;
2.1.1 计数清空
1.
private void cleancount_tssl_Click(object sender, EventArgs e)
{
// 清空发送
sendBuffer.Clear();
sendCount = 0;
sencount_tssl.Text = "0";
// 清空接收
reciveBuffer.Clear();
recive_rtb.Text = "";
reciveCount = 0;
recivecount_tssl.Text = "0";
}
2.“手动清空”
private void clear_btn_Click(object sender, EventArgs e)
{
recive_rtb.Text = "";
reciveBuffer.Clear();
reciveCount = 0;
recivecount_tssl.Text = "0";
}
3. “自动清空”
添加定时器timer1触发事件,每100ms触发一次,当接收到的字节数超过4096时,就清空接收缓冲区、接收计数从0开始、接收区的内容清空。
选中“自动清零”:定时器开始,取消:定时器停止
private void timer1_Tick(object sender, EventArgs e)
{
if (recive_rtb.Text.Length > 4096)
{
reciveBuffer.Clear();
recive_rtb.Text = "";
recivecount_tssl.Text = "0";
}
}
private void autoclear_chb_CheckedChanged(object sender, EventArgs e)
{
if (autoclear_chb.Checked)
{
timer1.Start();
}
else
{
timer1.Stop();
}
}
2.1.2 暂停接收
声明一个bool:isRxShow,只有当isRxShow==true时,才显示接收缓冲区的内容
private bool isRxShow = false;
“暂停接收”
private void stop_btn_Click(object sender, EventArgs e)
{
if (isRxShow == true)
{
isRxShow = false;
stop_btn.Text = "取消暂停";
}
else
{
isRxShow = true;
stop_btn.Text = "暂停";
}
}
2.1.3 接收事件
1、添加SerialPort1的接收事件
private void serialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
if (isRxShow == false) return;
try
{
String result = null;
byte[] dataTemp = new byte[serialPort1.BytesToRead];
serialPort1.Read(dataTemp, 0, dataTemp.Length);
reciveBuffer.AddRange(dataTemp);
reciveCount += dataTemp.Length;
this.Invoke(new EventHandler(delegate
{
for (int i = 0; i < dataTemp.Length; i++)
{
if (recivehex_chb.Checked == false)
{//转为16进制
result = Encoding.GetEncoding("gb2312").GetString(dataTemp);
}
else
{
result += (dataTemp[i].ToString("X2") + " ");
}
}
recive_rtb.AppendText(result + "\r");
recivecount_tssl.Text = reciveCount.ToString();
// 滚动到最新行
recive_rtb.SelectionStart = recive_rtb.Text.Length;
recive_rtb.ScrollToCaret();
}));
}
catch(Exception ex)
{
MessageBox.Show(ex.Message);
}
}
2.“十六进制显示”
private void recivehex_chb_CheckedChanged(object sender, EventArgs e)
{
if (recive_rtb.Text == "") return;
if (recivehex_chb.Checked==true)
{
string result = null;
byte[] dataTemp = new byte[serialPort1.BytesToRead];
reciveBuffer.AddRange(dataTemp);
for (int i = 0; i < dataTemp.Length; i++)
{
result += (dataTemp[i].ToString("X2") + " ");
}
recive_rtb.Text = result;
}
else
{
recive_rtb.Text = Encoding.GetEncoding("gb2312").GetString(reciveBuffer.ToArray()).Replace("\0", "\\0");
}
}
因为recive_rtb(接收区文本框)显示内容是FORM1的线程,而串口接收信息是另一个线程,为了避免跨线程操作时报错。
将检查跨线程操作至false(Control.CheckForIllegalCrossThreadCalls
属性用于控制控件是否检查跨线程调用)
public Form1()
{
InitializeComponent();
Control.CheckForIllegalCrossThreadCalls = false;
}
2.1.4 保存数据
添加了一个对话框 saveFileDialog1,用以提示保存文件的地址。
private void bcsj_btn_Click(object sender, EventArgs e)
{
if (recive_rtb.Text == "")
{
return;
}
try
{ //设置保存文件的格式
saveFileDialog1.Filter = "文本文件(*.txt)|*.txt";
if (saveFileDialog1.ShowDialog() == DialogResult.OK)
{
//使用“另存为”对话框中输入的文件名实例化StreamWriter对象
StreamWriter sw = new StreamWriter(saveFileDialog1.FileName, true);
//向创建的文件中写入内容
sw.WriteLine(recive_rtb.Text);
//关闭当前文件写入
sw.Close();
}
}
catch(Exception ex)
{
MessageBox.Show(ex.Message);
}
}
2.1.5 结果显示
2.3 单条发送
发送区想法做了一点点改变,保留了历史发送数据。用了两个文本框,一个用来写要发送的内容,另一个显示以往发送的内容。
2.3.1 清空发送
”清空“发送区内容,清空发送缓存,计数归零
private void clearSend_btn_Click(object sender, EventArgs e)
{
send_rtb.Clear();
sendBuffer.Clear();
sendCount = 0;
sencount_tssl.Text = "0";
}
2.3.2 发送(单条单次)
发送”tb_send"中的内容,如果“十六进制”未选中,就直接发送文本框内容,如果选中了就先把文本框中的每个字符转为其ASCII值的十六进制表示,再发送,最后将每条发送的内容,在send_rtb中显示
private void send_btn_Click(object sender, EventArgs e)
{
sendBuffer.Clear();
reciveBuffer.Clear();
if (tb_send.Text != "")
{
string Mystr = tb_send.Text;
Sendcommand(Mystr);
}
else
{
MessageBox.Show("请先输入发送数据!");
}
}
private void Sendcommand(string Mystr)
{
sendBuffer.Clear();
if (!serialPort1.IsOpen)
{
MessageBox.Show("串口未连接!");
return;
}
if (ck_HexSend.Checked == false)
{
sendBuffer.AddRange(Encoding.GetEncoding("gb2312").GetBytes(Mystr));
}
else
{
byte[] byteArr = Encoding.ASCII.GetBytes(Mystr);
string HexMystr = BitConverter.ToString(byteArr).Replace(" ", "-");
sendBuffer.AddRange(Encoding.GetEncoding("gb2312").GetBytes(HexMystr));
}
serialPort1.Write(sendBuffer.ToArray(), 0, sendBuffer.Count);
send_rtb.AppendText(Mystr + "\r");//显示
sendCount += sendBuffer.Count;
sencount_tssl.Text = sendCount.ToString();
}
2.3.3 结果显示
十六进制发送
2.4 多条字符串发送
多条字符串发送的功能也做了改变
2.4.1 发送选中
只发送CLst_Command(CheckedListBox)选中行的内容,如果无选中行或未打开串口,则报错
private int index = 0;
private void bt_SendClt_Click(object sender, EventArgs e)
{//只发送选中行的内容
index = 0;
if (CLst_Command.CheckedItems.Count == 0)
{
MessageBox.Show("未找到选中行!");
}
if (serialPort1.IsOpen)
{
while (index < CLst_Command.Items.Count)
{
if (CLst_Command.GetItemCheckState(index) == CheckState.Checked)
{
string Mystr = CLst_Command.Items[index].ToString();
Sendcommand(Mystr);
}
index++;
}
}
else
{
MessageBox.Show("串口未连接!");
}
}
2.4.2 循环发送
用计时器实现循环功能。复选框选中时,计时器每10ms触发一次,触发时开始循环发送CLst_Command中选中行的内容,当取消选中时,计时器停止,并清空发送缓冲区。
private void Loopsend_cb_CheckedChanged(object sender, EventArgs e)
{
index = 0;
if (CLst_Command.CheckedItems.Count == 0)
{
MessageBox.Show("未找到选中行!");
}
if (Loopsend_cb.Checked==true)
{
if (serialPort1.IsOpen)
{
timer2.Start();
}
else
{
MessageBox.Show("串口未连接!");
}
}
else
{
timer2.Stop();
sendBuffer.Clear();
}
}
private void timer2_Tick(object sender, EventArgs e)
{
while (index < CLst_Command.Items.Count)
{
if (CLst_Command.GetItemCheckState(index) == CheckState.Checked)
{
string Mystr = CLst_Command.Items[index].ToString();
Sendcommand(Mystr);
}
index++;
}
if (index == CLst_Command.Items.Count)
{
index = 0;
timer2.Start();
}
}
2.4.3 添加文件内容
逐行读取TXT文件的内容,并将各行的内容添加到CLst_Command中,并自动选中
private void Opnefile_btn_Click(object sender, EventArgs e)
{
openFileDialog1.Filter = "文本文件(*.txt)|*.txt";//设置打开文件的格式为TXT
if (openFileDialog1.ShowDialog() == DialogResult.OK)
{
try
{
//使用“打开”对话框中选择的文件实例化StreamReader对象
StreamReader sr = new StreamReader(openFileDialog1.FileName);
string line;
while ((line = sr.ReadLine()) != null)
{//使用ReadLine方法按行读取选中文件的全部内容
int i = CLst_Command.Items.Count;
CLst_Command.Items.Add(line);
CLst_Command.SetItemChecked(i, true);//选中新加行的内容
}
sr.Close();
}
catch(Exception ex)
{
MessageBox.Show(ex.Message, "Error");
}
}
}
2.4.4 结果显示
“发送选中”
“循环发送”
“打开文件”
完结。。。