简单问题: 100分求源程序,使用32位的API 通信函数

Ask2 2004-08-16 09:54:27
100分求源程序: 使用32位的API 进行最简单的RS232串口通讯,发送和接受ASCII字符。以下的例子有点难,从网上找的。

hainan_11@hotmail.com


⑴.在中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( hCom, PURGE_TXABORT | PURGE_RXABORT | PURGE_TXCLEAR

           | PURGE_RXCLEAR ); //清干净输入、输出缓冲区

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

   …………

SetCommTimeouts( hCom, &CommTimeOuts ) ;//设置读写操作所允许的超时

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, &dcb ) ; //串口参数配置

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

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

Windows提供了两种线程,辅助线程和用户界面线程。区别在于:辅助线程没有窗口,所以它没有自己的消息循环。但是辅助线程很容易编程,通常也很有用。

在次,我们使用辅助线程。主要用它来监视串口状态,看有无数据到达、通信有无错误;而主线程则可专心进行数据处理、提供友好的用户界面等重要的工作。

hCommWatchThread=

     CreateThread( (LPSECURITY_ATTRIBUTES) NULL, //安全属性

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

         (LPTHREAD_START_ROUTINE)CommWatchProc, //线程的全局函数

         GetSafeHwnd(), //此处传入了主框架的句柄

         0, &dwThreadID );

  ASSERT(hCommWatchThread!=NULL);

⑷为辅助线程写一个全局函数,主要完成数据接收的工作。

请注意OVERLAPPED结构的使用,以及怎样实现了非阻塞通信。

