2024年3月14日发(作者:)

MFC 串口通信编程介绍 主 要介绍 了用 CreateFile函 数和 WriteFile函数 读写

串 口的实 例以及 设置串 口属性 的实 例. 在工业控制中工控机一般都基于

Windows 平台经常需要与智能仪表通过串口进行通信.串口通信方便易行应用广泛.

一般情况下工控机和各智能仪表通过 RS485 总线进行通信.RS485 的通信方式是

半双工的只能由作为主节点的工控 PC 机依次轮询网络上的各智能控制单元子 节

点.每次通信都是由 PC 机通过串口向智能控制单元发布命令智能控制单元在接收

到正确的命令后作出应答. 在 Win32 下可以使用两种编程方式实现串口通信其一

是使用 ActiveX 控件这种方法程序简单但欠灵活.其二是调用 Windows 的 API

函数这种方法可以清楚地掌 握串口通信的机制并且自由灵活.下面只介绍 API 串

口通信部分. 串口的操作可以有两种操作方式:同步操作方式和重叠操作方式又称

为异步操作方式.同步操作时API 函数会阻塞直到操作完成以后才能返回在多线程

方式中虽然不会阻塞主线程但是仍然会阻塞监听线程而重叠操作方式API 函数会

立即返回操作在后台进行避免线程的阻塞. 无论哪种操作方式一般都通过四个步骤

来完成: 1打开串口 2配置串口 3读写串口 4关闭串口一 打开串口 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同步 I/O 方式打开串口的示例:HANDLE hCom//全局变量串口句柄

hComCreateFilequotCOM1quot//串口名称 GENERIC_READGENERIC_WRITE//允

许读和写 0//独占方式 NULL OPEN_EXISTING//打开而不是创建 0//同步方式

NULLifhComHANDLE-1 MessageBoxquot?蚩?COM 失败quot return FALSEreturn

TRUE重叠 I/O 打开串口的示例:HANDLE hCom//全局变量串口句柄hCom

CreateFilequotCOM1quot//串口名称 GENERIC_READGENERIC_WRITE//允许读和

写 0//独占方式 NULL OPEN_EXISTING//打开而不是创建

FILE_ATTRIBUTE_NORMALFILE_FLAG_OVERLAPPED//重叠方式

NULLifhComINVALID_HANDLE_VALUE MessageBoxquot打开 COM 失败quot

return FALSEreturn TRUE二 配置串口 在打开通讯设备句柄后常需要对串口进行一

些初始化配置工作.这需要通过一个DCB 结构来进行.DCB 结构包含了诸如波特

率、数据位数、奇偶校验和停止位数等信息.在查询或配置串口的属性时都要用 DCB

结构来作为缓冲区. 一般用 CreateFile 打开串口后可以调用 GetCommState 函数

来获取串口的初始配置.要修改串口的配置应该先修改 DCB 结构然后再调用

SetCommState 函数设置串口. DCB 结构包含了串口的各项参数设置下面仅介绍几

个该结构常用的变量: typedef struct _DCB ……… //波特率指定通信设备的传输速率.

这个成员可以是实际波特率值或者下面的 常量值之一: DWORD

BaudRate//CBR_110CBR_300CBR_600CBR_1200CBR_2400CBR_4800CBR_9600CB

R_19200//CBR_38400//CBR_56000CBR_57600CBR_115200CBR_128000CBR_25600

0CBR_14400 DWORD fParity//指定奇偶校验使能.若此成员为 1允许奇偶校验检

查 … BYTE ByteSize//通信字节位数4—8 BYTE Parity//指定奇偶校验方法.此成员

可以有下列值: //EVENPARITY 偶校验 NOPARITY 无校验 //MARKPARITY 标

记校验 ODDPARITY 奇校验 BYTE StopBits//指定停止位的位数.此成员可以有下

列值: //ONESTOPBIT 1 位停止位 TWOSTOPBITS 2 位停止位 //ONE5STOPBITS

1.5 位停止位 ……… DCB 在 winbase.h 文件中定义了以上用到的常量.如下所

示: define NOPARITY 0 define ODDPARITY 1 define EVENPARITY 2 define

ONESTOPBIT 0 define ONE5STOPBITS 1 define TWOSTOPBITS 2 define CBR_110

110 define CBR_300 300 define CBR_600 600 define CBR_1200 1200 define

CBR_2400 2400 define CBR_4800 4800 define CBR_9600 9600 define CBR_14400

14400 define CBR_19200 19200 define CBR_38400 38400 define CBR_56000 56000

define CBR_57600 57600 define CBR_115200 115200 define CBR_128000 128000

define CBR_256000 256000 GetCommState 函数可以获得 COM 口的设备控制块从

而获得相关参数: BOOL GetCommState HANDLE hFile //标识通讯端口的句柄

LPDCB lpDCB //指向一个设备控制块DCB 结构的指针 SetCommState 函数设置

COM 口的设备控制块: BOOL SetCommState HANDLE hFile LPDCB lpDCB 除了

在 BCD 中的设置外程序一般还需要设置 I/O 缓冲区的大小和超时.Windows用

I/O 缓冲区来暂存串口输入和输出的数据.如果通信的速率较高则应该设置较大的

缓冲区.调用 SetupComm 函数可以设置串行口的输入和输出缓冲区的大小. BOOL

SetupComm HANDLE hFile // 通信设备的句柄 DWORD dwInQueue // 输入缓冲区

的大小字节数 DWORD dwOutQueue // 输出缓冲区的大小字节数 在用 ReadFile

和 WriteFile 读写串行口时需要考虑超时问题.超时的作用是在指定的时间内没有

读入或发送指定数量的字符ReadFile 或 WriteFile 的操作仍然会结束. 要查询当前

的超时设置应调用 GetCommTimeouts 函数该函数会填充一个COMMTIMEOUTS

结构.调用 SetCommTimeouts 可以用某一个 COMMTIMEOUTS 结构的内容来设

置超时. 读写串口的超时有两种:间隔超时和总超时.间隔超时是指在接收时两个字

符之间的最大时延.总超时是指读写操作总共花费的最大时间.写操作只支持总超时

而读操作两种超时均支持.用 COMMTIMEOUTS 结构可以规定读写操作的超时.

COMMTIMEOUTS 结构的定义为: typedef struct _COMMTIMEOUTS DWORD

ReadIntervalTimeout//读间隔超时 DWORD ReadTotalTimeoutMultiplier//读时间系数

DWORD ReadTotalTimeoutConstant//读时间常量 DWORD

WriteTotalTimeoutMultiplier//写时间系数 DWORD WriteTotalTimeoutConstant//写时

间常量 COMMTIMEOUTSLPCOMMTIMEOUTS COMMTIMEOUTS 结构的成员

都以毫秒为单位.总超时的计算公式是:总超时=时间系数×要求读/写的字符数+时

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

ReadTotalTimeoutMultiplier×10+ReadTotalTimeoutConstant 可以看出:间隔超时和

总超时的设置是不相关的这可以方便通信程序灵活地设置各种超时. 如果所有写超

时参数均为 0那么就不使用写超时.如果 ReadIntervalTimeout 为0那么就不使用读

间隔超时.如果 ReadTotalTimeoutMultiplier 和ReadTotalTimeoutConstant 都为 0则