@L_403_0@
标签:?c#textboxbuttonobjectstring
2012-08-10 14:57?
18916人阅读?
?
收藏?
举报
 ?
分类:
?
?
版权声明:本文为博主原创文章,未经博主允许不得转载。
? ?附言:
1.?有网友反应我写的这篇文章还不错,索性就将它置顶了,希望对大家串口编程的学习有所帮助。
2.在此吐槽一下东家CSDN的编辑框,非常难用,刚才排版还好好的,现在打开又是一团糟,对你造成的阅读不便我带csdn向您道歉!
以下是正文: ===============================================================================================================================
??
? ? ??最近在公司让用C#写一个串口调试的工具,要求向串口中输入16进制数据或字符串。下面我将这次遇到的问题和解决方法奉献出来,希望对工作中需要的朋友有所帮助! ? ? ?? 我们来看具体的实现步骤。
? ?公司要求实现以下几个功能: 1):实现两台计算机之前的串口通信,以16进制形式和字符串两种形式传送和接收。 2):根据需要设置串口通信的必要参数。 3):定时发送数据。 4):保存串口设置。
? ? ??看着好像挺复杂,其实都是纸老虎,一戳就破,前提是你敢去戳。我尽量讲的详细一些,争取说到每个知识点。
? ? ? 在编写程序前,需要将你要测试的COM口短接,就是收发信息都在本地计算机,短接的方式是将COM口的2、3号针接起来。COM口各针的具体作用,度娘是这么说的:COM口。记住2、3针连接一定要连接牢固,我就是因为接触不良,导致本身就不通,白白花掉了一大半天时间调试代码。
下面给出主要的操作界面,如下:
![]()
 顺便,我将所有控件对应的代码名字也附上了,相信对初学者来说,再看下面的代码会轻松很多。控件名字命名的方法是“控件名+作用”的形式,例如“打开串口”的开关按钮,其名字是btnSwitch ?(btn就是button的简写了)。我认为这种命名控件的方式比较好,建议大家使用,如果你有好的命名方式,希望你能告诉我!
下面我们将各个功能按照从主到次的顺序逐个实现。(我分块给出代码实现,代码下载见文章最后。)
一、获取计算机的COM口总个数,将它们列为控件cbSerial的候选项,并将第一个设为cbSerial的默认选项。
这部分是在窗体加载时完成的。请看代码: (很多信息代码的注释里讲的很清楚,我就不赘述了。)
[csharp]
view plain
copy
print
?


