串口编程.docx

上传人:b****5 文档编号:8196794 上传时间:2023-01-29 格式:DOCX 页数:17 大小:25.24KB
下载 相关 举报
串口编程.docx_第1页
第1页 / 共17页
串口编程.docx_第2页
第2页 / 共17页
串口编程.docx_第3页
第3页 / 共17页
串口编程.docx_第4页
第4页 / 共17页
串口编程.docx_第5页
第5页 / 共17页
点击查看更多>>
下载资源
资源描述

串口编程.docx

《串口编程.docx》由会员分享,可在线阅读,更多相关《串口编程.docx(17页珍藏版)》请在冰豆网上搜索。

串口编程.docx

串口编程

1-在C++Builder6.0下基于api函数编写串口通信程序简介:

在dos/win95/win98的年代,操作系统对串口是不保护的,也就是说将串口的的资源完全

开放给用户,用户可以用直接操作硬件的函数(比如说TC2.0下的inport()和outport()函数)

跟串口直接打交道,这时候用户使用直接操作串口的函数怎样"折磨"串口都是没有问题的,

操作系统根本就不管不问,对串口操作所造成的一切后果都是用户一个人承担的,这时候用

户对串口具有高度自由的支配权;但是,这种情况好景不长,从win2000操作系统开始,微软

为了"照顾好"计算机上的硬件,开始实施了对硬件的保护策略,也就是说任何用户在他的操作

系统下企图操纵串口时必须经过他的同意方可进行,其实也就是变相的将用户往必须使用他的

通信api函数才能操作串口这条"羊肠小路"上赶(当然也有别的方法操作串口,但那些并非我等

普通用户能研究明白的),形象一点说就好像你想怎样操作串口的意图必须经过win2000的翻译

(其实是win2000的设备驱动程序)才能转达给串口一样,基于这一点我们说(其实是很多资料上

说的)win2000下通过api函数操作串口是具有"设备无关性的",什么意思呢?

就是说你想怎样

操作串口就用相应的api函数告诉操作系统你想对串口干什么,然后操作系统就把你的意思转

告给串口让其做出相应的动作,相对于dos/win95/win98下来说,据我理解也就相当于你原来

写的直接操作串口的函数在win2000下他替你完成了,但是你必须用win2000通信api函数清楚

地向操作系统表达清楚你到底想干什么,所以说在这种情况下要想写好串口驱动程序你就必须

至少弄明白win2000下的通信api函数都是干什么的方可,啰里啰唆唠叨了这么多......sorry,

还没完呢,至少还有一件事我想说,原来在dos/win95/win98系统下有好多高手用c/c++对串口

进行直接操作是非常熟练的,尤其是dos时代的turbo2.0操作串口的高手他们写的串口驱动程

序直到win98的时候还用的非常洋洋得意,但是到了win2000的时候,他们的程序突然不好使了

,而他们有的可能还会因为知识结构上的滞后始终弄不明白怎么回事儿,兄弟们,你们该明白

了吧?

闲话少叙,下面介绍笔者写串口通信函数时用到的各个api函数---------

2-CreateFile()

用途:

打开串口

原型:

HANDLECreateFile(LPCTSTRlpFileName,

DWORDdwDesiredAccess,

DWORDdwShareMode,

LPSECURITY_ATTRIBUTESlpSecurityAttributes,

DWORDdwCreationDistribution,

DWORDdwFlagsAndAttributes,

HANDLEhTemplateFile);

参数说明:

-lpFileName:

要打开的文件名称。

对串口通信来说就是COM1或COM2。

-dwDesiredAccess:

读写模式设置。

此处应该用GENERIC_READ及GENERIC_WRITE。

-dwShareMode:

串口共享模式。

此处不允许其他应用程序共享,应为0。

-lpSecurityAttributes:

串口的安全属性,应为0,表示该串口不可被子程序继承。

-dwCreationDistribution:

创建文件的性质,此处为OPEN_EXISTING.

-dwFlagsAndAttributes:

属性及相关标志,这里使用异步方式应该用FILE_FLAG_OVERLAPPED。

-hTemplateFile:

此处为0。

操作说明:

