65.9K
CodeProject 正在变化。 阅读更多。
Home

创建 Win32 串行通信

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.57/5 (56投票s)

2002年10月21日

CPOL

5分钟阅读

viewsIcon

957752

downloadIcon

53431

本文旨在介绍如何在 Win32 上进行串行端口接口操作。

Sample Image

引言

本文旨在介绍如何在 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* 声明的变量。它用于指定要创建串行端口句柄的端口名称。

 

图 2: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 所示,监视对话框显示了用于典型通信的默认值。

 

图 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,并结合 ReadTotalTimeoutConstantReadTotalTimeoutMultiplier 成员的零值,表示读取操作应立即返回,返回已接收到的字符,即使没有接收到任何字符。

ReadTotalTimeoutMultiplier

指定用于计算读取操作总超时时间的乘数(以毫秒为单位)。对于每次读取操作,此值将乘以要读取的请求字节数。

ReadTotalTimeoutConstant

指定用于计算读取操作总超时时间的常量(以毫秒为单位)。对于每次读取操作,此值将加到 ReadTotalTimeoutMultiplier 成员与请求读取的字节数乘积上。

ReadTotalTimeoutMultiplierReadTotalTimeoutConstant 成员的值都为零,表示读取操作不使用总超时。

WriteTotalTimeoutMultiplier

指定用于计算写入操作总超时时间的乘数(以毫秒为单位)。对于每次写入操作,此值将乘以要写入的字节数。

WriteTotalTimeoutConstant

指定用于计算写入操作总超时时间的常量(以毫秒为单位)。对于每次写入操作,此值将加到 WriteTotalTimeoutMultiplier 成员与要写入的字节数乘积上。

WriteTotalTimeoutMultiplierWriteTotalTimeoutConstant 成员的值都为零,表示写入操作不使用总超时。

注意:在用户成功设置通信超时后,串行端口已打开。

发送数据

串行端口的大部分数据传输是通过写入文件来完成的。程序员可以使用文件操作函数将数据发送到串行端口。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;
}

注意:如果函数成功,返回值将是非零。

© . All rights reserved.