如何用API函数实现WINDOWS下的串口写程

如何用API函数实现WINDOWS下的串口写程,第1张

用API函数实现Windows下的串行通讯

冯华亮 2002年4月 四川·电子科大

以往的DOS系统是通过DOS中断和BIOS中断向用户提供串行接口的通讯能力。在Windows环境下,C++的开发工具既没有提供象DOS和BIOS

中那样专门的串行通讯控制方法,也不允许用户直接控制串口的中断。

为了保证资源共享,Windows系统完全接管了各种硬件资源,使用中断来控制端口将破坏系统的多任务性,使系统的稳定性受到影响。

但Windows同时也提供了功能强大的API函数使用户能间接的控制串行通讯。

1、实现串行通讯的相关API函数

API函数不仅提供了打开和读写通讯端口的 *** 作方法,还提供了名目繁多的函数以支持对串行通讯的各种 *** 作。常用函数及作用如表5-1所示。

表5-1 常用串行通讯API函数及其作用

函数名 作用

CreateFile 打开串口

GetCommState 检测串口设置

SetCommState 设置串口

BuilderCommDCB 用字符串中的值来填充设备控制块

GetCommTimeouts 检测通信超时设置

SetCommTimeouts 设置通信超时参数

SetCommMask 设定被监控事件

WaitCommEvent 等待被监控事件发生

WaitForMultipleObjects 等待多个被监测对象的结果

WriteFile 发送数据

ReadFile 接收数据

GetOverlappedResult 返回最后重叠(异步) *** 作结果

PurgeComm 清空串口缓冲区,退出所有相关 *** 作

ClearCommError 更新串口状态结构体,并清除所有串口硬件错误

CloseHandle 关闭串行口

2、打开串口

函数CreateFile原本用于打开文件,但它同样可用于打开一个通信端口。与系统中其他对象一样,通信端口也是用句柄来标识的。

CreateFile函数返回被 *** 作的通信端口句柄,其调用方法如下:

HANDLE CreateFile (

LPCTSTR lpFileName, //指向文件名字符串的指针

DWORD dwDesireAccess, // *** 作模式

DWORD dwShareMode,  //共享方式

LPSECURITY_ATTRIBUTES lpSecurityAttributes, //指向安全属性的指针

DWORD dwCreationDistribution, //文件建立方式

DWORD dwFlagsAndAttributes //文件属性

HANDLE hTemplateFile //模板文件句柄

)

lpFileName:指向一个以NULL结束的字符串,该串指定了要创建、打开或截断的文件、管道、通信源、磁盘设备或控制台的名字。

当用CreateFile打开串口时,这个参数可用“COM1”指定串口1,用“COM2”指定串口2,依此类推。

dwDesireAccess: 指定对文件访问的类型,该参数可以为GENERIC_READ(指定对该文件的读访问权)

或ENERIC_WRITE(指定该文件的写访问权)两个值之一或同时为为这两个值。用ENERIC_READ|GENERIC_WRITE则指定可对串口进行读写

dwShareMode:指定此文件可以怎样被共享。因为串行口不支持任何共享模式,所以dwShareMode必须设为0

lpSecurityAttributes定义安全属性,一般不用,可设为NULL。Win 9x下该参数被忽略;

dwCreationDistribution定义文件创建方式, 对串口必须设为OPEN_EXISTING,表示打开已经存在的文件;

dwFlagsAndAttributes为该文件指定定义文件属性和标志,这个程序中设为FILE_FLAG_OVERLAPPED,表示异步通信方式;

hTemplateFile 指向一个模板文件的句柄,串口无模板可言,设为NULL。在 Windows 9x下该参数必须为NULL。

用异步读写方式打开串口1的函数调用如下:

m_hComm = CreateFile(“COM1”,//打开串口1

GENERIC_READ | GENERIC_WRITE, //读写方式

0, //不能共享

NULL, //不用安全结构

OPEN_EXISTING, //打开已存在的设备

FILE_FLAG_OVERLAPPED,//异步方式

0) //无模板

串口被成功打开时,返回其句柄,否则返回INVALID_HANDLE_VALUE(0XFFFFFFFF)。

3、串口设置

第一次打开串口时,串口设置为系统默认值,函数GetCommState和SetCommState可用于检索和设定端口设置的DCB(设备控制块)结构,

该结构中BaudRate、ByteSize、StopBits和Parity字段含有串口波特率、数据位数、停止位和奇偶校验控制等信息。

程序中可先用GetCommState检索端口的当前设置,修改其中的部分字段后再用SetCommState进行端口设定。这样可不必构造一个完整的DCB结构。

下面介绍几个主要的函数和结构体:

(1)GetCommState

BOOL GetCommState( hCommDev, lpdcb);