- ??
- ???????????string[]?str?=?SerialPort.GetPortNames();??
- ???????????if?(str?==?null)??
- ???????????{??
- ???????????????MessageBox.Show("本机没有串口!",?"Error");??
- ???????????????return;??
- ???????????}??
- ??
- ?????????????
- ???????????foreach?(string?s?in?System.IO.Ports.SerialPort.GetPortNames())??
- ???????????{??
- ???????????????cbSerial.Items.Add(s);??
- //串口设置默认选择项??
- ???????????cbSerial.SelectedIndex?=?0;???????????
二、“串口设置” 这面我没代码编程,直接从窗体上按照串口信息设置就行。我们仅设置它们的默认选项,但这里我用到了ini文件,暂时不讲,我们先以下面形式设置默认。
copy
cbBaudRate.SelectedIndex?=?5;??
?cbDataBits.SelectedIndex?=?3;??
?cbStop.SelectedIndex?=?0;??
?cbParity.SelectedIndex?=?0;??
?radio1.Checked?=?true;????
?rbRcvStr.Checked?=?true;??
三、打开串口
在发送信息之前,我们需要根据选中的选项设置串口信息,并设置一些控件的属性,最后将串口打开。
private void btnSwitch_Click(object sender,EventArgs e)? ? ? ? { //sp1是全局变量。?SerialPort>
[csharp]?
view plain
?copy
?print
?


?private?void?btnSwitch_Click(object?sender,?EventArgs?e)??
- ???????{??
- ??
四、发送信息因为这里涉及到字符的转换,难点在于,在发送16进制数据时,如何将文本框中的字符数据在内存中以同样的形式表现出来,例如我们输入16进制的“eb 90”显示到内存中,也就是如下形式:
 ?? ? ? ??
或输入我们想要的任何字节,如上面的“12 34 56 78 90”.内存中的数据时16进制显示的,而我们输入的数据时字符串,我们需要将字符串转换为对应的16进制数据,然后将这个16进制数据转换为字节数据,用到的主要方法是:
copy
? Convert.ToInt32??(String,?Int32);Convert.ToByte??(Int32);??
这是我想到的,如果你有好的方法,希望你能告诉我。 下面看代码:
copy
? private?void?btnSend_Click(object?sender,?EventArgs?e)?{???
????????if?(!sp1.IsOpen)???
????????????{?MessageBox.Show("请先打开串口!",?"Error");??
????????????return;???
????????????}???
????????String?strSend?=?txtSend.Text;???
????????if?(radio1.Checked?==?true)???
????????????{???
??????????????
????????????string?sendBuf?=?strSend;?string?sendnoNull?=?sendBuf.Trim();???
????????????string?sendNOComma?=?sendnoNull.Replace(',',?'?');???
????????????string?strSendNoComma2?=?sendNOComma1.Replace("0x",?"");???
????????????strSendNoComma2.Replace("0X",0); background-color:inherit">//去掉0X???
????????????string[]?strArray?=?strSendNoComma2.Split('?');????
????????????int?byteBufferLength?=?strArray.Length;???
????????????for?(int?i?=?0;?i?<strArray.Length;?i++?)???
????????????{??
????????????????if?(strArray[i]=="")???
????????????????{???
????????????????????byteBufferLength--;??
????????????????}???
????????????????}?byte[]?byteBuffer?=?new?byte[byteBufferLength];???
????????????}??
????????int?ii?=?0;???
????}??
五、数据的接收
亮点来了,看到这里,如果你还没吐(可能是我的代码比较拙劣!),那么下面的知识点对你也不成问题。这里需要用到 委托 的知识,我是搞C/C++出身,刚碰到这个知识点还真有点不适应。为了不偏离主题,关于委托,我仅给出两条比较好的链接,需要的网友可以去加深学习:C#委托、订阅委托事件。? ? ? ?在窗体加载时就订阅上委托是比较好的,所以在Form1_Load中添加以下代码:
copy
<pre?code_snippet_id="128560"?snippet_file_name="blog_20131226_6_5274381"?name="code"?class="csharp">Control.CheckForIllegalCrossThreadCalls?=?false;??????
sp1.DataReceived?+=?new?SerialDataReceivedEventHandler(sp1_DataReceived);???
??????注意,因为自.net?2.0以后加强了安全机制,,不允许在winform中直接跨线程(事件触发需要产生一个线程处理)访问控件的属性,第一条代码的意图是说在这个类中我们强制不检查跨线程的调用是否合法。处理这种问题的解决方案有很多,具体可参阅以下内容:解决方案。??
??????好了,订阅委托之后,我们就可以处理接收数据的事件了。??
?void?sp1_DataReceived(object?sender,?SerialDataReceivedEventArgs?e)??
????????{??
????????????if?(sp1.IsOpen)???????
????????????{??
????????????????byte[]?byteRead?=?new?byte[sp1.BytesToRead];??????
????????????????if?(rdSendStr.Checked)????????????????????????????
????????????????{??
????????????????????txtReceive.Text?+=?sp1.ReadLine()?+?"rn";???
????????????????????sp1.DiscardInBuffer();????????????????????????
????????????????}??
????????????????else??????????????????????????????????????????????
????????????????{??
????????????????????try??
????????????????????{??
????????????????????????Byte[]?receivedData?=?new?Byte[sp1.BytesToRead];??????????
????????????????????????sp1.Read(receivedData,?0,?receivedData.Length);???????????
????????????????????????sp1.DiscardInBuffer();????????????????????????????????????
????????????????????????string?strRcv?=?null;??
??
????????????????????????for?(int?i?=?0;?i?<?receivedData.Length;?i++)???
????????????????????????{??
????????????????????????????
????????????????????????????strRcv?+=?receivedData[i].ToString("X2");????
????????????????????????}??
????????????????????????txtReceive.Text?+=?strRcv?+?"rn";??
????????????????????}??
????????????????????catch?(System.Exception?ex)??
????????????????????????MessageBox.Show(ex.Message,?"出错提示");??
????????????????????????txtSend.Text?=?"";??
????????????????????}??
????????????}??
????????????else??
????????????{??
????????????????MessageBox.Show("请打开某个串口",?"错误提示");??
????????}??
</pre><br><br>??
? ? ? ?为了友好和美观,我将当前时间也显示出来,又将显示字体的颜色做了修改:
copy
//输出当前时间??
????????????????DateTime>??
做到这里,大部分功能就已实现了,剩下的工作就是些简单的操作设置了,有保存设置、定时发送信息、控制文本框输入内容等。六、保存设置这部分相对简单,但当时我没接触过,也花了点时间,现在想想,也不过如此。保存用户设置用ini文件是个不错的选择,虽然大部分都用注册表实现,但ini文件保存还是有比较广泛的使用。.ini 文件是Initialization File的缩写,也就是初始化文件。为了不偏离正题,也不过多说明,可参考相关内容(网上资源都不错,因人而异,就不加链接了)。使用Inifile读写ini文件,这里我用到了两个主要方法:
[csharp]
view plain
copy
print
?


//读出ini文件??
- a:=inifile.Readstring('节点','关键字',缺省值);??
- b:=inifile.Readinteger('节点',0); background-color:inherit">//?integer类型???
- c:=inifile.Readbool('节点',0); background-color:inherit">//?boolean类型???
- 其中[缺省值]为该INI文件不存在该关键字时返回的缺省值。???
- //写入INI文件:???
- inifile.writestring('节点',变量或字符串值);???
- inifile.writeinteger('节点',变量或整型值);???
- inifile.writebool('节点',变量或True或False);???
- 请看代码:??
- //using?省写了??
- namespace?INIFILE??
- {??
- ????class?Profile??
- ????{??
- ????????public?static?void?LoadProfile()??
- ????????????string?strPath?=?AppDomain.CurrentDomain.BaseDirectory;??
- ????????????_file?=?new?IniFile(strPath?+?"Cfg.ini");??
- ????????????G_BAUDRATE?=?_file.ReadString("CONFIG",?"BaudRate",?"4800");??????
- ????????????G_DATABITS?=?_file.ReadString("CONFIG",?"DataBits",?"8");??
- ????????????G_STOP?=?_file.ReadString("CONFIG",?"StopBits",?"1");??
- ????????????G_PARITY?=?_file.ReadString("CONFIG",?"Parity",?"NONE");??
- ???????????
- ????????public?static?void?SaveProfile()??
- ????????{??
- ????????????string?strPath?=?AppDomain.CurrentDomain.BaseDirectory;??
- ????????????_file?=?new?IniFile(strPath?+?"Cfg.ini");??
- ????????????_file.WriteString("CONFIG",?G_BAUDRATE);??????????????
- "G_PARITY",?G_PARITY);??
- ????????private?static?IniFile?_file;??
- ????????public?static?string?G_BAUDRATE?=?"1200";??
- ????????public?static?string?G_DATABITS?=?"8";??
- ????????public?static?string?G_STOP?=?"1";??
- ????????public?static?string?G_PARITY?=?"NONE";??????
- ????}??
- }??
_file声明成了内置对象,可以方便各函数的调用。 下面是“保存设置”的部分代码:
copy
private?void?btnSave_Click(object?sender,?EventArgs?e)??
??????????????
??????????????
????????????string?strBaudRate?=?cbBaudRate.Text;??
????????????string?strDateBits?=?cbDataBits.Text;??
????????????string?strStopBits?=?cbStop.Text;??
????????????Int32?iBaudRate?=?Convert.ToInt32(strBaudRate);??
????????????Int32?iDateBits?=?Convert.ToInt32(strDateBits);??
????????????Profile.G_BAUDRATE?=?iBaudRate+"";?????????
????????????Profile.G_DATABITS?=?iDateBits+"";?????????
????????????switch?(cbStop.Text)??????????????
????????????????case?"1":??
????????????????????Profile.G_STOP?=?"1";??
????????????????????break;??
????????????????case?"1.5":??
????????????????????Profile.G_STOP?=?"1.5";??
????????????????????break;??
?????????????????
????????……??
????????????}??
????????????switch?(cbParity.Text)???????????????
????????????????case?"无":??
????????????????????Profile.G_PARITY?=?"NONE";??
????????????????…………??
????????Profile.SaveProfile();????
}??
? ? 读取ini文件主要在加载窗体时执行: INIFILE.Profile.LoadProfile();//加载所有
七、控制文本输入这里倒挺简单,只是注意一点。当我们控制输入非法字符时,可通过控制e.Handed的属性值实现,注意这里的Handed属性是“操作过”的含义,而非“执行此处操作”之意,Handled是过去式,看字面意思,"操作过的=是;",将这个操作的状态设为已处理过,自然就不会再处理了。具体参见MSDN:Handed
copy
private?void?txtSend_KeyPress(object?sender,?KeyPressEventArgs?e)??
????????????if?(radio1.Checked==?true)??
??????????????????
????????????????string?patten?=?"[0-9a-fA-F]|b|0x|0X|?";???
????????????????Regex?r?=?new?Regex(patten);??
????????????????Match?m?=?r.Match(e.KeyChar.ToString());??
????????????????if?(m.Success?)??
????????????????????e.Handled?=?false;??
????????????????else??
????????????????????e.Handled?=?true;??
????????????}??
八、定时发送信息 ? ? ?这边看似很简单,但也有一点需要注意,当定时器生效时,我们要间隔访问“发送”按键的内容,怎么实现?还好MS给我们提供了必要的支持,使用Button的 PerformClick可以轻松做到, ?PerformClick参见MSDN:PerformClick
copy
private?void?tmSend_Tick(object?sender,0); background-color:inherit">//转换时间间隔??
????????????string?strSecond?=?txtSecond.Text;??
????????????try??
????????????????int?isecond?=?int.Parse(strSecond)?*?1000;??
????????????????tmSend.Interval?=?isecond;??
????????????????if?(tmSend.Enabled?==?true)??
????????????????????btnSend.PerformClick();???
????????????catch?(System.Exception?ex)??
????????????????MessageBox.Show("错误的定时输入!",?"Error");??
??????????????
????????}??
? ?千万注意在一些情况下不要忘了让定时器失效,如在取消“定时发送数据"和“关闭串口”时等。
代码下载: 有CSDN账号的童鞋:《C#串口通信工具》 无CSDN账户的童鞋:《C#串口通信工具》
顶
38
踩
0
?
?
- 上一篇c#数据操作:数据库访问 和 文件操作
- 下一篇《C++ Primer》 P415 消息处理机制 源代码
我的同类文章
?
-
?.Net Framework各版本之间的关系2013-01-21
-
?C#中ref和out的区别2013-01-15
猜你在找
C#.NET_面向对象编程技术
微信公众平台深度开发Java版 v2.0(第一季)完整版
使用C#开发信息管理系统
ASP.NET企业级开发基础
数据结构和算法
在C#中使用SerialPort类实现串口通信
C#串口通信MSComm控件使用详解
在C#中使用SerialPort类实现串口通信 遇到多线程问题
C#serialport类实现串口通信的源代码
C# 使用SerialPort控件用类及线程实现串口通信
id="iframeu1607657_0" src="http://pos.baidu.com/fcym?sz=728x90&rdid=1607657&dc=2&di=u1607657&dri=0&dis=0&dai=2&ps=10491x443&coa=at%3D3%26rsi0%3D728%26rsi1%3D90%26pat%3D6%26tn%3DbaiduCustNativeAD%26RSS1%3D%2523FFFFFF%26conBW%3D1%26adp%3D1%26ptt%3D0%26titFF%3D%2525E5%2525BE%2525AE%2525E8%2525BD%2525AF%2525E9%25259B%252585%2525E9%2525BB%252591%26titFS%3D%26RSS2%3D%2523000000%26titSU%3D0%26ptbg%3D90%26piw%3D0%26pih%3D0%26ptp%3D0&dcb=BAIDU_SSP_define&dtm=BAIDU_DUP_SETJSONADSLOT&dvi=0.0&dci=-1&dpt=none&tsr=0&tpr=1463452724928&ti=%E7%94%A8C%23%E4%B8%80%E6%AD%A5%E6%AD%A5%E5%86%99%E4%B8%B2%E5%8F%A3%E9%80%9A%E4%BF%A1%20-%20%E7%8E%8B%E6%B0%91%E5%88%A9%20-%20%E5%8D%9A%E5%AE%A2%E9%A2%91%E9%81%93%20-%20CSDN.NET&ari=1&dbv=2&drs=3&pcs=1663x907&pss=1663x14197&cfv=18&cpl=30&chi=1&cce=true&cec=UTF-8&tlm=1463452724<u=http%3A%2F%2Fblog.csdn.net%2Fgeekwangminli%2Farticle%2Fdetails%2F7851673<r=http%3A%2F%2Fsoguge.com%2F&ecd=1&psr=1680x1050&par=1680x1010&pis=-1x-1&ccd=24&cja=true&cmi=59&col=zh-CN&cdo=-1&tcn=1463452725&qn=189ec59d7467eed9&tt=1463452724915.20.288.290" width="728" height="90" align="center,center" vspace="0" hspace="0" marginwidth="0" marginheight="0" scrolling="no" frameborder="0" allowtransparency="true" style="border-width: 0px; vertical-align: bottom; margin: 0px;">
23楼?
xulichun9?2016-03-09 11:06发表?[回复]

