1 引言
在很多情况下,远程监控和工业自动化领域系统经常采用串并口通信编程,其中串行接口被广泛地应用于工程实践的长距离通信中。运用Windows通信API可以在Windows环境下进行串口编程,不用对硬件直接进行操作,并通过VC、VB和Delphi等语言进行调用,大大方便了对数据的处理。本文对和串口通信相关的32位Windows API函数进行了介绍,并给出了相应的程序实例。
2 Windows API简介
Win32 API作为 Microsoft 32位平台(包括:Windows 9x,Windows NT3.1/4.0/5.0,WindowsCE)的应用程序编程接口,它是构筑所有32位Windows平台的基石,所有在Windows平台上运行的应用程序都可以调用这些函数。API是windows的核心,从事Windows应用程序开发,离不开对Win32 API函数的调用。只有充分理解和利用API函数,才能深入到Windows的内部,充分挖掘系统提供的强大功能和灵活性。
3 Windows API相关串口通信函数介绍
在32位的Windows系统中,串口通信是作为文件处理的,串口操作一般为的打开、关闭、读取、写入等操作,相应的Windows API 函数如下。
3.1 打开和关闭串口
1 打开串口
在Windows系统中串口通信会话以调用CreateFile ( )函数开始。CreateFile ( )函数可以读写访问串口,并返回一个句柄,并在以后的端口操作中使用。
CreateFile ( )函数声明如下:
HANDLE CreateFile(
LPCTSTR lpszNAME, // 指定要打开的串口逻辑名
DWORD fdwAccess, // 指定串口访问的类型
DWORD fdwShareMode, // 指定端口的共享属性
LPSECURITY_ATTRIBUTES lpsa, // 引用安全属性结构SECURITY_ATTRIBUTES
DWORD fdwCreate, // 指定CreateFile( )正在被已有的文件调用时应采取的措施
DWORD fdwAttrsAndFlags, // 描述端口的各种属性
HANDLE hTemolateFile // 指向模板文件的句柄
)
其中安全属性结构 SECURITY_ATTRIBUTES结构声明如下:
typedef struct_SECURITY_ATTRIBUTES
{
DWORD nLength; // 指明该结构的长度
LPVOID lpSecurityDescriptor; // 指向一个安全描述字符
BOOL bInheritHandle; // 表明句柄是否能被继承
}SECURITY_ATTRIBUTES;
调用CreateFile ( )函数打开COM1串口操作如下所示:
HANDLE hCom;
hCom = CreateFile("COM1", // Specify port device: default "COM1"
GENERIC_READ | GENERIC_WRITE, // Specify mode that open device.
0, // the devide isn't shared.
NULL, // the object gets a default security.
OPEN_EXISTING, // Specify which action to take on file.
0, // default.
NULL);
if(hCOM==INVALID_HANDLE_VALUE)
{
dwError=GetLastError( ); // Error
}
一旦串口处于打开状态,就可以分配一个发送缓冲区和接收缓冲区,并且通过调用SetupComm( )函数实现其他初始化工作。
SetupComm( )函数声明如下:
BOOL SetupComm(
HANDLE Hfile, // 由CreatFile ( )返回的指向已打开端口的句柄句柄
DWORD dwInQueue, // 输入缓冲区大小
DWORD dwOutQueue // 输出缓冲区大小
);
2 关闭串口
关闭串口通过调用CloseHandle ( )函数关闭由CreatHandle ( )函数返回的句柄来完成。
CloseHandle ( )函数声明如下:
BOOL CloseHandle(
HANDLE hObject // 需关闭的设备句柄
);
3.2 串口配置和串口属性
在用CreatFile ( )函数打开串口后,系统将根据上次打开串口时设置的值来初始化串口,可以集成上次打开操作后的数值,包括设备控制块(DCB)和超时控制结构(COMMTIMEOUTS)。如果是首次打开串口,Windows会使用缺省配置。
1 串口配置
Windows 2000 中使用GetCommState( )函数获取串口的当前配置,使用SetCommState ( )函数重新分配串口资源的各个参数。
GetCommState ( )函数声明如下:
BOOL GetCommState(
HANDLE hFile, // 由CreatFile ( )函数返回的指向已打开的串口的句柄
LPDCB lpDCB // 指向device-control block structure 的指针
);
其中DCB的结构声明如下:
typedef struct_DCB{
DWORD DCBlength; // DCB块大小
DWORD BaudRate; // 数据传输率
DWORD fBinary:1; // 二进制模式,不检验EOF
DWORD fParity:1; // 允许奇偶校验
DWORD fOutCtsFlow:1; // CTS输出流控制
DWORD fOutDsrFlow:1; // DSR输出流控制
DWORD fDtrContorl:2; // DTR流控制类型
DWORD fDsrSensitivity:1; // 对DTR信号线是否敏感
DWORD fTXContinueOnOxff:1; // XOFF continue Tx
DWORD fOutX:1; // XON/XOFF输出流控制
DWORD fInX:1; // XON/XOFF输入流控制
DWORD fErrorChar:1; // 错误替换
DWORD fNull:1; // 是否丢弃接收到的NULL字符
DWORD fRtsControl:2; // RTS流控制
DWORD fAbortOnError:1; // 发送错误,指定是否终止读、写操作
DWORD fDummy2:17; // 保留
WORD wReserved; // 现在不用
WORD XonLim; // XOFF字符发送之前接收到缓冲区中可允许的最小字节数
WORD XoffLim; // XOFF字符发送之前缓冲区中可允许的最小可用字节数
BYTE ByteSize; // 端口当前使用的数据位数
BYTE Parity; // 当前使用的奇偶校验法
BYTE StopBits; // 当前使用的停止位数
char XonChar; // 发送和接收的XON字符值
char XoffChar; //发送和接收的XOFF字符值
char ErrorChar; // 用来替代接收到的奇偶校验发生错误的字符
char EofChar; // 表示数据的结束
char EvtChar; // 事件字符
WORD wReserved1; // 保留的位
}DCB;
如果GetCommState ( )函数调用成功,则返回值不为零。若函数调用失败,则返回值为零,可以调用GetLastError ( )函数来获取进一步的错误信息。
如果应用程序需要修改配置,可以通过调用GetCommState ( )函数获得当前的DCB结构,然后更改DCB结构中的参数,调用SetCommState ( )函数配置修改过的DCB来配置端口。
SetCommState ( )函数声明如下:
BOOL SetCommState (
HANDLE hFile, // 由CreatFile ( )函数返回的已打开的串口的句柄
LPDCB lpDCB // 指向DCB结构的指针
);
2 串口属性
串口的属性通过GetCommProperties ( )函数获得.
GetCommProperties ( )函数声明如下:
BOOL GetCommProperties(
HANDLE hFile, //返回句柄
LPCOMMPROP lpCommProp //指向COMMPROP的结构
);
其中lpCommProp指向一个COMMPROP的结构,串口的性能从COMMPROP中返回。
3 通信设备配置
Windows API提供了CommConfigDialog ( )函数对通信设备进行配置,从中改变数据传输速率、数据位、奇偶校验方法、停止位和流控制方法。
CommConfigDialog ( )函数的声明如下:
BOOL CommConfigDialog(
LPTSTR lpszName, // 要配置的端口名
HWND hWnd, // 拥有对话框的窗口句柄
LPCOMMCONFIG lpCC // 指向一个COMMCONFIG结构
);
当CommConfigDialog ( )函数返回时,选定的设置在COMMFIG的DCB参数中返回,对已打开的串口,对端口设置进行更改通过SetCommState ( )函数来改变。
Windows API提供了CommConfigDialog ( )函数对通信设备进行配置,从中改变数据传输速率、数据位、奇偶校验方法、停止位和流控制方法。
CommConfigDialog ( )函数的声明如下:
BOOL CommConfigDialog(
LPTSTR lpszName, // 要配置的端口名
HWND hWnd, // 拥有对话框的窗口句柄
LPCOMMCONFIG lpCC // 指向一个COMMCONFIG结构
);
当CommConfigDialog ( )函数返回时,选定的设置在COMMFIG的DCB参数中返回,对已打开的串口,对端口设置进行更改通过SetCommState ( )函数来改变。
3.3 读写串口
1 读串口操作
一般在程序中使用Win32 API ReadFile ( )函数从串口中读取数据。
ReadFile ( )函数声明如下:
BOOL ReadFile(
HANDLE hFILE, // 指向由CreatFile ( )函数产生的句柄
LPVOID lpbuffer, // 指向一个缓冲区
DWORD nNumberOfBytesToRead, // 读取的字节数
LPDWORD lpNumberOfBytesToRead, // 指向调用该函数读出的字节数
LPOVERLAPPED lpOverlapped // 一个OVERLAPPED结构
);
2 写串口操作
一般在程序中使用Win32 API WriteFile ( )函数向串口中写数据。
WriteFile ( )函数声明如下:
BOOL WriteFile(
HANDLE hFILE, // 指向由CreatFile( )函数产生的句柄
LPVOID lpbuffer, // 指向一个缓冲区
DWORD nNumberOfBytesToWrite, // 向串口设备写入的字节数
LPDWORD lpNumberOfBytesToWritten, // 指向调用该函数已写入的字节数
LPOVERLAPPED lpOverlapped // 一个OVERLAPPED结构
);
3 异步I/O操作
读、写串口操作中的OVERLAPPED结构用于在Windows中进行异步I/O操作,使应用程序可以在前台、后台同时执行不同的任务,并由GetOverLappedResult ( )函数获取结果。
OVERLAPPED结构类型声明如下:
Typedef struct_OVERLAPPED{
DWORD Internal; // 指出一个和系统相关的状态
DWORD InternalHigh; // 指出发送或接收的数据长度
DWORD Offset;
DWORD OffsetHigh; // Offset和OffsetHigh指明文件传送的开始位置和字节偏移量
HANDLE hEvent; // 指定一个I/O操作完成后出发的事件
}OVERLAPPED;
异步 I/O 操作可以由 GetOverLappedResult ( ) 函数来获取结果。
GetOverLappedResult ( )函数声明如下:
BOOL GetOverLappedResult(
HANDLE hFILE, // 标识通信句柄,开始调用重叠结构ReadFile、WriteFile
LPOVERLAPPED lpOverlapped, // 启动异步操作时指定的OVERLAPPED结构
LPDWORD lpNumberOfBytesTransferred, // 接收读、写操作实际传递的字节数
BOOL bWait // 指定函数是否等待挂起的异步操作完成。
);
4 超时设置
Windows 2000中读写串口引入了超时结构。超时结构直接影响读和写的操作行为,当事先设定的超时间隔消逝时,ReadFile ( )、WriteFile ( )操作将被无条件结束。
超时结构定义如下
typedef struct_COMMTIMEOUTS{
DWORD ReadIntervalTimeout;
DWORD ReadTotalTimoutMultiplier;
DWORD ReadTotalTimouConstant;
DWORD WriteTotalTimoutMultiplier;
DWORD WriteTotalTimoutConstant;
} COMMTIMEOUTS,*LPCOMMTIMEOUTS;
其中:ReadIntervalTimeout以ms为单位指定通信线路上两个字符到达之间的最大时间间隔;ReadTotalTimoutMultiplier以ms为单位指定一个系数,该系数用来计算读操作的总超时时间;ReadTotalTimouConstant以ms为单位指定一个常数,该常数用来计算读操作的总超时时间;WriteTotalTimoutMultiplier以ms为单位指定一个系数,该系数用来计算写操作的总超时时间;WriteTotalTimoutConstant以ms为单位指定一个常数,该常数用来计算读写作的总超时时间。
Windows API GetCommTimeOuts ( )函数来获得当前超时参数。
GetCommTimeOuts ( )函数声明如下:
BOOL GetCommTimeOuts (
HANDLE hFILE, // 标识通信设备,CreatFile ( )函数返回该句柄
LPCOMMTIMEOUTS lpCommTimeouts // 指向一个COMMTIMEOUTS结构,返回超时信息
);
如果想获得进一步的错误信息,可以调用GetLastError ( )函数来获取。
5 通信状态和通信错误
如果在串口通信中发生错误,如发生终端、奇偶错误等,I/O操作将会终止。如果程序要进一步执行I/O操作,必须调用ClearCommError ( )函数。ClearCommError ( )函数有两个作用,一是清除错误条件,一是确定串口通信状态。
ClearCommError ( )函数声明如下:
BOOL ClearCommError(
HANDLE hFILE, // 由CreatFile ( )函数返回的句柄
LPDWORD lpErrors, // 指向一个指明错误类型的掩码填充的32位变量
LPCOMSTAT lpStat // 指向一个COMSTAT结构接收设备的状态
);
3.4 程序实例
下面的程序为打开并初始化端口:
HANDLE hCom;
DWORD dwError;
DCB dcb;
COMMTIMEOUTS TimeOuts;
hCom=CreateFile(“COM1”, //对串口1进行操作
GENERIC_READ | GENERIC_WRITE, //允许读和写
0, //独占方式
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, //重叠方式
NULL
);
if(hCom==INVALID_HANDLE_VALUE)
{ dwError=GetLastRrror( );
. …//错误处理
}
SetupComm(hCom,1024,1024) //缓冲区的大小为1024
TimeOuts.ReadIntervalTimeout=1000;
TimeOuts.ReadTotalTimoutMultiplier=500;
TimeOuts.ReadTotalTimouConstant=5000;
TimeOuts.WriteTotalTimoutMultiplier=500;
TimeOuts.WriteTotalTimoutConstant=5000;
SetCommTimeouts(hCom,&TimeOuts); // 设置超时
GetCommState(hCom,&dcb);
dcb.BaudRate=2400; // 数据传输速率为2400
dcb.ByteSize=8; // 每个字符为8位
dcb.Parity=NOPARITY; // 无校验
dcb.StopBits=ONESTOPBIT; // 一个停止位
SetCommState(hCom,&dcb);
4 结束语
Win32 API作为 Windows平台的应用程序编程接口,是windows的核心。通过充分理解和利用API函数,可以使我们深入到Windows的内部,充分挖掘系统提供的强大功能和灵活性,为我们在工程实践中进行串口通信编程提供方便。
参考:http://wenku.baidu.com/view/85339b85ec3a87c24028c43a.html
其他相关帖子:http://www.cnblogs.com/xi52qian/archive/2011/08/30/2159675.html
http://blog.csdn.net/zhaozidong86/article/details/5884503