若文件打开成功,串口即可使用了,该函数返回串口的句柄,以后对串口操作时

即可使用该句柄。

举例:

HANDLEhComm;

hComm=CreateFile("COM1",//串口号

GENERIC_READ|GENERIC_WRITE,//允许读写

0,//通讯设备必须以独占方式打开

NULL,//无安全属性

OPEN_EXISTING,//通讯设备已存在

FILE_FLAG_OVERLAPPED,//异步I/O

0);//通讯设备不能用模板打开

hComm即为函数返回的串口1的句柄。

3-CloseHandle()

用途:

关闭串口

原型:

BOOLCloseHandle(HANDLEhObjedt)

参数说明:

-hObjedt:

串口句柄

操作说明:

成功关闭串口时返回true,否则返回false

举例:

CloseHandle(hComm);

4-GetCommState()

用途:

取得串口当前状态

原型:

BOOLGetCommState(HANDLEhFile,

LPDCBlpDCB);

参数说明:

-hFile:

串口句柄

-lpDCB:

设备控制块(DeviceControlBlock)结构地址。

此结构中含有和设备相关的

参数。

此处是与串口相关的参数。

由于参数非常多,当需要设置串口参数

时,通常是先取得串口的参数结构,修改部分参数后再将参数结构写入。

在此仅介绍少数的几个常用的参数:

DWORDBaudRate:

串口波特率

DWORDfParity:

为1的话激活奇偶校验检查

DWORDParity:

校验方式,值0~4分别对应无校验、奇校验、偶校验、校验

置位、校验清零

DWORDByteSize:

一个字节的数据位个数,范围是5~8

DWORDStopBits:

停止位个数,0~2分别对应1位、1.5位、2位停止位

操作举例:

DCBComDCB;//串口设备控制块

GetCommState(hComm,&ComDCB);

5-SetCommState()

用途:

设置串口状态,包括常用的更改串口号、波特率、奇偶校验方式、数据位数等

原型:

BOOLSetCommState(HANDLEhFile,

LPDCBlpDCB);

参数说明:

-hFile:

串口句柄

-lpDCB:

设备控制块(DeviceControlBlock)结构地址。

要更改的串口参数包含在此结构中。

操作举例:

DCBComDCB;

GetCommState(hComm,&ComDCB);//取得当前串口状态

ComDCB.BaudRate=9600;//更改为9600bps,该值即为你要修改后的波特率

