原创 基于VC++的串口通信

2010-1-19 11:24 2237 4 4 分类: 软件与OS

转载于中国工控网


作者:苏加庆


1 引言<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />


      在当今的工业控制领域,串口通信是计算机与其他设备进行数据通信时经常使用的方法,具有实现简单、使用灵活、数据传输可靠等几个优点,特别是在实时监控系统中得到广泛应用,在我们使用的计算机上使用的串口一般是RS232,使用RS232接口只能进行一对一的通信,然而在工业控制领域往往是一台工控机和多台智能设备进行通信,并且要求传输距离远,因为这些需求,在工控领域一般使用RS485


      Win32下,可以使用两种编程方式实现串口通信,其一是使用MScomm控件,这种方法程序简单,但欠灵活。其二是调用WindowsAPI函数,这种方法可以清楚地掌握串口通信的机制,并且自由灵活。使用控件的方法在本质上也是使用API进行串口通信,控件只不过是对API的一个封装处理,本文只介绍使用API进行串口通信编程的方法。


2 串口通信的一般步骤


2.1 打开串口


       32Windows中,串口和其他通信设备(如磁盘等)都被作为文件进行处理,在使用前必须先将其打开,为保证串口通信数据传输的可靠性,串口一般以非共享模式打开,也就是在被串口打开后,其他程序不能在去打开此设备。


2.2 配置串口


       在使用串口进行数据通信前必须对其进行正确的配置,串口需要配置的主要参数有波特率、数据位、停止位、奇偶校验、收发数据缓冲区大小。除此之外还要对串口进行超时设置,以防止在串口通信时数据传输突然中断而导致读写操作进入无限期等待的状态,设置了超时,如果在指定时间内没有完成所进行的操作,则此操作被自动放弃。


2.3 读写串口


      在串口被打开并设置好后,就可以使用串口进行读写数据了,读写数据可以采用同步、异步及事件驱动等多种方式。


2.4 关闭串口


      在使用完串口后应该将其关闭,如果没有关闭,该串口会处于打开状态,其他的应用程序便无法打开使用该串口。


3 利用API函数实现串口通信


3.1 打开串口


      Win32系统把文件的概念进行了扩展。无论是文件、通信设备、命名管道、邮件槽、磁盘、还是控制台,都是用API函数CreateFile来打开或创建的。该函数的原型为:


HANDLE CreateFile(LPCTSTR lpFileName,


                  DWORD dwDesiredAccess,


                  DWORD dwShareMode,


                  LPSECURITY_ATTRIBUTES lpSecurityAttributes,


                  DWORD dwCreationDistribution,


DWORD dwFlagsAndAttributes,


HANDLE hTemplateFile);


各个参数说明如下:


lpFileName:将要打开的串口逻辑名,如“COM1”


dwDesiredAccess:指定串口访问的类型,可以是读取、写入或二者并列;


dwShareMode:指定共享属性,由于串口不能共享,该参数必须置为0


lpSecurityAttributes:引用安全性属性结构,缺省值为NULL


dwCreationDistribution:创建标志,对串口操作该参数必须置为OPEN_EXISTING


dwFlagsAndAttributes:属性描述,用于指定该串口是否进行异步操作,该值为FILE_FLAG_OVERLAPPED,表示使用异步的I/O;该值为0,表示同步I/O操作;


hTemplateFile:对串口而言该参数必须置为NULL


3.2 配置串口


      在打开通讯设备句柄后,常常需要对串口进行一些初始化配置工作。这需要通过一个DCB结构来进行。DCB结构包含了诸如波特率、数据位数、奇偶校验和停止位数等信息。在查询或配置串口的属性时,都要用DCB结构来作为缓冲区。在打开串口后,可以调用GetCommState函数来获取串口的默认配置,该函数获取一个DCB结构体,只要在该结构内对应该先修改DCB结构,然后再调用SetCommState函数以修改后的DCB结构设置串口。DCB主要有以下几个重要的成员:


BYTE ByteSize; // 通信字节位数


BYTE Parity;   //指定奇偶校验方法。此成员可以有下列值:


//EVENPARITY 偶校验     NOPARITY 无校验


//MARKPARITY 标记校验   ODDPARITY 奇校验


BYTE StopBits;  //指定停止位的位数。此成员可以有下列值:


//ONESTOPBIT   1位停止位  


//TWOSTOPBITS  2位停止位


//ONE5STOPBITS 1.5位停止位


      除了使用BCD设置串口的一些基本参数外,一般还需要设置串口收发数据缓冲区的大小和超时,超时的作用是在指定的时间内没有读入或发送指定数量的字符,读写操作仍然会结束。WindowsI/O缓冲区来暂存串口输入和输出的数据,如果通信的速率较高,则应该设置较大的缓冲区。我们可以使用API函数SetupComm设置串口的输入和输出缓冲区的大小,其原型如下:


BOOL SetupComm(


    HANDLE hFile,          // 串口句柄


    DWORD dwInQueue,      // 输入缓冲区的大小(字节数)


    DWORD dwOutQueue );   // 输出缓冲区的大小(字节数)


关于读写串口的超时设置,windows给我们提供一个专门的结构体COMMTIMEOUTS,其定义如下:


typedef struct _COMMTIMEOUTS {


     DWORD ReadIntervalTimeout;         //读间隔超时


    DWORD ReadTotalTimeoutMultiplier;   //读时间系数


    DWORD ReadTotalTimeoutConstant;    //读时间常量


    DWORD WriteTotalTimeoutMultiplier;   //写时间系数


    DWORD WriteTotalTimeoutConstant;    //写时间常量


} COMMTIMEOUTS,*LPCOMMTIMEOUTS;


COMMTIMEOUTS结构的成员都以毫秒为单位。总超时的计算公式是:


总超时=时间系数×要求读/写的字符数+时间常量


例如,要读入10个字符,那么读操作的总超时的计算公式为:


读总超时=ReadTotalTimeoutMultiplier×10ReadTotalTimeoutConstant


通过该结构体windowsAPI为我们提供两个函数:GetCommTimeoutsSetCommTimeouts,前者获取当前的超时设置,后者使用修改后的COMMTIMEOUTS设置超时,与设置串口阐述类似。


在读写串口之前,还要用PurgeComm(…)函数清空缓冲区,该函数原型:


BOOL PurgeComm(


    HANDLE hFile,      //串口句柄


    DWORD dwFlags );   //需要完成的操作


参数dwFlags指定要完成的操作,可以是下列值的组合:


PURGE_TXABORT  中断所有写操作并立即返回,即使写操作还没有完成。


PURGE_RXABORT  中断所有读操作并立即返回,即使读操作还没有完成。


PURGE_TXCLEAR  清除输出缓冲区


PURGE_RXCLEAR  清除输入缓冲区


3.3 读写串口


读写串口使用ReadFileWriteFile两个函数,其原型如下:


BOOL ReadFile(


    HANDLE hFile,                     //串口的句柄


    LPVOID lpBuffer,                  //保存读入数据的指针


DWORD nNumberOfBytesToRead,     //要读入的数据的字节数


LPDWORD lpNumberOfBytesRead,   //实际读入的字节数


    LPOVERLAPPED lpOverlapped );    //OVERLAPPED,同步为NULL


BOOL WriteFile(


  HANDLE hFile,                    //串口的句柄


  LPCVOID lpBuffer,                 //要写入数据的地址


  DWORD nNumberOfBytesToWrite,    //要写入数据的字节数


  LPDWORD lpNumberOfBytesWritten,  //实际写入的字节数


  LPOVERLAPPED lpOverlapped);      //OVERLAPPED,同步为NULL


       在进行同步操作时,读写函数要等到执行完才返回,而在异步操作时函数立即返回,但不保证读写操作完成,这时候就需要使用OVERLAPPED结构进行异步控制,该结构体有一个重要的成员hEvent,该成员是windows事件对象的句柄在控制线程同步及异步操作时常用到,如果是异步操作,我们可以使用CreateEvent)创建事件对象并将返回值赋给hEvent,然后使用WaitForSingleObjectGetOverlappedResult等待读写操作完成,进而达到控制异步操作的目的。


3.4 关闭串口


      在不使用串口的时候应该将其关闭,以释放windows的资源供其他程序使用,关闭串口只需调用CloseHandlehComm/*串口句柄*/)即可。

PARTNER CONTENT

文章评论0条评论)

登录后参与讨论
EE直播间
更多
我要评论
0
4
关闭 站长推荐上一条 /3 下一条