接收的代码我改了一下:
[csharp]?
view plain
?copy
??
if(rbRcvStr.Checked)??
- ????????????????{??
- ????????????????????try??
- ????????????????????{??
- ????????????????????????txtReceive.Text?+=?sp1.ReadLine()?+?"rn";???
- ????????????????????????sp1.DiscardInBuffer();????????????????????????
- ????????????????????}??
- ????????????????????catch?(Exception)??
- ????????????????????{??
- ????????????????????????sp1.DiscardInBuffer();??
- ????????????????????????MessageBox.Show("发送端可能不是以字符串发送,尝试16进制看");??
- ????????????????????????rbRcv16.Checked?=?true;??
- ??????????????????????
- ????????????????}??
22楼?
仙人掌的球?2015-05-07 15:36发表?[回复]

楼主讲的很细!
当时就是学的他的教程。
21楼?
cyp1230?2014-05-13 22:11发表?[回复]

数据接收有问题啊。。
txtReceive.Text += sp1.ReadLine() + "rn" 这一句显示(由于线程退出或应用程序请求,已中止 I/O 操作)
20楼?
um哈士奇?2013-12-03 12:49发表?[回复]

hi,你好 上面的memory1,左边显示 十六进制,右边显示字母的程序要怎么写呢?多谢
19楼?
longdreams?2013-11-20 09:44发表?[回复]

lz,能告诉我什么COM口短接,即就是收发信息都在本地 ..
Re:?
王民利?2013-11-25 17:41发表?[回复]

回复longdreams:你找跟金属线将2、3两镇短接就行,我直接用一段铁丝缠上的。
18楼?
ShadowfaxGHH?2013-11-13 16:46发表?[回复]

赞一个 楼主写的很不错哦?
很详细,适合初学者,可以再把RS232的那张图贴上
17楼?
sonyshang_s?2013-11-13 13:14发表?[回复]

鼎楼主
16楼?
mznxbc123456?2013-08-07 11:33发表?[回复]

LZ,我在2010下编译代码第143行会报错,就是你打开com9那行代码,我注释以后运行的话,是不是我没有串口在打开?我是台式机没有串口...提示Error未将对象引用设置到对象的实例 意思是不是没有串口在打开啊
Re:?
sonyshang_s?2013-12-09 17:05发表?[回复]

回复mznxbc123456:在cbSerial的Item里边设置COM1,COM2==
Re:?
80donet?2013-09-09 16:52发表?[回复]

回复mznxbc123456:选的端口号不对,不要注释,改写索引值就行了
15楼?
mznxbc123456?2013-08-07 11:18发表?
很不错 在努力学习中
14楼?
kingie?2013-08-05 23:18发表?[回复]

写得不错,开源精神更好,顶顶
13楼?
kingboyszxf?2013-07-29 12:04发表?[回复]

刚下载了你写的这个程序,为什么我打开COM1之后,选好发送方:字符串,接收方:字符串,点了发送之后没反应呢?接收方的框内也不显示数据,不知道是啥原因?我用COM1 COM2都试了一样的问题.
王民利?2013-08-05 21:47发表?
回复kingboyszxf:挨个COM口测试一下看看呢?我这里测试用的是COM9口。
12楼?
kingboyszxf?2013-07-29 11:59发表?
请教一下楼主:串口如果不接设备的话,可以自己发送一个信息,然后再接收回来吗?我下载了几个串口调试工具,发送出去之后都没有反应,不知道是什么原因..
80donet?2013-09-09 16:49发表?
回复kingboyszxf:不连单片机或者PC怎么会收到返回值呢?都要的,要不PC与PC通信,要不PC与单片机连
11楼?
HsuWin?2013-07-23 17:47发表?[回复]

感謝分享~很詳盡^____^
10楼?
linch2012?2013-07-18 14:17发表?[回复]

写的很详细
9楼?
lfc12345678?2013-06-27 20:43发表?[回复]

写的不错,楼主真是好人
8楼?
你是最重要的决定?2013-06-19 10:55发表?[回复]

楼主写得很好,很有用,可还是有不明白的地方,加了楼主的QQ,希望能加我,麻烦您啦
7楼?
xukai871105?2013-06-07 13:29发表?[回复]

写的非常不错,也花了楼主不少时间吧,先向你学习了!
6楼?
Tigerdawn?2013-05-09 22:03发表?[回复]

楼主好人,一生平安呀!!!
5楼?
lelliao?2013-05-03 10:21发表?[回复]

楼主好人啊, 现在正在写发卡器程序, 参考了, 谢谢!
4楼?
lajalvam?2013-05-01 11:15发表?[回复]

很好,谢谢楼主,我正在做串口。看起来简单,可是问题频出。
3楼?
暮色流年?2013-04-26 15:46发表?[回复]

楼主,也给我发个源码zongruibiao@163.com.谢谢了
王民利?2013-04-27 14:59发表?
回复暮色流年:http://download.csdn.net/detail/rehongchen/4556190
2楼?
u010231733?2013-04-12 09:20发表?[回复]

你好,为什么那个SerialPortConnection(串口调试)程序收发信息模块无法实现呢?
1楼?
marlin3018?2012-09-05 11:08发表?[回复]

博主讲的很详细,最近也要做一个串口通信的界面,正在学习中。希望博主能上传源码。谢谢。
Re:?
黑色的彩?2013-04-01 15:43发表?[回复]

回复marlin3018:您好,我是大一的学生,最近我们实验室让我们自己在网上找资料进行自学用C#编程写串口通信,可是我都只找到一些零碎的东西,看不明白,请问您有什么好的建议吗???希望您能帮帮我!!!谢谢!!我的邮箱是c1264483422@163.com
王民利?2012-09-05 19:43发表?
回复marlin3018:不好意思,我原本想完善之后立即上传的,时间长了也放下了。现在源代码在公司那台计算机上,我几天会会公司传给你吧。
Re:?
marlin3018?2012-09-05 21:10发表?[回复]

回复王民利:嗯,谢谢。最近刚开始看串口通信,一直没能入门。正纠结着。我的邮箱是243211816@qq.com!
Re:?
王民利?2012-09-05 21:21发表?[回复]

回复marlin3018:好的,周六我去公司,我上传网络,你直接(0积分)下载就可以了。
Re:?
marlin3018?2012-09-06 20:52发表?[回复]

回复王民利:可以加你QQ好友吗,有些串口方面的疑惑想请教你。
Re:?
王民利?2012-09-08 10:06发表?[回复]

回复marlin3018:代码我已上传,你可以去下载:http://download.csdn.net/detail/rehongchen/4556190
Re:?
王民利?2012-09-06 21:58发表?
回复marlin3018:我也是临时抱佛脚学的串口通信,比较水的,只能说互相学习吧,QQ:974484821
(编辑:北几岛)
【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!
|