创建 Win32 串行通信
本文旨在介绍如何在 Win32 上进行串行端口接口操作。
引言
本文旨在介绍如何在 Win32 上进行串行端口接口操作。串行端口可以通过多种技术实现,例如 ActiveX、访问 I/O 和文件操作。本文通过文件操作技术解释了在 Win32 平台上的串行端口使用。程序员可以使用 Microsoft Visual C++ 6.0 提供的 kernel32.lib 库。在 Microsoft Windows(2000、Me、XP 和 95/98)中,串行端口可以被视为一个文件。因此,可以使用 Windows 文件创建函数打开串行端口。
本文不仅解释了串行通信,还介绍了如何实现可以应用于我们的“串行端口”项目的多任务处理。之所以采用多任务处理方法实现软件(串行通信),是因为串行通信应用程序必须同时处理多个任务。例如,数据读取任务、数据发送任务、GUI 任务等。
这些主题描述了在 Win32 上进行串行端口接口操作的基本操作。
初始化/打开串行端口通信。
接收/发送数据
设计方法
初始化/打开串行端口
打开串行端口的第一步是初始化或设置串行端口的配置。目的是创建串行端口代理。在整篇文章中,我们将使用文件句柄作为串行端口代理。
创建端口句柄
串行端口句柄是用于访问串行端口对象的句柄。用于创建串行端口句柄的函数是 CreateFile
函数。以下代码显示了用于创建句柄的函数。
handlePort_ = CreateFile(portName, // 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); // default.
如图 2 所示,portName
=“COM1”:portName
是一个由 const char*
声明的变量。它用于指定要创建串行端口句柄的端口名称。
CreateFile
函数
恢复配置
串行端口配置的恢复是获取控制设备的当前配置。串行端口的配置包括用于设置串行通信设备的参数。
GetCommState
函数用于获取当前设备控制,然后使用指定通信设备的当前控制设置填充设备控制块(DBC 结构)。以下代码显示了用于获取当前设备控制的函数。
// Get current configuration of serial communication port.
if (GetCommState(handlePort_,&config_) == 0)
{
AfxMessageBox("Get configuration port has problem.");
return FALSE;
}
修改配置
当您已经以 DBC 格式获得了串行端口配置时,您需要稍微修改参数。以下代码显示了修改后的参数。
// Assign user parameter.
config_.BaudRate = dcb.BaudRate; // Specify buad rate of communicaiton.
config_.StopBits = dcb.StopBits; // Specify stopbit of communication.
config_.Parity = dcb.Parity; // Specify parity of communication.
config_.ByteSize = dcb.ByteSize; // Specify byte of size of communication.
DWORD BaudRate
:当前波特率(默认 = 9600)
BYTE StopBits
:0,1,2 = 1, 1.5, 2(默认 = 0)
BYTE Parity
:0-4 = 无、奇、偶、标记、空格(默认 = 0)
BYTE ByteSize
:每字节的位数,4-8(默认 = 8)
注意:建议程序员在典型通信中使用默认值。如图 3 所示,监视对话框显示了用于典型通信的默认值。
存储配置
下一步是将已修改的新配置存储到设备控制中。调用 SetCommState
API 函数来存储配置。SetCommState
函数根据设备控制块(DBC 结构)中的规范配置通信设备。该函数重新初始化所有硬件和控制设置,但它不会清空输入或输出队列。以下代码显示了新配置的存储。
if (SetCommState(handlePort_,&config_) == 0)
{
AfxMessageBox("Set configuration port has problem.");
return FALSE;
}
设置超时通信
打开串行端口的最后一步是使用 COMMTIMEOUTS
数据结构设置通信超时,并调用 SetCommTimeouts
函数。下面的代码显示了通信超时设置。
// instance an object of COMMTIMEOUTS.
COMMTIMEOUTS comTimeOut;
// Specify time-out between charactor for receiving.
comTimeOut.ReadIntervalTimeout = 3;
// Specify value that is multiplied
// by the requested number of bytes to be read.
comTimeOut.ReadTotalTimeoutMultiplier = 3;
// Specify value is added to the product of the
// ReadTotalTimeoutMultiplier member
comTimeOut.ReadTotalTimeoutConstant = 2;
// Specify value that is multiplied
// by the requested number of bytes to be sent.
comTimeOut.WriteTotalTimeoutMultiplier = 3;
// Specify value is added to the product of the
// WriteTotalTimeoutMultiplier member
comTimeOut.WriteTotalTimeoutConstant = 2;
// set the time-out parameter into device control.
SetCommTimeouts(handlePort_,&comTimeOut);
ReadIntervalTimeout
指定在通信线路上两次字符到达之间允许的最大时间(以毫秒为单位)。在 ReadFile
操作期间,时间段从第一个字符接收时开始。如果任何两个字符到达之间的间隔超过此量,则 ReadFile
操作将完成,并返回任何已缓冲的数据。值为零表示不使用间隔超时。
值为 MAXDWORD
,并结合 ReadTotalTimeoutConstant
和 ReadTotalTimeoutMultiplier
成员的零值,表示读取操作应立即返回,返回已接收到的字符,即使没有接收到任何字符。
ReadTotalTimeoutMultiplier
指定用于计算读取操作总超时时间的乘数(以毫秒为单位)。对于每次读取操作,此值将乘以要读取的请求字节数。
ReadTotalTimeoutConstant
指定用于计算读取操作总超时时间的常量(以毫秒为单位)。对于每次读取操作,此值将加到 ReadTotalTimeoutMultiplier
成员与请求读取的字节数乘积上。
ReadTotalTimeoutMultiplier
和 ReadTotalTimeoutConstant
成员的值都为零,表示读取操作不使用总超时。
WriteTotalTimeoutMultiplier
指定用于计算写入操作总超时时间的乘数(以毫秒为单位)。对于每次写入操作,此值将乘以要写入的字节数。
WriteTotalTimeoutConstant
指定用于计算写入操作总超时时间的常量(以毫秒为单位)。对于每次写入操作,此值将加到 WriteTotalTimeoutMultiplier
成员与要写入的字节数乘积上。
WriteTotalTimeoutMultiplier
和 WriteTotalTimeoutConstant
成员的值都为零,表示写入操作不使用总超时。
注意:在用户成功设置通信超时后,串行端口已打开。
发送数据
串行端口的大部分数据传输是通过写入文件来完成的。程序员可以使用文件操作函数将数据发送到串行端口。WriteFile
函数是用于在串行端口通信中发送数据的函数。
if (WriteFile(handlePort_, // handle to file to write to
outputData, // pointer to data to write to file
sizeBuffer, // number of bytes to write
&length,NULL) == 0) // pointer to number of bytes written
{
AfxMessageBox("Reading of serial communication has problem.");
return FALSE;
}
注意:如果函数成功,返回值将是非零。
接收数据
串行通信的大部分数据接收是通过读取文件来完成的。程序员可以使用文件操作函数从串行端口接收数据。ReadFile
函数是处理串行端口通信中数据读取的函数。
if (ReadFile(handlePort_, // handle of file to read
inputData, // handle of file to read
sizeBuffer, // number of bytes to read
&length, // pointer to number of bytes read
NULL) == 0) // pointer to structure for data
{
AfxMessageBox("Reading of serial communication has problem.");
return FALSE;
}
注意:如果函数成功,返回值将是非零。
关闭串行端口
串行端口关闭调用 CloseHandle
API 函数来关闭设备控制的句柄。
if(CloseHandle(handlePort_) == 0) // Call this function to close port.
{
AfxMessageBox("Port Closeing isn't successed.");
return FALSE;
}
注意:如果函数成功,返回值将是非零。