基于VC++的串口通信的设计与实现.docx
《基于VC++的串口通信的设计与实现.docx》由会员分享,可在线阅读,更多相关《基于VC++的串口通信的设计与实现.docx(21页珍藏版)》请在冰点文库上搜索。
基于VC++的串口通信的设计与实现
课程论文首页
院、系(部)
电子信息工程系
专业
通信工程
班级
092
学号
910705241
姓名
课程教师
林元模
课程名称
软件开发与技术
论文题目
基于VC++的串口通信的设计与实现
成绩
评
语
签字:
年月日
复
核
人
意
见
签字:
年月日
基于VC++的串口通信的设计与实现
中文摘要:
在visualC++6.0平台下,利用MSComm控件编写串口通信程序,实现了串口通信参数设置与显示、打开和关闭串口、接收和发送数据、自动发送、十六进制发送与显示、清空接收区和发送区内容的功能。
关键词:
串口MSComm
1串口通信
1.1基本概念
串行通信是指通信的发送方和接收方之间数据信息的传输是在单根数据线上,以每次一个二进制的0、1为最小单位逐位进行传输,如图1所示。
图1串行通信
串行数据传送的特点是:
数据传送按位顺序进行,最少只需要一根传输线即可完成,节省传输线。
与并行通信相比,串行通信还有较为显著的优点:
传输距离长,可以从几米到几千米;在长距离内串行数据传送速率会比并行数据传送速率快;串行通信的通信时钟频率容易提高;串行通信的抗干扰能力十分强,其信号间的互相干扰完全可以忽略。
但是串行通信传送速度比并行通信慢得多,并行通信时间为T,则串行时间为NT。
正是由于串行通信的接线少、成本低,因此它在数据采集和控制系统中得到了广泛的应用,产品也多种多样。
1.2工作模式
通过单线传输信息是串行数据通信的基础。
数据通常是在两个站(点对点)之间进行传送,按照数据流的方向可分成3种传送模式:
单工、半双工和全双工。
(1)单工形式。
单工形式的数据传送是单向的。
通信双方中,一方固定为发送端,另一方则固定为接收端。
信息只能沿一个方向传送,使用一根传输线,如图2所示。
单工形式一般用在只向一个方向传送数据的场合。
例如,计算机与打印机之间的通信是单工形式,因为只有计算机向打印机传送数据,而没有相反的数据传送。
还有在某些通信信道中,如单工无线发送等。
图2单工形式
(2)半双工形式。
半双工通信使用同一根传输线,既可发送数据又可接收数据,但不能同时发送和接收。
在任何时刻只能由其中的一方发送数据,另一方接收数据。
因此半双工形式
既可以使用一条数据线,也可以使用两条数据线,如图3所示。
图3半双工形式
半双工通信中每端需有一个收/发切换电子开关,通过切换来决定数据向哪个方向传输。
因为有切换,所以会产生时间延迟。
信息传输效率低些。
但是对于像打印机这样单方向传输的外围设备,用半双工方式就能满足要求了,不必采用全双工方式,可节省一根传输线。
(3)全双工形式。
全双工数据通信分别由两根可以在两个不同的站点同时发送和接收的传输线进行传送,通信双方都能在同一时刻进行发送和接收操作,如图4所示。
图4全双工形式
在全双工方式中,每一端都有发送器和接收器,有两条传送线,可在交互式应用和远程监控系统中使用,信息传输效率较高。
1.3异步传输与同步传输
串行传输中,数据是一位一位按照到达的顺序依次传输的,每位数据的发送和接收都需要时钟来控制。
发送端通过发送时钟确定数据位的开始和结束,接收端需要在适当的时间间隔对数据流进行采样来正确地识别数据。
接收端和发送端必须保持步调一致,否则就会在数据传输中出现差错。
为了解决以上问题,串行传输可采用以下两种方法:
异步传输和同步传输。
(1)异步传输。
在异步传输方式中,字符是数据传输单位。
在通信的数据流中,字符间异步,字符内部各位间同步。
异步通信方式的“异步”主要体现在字符与字符之间通信没有严格的定时要求。
异步传输中,字符可以是连续地、一个个地发送,也可以是不连续地、随机地进行单独发送。
在一个字符格式的停止位之后,立即发送下一个字符的起始位,开始一个新的字符的传输,这叫做连续的串行数据发送,即帧与帧之间是连续的。
断续的串行数据传送是指在一帧结束之后维持数据线的“空闲”状态,新的起始位可在任何时刻开始。
一旦传送开始,组成这个字符的各个数据位将被连续发送,并且每个数据位持续的时间是相等的。
接收端根据这个特点与数据发送端保持同步,从而正确地恢复数据。
收/发双方则以预先约定的传输速率,在时钟的作用下,传送这个字符中的每一位。
(2)同步传输。
在同步传输方式中,比特块以稳定的比特流的形式传输,数据被封装成更大的传输单位,称为帧。
每个帧中含有多个字符代码,而且字符代码与字符代码之间没有间隙以及起始位和停止位。
和异步传输相比,数据传输单位的加长容易引起时钟漂移。
为了保证接收端能够正确地区分数据流中的每个数据位,收发双方必须通过某种方法建立起同步的时钟。
可以在发送器和接收器之间提供一条独立的时钟线路,由线路的一端(发送器或者接收器)定期地在每个比特时间中向线路发送一个短脉冲信号,另一端则将这些有规律的脉冲作为时钟。
这种技术在短距离传输时表现良好,但在长距离传输中,定时脉冲可能会和信息信号一样受到破坏,从而出现定时误差。
另一种方法是通过采用嵌有时钟信息的数据编码位向接收端提供同步信息
1.4基本参数
波特率:
实际上就是传输速度,它表示每秒钟传送的bit的个数。
当我们提到时钟周期时,我们就是指波特率。
波特率可以远远大于这些值,但是波特率和距离成反比。
数据位:
是衡量通信中实际数据位的参数。
当计算机发送一个信息包,实际的数据不会是8位的,标准的值是5、7和8位。
每个包是指一个字节,包括开始/停止位,数据位和奇偶校验位。
停止位:
用于表示单个包的最后一位。
典型的值为1,1.5和2位。
由于数据是在传输线上定时的,并且每一个设备有其自己的时钟,适用于停止位的位数越多,不同时钟同步的容忍程度越大,但是数据传输率同时也越慢。
奇偶校验位:
在串口通信中一种简单的检错方式。
有四种检错方式:
偶、奇、高和低。
当然没有校验位也是可以的。
2VC++的MicrosoftCommunicationsControl控件
Microsoft公司在WINDOWS中提供了一个串口通讯控件,用它,我们可以很简单的利用串口进行通讯。
在使用它之前,应将控件加在应用程序的对话框上。
然后再用ClassWizard生成相应的对象。
现在我们可以使用它了。
该控件有很多自己的属性,可以通过它的属性窗口来设置,也可以用程序设置。
用程序设置,更灵活。
以下介绍设置中遇到的几个相关函数。
SetCommPort:
指定使用的串口。
GetCommPort:
得到当前使用的串口。
SetSettings:
指定串口的参数。
一般设为默认参数"9600,N,8,1"。
这样方便与其他串口进行通讯。
GetSettings:
取得串口参数。
SetPortOpen:
打开或关闭串口,当一个程序打开串口时,另外的程序将无法使用该串口。
GetPortOpen:
取得串口状态。
GetInBufferCount:
输入缓冲区中接受到的字符数。
SetInPutLen:
一次读取输入缓冲区的字符数。
设置为0时,程序将读取缓冲区的全部字符。
GetInPut:
读取输入缓冲区。
GetOutBufferCount:
输出缓冲区中待发送的字符数。
SetOutPut:
写入输出缓冲区。
3使用MSComm控件编程过程
3.1建立工程
打开VC++6.0建立基于对话框的MFC应用程序liyongtang,然后点击OK,下个界面点击finish。
如图5~图6
图5
图6
3.2在项目中插入MSComm控件
选择project->addtoproject->ComponentsandControls->双击RegisteredActiveXControls->选择MicrosoftCommunicationsControl,version6.0->Insert,按默认值添加,多了个电话图标,这是增加后串口通信控件。
如图7~图8
图7
图8
这时在“ClassView”视窗中就可以看到“CMSComm”类了,并且在控件工具栏Controls中出现了电话图标,即MSComm控件图标。
将CMSComm控件利用鼠标拖放到对话框的资源中,如图9所示。
图9
3.3在对话框添加控件
(1)先向主对话框中添加两个编辑框,一个用于接收显示数据ID为IDC_EDIT_RXDATA,另一个用于输入发送数据,ID为IDC_EDIT_TXDATA;将接收编辑框的Properties->Styles中把Miltiline和VerticalScroll属性选上,发送和接收编辑框就可以输入多行文字。
再打开ClassWizard->MemberViariables选项卡,选择CSCommTestDlg类,为IDC_EDIT_RXDATA添加CString变量m_strRXData,为IDC_EDIT_TXDATA添加CString变量m_strTXData。
说明:
m_strRXData和m_strTXData
分别用来放入接收和发送的字符数据。
(2)添加一个发送按钮两和个清空按钮,功能分别是按一次就把发送编辑框中的内容发送一次和清空已接收的数据和要发送的数据,将发送按钮的ID设为IDC_BTN_SEND;接收数据的清空按钮的ID设为IDC_CLEAR_RECEIVE,要发送数据的清空按钮的ID设为IDC_CLEAR_SEND。
(3)再加入三个复选按钮,分别是十六进制显示,十六进制和自动发送。
自动发送的ID为IDC_CHECK_AUTOSEND,为其添加BOOL型变量m_bAutoSend,设定周期为1s.再利用ClassWizard为其添加BN_CLICK消息处理函数OnC合成卡Autosend()。
十六进制显示的ID为IDC_CHECK_HEXDISPLAY,并添加控制变量m_ctrlHexDiaplay。
十六进制的ID为IDC_CHECK_HEX,并添加控制变量m_ctrlHexSend。
布局如图10。
图11具有MSComm控件布局
3.5添加串口事件消息处理函数OnComm()
查看->建立类向导MFCClassWizard->MessageMaps,在ClassName中选择类CmytestDlg,再在ObjectIDs中选择IDC_MSCOMM1,然后在Message中双击消息OnCom,在弹出的对话框中将函数名改为OnComm(好记),单击“OK”,就加入了串口事件的消息处理函数,如图12:
图12
然后编写OnComm()中的代码,主要任务是从串口接收数据并显示在接收编辑框中。
代码如下:
voidCMytestDlg:
:
OnComm()
{
VARIANTvariant_inp;
COleSafeArraysafearray_inp;
LONGlen,k;
BYTErxdata[2048];//设置BYTE数组
CStringstrtemp;
if(m_ctrlComm.GetCommEvent()==2)
//事件值为2表示接收缓冲区内有字符
{
variant_inp=m_ctrlComm.GetInput();
//读缓冲区
safearray_inp=variant_inp;//VARIANT型变量转换为ColeSafeArray型变量
len=safearray_inp.GetOneDimSize();
//得到有效数据长度
for(k=0;ksafearray_inp.GetElement(&k,rxdata+k);
//转换为BYTE型数组
for(k=0;k//将数组转换为Cstring型变量
{BYTEbt=*(char*)(rxdata+k);//字符型
strtemp.Format("%c",bt);
//将字符送入临时变量strtemp存放
m_strEditRXData+=strtemp;
//加入接收编辑框对应字符串
}
}
UpdateData(FALSE);
//更新编辑框内容
}
3.6串口初始化打开和参数设置模块
如果要进行串口通信,首先必须打开串口,所以我们在程序初始化阶段直接打开串口,即再主对话框的CMSCommTest:
:
OnInitDialog()函数中打开串口。
代码如下:
if(m_ctrlComm.GetPortOpen())
m_ctrlComm.SetPortOpen(FALSE);
m_ctrlComm.SetCommPort
(1);//选择com1
if(!
m_ctrlComm.GetPortOpen())
m_ctrlComm.SetPortOpen(TRUE);
//打开串口
else
AfxMessageBox("cannotopenserialport");
m_ctrlComm.SetSettings("9600,n,8,1");
//波特率9600,无校验,8个数据位,1个停止位
m_ctrlComm.SetInputMode
(1);//1:
表示以二进制方式检取数据
m_ctrlComm.SetRThreshold
(1);//串口接收缓冲区中有1个字符就引发接收OnComm事件
m_ctrlComm.SetInputLen(0);//设置当前接收区数据长度为0
m_ctrlComm.GetInput();//先预读缓冲区以清除残留数据
returnTRUE;
3.7十六进制数据的发送
3.7.1字符串与十六进制的转换
代码如下:
intCMSCommTestDlg:
:
String2Hex(CStringstr,CByteArray&senddata)
{inthexdata,lowhexdata;
inthexdatalen=0;
intlen=str.GetLength();
senddata.SetSize(len/2);
for(inti=0;i{charlstr,hstr=str[i];
if(hstr=='')
{i++;
continue;}
i++;
if(i>=len)
break;
lstr=str[i];
hexdata=ConvertHexChar(hstr);
lowhexdata=ConvertHexChar(lstr);if((hexdata==16)||(lowhexdata==16))
break;
else
hexdata=hexdata*16+lowhexdata;
i++;senddata[hexdatalen]=(char)hexdata;
hexdatalen++;}
senddata.SetSize(hexdatalen);
returnhexdatalen;}
3.7.2十六进制与字符串转换
代码如下:
charCMSCommTestDlg:
:
ConvertHexChar
(charch)
{if((ch>='0')&&(ch<='9'))
returnch-0x30;
elseif((ch>='A')&&(ch<='F'))
returnch-'A'+10;
elseif((ch>='a')&&(ch<='f'))
returnch-'a'+10;
elsereturn(-1);}
3.7.3十六进制数据的发送
在ClassView中为SCommTestDlg类添加以下两个PUBLIC成员函数,并输入相应代码;
由于这个转换函数的格式限制,在发送框中的十六制字符应该每两个字符之间插入一个空隔
代码如下:
voidCMSCommTestDlg:
:
OnBtnSend()
{UpdateData(TRUE);//读取编辑框内容
if(m_ctrlHexSend.GetCheck())
{CByteArrayhexdata;
intlen=String2Hex(m_strTXData,hexdata);
//len可以用于计算发送了多少个十六进制数
m_ctrlComm.SetOutput(COleVariant(hexdata));//发送十六进制数据}
else
m_ctrlComm.SetOutput(COleVariant(m_strTXData));//发送ASCII字符数据}
3.8十六进制数据的显示
首先需要在主对话框中加入一个复选接钮,然后再主框架中添加资源IDC_CHECK_HEXDISPLAYCaption:
十六进制显示,再利用ClassWizard为其添加控制变量:
m_ctrlHexDiaplay。
然后修改CSCommTestDlg:
:
OnComm()函数:
代码如下:
if(m_ctrlHexDiaplay.GetCheck())
strtemp.Format("%02X",bt);
//送入临时变量strtemp存放
else
strtemp.Format("%c",bt);
//将字符送入临时变量strtemp存放
3.9串口发送和清除数据模块
代码如下:
voidCMSCommTestDlg:
:
OnBtnSend()
{UpdateData(TRUE);//读取编辑框内容
m_ctrlComm.SetOutput(COleVariant(m_strTXData));//发送数据}
3.10自动发送
在ClassWizard中选上MessageMap卡,然后在ObjectsIDs选中CSCommTestDlg类,再在Messages框中选上WM_TIMER消息,单击ADD_FUNCTION加入voidCSCommTestDlg:
:
OnTimer(UINTnIDEvent)函数,这个函数是放入“发送时间到”后要处理的内容。
代码如下:
voidCMSCommTestDlg:
:
OnCheckAutosend()
{m_bAutoSend=!
m_bAutoSend;
if(m_bAutoSend)
{SetTimer(1,1000,NULL);
//时间为1000毫秒}
else
{KillTimer
(1);//取消定时}
}
3.11退出按钮弹出的的对话框模块
voidCMSCommTestDlg:
:
OnOK()
{CDialog:
:
OnOK();
AfxMessageBox
(_T("再见,串口通信!
"));
4调试分析
(1)首先打开串口调试助手,并将串口设在COM2,然后运行VC6.0中的liyongtang文件,会弹出一个对话框界面如图14,通过串口大师软件,在发送区域输入“你好,我是通信092的”,并点击发送,在编辑框的接收端显示“你好,我是通信092的”。
如图13
图13发送数据
图14接收数据
(2)在编辑框中输入“你好,请问你是谁”,然后单击“发送”在串口调试助手中同样也能够接收到相应的字符,表明数据发送成功。
如图15,16所示。
图15编辑要发送的数据图16接收数据
(3)在编辑框内选择复选框的自动发送,然后在要发送的数据的文本框内输入“你好,请问你是谁”,如图17所示,自动发送实现的是每隔1s的时间连续发送一次数据。
自动发送的数据在串口大师端显示如图18,表明了数据发送成功。
图17
图18显示接收到的数据
(4)单击发送数据框旁“清除”按钮,刚才所编辑的数据全部被清除。
如图19所示,同样,单击接收数据框旁“清除”按钮,也能把接收到的数据给清除。
图19成功清除发送数据
(5)首先在串口大师接收数据处选择“16”进制,然后在编辑框内选择复选框的十六进制。
并在输入框中输入十六进制字符“A2D2DE”,点击发送,同样在串口助手接收框收到结果相同的十六进制的数据,如图20和图21所示。
图20图21
(6)在串口大师发送框中输入十六进制字符“B258EFDE”,并选上以十六进制发送,单击手动发送,同样在编辑框的接收框收到结果相同的十六进制的数据,如图22和图23所示
图22图23
(7)通信结束后,点击退出按钮,就会显示消息框“再见,串口通信!
”,如图24。
图24退出消息框
5心得体会
通过一段时间VC++上机操作和本次的课程设计,我从中学到了很多知识,在实验过程中,通过查资料和搜集有关的文献,培养了自学能力和动手能力。
这次实验是用MSComm控件完成的,这种方法程序比较简单,还可以调用Windows的API函数,这种方法可以清楚地掌握串口通信的机制,相对比较自由灵活,但是本程序也存在一些不足,如:
十六进制发送时,只要其中有一个非十六进制数,则不能把数据发送出去。
还有在实验过程中需要注意在添加控件的时候要及时编辑它的名称和控制变量,并在程序的调用中正确使用,否则一个不小心就会出现错误。
总之,要想学好c++这门课,除了要有扎实的基础知识,还必须有细心,有耐心,能善于思考勇于实践。
参考文献:
[1]代勇.Visualc++网络通信编程技术详解.机械工业出版社
[2]张筠莉.VisualC++实践与提高.串口通信与工程应用篇[M].北京:
中国铁道出版社,2005.
[4]李现勇.VisualC++串口通信与工程实践[M].北京:
人民邮电出版社,2005.