UINT CommWatchProc(HWND hSendWnd){

  DWORD dwEvtMask=0 ;

  SetCommMask( hCom, EV_RXCHAR|EV_TXEMPTY );//有哪些串口事件需要监视?

  WaitCommEvent( hCom, &dwEvtMask, os );// 等待串口通信事件的发生

  检测返回的dwEvtMask,知道发生了什么串口事件:

  if ((dwEvtMask & EV_RXCHAR) == EV_RXCHAR){ // 缓冲区中有数据到达

  COMSTAT ComStat ; DWORD dwLength;

  ClearCommError(hCom, &dwErrorFlags, &ComStat ) ;

  dwLength = ComStat.cbInQue ; //输入缓冲区有多少数据?

  if (dwLength > 0) {

BOOL fReadStat ;  

  fReadStat = ReadFile( hCom, lpBuffer,dwLength, &dwBytesRead,

            &READ_OS( npTTYInfo ) ); //读数据

注:我们在CreareFile()时使用了FILE_FLAG_OVERLAPPED,现在ReadFile()也必须使用

  LPOVERLAPPED结构.否则,函数会不正确地报告读操作已完成了.

    使用LPOVERLAPPED结构, ReadFile()立即返回,不必等待读操作完成,实现非阻塞

    通信.此时, ReadFile()返回FALSE, GetLastError()返回ERROR_IO_PENDING.

if (!fReadStat){

   if (GetLastError() == ERROR_IO_PENDING){

     while(!GetOverlappedResult(hCom,

       &READ_OS( npTTYInfo ), & dwBytesRead, TRUE )){

       dwError = GetLastError();

       if(dwError == ERROR_IO_INCOMPLETE) continue;

             //缓冲区数据没有读完,继续

       …… ……      

   ::PostMessage((HWND)hSendWnd,WM_NOTIFYPROCESS,0,0);//通知主线程,串口收到数据  }

  所谓的非阻塞通信,也即异步通信。是指在进行需要花费大量时间的数据读写操作(不仅仅是指串行通信操作)时,一旦调用ReadFile()、WriteFile(), 就能立即返回,而让实际的读写操作在后台运行;相反,如使用阻塞通信,则必须在读或写操作全部完成后才能返回。由于操作可能需要任意长的时间才能完成,于是问题就出现了。

非常阻塞操作还允许读、写操作能同时进行(即重叠操作?),在实际工作中非常有用。

要使用非阻塞通信,首先在CreateFile()时必须使用FILE_FLAG_OVERLAPPED;然后在 ReadFile()时lpOverlapped参数一定不能为NULL,接着检查函数调用的返回值,调用GetLastError(),看是否返回ERROR_IO_PENDING。如是,最后调用GetOverlappedResult()返回重叠操作(overlapped operation)的结果;WriteFile()的使用类似。

⑸.在主线程中发送下行命令。

BOOL  fWriteStat ; char szBuffer[count];

       …………//准备好发送的数据,放在szBuffer[]中

fWriteStat = WriteFile(hCom, szBuffer, dwBytesToWrite,

           &dwBytesWritten, &WRITE_OS( npTTYInfo ) ); //写数据

注:我们在CreareFile()时使用了FILE_FLAG_OVERLAPPED,现在WriteFile()也必须使用   LPOVERLAPPED结构.否则,函数会不正确地报告写操作已完成了.

   使用LPOVERLAPPED结构,WriteFile()立即返回,不必等待写操作完成,实现非阻塞 通信.此时, WriteFile()返回FALSE, GetLastError()返回ERROR_IO_PENDING.

int err=GetLastError();

if (!fWriteStat) {

   if(GetLastError() == ERROR_IO_PENDING){

    while(!GetOverlappedResult(hCom, &WRITE_OS( npTTYInfo ),

           &dwBytesWritten, TRUE )) {

      dwError = GetLastError();

      if(dwError == ERROR_IO_INCOMPLETE){

           // normal result if not finished

        dwBytesSent += dwBytesWritten; continue; }

    
综上,我们使用了多线程技术,在辅助线程中监视串口,有数据到达时依靠事件驱动,读入数据并向主线程报告(发送数据在主线程中,相对说来,下行命令的数据总是少得多);并且,WaitCommEvent()、ReadFile()、WriteFile()都使用了非阻塞通信技术,依靠重叠(overlapped)读写操作,让串口读写操作在后台运行。

依托vc6.0丰富的功能,结合我们提及的技术,写出有强大控制能力的串口通信应用程序。就个人而言,我更偏爱API技术,因为控制手段要灵活的多,功能也要强大得多。



...全文
89 8 打赏 收藏 转发到动态 举报
写回复
用AI写文章
8 条回复
切换为时间正序
请发表友善的回复…
发表回复
Ask2 2004-08-17
  • 打赏
  • 举报
回复
当然可以封装成库了--> 能否做一个? 先谢了
DerryZhang 2004-08-17
  • 打赏
  • 举报
回复
当然可以封装成库了
smallsword 2004-08-17
  • 打赏
  • 举报
回复
网上龚建伟的串口调试助手源程序不是挺好的吗
他的主页上还有对串口编程的详细介绍

查 龚建伟 串口编程

DerryZhang 2004-08-17
  • 打赏
  • 举报
回复
给你发过去了,你参考一下吧
你收一下
Ask2 2004-08-17
  • 打赏
  • 举报
回复
?
flyelf 2004-08-16
  • 打赏
  • 举报
回复
水利出版社有一本关于串口的书
Ask2 2004-08-16
  • 打赏
  • 举报
回复
进一步问题,可否把它写成DLL? 这样就好用了!
Ask2 2004-08-16
  • 打赏
  • 举报
回复
100分求源程序: 使用32位的API 进行最简单的RS232串口通讯,发送和接受ASCII字符。例子有点难,从网上找的。

hainan_11@hotmail.com

16,471

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC相关问题讨论
社区管理员
  • 基础类社区
  • Web++
  • encoderlee
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

        VC/MFC社区版块或许是CSDN最“古老”的版块了,记忆之中,与CSDN的年龄几乎差不多。随着时间的推移,MFC技术渐渐的偏离了开发主流,若干年之后的今天,当我们面对着微软的这个经典之笔,内心充满着敬意,那些曾经的记忆,可以说代表着二十年前曾经的辉煌……
        向经典致敬,或许是老一代程序员内心里面难以释怀的感受。互联网大行其道的今天,我们期待着MFC技术能够恢复其曾经的辉煌,或许这个期待会永远成为一种“梦想”,或许一切皆有可能……
        我们希望这个版块可以很好的适配Web时代,期待更好的互联网技术能够使得MFC技术框架得以重现活力,……

试试用AI创作助手写篇文章吧