SetCommState(hComm,&ComDCB;//将更改后的参数写入串口

6-WriteFile()

用途:

向串口写数据

原型:

BOOLWriteFile(HANDLEhFile,

LPCVOIDlpBuffer,

DWORDnNumberOfBytesToWrite,

LPDWORDlpNumberOfBytesWritten,

LPOVERLAPPEDlpOverlapped);

参数说明:

-hFile:

串口句柄

-lpBuffer:

待写入数据的首地址

-nNumberOfBytesToWrite:

待写入数据的字节数长度

-lpNumberOfBytesWritten:

函数返回的实际写入串口的数据个数的地址,利用此变量可判断

实际写入的字节数和准备写入的字节数是否相同。

-lpOverlapped:

重叠I/O结构的指针

操作举例:

DWORDBytesSent=0;

unsignedcharSendBytes[5]={1,2,3,4,5};

OVERLAPPEDov_Write;

ov_Write.Offset=0;

ov_Write.OffsetHigh=0;

WriteFile(hComm,//调用成功返回非零,失败返回零

SendBytes,//输出缓冲区

5,//准备发送的字符长度

&BytesSent,//实际发出的字符数

&ov_Write);//重叠结构

如果函数执行成功的话检查BytesSent的值应该为5,此函数是WriteFile函数执行完毕后

自行填充的,利用此变量的填充值可以用来检查该函数是否将所有的数据成功写入串口

7-ReadFile()

用途:

读串口数据

原型:

BOOLReadFile(HANDLEhFile,

LPVOIDlpBuffer,

DWORDnNumberOfBytesToRead,

lpNumberOfBytesRead,

lpOverlapped);

参数说明:

-hFile:

串口句柄

-lpBuffer:

存储被读出数据的首地址

-nNumberOfBytesToRead:

准备读出的字节个数

-NumberOfBytesRead:

实际读出的字节个数

-lpOverlapped:

异步I/O结构,

操作举例:

unsignedcharucRxBuff[20];

COMSTATComStat;

DWORDdwError=0;

DWORDBytesRead=0;

OVERLAPPEDov_Read;

ov_Read.hEvent=CreateEvent(NULL,true,false,NULL);//必须创建有效事件

ClearCommError(hComm,&dwError,&ComStat);//检查串口接收缓冲区中的数据个数

bResult=ReadFile(hComm,//串口句柄

ucRxBuff,//输入缓冲区地址

ComStat.cbInQue,//想读入的字符数

&BytesRead,//实际读出的字节数的变量指针

&ov_Read);//重叠结构指针

假如当前串口中有5个字节数据的话,那么执行完ClearCommError()函数后,ComStat

结构中的ComStat.cbInQue将被填充为5,此值在ReadFile函数中可被直接利用。

8-ClearCommError()

用途:

清除串口错误或者读取串口现在的状态

原型:

BOOLClearCommError(HANDLEhFile,

LPDWORDlpErrors,

LPCOMATATlpStat

);

参数说明:

-hFile:

串口句柄

-lpErrors:

返回错误数值,错误常数如下:

1-CE_BREAK:

检测到中断信号。

意思是说检测到某个字节数据缺少合法的停止位。

2-CE_FRAME:

硬件检测到帧错误。

3-CE_IOE:

通信设备发生输入/输出错误。

4-CE_MODE:

设置模式错误,或是hFile值错误。

5-CE_OVERRUN:

溢出错误,缓冲区容量不足,数据将丢失。

6-CE_RXOVER:

溢出错误。

7-CE_RXPARITY:

硬件检查到校验位错误。

8-CE_TXFULL:

发送缓冲区已满。

-lpStat:

指向通信端口状态的结构变量,原型如下:

typedefstruct_COMSTAT{

...

...

DWORDcbInQue;//输入缓冲区中的字节数

DWORDcbOutQue;//输出缓冲区中的字节数

}COMSTAT,*LPCOMSTAT;

该结构中对我们很重要的只有上面两个参数,其他的我们可以不用管。

操作举例:

COMSTATComStat;

DWORDdwError=0;

ClearCommError(hComm,&dwError,&ComStat);

上式执行完后,ComStat.cbInQue就是串口中当前含有的数据字节个数,我们利用此

数值就可以用ReadFile()函数去读串口中的数据了。

9-PurgeComm()

用途:

清除串口缓冲区

原型:

BOOLPurgeComm(HANDLEhFile,

DWORDdwFlags

);

参数说明:

-hFile:

串口句柄

-dwFlags:

指定串口执行的动作,由以下参数组成:

-PURGE_TXABORT:

停止目前所有的传输工作立即返回不管是否完成传输动作。

-PURGE_RXABORT:

停止目前所有的读取工作立即返回不管是否完成读取动作。

-PURGE_TXCLEAR:

清除发送缓冲区的所有数据。

-PURGE_RXCLEAR:

清除接收缓冲区的所有数据。

操作举例:

PurgeComm(hComm,PURGE_RXCLEAR|PURGE_TXCLEAR|PURGE_RXABORT|PURGE_TXABORT);

清除串口的所有操作。

10-SetCommMask()

用途:

设置串口通信事件。

原型:

BOOLSetCommMask(HANDLEhFile,

DWORDdwEvtMask

);

参数说明:

-hFile:

串口句柄

-dwEvtMask:

准备监视的串口事件掩码

注:

在用api函数撰写串口通信函数时大体上有两种方法,一种是查寻法,另外一种是事件通知法。

这两种方法的区别在于收串口数据时,前一种方法是主动的周期性的查询串口中当前有没有

数据;后一种方法是事先设置好需要监视的串口通信事件,然后依靠单独开设的辅助线程进行

监视该事件是否已发生,如果没有发生的话该线程就一直不停的等待直到该事件发生后,将

该串口事件以消息的方式通知主窗体,然后主窗体收到该消息后依据不同的事件性质进行处理。

比如说当主窗体收到监视线程发来的RX_CHAR(串口中有数据)的消息后,就可以用ReadFile()

函数去读串口。

该参数有如下信息掩码位值:

EV_BREAK:

收到BREAK信号

EV_CTS:

CTS(cleartosend)线路发生变化

EV_DSR:

DST(DataSetReady)线路发生变化

EV_ERR:

线路状态错误,包括了CE_FRAME\CE_OVERRUN\CE_RXPARITY3钟错误。

EV_RING:

检测到振铃信号。

EV_RLSD:

CD(CarrierDetect)线路信号发生变化。

EV_RXCHAR:

输入缓冲区中已收到数据。

EV_RXFLAG:

使用SetCommState()函数设置的DCB结构中的等待字符已被传入输入缓冲区中。

EV_TXEMPTY:

输出缓冲区中的数据已被完全送出。

操作举例:

SetCommMask(hComm,EV_RXCHAR|EV_TXEMPTY);

上面函数执行完毕后将监视串口中有无数据和发送缓冲区中的数据是否全部发送完毕。

11-WaitCommEvent()

用途:

用来判断用SetCommMask()函数设置的串口通信事件是否已发生。

原型:

BOOLWaitCommEvent(HANDLEhFile,

LPDWORDlpEvtMask,

LPOVERLAPPEDlpOverlapped

);

参数说明:

-hFile:

串口句柄

-lpEvtMask:

函数执行完后如果检测到串口通信事件的话就将其写入该参数中。

-lpOverlapped:

异步结构,用来保存异步操作结果。

操作举例:

OVERLAPPEDos;

DWORDdwMask,dwTrans,dwError=0,err;

memset(&os,0,sizeof(OVERLAPPED));

os.hEvent=CreateEvent(NULL,TRUE,FALSE,NULL);

if(!

WaitCommEvent(hComm,&dwMask,&os)){

//如果异步操作不能立即完成的话,函数返回FALSE,并且调用GetLastError()函

//数分析错误原因后返回ERROR_IO_PENDING,指示异步操作正在后台进行.这种情

//况下,在函数返回之前系统设置OVERLAPPED结构中的事件为无信号状态,该函数

//等待用SetCommMask()函数设置的串口事件发生,共有9种事件可被监视:

//EV_BREAK,EV_CTS,EV_DSR,EV_ERR,EV_RING,EV_RLSD,EV_RXCHAR,

//EV_RXFLAG,EV_TXEMPTY;当其中一个事件发生或错误发生时,函数将

//OVERLAPPED结构中的事件置为有信号状态,并将事件掩码填充到dwMask参数中

if(GetLastError()==ERROR_IO_PENDING){

/**************************************************************/

/*在此等待异步操作结果,直到异步操作结束时才返回.实际上此时*/

/*WaitCommEvent()函数一直在等待串口监控的事件之一发生,当事件发*/

/*生时该函数将OVERLAPPED结构中的事件句柄置为有信号状态,此时*/

/*GetOverlappedResult()函数发现此事件有信号后马上返回,然后下面*/

/*的程序马上分析WaitCommEvent()函数等到的事件是被监视的串口事*/

/*件中的哪一个,然后执行相应的动作并发出相应消息.*/

/**************************************************************/

GetOverlappedResult(hComm,&os,&dwTrans,true);

switch(dwMask){

caseEV_RXCHAR:

PostMessage(Parent,WM_COMM_RXCHAR,0,0);

break;

caseEV_TXEMPTY:

PostMessage(Parent,WM_COMM_TXEMPTY,0,0);

break;

caseEV_ERR:

switch(dwError){

caseCE_FRAME:

err=0;

break;

caseCE_OVERRUN:

err=1;

break;

caseCE_RXPARITY:

err=2;

break;

default:

break;

}

PostMessage(Parent,WM_COMM_ERR,(WPARAM)0,(LPARAM)err);

break;

caseEV_BREAK:

PostMessage(Parent,WM_COMM_BREAK,0,0);

break;

case...:

//其他用SetCommMask()函数设置的被监视的串口通信事件。

......

break;

default:

break;

}

}

12-以上简要介绍了大部分的串口通信api函数,笔者所写的串口通信软件用的是事件通知方式,该方式是

windows2000下效率较高的一种方式。

而且只熟悉这些api函数也还是不够的,该机制下还要牵涉到多

线程和消息机制,其中读写串口的动作是由主线程来完成的,比如说操作者按下发送数据的按钮之后

,相应函数马上将某特定区域里面的数据发送出去,所以说用api函数写串口发送数据的功能是相对较

简单的。

收数据的时候就要麻烦一点,在打开串口后首先主线程要设置要监视的串口通信事件,然后

将监视线程打开,用来监视主线程设置的这些串口通信事件是否已发生,当其中的某个事件发生后,

监视线程马上将该消息发送给主线程,其中监视线程在发送消息之前要确保主线程在收到消息后肯定

的知道串口究竟发生了什么样的事件,然后根据不同的事件类型进行处理。

下面给出大致的主线程和

监视线程的大致工作流程:

主线程打开(其实就是主窗体打开之后)

|

|

V

打开串口(设置波特率、校验方式、数据位数、停止位数)

|

|

V

设置监视线程需要监视的串口通信事件

|

|

V

打开监视线程

|

|

V

等待各种事件的发生(比如发送数据单击事件,更改通信参数事件,监视线程发来的消息等)

--------------------------------------------------------------------------------

监视线程被打开

|

|

V

串口事件发生否(WaitCommEvent())(无论发生否均进入下面的代码)

|

|

V

异步操作是否正在后台进行?

(if(GetLastError()==ERROR_IO_PENDING))

|

|

V

在此等待异步操作结果(GetOverlappedResult(hComm,&os,&dwTrans,true))

|

|

V

处理通信事件,根据事件类型的不同给主窗体发送不同的消息

---------------------------------------------------------------------------------

以上给出最最简单的工作流程,其实我感觉任何知识都是依靠查资料、问别人等等这些途径获得入门的

基本信息之后再依靠自己孜孜不倦的钻研得来的,饭来张口得到的那种东西往往不如自己嚼出来的东西

体会更深,有一句话我感觉很有味道:

"书读百遍自然熟",但得是用心的读,或许一遍不懂,两遍不懂

,然后没有恒心的人便开始悄悄的准备放弃了,但有恒心的人当再读完一遍之后会越发的发现:

奥,...

...,原来上次不懂的地方是这么回事...,但我个人认为,刚开始是很重要的,如果你连这个课题的最最

基本的东西都不知道的话那就很难了,所以任何人都应该有问别人的时候。

本文来自:

中科软件园()详细出处参考:

前言:

总所周之,利用串口进行数据通讯在在通讯通讯领域重占有着重要的地位。

利用RS232-RS485进行数据信号的采集和传递是VC编程的又一大热点。

串口通讯在通讯软件重有着十分广泛的应用。

如电话、传真、视频和各种控制等。

在各种开发工具中间,VC由于功能强大和灵活,同时也得到了Microsoft的最大支持,所以在一般进行涉及硬件操作的通讯编程中,大都推荐使用VC作为开发工具。

然而工业控制串口通讯这个又不同于一般的串口通讯程序,因为控制外围设备传送的大都是十六进制数据(BYTE类型),所以,为了提高程序的运行稳定性,我们在编写程序进行通讯时可以不考虑传送BYTE类型数据的工作。

串口通讯目前流行的方法大概有两种:

一是利用Microsoft提供的CMSCOMM控件进行通讯,不过现在很多程序员都觉应该放弃这种方式。

二是利用WINAPI函数进行编程,这种编程的难度最高,要求你要掌握很多的API函数。

三是利用现在网络上面提供的一些串口通讯控件进行编写,比如CSerial类等。

程序实现:

我在经过许多的项目的开发和实践中发现,采用WINAPI函数进行串口的开发能够给程序员很大的空间,并且程序运也很稳定。

所以我将与串口接触的函数进行封装,然后在各个工程中进行调用,效果还是比较好的,现将各个函数和调用方法列举出来,希望对各位有所帮助。

一、设置串口相关工作

#defineMAXBLOCK2048

#defineXON0x11

#defineXOFF0x13

BOOLSet

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 表格模板 > 合同协议

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1