用MFC写串口Word格式.docx

上传人:b****5 文档编号:18080905 上传时间:2022-12-13 格式:DOCX 页数:28 大小:34.95KB
下载 相关 举报
用MFC写串口Word格式.docx_第1页
第1页 / 共28页
用MFC写串口Word格式.docx_第2页
第2页 / 共28页
用MFC写串口Word格式.docx_第3页
第3页 / 共28页
用MFC写串口Word格式.docx_第4页
第4页 / 共28页
用MFC写串口Word格式.docx_第5页
第5页 / 共28页
点击查看更多>>
下载资源
资源描述

用MFC写串口Word格式.docx

《用MFC写串口Word格式.docx》由会员分享,可在线阅读,更多相关《用MFC写串口Word格式.docx(28页珍藏版)》请在冰豆网上搜索。

用MFC写串口Word格式.docx

HANDLEhFile,//通信设备串口句柄

DWORDdwInQueue,//输入缓冲区大小

DWORDdwOutQueue//输出缓冲区大小

);

返回值:

若调用成功,返回非零值;

不成功,则为0,有错误时,可调用GetLastError函数得到错误信息

说明:

串口打开后,就可以使用SetupComm为其设置缓冲区大小,若不设置,则系统自动将其他设置成缺省大小。

设置时应避免穿冲区溢出,即比实际大小稍大一点。

(3)GetCommState获得串口当前配置函数

