Introduction
The purpose of this article is to describe how to interface to serial port on Win32. The serial port can be implemented by several techniques such as ActiveX, access I/O and file operation. This article explains the use of serial port on Win32 platform by file operation technique. The programmer can use kernel32.lib library that is provided with the Microsoft Visual C++ Version 6.0. In Microsoft Windows (2000, Me, XP and 95/98), serial port can be treated as a file. Therefore it's possible to open a serial port by using Windows file-creating function.
This article explains not only about serial port communication but also how to implement multi-tasking that can apply with our project "serial port" application. The reason why the software (serial communication) will be implemented with multi-tasking method is that the serial communication application has to handle work with more than one task at the same time. For example data-reading task, data-sending task, GUI task etc.
These topics describe the basic operation of interfacing a serial port on Win32:
Initial/Open serial port communication.
Receive/Send data
Design approach
Initial/Open serial port
The first step in opening a serial port is initiation or setting a serial port's configuration. The purpose of this is to create the serial port agent. All throughout the article we are going to use a file handle as serial port agent.
The serial port's handle is a handle that can be used to access the object of serial port. The function that is used to create the serial port handle is the CreateFile
function. The following code shows the function that is used to create a handle:
handlePort_ = CreateFile(portName, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
As figure 2 shows, portName
= "COM1": the portName
is a variable that is declared by const char*
. It is used to specify port name that wants to create a serial port handle.
Figure 2: CreateFile
function
The restoration of serial port configuration is getting current configuration at control device. The configuration of serial port includes parameters that are used for setting a serial communications device.
The GetCommState
function is used to get the current device-control and then fills to a device-control block (a DBC structure) with the current control settings for a specified communications device. The following code shows the function that is used to get the current control device:
if (GetCommState(handlePort_,&config_) == 0)
{
AfxMessageBox("Get configuration port has problem.");
return FALSE;
}
When you already have serial port configuration in the DBC format, you have to modify parameters a bit. Following code shows the parameters modified:
config_.BaudRate = dcb.BaudRate; config_.StopBits = dcb.StopBits; config_.Parity = dcb.Parity; config_.ByteSize = dcb.ByteSize;
DWORD BaudRate
:
Current baud rate (default = 9600)
BYTE StopBits
:
0,1,2 = 1, 1.5, 2 (default = 0)
BYTE Parity
:
0-4= no, odd, even, mark, space (default = 0)
BYTE ByteSize
:
Number of bits/byte, 4-8 (default = 8)
Note: Recommend that programmers use default value for typical communication. As shown in figure 3, Watch Dialog Box shows the default values that are used for typical communication.
Figure 3: Serial port configuration
The next step is the storage of new configuration that is modified already into device control. Call SetCommState
API function to store the configuration. The SetCommState
function configures a communications device according to the specifications in a device-control block (a DBC structure). The function reinitializes all hardware and control settings, but it does not empty output or input queues. Following code shows storage of a new configuration:
if (SetCommState(handlePort_,&config_) == 0)
{
AfxMessageBox("Set configuration port has problem.");
return FALSE;
}
The final step in serial port opening is setting communication Time-out by using the COMMTIMEOUTS
data-structure and calling SetCommTimeouts
function. The code below shows setting time-out of communication:
COMMTIMEOUTS comTimeOut;
comTimeOut.ReadIntervalTimeout = 3;
comTimeOut.ReadTotalTimeoutMultiplier = 3;
comTimeOut.ReadTotalTimeoutConstant = 2;
comTimeOut.WriteTotalTimeoutMultiplier = 3;
comTimeOut.WriteTotalTimeoutConstant = 2;
SetCommTimeouts(handlePort_,&comTimeOut);
ReadIntervalTimeout
Specifies the maximum time, in milliseconds, allowed to elapse between the arrival of two characters on the communications line. During a ReadFile
operation, the time period begins when the first character is received. If the interval between the arrival of any two characters exceeds this amount, the ReadFile
operation is completed and any buffered data is returned. A value of zero indicates that interval time-outs are not used.
A value of MAXDWORD
, combined with zero values for both the ReadTotalTimeoutConstant
and ReadTotalTimeoutMultiplier
members, specifies that the read operation is to return immediately with the characters that have already been received, even if no characters have been received.
ReadTotalTimeoutMultiplier
Specifies the multiplier, in milliseconds, used to calculate the total time-out period for read operations. For each read operation, this value is multiplied by the requested number of bytes to be read.
ReadTotalTimeoutConstant
Specifies the constant, in milliseconds, used to calculate the total time-out period for read operations. For each read operation, this value is added to the product of the ReadTotalTimeoutMultiplier
member and the requested number of bytes.
A value of zero for both the ReadTotalTimeoutMultiplier
and ReadTotalTimeoutConstant
members indicates that total time-outs are not used for read operations.
WriteTotalTimeoutMultiplier
Specifies the multiplier, in milliseconds, used to calculate the total time-out period for write operations. For each write operation, this value is multiplied by the number of bytes to be written.
WriteTotalTimeoutConstant
Specifies the constant, in milliseconds, used to calculate the total time-out period for write operations. For each write operation, this value is added to the product of the WriteTotalTimeoutMultiplier
member and the number of bytes to be written.
A value of zero for both the WriteTotalTimeoutMultiplier
and WriteTotalTimeoutConstant
members indicates that total time-outs are not used for write operations.
Note: After the user has set the time-out of communication without any error, the serial port has opened already.
Most of data transmission of serial port is done as writing a file. Programmer can apply file operation functions for sending data to serial port. The WriteFile
function is a function used to send data in serial port communication.
if (WriteFile(handlePort_, outputData, sizeBuffer, &length,NULL) == 0) {
AfxMessageBox("Reading of serial communication has problem.");
return FALSE;
}
Note: If the function succeeds, the return value is nonzero.
Most of data reception of serial communication is done as reading a file. Programmer can apply file operation functions for receiving data from serial port. The ReadFile
function is the function that handles reading data in serial port communication.
if (ReadFile(handlePort_, inputData, sizeBuffer, &length, NULL) == 0) {
AfxMessageBox("Reading of serial communication has problem.");
return FALSE;
}
Note: If the function succeeds, the return value is nonzero.
The serial port closing calls the CloseHandle
API function to close handle of device control.
if(CloseHandle(handlePort_) == 0) {
AfxMessageBox("Port Closeing isn't successed.");
return FALSE;
}
Note: If the function succeeds, the return value is nonzero.