参数hCommDev标识通信设备,应使用CreateFile返回的句柄。Lpdcb是指向DCB结构的指针,

函数调用后当前串口配置信息将被保存在这个结构内。如果函数成功返回值为TRUE;否则返回值为FALSE。

SetCommState用法与GetCommState相似,在此不再重复。DCB结构定义如下(只介绍主要的几项):

typedef struct _ DCB{

……

DWORD BardRate //波特率的设置

BYTE ByteSize; //数据位的个数

BYTE Parity//是否有奇偶校验位

BYTE StopBits //停止位的个数

……

}DCB;

(2)SetCommTimeouts

BOOL SetCommTimeouts( hCommDev, lpctmo );

Lpctmo指向包含新的超时参数的COMMTIMEOUTS结构。COMMTIMEOUTS结构定义如下:

typedef struct _ COMMTIMEOUTS{

DWORD ReadIntervalTimeout

DWORD ReadTotalTimeoutMultiplier

DWORD ReadTotalTimeoutconstant

DWORD WriteTotalTimeoutMultiplier

DWORD WriteTotalTimeoutconstant

}COMMTIMEOUTS, LPCOMMTIMEOUTS

ReadIntervalTimeout: 以毫秒为单位指定通信线上两个字符到达之间的最大时间。在ReadFile *** 作其间,

收到第一个字符时开始计算时间。若任意两个字符到达之间的间隔超过这个最大值,ReadFile *** 作完成,

返回缓冲数据。0值表示不用间隔限时。若该成员为MAXDWORD,且ReadTotalTimeoutconstant和

ReadTotalTimeoutMultiplier成员为零,则指出读 *** 作要立即返回已接收到的字符,即使未收到字符,

读 *** 作也要返回。

ReadTotalTimeoutMultiplier:以毫秒为单位指定一个乘数,该乘数用来计算读 *** 作的总限时时间。每个读 *** 作的总限时时间等于读 *** 作所需的字节数与该值的乘积。

ReadTotalTimeoutConstant:以毫秒为单位指定一个常数,用于计算读 *** 作的总限时时间。每个 *** 作的总限时时间等于ReadTotalTimeoutMultiplier成员乘以读 *** 作所需字节数再加上该值的和。ReadTotalTimeoutMultiplier和ReadTotalTimeoutConstant成员的值为0表示读 *** 作不使用限时时间。

WriteTotalTimeoutMultiplier和WriteTotalTimeoutconstant的意义和作用分别与ReadTotalTimeoutMultiplier和ReadTotalTimeoutConstant相似,不再重复。

(3)BuilderCommDCB

BOOL BuilderCommDCB(lpszDef,lpdcb)

这个函数按lpszDef字符串所指定的格式来配置串口的DCB。

LpszDef:指向一个以NULL结束的字符串,该字符串指定串口的控制信息。比如,“1200,N,8,1”指定波特率为1200,无奇偶校验位,有8个数据位和1个停止位。

lpdcb:指向被填充的DCB结构。

(4)SetCommMask

BOOL SetCommMask(hCommDev,fdwEvtMask)

fdwEvtMask指向一个32位的屏蔽码,如果指定为EV_RXCHAR | EV_CTS,表示程序监控串口的收、发事件。

下面以简单的例子说明串口设置的步骤:

m_CommTimeouts.ReadIntervalTimeout = 1000

m_CommTimeouts.ReadTotalTimeoutMultiplier = 1000

m_CommTimeouts.ReadTotalTimeoutConstant = 1000

m_CommTimeouts.WriteTotalTimeoutMultiplier = 1000

m_CommTimeouts.WriteTotalTimeoutConstant = 1000

if (SetCommTimeouts(m_hComm, &m_CommTimeouts))

// 串口超时参数设置

if (SetCommMask(m_hComm, dwCommEvents))

// 设置串口事件掩码

if (GetCommState(m_hComm, &m_dcb))

// 获取串口当前状态

if (BuildCommDCB(“1200,N,8,1”, &m_dcb))

// 建立串口设备控制块

if (SetCommState(m_hComm, &m_dcb))

// 设置串口参数

……

以上任何一个if语句的判断条件为假时都将调用GetLastError函数获取错误信息,进行错误处理。

4、读写串口数据

你的串口助手发送不知道后面有没有加上/r /n什么的转义字符 人家的程序跟你差不多 那说明你们程序不一样 看看你们的单片机里面对于接受传来的字符(命令)在处理上有没有不同

是否需要按照16进制发送


欢迎分享,转载请注明来源:内存溢出

原文地址:https://54852.com/yw/8134286.html

(0)
打赏 微信扫一扫微信扫一扫 支付宝扫一扫支付宝扫一扫
上一篇 2023-04-13
下一篇2023-04-13

发表评论

登录后才能评论

评论列表(0条)

    保存