BOOLGetCommState(

HANDLEhFile,

LPDCB 

lpDCB

如果函数调用成功,返回非0值;

调用失败,返回0,这时可调用GetLastError得到有关错误信息。

SetCommState函数通过DCB结果来定义串口配置,当前的串口配置由GetCommState函数得到。

在设置过程中,有时只需要更改几个变量的值,因此,DCB结构中其他值需要保持原值,以保证DCB中的其他成员变量值正确,这些原值就是右GetCommState得到的。

如果设置时出现DCB成员变量XonChar与XoffChar相同,则SetCommState设置失败。

在设置8250时,数据位只能是5-8位。

(5)GetCommProperties获得串口属性函数

BOOLGetCommProperties(

HANDLEhFile, 

//通信设备句柄

LPCOMMPROPlpCommProp 

//指向COMMPROP结构

由该函数得到的串口(或其他通信设备,如并口等)信息可用与SetCommState,SetCommTimeouts和SetupComm三个函数去配置串口信息。

COMMPROP结构说明:

COMMPROP结构只涉及到本函数,因此在这里介绍。

COMMPROP结构声明:

typedefstruct_COMMPROP(

WORDwPacketLength;

//数据簿大小

WORDwPacketVersion;

//COMMPROP结构版本号

DWORDdwServiceMask;

//设置一位掩码

DWORDdwReservedl;

//reserved保留

DWORDdwMaxTxQueue;

//驱动程序发送缓冲区最大允许长度(字节)

DWORDdwMaxRxQueue;

//驱动程序接收缓冲区最大允许长度(字节)

DWORDdwMaxBqud;

//最大波特率

DWORDdwProvSubType;

//设置设备类型

DWORDdwProvCapabiliteis;

//支持功能

DWORDdwSettableParams;

//可修改的通信参数

DWORDdwSettableBaud;

//可设置的波特率

WORD 

wSettableData;

//可设置的数据位

wSettableStopParity;

//可设置的停止位

DWORDdwCurrentTxQueue;

//当前发送缓冲区大小(字节)

DWORDdwCurrentRxQueue;

//当前接收缓冲区大小(字节)

DWORDdwProvSpec1;

//未定义

DWORDdwProvSpec2;

WCHARwcProvChar[1];

(6)BuildCommDCB设备控制块DCB填充函数

BOOLBuildCommDCB(

LPCTSTRlpDef,//设备控制字符串

LPDCBlpDCB//DCB结构

);

返回值:

若调用成功,返回非0零值;

不成功,则为0,有错误时调用GetLastError函数得到错误信息

该函数用来获取指定通信设备的超时参数值。

请教用WriteFile()写串口的问题 

kin 

用WriteFile()写串口,用GetLastError()的得到的错误是ERROR_IO_PENDING

请问这是什么错误,我该如何改正?

多谢!

2003-8-19 

13:

50:

42 

harrymeng 

好好看一下下面的文章,相信你就可以搞定了,:

本文详细介绍了串行通信的基本原理,以及在Windows 

NT、Win98环境下用MFC实现串口(COM)通信的方法:

使用ActiveX控件或Win 

API.并给出用Visual 

C++6.0编写的相应MFC32位应用程序。

关键词:

串行通信、VC++6.0、ActiveX控件、Win 

API、MFC32位应用程序、事件驱动、非阻塞通信、多线程. 

  在Windows应用程序的开发中,我们常常需要面临与外围数据源设备通信的问题。

计算机和单片机(如MCS-51)都具有串行通信口,可以设计相应的串口通信程序,完成二者之间的数据通信任务。

  实际工作中利用串口完成通信任务的时候非常之多。

已有一些文章介绍串口编程的文章在计算机杂志上发表。

但总的感觉说来不太全面,特别是介绍32位下编程的更少,且很不详细。

笔者在实际工作中积累了较多经验,结合硬件、软件,重点提及比较新的技术,及需要注意的要点作一番探讨。

希望对各位需要编写串口通信程序的朋友有一些帮助。

一.串行通信的基本原理 

串行端口的本质功能是作为CPU和串行设备间的编码转换器。

当数据从 

CPU经过串行端口发送出去时,字节数据转换为串行的位。

在接收数据时,串行的位被转换为字节数据。

在Windows环境(Windows 

NT、Win98、Windows2000)下,串口是系统资源的一部分。

应用程序要使用串口进行通信,必须在使用之前向操作系统提出资源申请要求(打开串口),通信完成后必须释放资源(关闭串口)。

串口通信程序的流程如下图:

二.串口信号线的接法 

一个完整的RS-232C接口有22根线,采用标准的25芯插头座(或者9芯插头座)。

25芯和9芯的主要信号线相同。

以下的介绍是以25芯的RS-232C为例。

①主要信号线定义:

     

2脚:

发送数据TXD;

3脚:

接收数据RXD;

4脚:

请求发送RTS;

5脚:

清除发送CTS;

6脚:

数据设备就绪DSR;

20脚:

数据终端就绪DTR;

8脚:

数据载波检测DCD;

1脚:

保护地;

   

7脚:

信号地。

②电气特性:

数据传输速率最大可到20K 

bps,最大距离仅15m. 

注:

看了微软的MSDN 

6.0,其Windows 

API中关于串行通讯设备(不一定都是串口RS-232C或RS-422或RS-449)速率的设置,最大可支持到RS_256000,即256K 

bps!

也不知道到底是什么串行通讯设备?

但不管怎样,一般主机和单片机的串口通讯大多都在9600 

bps,可以满足通讯需求。

③接口的典型应用:

大多数计算机应用系统与智能单元之间只需使用3到5根信号线即可工作。

这时,除了TXD、RXD以外,还需使用RTS、CTS、DCD、DTR、DSR等信号线。

(当然,在程序中也需要对相应的信号线进行设置。

) 

         

图 

最简单的RS232-C信号线接法 

以上接法,在设计程序时,直接进行数据的接收和发送就可以了,不需要   

对信号线的状态进行判断或设置。

(如果应用的场合需要使用握手信号等,需要对相应的信号线的状态进行监测或设置。

三.16位串口应用程序的简单回顾 

  16位串口应用程序中,使用的16位的Windows 

API通信函数:

① 

OpenComm() 

打开串口资源,并指定输入、输出缓冲区的大小(以字节计);

CloseComm() 

关闭串口;

例:

int 

idComDev;

idComDev 

OpenComm("

 

1024, 

128);

CloseComm(idComDev);

② 

BuildCommDCB() 

、setCommState()填写设备控制块DCB,然后对已打开的串口进行参数配置;

DCB 

dcb;

BuildCommDCB("

COM1:

2400,n,8,1"

&

dcb);

SetCommState(&

③ 

ReadComm 

、WriteComm()对串口进行读写操作,即数据的接收和发送. 

char 

*m_pRecieve;

count;

ReadComm(idComDev,m_pRecieve,count);

Char 

wr[30];

count2;

WriteComm(idComDev,wr,count2);

16位下的串口通信程序最大的特点就在于:

串口等外部设备的操作有自己特有的API函数;

而32位程序则把串口操作(以及并口等)和文件操作统一起来了,使用类似的操作。

四.在MFC下的32位串口应用程序 

32位下串口通信程序可以用两种方法实现:

利用ActiveX控件;

使用API 

通信函数。

使用ActiveX控件,程序实现非常简单,结构清晰,缺点是欠灵活;

通信函数的优缺点则基本上相反。

以下介绍的都是在单文档(SDI)应用程序中加入串口通信能力的程序。

㈠ 

使用ActiveX控件:

VC++ 

6.0提供的MSComm控件通过串行端口发送和接收数据,为应用程序提供串行通信功能。

使用非常方便,但可惜的是,很少有介绍MSComm控件的资料。

  ⑴.在当前的Workspace中插入MSComm控件。

Project菜单------>

Add 

to 

Project---->

Components 

and 

Controls----->

Registered 

ActiveX 

Controls--->

选择Components:

Microsoft 

Communications 

Control, 

version 

6.0 

插入到当前的Workspace中。

结果添加了类CMSComm(及相应文件:

mscomm.h和mscomm.cpp 

)。

  ⑵.在MainFrm.h中加入MSComm控件。

protected:

CMSComm 

m_ComPort;

在Mainfrm.cpp:

:

OnCreare()中:

  DWORD 

style=WS_VISIBLE|WS_CHILD;

if 

(!

m_ComPort.Create(NULL,style,CRect(0,0,0,0),this,ID_COMMCTRL)){ 

TRACE0("

Failed 

create 

OLE 

Control\n"

return 

-1;

// 

fail 

    } 

  ⑶.初始化串口 

m_ComPort.SetCommPort

(1);

  //选择COM?

m_ComPort. 

SetInBufferSize(1024);

//设置输入缓冲区的大小,Bytes 

SetOutBufferSize(512);

//设置输入缓冲区的大小,Bytes// 

if(!

m_ComPort.GetPortOpen()) 

//打开串口 

m_ComPort.SetPortOpen(TRUE);

m_ComPort.SetInputMode

(1);

//设置输入方式为二进制方式 

m_ComPort.SetSettings("

9600,n,8,1"

//设置波特率等参数 

m_ComPort.SetRThreshold

(1);

//为1表示有一个字符引发一个事件 

m_ComPort.SetInputLen(0);

⑷.捕捉串口事项。

MSComm控件可以采用轮询或事件驱动的方法从端口获取数据。

我们介绍比较使用的事件驱动方法:

有事件(如接收到数据)时通知程序。

在程序中需要捕获并处理这些通讯事件。

在MainFrm.h中:

afx_msg 

void 

OnCommMscomm();

DECLARE_EVENTSINK_MAP() 

在MainFrm.cpp中:

BEGIN_EVENTSINK_MAP(CMainFrame,CFrameWnd 

)   

ON_EVENT(CMainFrame,ID_COMMCTRL,1,OnCommMscomm,VTS_NONE) 

           

//映射ActiveX控件事件 

END_EVENTSINK_MAP() 

⑸.串口读写. 

完成读写的函数的确很简单,GetInput()和SetOutput()就可。

两个函数的原型是:

VARIANT 

GetInput();

及 

SetOutput(const 

VARIANT&

newValue);

都要使用VARIANT类型(所有Idispatch:

Invoke的参数和返回值在内部都是作为VARIANT对象处理的)。

无论是在PC机读取上传数据时还是在PC机发送下行命令时,我们都习惯于使用字符串的形式(也可以说是数组形式)。

查阅VARIANT文档知道,可以用BSTR表示字符串,但遗憾的是所有的BSTR都是包含宽字符,即使我们没有定义_UNICODE_UNICODE也是这样!

WinNT支持宽字符, 

而Win95并不支持。

为解决上述问题,我们在实际工作中使用CbyteArray,给出相应的部分程序如下:

    void 

CMainFrame:

OnCommMscomm(){ 

vResponse;

k;

if(m_commCtrl.GetCommEvent()==2) 

{       

k=m_commCtrl.GetInBufferCount();

//接收到的字符数目 

if(k>

0) 

vResponse=m_commCtrl.GetInput();

//read 

SaveData(k,(unsigned 

char*) 

vResponse.parray->

pvData);

接收到字符,MSComm控件发送事件 

处理其他MSComm控件 

OnCommSend() 

准备需要发送的命令,放在TxData[]中 

CByteArray 

array;

array.RemoveAll();

array.SetSize(Count);

for(i=0;

i<

Count;

i++) 

array.SetAt(i, 

TxData[i]);

m_ComPort.SetOutput(COleVariant(array));

发送数据 

请大家认真关注第⑷、⑸中内容,在实际工作中是重点、难点所在。

㈡ 

使用32位的API 

通信函数:

可能很多朋友会觉得奇怪:

用32位API函数编写串口通信程序,不就是把16位的API换成32位吗?

16位的串口通信程序可是多年之前就有很多人研讨过了…… 

此文主要想介绍一下在API串口通信中如何结合非阻塞通信、多线程等手段,编写出高质量的通信程序。

特别是在CPU处理任务比较繁重、与外围设备中有大量的通信数据时,更有实际意义。

⑴.在中MainFrm.cpp定义全局变量 

HANDLE    hCom;

准备打开的串口的句柄 

HANDLE    hCommWatchThread 

;

//辅助线程的全局函数 

⑵.打开串口,设置串口 

hCom 

=CreateFile( 

COM2"

GENERIC_READ 

GENERIC_WRITE, 

允许读写 

0,          // 

此项必须为0 

NULL,         

no 

security 

attrs 

OPEN_EXISTING,    //设置产生方式 

FILE_FLAG_OVERLAPPED, 

我们准备使用异步通信 

NULL 

请大家注意,我们使用了FILE_FLAG_OVERLAPPED结构。

这正是使用API实现非阻塞通信的关键所在。

ASSERT(hCom!

=INVALID_HANDLE_VALUE);

//检测打开串口操作是否成功 

SetCommMask(hCom, 

EV_RXCHAR|EV_TXEMPTY 

//设置事件驱动的类型 

SetupComm( 

hCom, 

1024,512) 

//设置输入、输出缓冲区的大小 

PurgeComm( 

PURGE_TXABORT 

PURGE_RXABORT 

PURGE_TXCLEAR 

PURGE_RXCLEAR 

//清干净输入、输出缓冲区 

COMMTIMEOUTS 

CommTimeOuts 

//定义超时结构,并填写该结构 

………… 

SetCommTimeouts( 

//设置读写操作所允许的超时 

DCB    dcb 

定义数据控制块结构 

GetCommState(hCom, 

dcb 

//读串口原来的参数设置 

dcb.BaudRate 

=9600;

dcb.ByteSize 

=8;

dcb.Parity 

NOPARITY;

dcb.StopBits 

ONESTOPBIT 

dcb.fBinary 

TRUE 

dcb.fParity 

FALSE;

SetCommState(hCom, 

//串口参数配置 

上述的COMMTIMEOUTS结构和DCB都很重要,实际工作中需要仔细选择参数。

⑶启动一个辅助线程,用于串口事件的处理。

Windows提供了两种线程,辅助线程和用户界面线程。

区别在于:

辅助线程没有窗口,所以它没有自己的消息循环。

但是辅助线程很容易编程,通常也很有用。

在次,我们使用辅助线程。

主要用它来监视串口状态,看有无数据到达、通信有无错误;

而主线程则可专心进行数据处理、提供友好的用户界面等重要的工作。

hCommWatchThread= 

CreateThread( 

(LPSECURITY_ATTRIBUTES) 

NULL, 

//安全属性 

0,//初始化线程栈的大小,缺省为与主线程大小相同 

(LPTHREAD_START_ROUTINE)CommWatchProc, 

//线程的全局函数 

GetSafeHwnd(), 

//此处传入了主框架的句柄 

0, 

dwThreadID 

 

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

当前位置:首页 > 高中教育 > 其它课程

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

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