利用C#NET进行串口编程.docx
- 文档编号:8800526
- 上传时间:2023-05-15
- 格式:DOCX
- 页数:31
- 大小:78.44KB
利用C#NET进行串口编程.docx
《利用C#NET进行串口编程.docx》由会员分享,可在线阅读,更多相关《利用C#NET进行串口编程.docx(31页珍藏版)》请在冰点文库上搜索。
利用C#NET进行串口编程
利用C#.NET进行串口编程
总算最后时间把【智能水电表】的项目啃下来了,总体来说这个项目技术难点不是特别多,主要是一个实现串口通讯的问题,其次就是水电表数据协议的解析问题。
目前已经开始在部署阶段了,利用休息时间将内容整理如下:
一、需求分析
1、水电表部署在家居中正常使用(当然水电表不是普通的家庭用表,而是智能家居用表,具有无线通信功能);
2、水电表通过无线通信协议将数据发送到家庭网关中;
3、家庭网关通过串口与PC机相连,通过串口通讯发给PC机接收;
4、PC机通过串口接收到网关传来的数据,进行解析显示,并存储在MySQL数据中(如何配置数据库已经在前面的
5、JSP页面读取MySQL中的数据,并显示;
6、烧录机顶盒内核,将JSP页面显示在电视机中。
二、串口编程
本项目的技术难点主要是获取串口数据,并依据现有的通信协议对数据包进行解析并显示。
之前有做过类似的串口编程用于WSN,但是现在才发现代码冗余量太大,而且不易于扩展,现在将总体过程整理如下:
2.1创建SerialPort实例
该步骤可以按照如下方式创建,当然也可以直接在工具箱中拖进SerialPort。
viewplaincopytoclipboardprint?
usingSystem.IO.Ports;
SerialPortserialport=newSerialPort();
usingSystem.IO.Ports;
SerialPortserialport=newSerialPort();
2.2列举可用的串口名
窗口首次加载时,我们将获取计算机上所有可用的串口名称并将这些名称添加到ComboBox控件里面。
双击窗体实现Form1_Load事件处理。
viewplaincopytoclipboardprint?
privatevoidForm1_Load(objectsender,EventArgse)
{
string[]portNames=SerialPort.GetPortNames();
for(inti=0;i { this.cbbPorts.Items.Add(portNames[i]); } this.cbbPorts.Items.Add(this.serialPort1.PortName); this.btdisconn.Enabled=false; } privatevoidForm1_Load(objectsender,EventArgse) { string[]portNames=SerialPort.GetPortNames(); for(inti=0;i { this.cbbPorts.Items.Add(portNames[i]); } this.cbbPorts.Items.Add(this.serialPort1.PortName); this.btdisconn.Enabled=false; } 按照以下的方法经常会出现问题(比如不能获得正确的串口名称),后面通过查阅资料得出了以下的一个解决方案,首先需要引用Microsoft.VisualBasic,用以下遍历SerialPortNames,获得所有的串口: viewplaincopytoclipboardprint? privatevoidForm1_Load(objectsender,EventArgse) { this.timer1.Enabled=true; serialport.DataReceived+=newSerialDataReceivedEventHandler(serialport_DataReceived); Computerpc=newComputer(); string[]portNames=SerialPort.GetPortNames(); foreach(stringsinpc.Ports.SerialPortNames) { this.cbbPorts.Items.Add(s); } this.btdisconn.Enabled=false; } privatevoidForm1_Load(objectsender,EventArgse) { this.timer1.Enabled=true; serialport.DataReceived+=newSerialDataReceivedEventHandler(serialport_DataReceived); Computerpc=newComputer(); string[]portNames=SerialPort.GetPortNames(); foreach(stringsinpc.Ports.SerialPortNames) { this.cbbPorts.Items.Add(s); } this.btdisconn.Enabled=false; } 注意还要添加DataReceived事件: viewplaincopytoclipboardprint? this.serialPort1.DataReceived+=newSystem.IO.Ports.SerialDataReceivedEventHandler(this.serialPort1_DataReceived); this.serialPort1.DataReceived+=newSystem.IO.Ports.SerialDataReceivedEventHandler(this.serialPort1_DataReceived); 2.3打开串口 选择串口名后,用户点击【连接】按钮以打开所选择的端口,代码实现如下: viewplaincopytoclipboardprint? privatevoidbtconn_Click(objectsender,EventArgse) { if(this.serialPort1.IsOpen) { this.serialPort1.Close(); } try { this.serialPort1.Encoding=System.Text.Encoding.Unicode; this.serialPort1.Open(); this.lbMsg.Text=this.serialPort1.PortName.ToString()+"Connected."; this.btconn.Enabled=false; this.btdisconn.Enabled=true; this.rtbData.BeginInvoke(newmyDelegate(updateTextBox)); this.lvdata.BeginInvoke(newmyDelegate(updateListView)); } catch(Exceptionex) { //MessageBox.Show(ex.ToString()); return; } } privatevoidbtconn_Click(objectsender,EventArgse) { if(this.serialPort1.IsOpen) { this.serialPort1.Close(); } try { this.serialPort1.Encoding=System.Text.Encoding.Unicode; this.serialPort1.Open(); this.lbMsg.Text=this.serialPort1.PortName.ToString()+"Connected."; this.btconn.Enabled=false; this.btdisconn.Enabled=true; this.rtbData.BeginInvoke(newmyDelegate(updateTextBox)); this.lvdata.BeginInvoke(newmyDelegate(updateListView)); } catch(Exceptionex) { //MessageBox.Show(ex.ToString()); return; } } 2.4断开串口连接 断开串口连接只需要调用一个方法即可。 viewplaincopytoclipboardprint? privatevoidbtdisconn_Click(objectsender,EventArgse) { try { this.serialPort1.Close(); this.lbMsg.Text=this.serialPort1.PortName+"Disconnected."; this.btconn.Enabled=true; this.btdisconn.Enabled=false; } catch(Exceptionex) { //MessageBox.Show(ex.ToString()); return; } } privatevoidbtdisconn_Click(objectsender,EventArgse) { try { this.serialPort1.Close(); this.lbMsg.Text=this.serialPort1.PortName+"Disconnected."; this.btconn.Enabled=true; this.btdisconn.Enabled=false; } catch(Exceptionex) { //MessageBox.Show(ex.ToString()); return; } } 2.5接收串口的数据 SerialPort类的一个良好的特性是,无需不断的查询数据是否已经到达,而只需处理DataReceived事件,它将在检测到数据到达时自动触发,不过,因为事件运行在独立的线程里,任何试图直接更新主窗体的尝试都会引发错误,因此,需要使用一个代理来更新主线程里的控件(这个尤为重要,否则一切都白搭)。 viewplaincopytoclipboardprint? privatevoidserialport_DataReceived(Objectsender,SerialDataReceivedEventArgse) { this.rtbData.BeginInvoke(newmyDelegate(updateTextBox)); this.lvdata.BeginInvoke(newmyDelegate(updateListView)); } privatevoidserialport_DataReceived(Objectsender,SerialDataReceivedEventArgse) { this.rtbData.BeginInvoke(newmyDelegate(updateTextBox)); this.lvdata.BeginInvoke(newmyDelegate(updateListView)); } 定义代理如下所示: viewplaincopytoclipboardprint? publicdelegatevoidmyDelegate(); publicvoidupdateTextBox() { try { //求出需要读取的Bytes数 //intbytesToRead=serialport.BytesToRead; intbytesToRead=this.serialPort1.BytesToRead; //声明char数组 byte[]ch=newbyte[bytesToRead]; //char[]ch1=newchar[bytesToRead]; intbytesRead=0; //将读取到的bytes存储在ch数组中 //bytesRead=serialport.Read(ch,0,bytesToRead); bytesRead=this.serialPort1.Read(ch,0,bytesToRead); //bytesRead=this.serialPort1.Read(ch1,0,bytesToRead); //将ch数组转换为string类型 str=this.ByteArrayToHexString(ch).Replace("","").Trim(); //str=newstring(ch1,0,bytesRead); //测试代码 //str="5353535342621708005262000704000000000000E9F245"; //将string类型放置在文本框中 this.rtbData.AppendText(str); //MessageBox.Show(str.Length.ToString()); this.rtbData.ScrollToCaret(); stringrtbstr=this.rtbData.Text.ToString(); if((rtbstr.Length>=46)&&(rtbstr.IndexOf("5353535342") { stringstrnew=rtbstr.Substring(rtbstr.IndexOf("5353535342"),46); if(strnew.Substring(44,2).Trim().ToString()=="45") { DataAnalyse(strnew); this.rtbData.BeginInvoke(newmyDelegate(clearTextBox)); } } else { this.rtbData.BeginInvoke(newmyDelegate(clearTextBox)); } DataStore(); } catch(Exceptionex) { //MessageBox.Show(ex.ToString()); return; } } publicvoidupdateListView() { try { if(this.TableID.ToString().Trim()! ="") { ListViewItemlist=newListViewItem(); list.Text=TableID; list.SubItems.Add(TableID); list.SubItems.Add(ReadFlag);list.SubItems.Add(TableType); list.SubItems.Add(TableState);list.SubItems.Add(TableNum); list.SubItems.Add(PreNum);list.SubItems.Add(CRCNum); list.SubItems.Add(date); list.SubItems.Add(DataTail); this.lvdata.Items.Add(list); } } catch(Exceptionex) { //MessageBox.Show(ex.Message.ToString()); //throw; return; } } publicdelegatevoidmyDelegate(); publicvoidupdateTextBox() { try { //求出需要读取的Bytes数 //intbytesToRead=serialport.BytesToRead; intbytesToRead=this.serialPort1.BytesToRead; //声明char数组 byte[]ch=newbyte[bytesToRead]; //char[]ch1=newchar[bytesToRead]; intbytesRead=0; //将读取到的bytes存储在ch数组中 //bytesRead=serialport.Read(ch,0,bytesToRead); bytesRead=this.serialPort1.Read(ch,0,bytesToRead); //bytesRead=this.serialPort1.Read(ch1,0,bytesToRead); //将ch数组转换为string类型 str=this.ByteArrayToHexString(ch).Replace("","").Trim(); //str=newstring(ch1,0,bytesRead); //测试代码 //str="5353535342621708005262000704000000000000E9F245"; //将string类型放置在文本框中 this.rtbData.AppendText(str); //MessageBox.Show(str.Length.ToString()); this.rtbData.ScrollToCaret(); stringrtbstr=this.rtbData.Text.ToString(); if((rtbstr.Length>=46)&&(rtbstr.IndexOf("5353535342") { stringstrnew=rtbstr.Substring(rtbstr.IndexOf("5353535342"),46); if(strnew.Substring(44,2).Trim().ToString()=="45") { DataAnalyse(strnew); this.rtbData.BeginInvoke(newmyDelegate(clearTextBox)); } } else { this.rtbData.BeginInvoke(newmyDelegate(clearTextBox)); } DataStore(); } catch(Exceptionex) { //MessageBox.Show(ex.ToString()); return; } } publicvoidupdateListView() { try { if(this.TableID.ToString().Trim()! ="") { ListViewItemlist=newListViewItem(); list.Text=TableID; list.SubItems.Add(TableID); list.SubItems.Add(ReadFlag);list.SubItems.Add(TableType); list.SubItems.Add(TableState);list.SubItems.Add(TableNum); list.SubItems.Add(PreNum);list.SubItems.Add(CRCNum); list.SubItems.Add(date); list.SubItems.Add(DataTail); this.lvdata.Items.Add(list); } } catch(Exceptionex) { //MessageBox.Show(ex.Message.ToString()); //throw; return; } } 2.6传输Unicode字符 默认情况下,SerialPort类只传输ASCII字符,这是通过SerialPort类的Encoding属性设置的,如果你想传输另一种语言,就需要设置SerialPort类的Encoding属性为Unicode,以保证数据的正常发送与接收。 2.7串口发送数据 要通过串口向接收者发送数据,使用SerialPort类的Write()方法即可。 viewplaincopytoclipboardprint? privatevoidbtrefresh_Click(objectsender,EventArgse) { try { this.serialPort1.Write(this.tbsend.Text.ToString()+Environment.NewLine); tbsend.Text=string.Empty; } catch(Exceptionex) { } } privatevoidbtrefresh_Click(objectsender,EventArgse) { try { this.serialPort1.Write(this.tbsend.Text.ToString()+Environment.NewLine); tbsend.Text=string.Empty; } catch(Exceptionex) { } } 三、运行测试 由于今天图片上传功能暂时关闭,所以不能上传图片,所有的代码如下所示: viewplaincopytoclipboardprint? usingSystem; usingSystem.Collections.Gene
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 利用 NET 进行 串口 编程