c#上位机串口通信助手源代码详解.docx
《c#上位机串口通信助手源代码详解.docx》由会员分享,可在线阅读,更多相关《c#上位机串口通信助手源代码详解.docx(23页珍藏版)》请在冰豆网上搜索。
c#上位机串口通信助手源代码详解
c#上位机串口通信助手源代码实例详解
一、功能
1软件打开时,自动检测有效COM端口
2软件打开时,自动复原到上次关闭时的状态
3不必关闭串口,即可直接进行更改初始化设置内容(串口号、波特率、数据位、停止位、校验位),可按更改后的信息自动将串口重新打开
4可统计接收字节和发送字节的个数
5接收数据可按16进制数据和非16进制数据进行整体转换
6可将接收到数据进行保存
7可设置自动发送,发送时间可进行实时更改
8可按字符串、16进制字节、文件方式进行发送,字符串和16进制字节可分别进行存储,内容互不干扰
9按16进制发送时,可自动校验格式,不会输错
10可清空发送或接收区域的数据
二、使用工具
VisualStudio2015
三、程序详解
1界面创建
图1
用winform创建如图1所示界面,控件名字分别为:
端口号:
cbxCOMPort波特率:
cbxBaudRate
数据位:
cbxDataBits停止位:
cbxStopBits
校验位:
label5打开串口按钮:
btnOpenCom
发送(byte):
tbSendCount接收(byte):
tbReceivedCount
清空计数按钮:
btnClearCount按16进制显示:
cb16Display
接收区清空内容按钮:
btnClearReceived保存数据按钮:
btnSaveFile
接收数据框:
tbReceivedData发送数据框:
tbSendData
自动发送:
cbAutomaticSend间隔时间:
tbSpaceTime
按16进制发送:
cb16Send发送区清空内容按钮:
btnClearSend
读入文件按钮:
btnReadFile发送按钮:
btnSend
2创建一个方法类
按Ctrl+shift+A快捷键创建一个类,名字叫Methods,代码为:
usingSystem;
usingSystem.Collections;
usingSystem.Collections.Generic;
usingSystem.IO.Ports;
usingSystem.Linq;
usingSystem.Text;
usingSystem.Threading.Tasks;
namespace串口助手sdd
{
classMethods
//获取有效的COM口
publicstaticstring[]ActivePorts()
ArrayListactivePorts=newArrayList();
foreach(stringpnameinSerialPort.GetPortNames())
activePorts.Add(Convert.ToInt32(pname.Substring(3)));
}
activePorts.Sort();
string[]mystr=newstring[activePorts.Count];
inti=0;
foreach(intnuminactivePorts)
mystr[i++]="COM"+num.ToString();
returnmystr;
//16进制字符串转换为byte字符数组
publicstaticByte[]_16strToHex(stringstrValues)
string[]hexValuesSplit=strValues.Split('');
Byte[]hexValues=newByte[hexValuesSplit.Length];
Console.WriteLine(hexValuesSplit.Length);
for(inti=0;i{hexValues[i]=Convert.ToByte(hexValuesSplit[i],16);}returnhexValues;}//byte数组以16进制形式转字符串publicstaticstringByteTo16Str(byte[]bytes){stringrecData=null;//创建接收数据的字符串foreach(byteoutByteinbytes)//将字节数组以16进制形式遍历到一个字符串内{recData+=outByte.ToString("X2")+"";}returnrecData;}//16进制字符串转换字符串publicstaticstring_16strToStr(string_16str){stringoutStr=null;byte[]streamByte=_16strToHex(_16str);outStr=Encoding.Default.GetString(streamByte);returnoutStr;}}} 2Form1.cs的代码为:usingSystem;usingSystem.Collections.Generic;usingSystem.ComponentModel;usingSystem.Data;usingSystem.Drawing;usingSystem.IO.Ports;usingSystem.Linq;usingSystem.Text;usingSystem.Text.RegularExpressions;usingSystem.Threading.Tasks;usingSystem.Windows.Forms;usingSystem.IO;usingSystem.Collections;namespace串口助手sdd{publicpartialclassForm1:Form{//声明变量SerialPortsp=newSerialPort();boolisSetProperty=false;//串口属性设置标志位privateenumPortState//声明接口显示状态,枚举型{打开,关闭}stringpath=AppDomain.CurrentDomain.BaseDirectory+"confing.ini";//声明配置文件路径stringtbSendDataStr="";//发送窗口字符串存储stringtbSendData16="";//发送窗口16进制存储ListreceivedDatas=newList();//接收数据泛型数组//接收串口数据privatevoidsp_DataReceived(objectsender,SerialDataReceivedEventArgse){byte[]ReceivedData=newbyte[sp.BytesToRead];//创建接收字节数组sp.Read(ReceivedData,0,ReceivedData.Length);//读取所接收到的数据receivedDatas.AddRange(ReceivedData);tbReceivedCount.Text=(Convert.ToInt32(tbReceivedCount.Text)+ReceivedData.Length).ToString();if(cb16Display.Checked)tbReceivedData.Text=Methods.ByteTo16Str(receivedDatas.ToArray());elsetbReceivedData.Text=Encoding.Default.GetString(receivedDatas.ToArray());sp.DiscardInBuffer();//丢弃接收缓冲区数据}//发送串口数据privatevoidDataSend(){try{if(cb16Send.Checked){byte[]hexBytes=Methods._16strToHex(tbSendData16);sp.Write(hexBytes,0,hexBytes.Length);tbSendCount.Text=(Convert.ToInt32(tbSendCount.Text)+hexBytes.Length).ToString();}else{sp.WriteLine(tbSendDataStr);tbSendCount.Text=(Convert.ToInt32(tbSendCount.Text)+tbSendDataStr.Length).ToString();}}catch(Exceptionex){MessageBox.Show(ex.Message.ToString());return;}}//设置串口属性privatevoidSetPortProperty(){sp.PortName=cbxCOMPort.Text.Trim();//设置串口名sp.BaudRate=Convert.ToInt32(cbxBaudRate.Text.Trim());//设置波特率switch(cbxStopBits.Text.Trim())//设置停止位{case"1":sp.StopBits=StopBits.One;break;case"1.5":sp.StopBits=StopBits.OnePointFive;break;case"2":sp.StopBits=StopBits.Two;break;default:sp.StopBits=StopBits.None;break;}sp.DataBits=Convert.ToInt32(cbxDataBits.Text.Trim());//设置数据位switch(cbxParity.Text.Trim())//设置奇偶校验位{case"无":sp.Parity=Parity.None;break;case"奇校验":sp.Parity=Parity.Odd;break;case"偶校验":sp.Parity=Parity.Even;break;default:sp.Parity=Parity.None;break;}sp.ReadTimeout=5000;//设置超时时间为5sControl.CheckForIllegalCrossThreadCalls=false;//这个类中我们不检查跨线程的调用是否合法(因为.net2.0以后加强了安全机制,,不允许在winform中直接跨线程访问控件的属性)//定义DataReceived事件的委托,当串口收到数据后出发事件sp.DataReceived+=newSerialDataReceivedEventHandler(sp_DataReceived);}//设置端口显示状态privatevoidDisplayPortState(PortStateportState){toolStripStatusLabel1.Text=cbxCOMPort.Text+"端口处于"+portState+"状态"+cbxBaudRate.Text+""+cbxDataBits.Text+""+cbxStopBits.Text+""+cbxParity.Text;}//重新打开串口privatevoidAgainOpenPort(){if(sp.IsOpen){try{sp.Close();SetPortProperty();isSetProperty=true;sp.Open();}catch(Exception){isSetProperty=false;btnOpenCom.Text="打开串口";DisplayPortState(PortState.关闭);MessageBox.Show("串口无效或已被占用!","错误提示");return;}DisplayPortState(PortState.打开);}else{DisplayPortState(PortState.关闭);}}publicForm1(){InitializeComponent();} //软件启动时加载事件privatevoidForm1_Load(objectsender,EventArgse){#region加载配置文件Hashtableht=newHashtable();if(File.Exists(path)){try{stringmyline="";string[]str=newstring[2];using(StreamReadersr=newStreamReader(path)){myline=sr.ReadLine();while(myline!=null){str=myline.Split('=');ht.Add(str[0],str[1]);myline=sr.ReadLine();}}}catch(Exceptionex){MessageBox.Show(ex.Message.ToString());}}#endregion#region设置窗口为固定大小且不可最大化this.MaximumSize=this.Size;this.MinimumSize=this.Size;this.MaximizeBox=false;#endregion#region列出常用的波特率cbxBaudRate.Items.Add("1200");cbxBaudRate.Items.Add("2400");cbxBaudRate.Items.Add("4800");cbxBaudRate.Items.Add("9600");cbxBaudRate.Items.Add("19200");cbxBaudRate.Items.Add("38400");cbxBaudRate.Items.Add("43000");cbxBaudRate.Items.Add("56000");cbxBaudRate.Items.Add("57600");cbxBaudRate.Items.Add("115200");if(ht.ContainsKey("cbxBaudRate"))cbxBaudRate.SelectedIndex=cbxBaudRate.Items.IndexOf(ht["cbxBaudRate"].ToString());elsecbxBaudRate.SelectedIndex=3;cbxBaudRate.DropDownStyle=ComboBoxStyle.DropDownList;#endregion#region列出停止位cbxStopBits.Items.Add("1");cbxStopBits.Items.Add("1.5");cbxStopBits.Items.Add("2");if(ht.ContainsKey("cbxStopBits"))cbxStopBits.SelectedIndex=cbxStopBits.Items.IndexOf(ht["cbxStopBits"].ToString());elsecbxStopBits.SelectedIndex=0;cbxStopBits.DropDownStyle=ComboBoxStyle.DropDownList;#endregion#region列出数据位cbxDataBits.Items.Add("8");cbxDataBits.Items.Add("7");cbxDataBits.Items.Add("6");cbxDataBits.Items.Add("5");if(ht.ContainsKey("cbxDataBits"))cbxDataBits.SelectedIndex=cbxDataBits.Items.IndexOf(ht["cbxDataBits"].ToString());elsecbxDataBits.SelectedIndex=0;cbxDataBits.DropDownStyle=ComboBoxStyle.DropDownList;#endregion#region列出奇偶校验位cbxParity.Items.Add("无");cbxParity.Items.Add("奇校验");cbxParity.Items.Add("偶校验");if(ht.ContainsKey("cbxParity"))cbxParity.SelectedIndex=cbxParity.Items.IndexOf(ht["cbxParity"].ToString());elsecbxParity.SelectedIndex=0;cbxParity.DropDownStyle=ComboBoxStyle.DropDownList;#endregion#regionCOM口重新加载cbxCOMPort.Items.Clear();//清除当前串口号中的所有串口名称cbxCOMPort.Items.AddRange(Methods.ActivePorts());if(ht.ContainsKey("cbxCOMPort")&&cbxCOMPort.Items.Contains(ht["cbxCOMPort"].ToString()))cbxCOMPort.SelectedIndex=cbxCOMPort.Items.IndexOf(ht["cbxCOMPort"].ToString());elsecbxCOMPort.SelectedIndex=0;cbxCOMPort.DropDownStyle=ComboBoxStyle.DropDownList;#endregion#region初始化计数器tbSendCount.Text="0";tbSendCount.ReadOnly=true;tbReceivedCount.Text="0";tbReceivedCount.ReadOnly=true;#endregion#region初始化当前时间toolStripStatusLabel3.Text=DateTime.Now.ToString();#endregion#region初始化串口状态toolStripStatusLabel1.ForeColor=Color.Blue;if(!isSetProperty)//串口未设置则设置串口属性{SetPortProperty();isSetProperty=true;}try{sp.Open();btnOpenCom.Text="关闭串口";DisplayPortState(PortState.打开);}catch(Exception){//串口打开失败后,串口属性设置标志位设为falseisSetProperty=false;MessageBox.Show("串口无效或已被占用!","错误提示");}#endregion#region初始化间隔时间if(ht.ContainsKey("tbSpaceTime"))tbSpaceTime.Text=ht["tbSpaceTime"].ToString();elsetbSpaceTime.Text="1000";#endregion#region初始化按16进制显示状态if(ht.ContainsKey("cb16Display")&&ht["cb16Display"].ToString()=="True")cb16Display.Checked=true;elsecb16Display.Checked=false;#endregion#region初始化按16进制发送状态if(ht.ContainsKey("cb16Send")&&ht["cb16Send"].ToString()=="True")cb16Send.Checked=true;elsecb16Send.Checked=false;#endregion#region初始化发送区文本if(ht.ContainsKey("tbSendData16")&&ht.ContainsKey("tbSendDataStr")){tbSendData16=ht["tbSendData16"].ToString();tbSendDataStr=ht["tbSendDataStr"].ToString();if(cb16Send.Checked)tbSendData.Text=ht["tbSendData16"].ToString();elsetbSendData.Text=ht["tbSendDataStr"].ToString();}#endregiontbSendData.Focus();} //显示当前时间privatevoidtimer1_Tick(objectsender,EventArgse){toolStripStatusLabel3.Text=DateTime.Now.ToString();} //点击打开串口按钮privatevoidbtnOpenCom_Click
hexValues[i]=Convert.ToByte(hexValuesSplit[i],16);
returnhexValues;
//byte数组以16进制形式转字符串
publicstaticstringByteTo16Str(byte[]bytes)
stringrecData=null;//创建接收数据的字符串
foreach(byteoutByteinbytes)//将字节数组以16进制形式遍历到一个字符串内
recData+=outByte.ToString("X2")+"";
returnrecData;
//16进制字符串转换字符串
publicstaticstring_16strToStr(string_16str)
stringoutStr=null;
byte[]streamByte=_16strToHex(_16str);
outStr=Encoding.Default.GetString(streamByte);
returnoutStr;
2Form1.cs的代码为:
usingSystem.ComponentModel;
usingSystem.Data;
usingSystem.Drawing;
usingSystem.Text.RegularExpressions;
usingSystem.Windows.Forms;
usingSystem.IO;
publicpartialclassForm1:
Form
//声明变量
SerialPortsp=newSerialPort();
boolisSetProperty=false;//串口属性设置标志位
privateenumPortState//声明接口显示状态,枚举型
打开,
关闭
stringpath=AppDomain.CurrentDomain.BaseDirectory+"confing.ini";//声明配置文件路径
stringtbSendDataStr="";//发送窗口字符串存储
stringtbSendData16="";//发送窗口16进制存储
ListreceivedDatas=newList();//接收数据泛型数组
//接收串口数据
privatevoidsp_DataReceived(objectsender,SerialDataReceivedEventArgse)
byte[]ReceivedData=newbyte[sp.BytesToRead];//创建接收字节数组
sp.Read(ReceivedData,0,ReceivedData.Length);//读取所接收到的数据
receivedDatas.AddRange(ReceivedData);
tbReceivedCount.Text=(Convert.ToInt32(tbReceivedCount.Text)+ReceivedData.Length).ToString();
if(cb16Display.Checked)
tbReceivedData.Text=Methods.ByteTo16Str(receivedDatas.ToArray());
else
tbReceivedData.Text=Encoding.Default.GetString(receivedDatas.ToArray());
sp.DiscardInBuffer();//丢弃接收缓冲区数据
//发送串口数据
privatevoidDataSend()
try
if(cb16Send.Checked)
byte[]hexBytes=Methods._16strToHex(tbSendData16);
sp.Write(hexBytes,0,hexBytes.Length);
tbSendCount.Text=(Convert.ToInt32(tbSendCount.Text)+hexBytes.Length).ToString();
sp.WriteLine(tbSendDataStr);
tbSendCount.Text=(Convert.ToInt32(tbSendCount.Text)+tbSendDataStr.Length).ToString();
catch(Exceptionex)
MessageBox.Show(ex.Message.ToString());
return;
//设置串口属性
privatevoidSetPortProperty()
sp.PortName=cbxCOMPort.Text.Trim();//设置串口名
sp.BaudRate=Convert.ToInt32(cbxBaudRate.Text.Trim());//设置波特率
switch(cbxStopBits.Text.Trim())//设置停止位
case"1":
sp.StopBits=StopBits.One;break;
case"1.5":
sp.StopBits=StopBits.OnePointFive;break;
case"2":
sp.StopBits=StopBits.Two;break;
default:
sp.StopBits=StopBits.None;break;
sp.DataBits=Convert.ToInt32(cbxDataBits.Text.Trim());//设置数据位
switch(cbxParity.Text.Trim())//设置奇偶校验位
case"无":
sp.Parity=Parity.None;break;
case"奇校验":
sp.Parity=Parity.Odd;break;
case"偶校验":
sp.Parity=Parity.Even;break;
sp.ReadTimeout=5000;//设置超时时间为5s
Control.CheckForIllegalCrossThreadCalls=false;//这个类中我们不检查跨线程的调用是否合法(因为.net2.0以后加强了安全机制,,不允许在winform中直接跨线程访问控件的属性)
//定义DataReceived事件的委托,当串口收到数据后出发事件
sp.DataReceived+=newSerialDataReceivedEventHandler(sp_DataReceived);
//设置端口显示状态
privatevoidDisplayPortState(PortStateportState)
toolStripStatusLabel1.Text=cbxCOMPort.Text+"端口处于"+portState+"状态"+cbxBaudRate.Text+""+cbxDataBits.Text+""+cbxStopBits.Text+""+cbxParity.Text;
//重新打开串口
privatevoidAgainOpenPort()
if(sp.IsOpen)
sp.Close();
SetPortProperty();
isSetProperty=true;
sp.Open();
catch(Exception)
isSetProperty=false;
btnOpenCom.Text="打开串口";
DisplayPortState(PortState.关闭);
MessageBox.Show("串口无效或已被占用!
","错误提示");
DisplayPortState(PortState.打开);
publicForm1()
InitializeComponent();
//软件启动时加载事件
privatevoidForm1_Load(objectsender,EventArgse)
#region加载配置文件
Hashtableht=newHashtable();
if(File.Exists(path))
stringmyline="";
string[]str=newstring[2];
using(StreamReadersr=newStreamReader(path))
myline=sr.ReadLine();
while(myline!
=null)
str=myline.Split('=');
ht.Add(str[0],str[1]);
#endregion
#region设置窗口为固定大小且不可最大化
this.MaximumSize=this.Size;
this.MinimumSize=this.Size;
this.MaximizeBox=false;
#region列出常用的波特率
cbxBaudRate.Items.Add("1200");
cbxBaudRate.Items.Add("2400");
cbxBaudRate.Items.Add("4800");
cbxBaudRate.Items.Add("9600");
cbxBaudRate.Items.Add("19200");
cbxBaudRate.Items.Add("38400");
cbxBaudRate.Items.Add("43000");
cbxBaudRate.Items.Add("56000");
cbxBaudRate.Items.Add("57600");
cbxBaudRate.Items.Add("115200");
if(ht.ContainsKey("cbxBaudRate"))
cbxBaudRate.SelectedIndex=cbxBaudRate.Items.IndexOf(ht["cbxBaudRate"].ToString());
cbxBaudRate.SelectedIndex=3;
cbxBaudRate.DropDownStyle=ComboBoxStyle.DropDownList;
#region列出停止位
cbxStopBits.Items.Add("1");
cbxStopBits.Items.Add("1.5");
cbxStopBits.Items.Add("2");
if(ht.ContainsKey("cbxStopBits"))
cbxStopBits.SelectedIndex=cbxStopBits.Items.IndexOf(ht["cbxStopBits"].ToString());
cbxStopBits.SelectedIndex=0;
cbxStopBits.DropDownStyle=ComboBoxStyle.DropDownList;
#region列出数据位
cbxDataBits.Items.Add("8");
cbxDataBits.Items.Add("7");
cbxDataBits.Items.Add("6");
cbxDataBits.Items.Add("5");
if(ht.ContainsKey("cbxDataBits"))
cbxDataBits.SelectedIndex=cbxDataBits.Items.IndexOf(ht["cbxDataBits"].ToString());
cbxDataBits.SelectedIndex=0;
cbxDataBits.DropDownStyle=ComboBoxStyle.DropDownList;
#region列出奇偶校验位
cbxParity.Items.Add("无");
cbxParity.Items.Add("奇校验");
cbxParity.Items.Add("偶校验");
if(ht.ContainsKey("cbxParity"))
cbxParity.SelectedIndex=cbxParity.Items.IndexOf(ht["cbxParity"].ToString());
cbxParity.SelectedIndex=0;
cbxParity.DropDownStyle=ComboBoxStyle.DropDownList;
#regionCOM口重新加载
cbxCOMPort.Items.Clear();//清除当前串口号中的所有串口名称
cbxCOMPort.Items.AddRange(Methods.ActivePorts());
if(ht.ContainsKey("cbxCOMPort")&&cbxCOMPort.Items.Contains(ht["cbxCOMPort"].ToString()))
cbxCOMPort.SelectedIndex=cbxCOMPort.Items.IndexOf(ht["cbxCOMPort"].ToString());
cbxCOMPort.SelectedIndex=0;
cbxCOMPort.DropDownStyle=ComboBoxStyle.DropDownList;
#region初始化计数器
tbSendCount.Text="0";
tbSendCount.ReadOnly=true;
tbReceivedCount.Text="0";
tbReceivedCount.ReadOnly=true;
#region初始化当前时间
toolStripStatusLabel3.Text=DateTime.Now.ToString();
#region初始化串口状态
toolStripStatusLabel1.ForeColor=Color.Blue;
if(!
isSetProperty)//串口未设置则设置串口属性
btnOpenCom.Text="关闭串口";
//串口打开失败后,串口属性设置标志位设为false
#region初始化间隔时间
if(ht.ContainsKey("tbSpaceTime"))
tbSpaceTime.Text=ht["tbSpaceTime"].ToString();
tbSpaceTime.Text="1000";
#region初始化按16进制显示状态
if(ht.ContainsKey("cb16Display")&&ht["cb16Display"].ToString()=="True")
cb16Display.Checked=true;
cb16Display.Checked=false;
#region初始化按16进制发送状态
if(ht.ContainsKey("cb16Send")&&ht["cb16Send"].ToString()=="True")
cb16Send.Checked=true;
cb16Send.Checked=false;
#region初始化发送区文本
if(ht.ContainsKey("tbSendData16")&&ht.ContainsKey("tbSendDataStr"))
tbSendData16=ht["tbSendData16"].ToString();
tbSendDataStr=ht["tbSendDataStr"].ToString();
tbSendData.Text=ht["tbSendData16"].ToString();
tbSendData.Text=ht["tbSendDataStr"].ToString();
tbSendData.Focus();
//显示当前时间
privatevoidtimer1_Tick(objectsender,EventArgse)
//点击打开串口按钮
privatevoidbtnOpenCom_Click
copyright@ 2008-2022 冰豆网网站版权所有
经营许可证编号:鄂ICP备2022015515号-1