Click here to Skip to main content
15,867,568 members
Articles / Programming Languages / C++
Article

Non Overlapped Serial Port Communication using Win32

Rate me:
Please Sign up or sign in to vote.
4.07/5 (22 votes)
23 Nov 20046 min read 307.5K   7.5K   83   44
Demonstration of the use of Win32 function for serial port communication

Introduction

The purpose of this article is to demonstrate the use of Win32 functions for serial port communication in Visual C++. A C++ class CSyncSerialComm has been developed to implement the following serial port communication operations:

  • Open
  • Configuration
  • Read
  • Write
  • Close

A background in Visual C++ programming is sufficient to grasp the technical details of this article. Access to MSDN is required for looking at the definition of functions, structures etc. used in this article. The article takes a look at only non-overlapped (synchronous) operations supported by Win32. My next article will show implementation of serial port communication using overlapped (asynchronous) structures.

I. Open

Before starting any communication on a serial port, we must first open a connection. This is achieved by using CreateFile function in Win32. (Those of you familiar with File I/O must be aware of this function.) The following code is used to open a serial port connection in non-overlapped mode.

m_hSerialComm = CreateFile(m_pszPortName, 
            GENERIC_READ | GENERIC_WRITE, 
            0, 
            NULL, 
            OPEN_EXISITING, 
            0, 
            NULL);

if (m_hSerialComm == INVALID_HANDLE_VALUE)
    //Handle Error Condition

The CreateFile function takes in seven parameters. (Please take a brief moment to look at this function in MSDN.)

  • The first parameter specifies the port name. In our case, this is usually COM, COM2, COM3 or COM4.
  • The second parameter must be GENERIC_READ | GENERIC_WRITE to support both read and write access.
  • The third parameter must always be 0 for serial port communication because unlike files, serial port access cannot be shared.
  • The fourth parameter is used to set security attributes. If no security attribute needs to be specified, just use NULL.
  • The fifth parameter must always be set to OPEN_EXISTING.
  • The sixth parameter is used to specify flags and attributes (either 0 or FILE_ATTRIBUTE_NORMAL can be used).
  • The last parameter must always be NULL as we only support non-overlapped communication.

The HANDLE m_hSerialComm that is returned by the CreateFile function can now be used for performing operations like Configure, Read and Write.

II. Configuration

After opening connection to a serial port, the next step is usually to configure the serial port connect settings like Baud Rate, Parity Checking, Byte Size, Error Character, EOF Character etc. Win32 provides a DCB struct that encapsulates these settings (refer to MSDN for DCB struct definition). Configuration of the serial port connection settings is performed in the following three steps:

  1. First, we have to access the present settings of the serial port using the GetCommState function. The function takes in two parameters:
    • The first parameter is the HANDLE we received from the call to the CreateFile function.
    • The second parameter is an output parameter, which returns the DCB structure containing the present settings.
  2. Next, using the DCB structure that we obtained from the previous step, we can modify the necessary settings according to the application needs.
  3. Finally, we update the changes by using the SetCommState method.

The following code is a sample shown explaining the use of these functions. (Note: A number of the fields in the DCB struct are not used in the example. A more sophisticated application must allow the client to configure these settings.)

DCB dcbConfig;

if(GetCommState(m_hSerialComm, &dcbConfig))
{
    dcbConfig.BaudRate = dwBaudRate;
    dcbConfig.ByteSize = 8;
    dcbConfig.Parity = NOPARITY;
    dcbConfig.StopBits = ONESTOPBIT;
    dcbConfig.fBinary = TRUE;
    dcbConfig.fParity = TRUE;
}

else
    //Handle Error Condition

if(!SetCommState(m_hSerialComm, &dcbConfig))
    //Handle Error Condition

Another important part of configuration of serial port connection settings is setting timeouts. Again, Win32 provides a COMMTIMEOUTS struct for setting Read and Write Timeouts. We are also provided with two functions GetCommTimeouts and SetCommTimeouts to access, modify, and update the timeout settings. The following code can be used to set the serial port timeouts:

COMMTIMEOUTS commTimeout;

if(GetCommTimeouts(m_hSerialComm, &commTimeout))
{
    commTimeout.ReadIntervalTimeout     = 1000 * dwReadTimeOutIntervalInSec;
    commTimeout.ReadTotalTimeoutConstant     = 1000 * dwReadTimeOutConstantInSec;
    commTimeout.ReadTotalTimeoutMultiplier     = 1000 * dwReadTimeOutMultiplier;
    commTimeout.WriteTotalTimeoutConstant     = 1000 * dwWriteTimeOutInSec;
    commTimeout.WriteTotalTimeoutMultiplier = 1000 * dwWriteTimeOutMultiplier;
}

else
    //Handle Error Condition

if(!SetCommTimeouts(m_hSerialComm, &commTimeout))
//Handle Error Condition

III. Read

There are many different implementations for reading from a Serial Port Connection. In the CSyncSerialComm class that is provided with this article, serial communication events are used in the implementation of the Read operation. There are three important sets in this implementation.

  1. First, we setup a Read Event using the SetCommMask function. (Note: This function can also be used to set many other different types of serial communication events.) This event is fired when a character is read and buffered internally by Windows Operating System. The SetCommMask function takes in two parameters:
    • The first parameter is the HANDLE we received from the call to the CreateFile function.
    • The second parameter is used to specify the event type. To specify a Read Event, we use EV_RXCHAR flag.
  2. After calling the SetCommMask function, we call the WaitCommEvent function to wait for the event to occur. This function takes in three parameters:
    • The first parameter is the HANDLE we received from the call to the CreateFile function.
    • The second parameter is an output parameter, which reports the event type that was fired.
    • The third parameter is a pointer to an OVERLAPPED structure. Since, our implementation is for Non-Overlapped communication, it must be set to NULL.
  3. Once this event is fired, we then use the ReadFile function to retrieve the bytes that were buffered internally. The ReadFile function takes in five parameters:

    • The first parameter is the HANDLE we received from the call to the CreateFile function.
    • The second parameter is a buffer that would receive the bytes if the ReadFile function returns successfully.
    • The third parameter specifies the size of our buffer we passed in as the second parameter.
    • The fourth parameter is an output parameter that will notify the user about the number of bytes that were read.
    • The last parameter is always NULL for our purpose since we do not deal with non-overlapped mode.

In our example, we read one byte at a time and store it in a temporary buffer. This continues until the case when ReadFile function returns successfully and the fourth parameter has a value of 0. This indicates that the internal buffer used by Windows OS is empty and so we stopping reading. The following code shows the implementation of this technique:

std::stringbuf sb;
DWORD dwEventMask;

if(!SetCommMask(m_hSerialComm, EV_RXCHAR))
    //Handle Error Condition

if(WaitCommEvent(m_hSerialComm, &dwEventMask, NULL))
{
    char szBuf;
    DWORD dwIncommingReadSize;

    do
    {
        if(ReadFile(m_hSerialComm, &szBuf, 1, &dwIncommingReadSize, NULL) != 0)
        {
            if(dwIncommingReadSize > 0)
            {
                dwSize += dwIncommingReadSize;
                sb.sputn(&szBuf, dwIncommingReadSize);
            }
        }

        else
            //Handle Error Condition
    } while(dwIncommingReadSize > 0);
}

else
    //Handle Error Condition

IV. Write

Write operation is easier to implement than Read. It involves using just one function, WriteFile. It takes in five parameters similar to ReadFile function. The second parameter in WriteFile specifies the buffer to be written to the serial port. The following example shows implementation of Write using WriteFile. It writes one byte at a time until all the bytes in our buffer are written:

unsigned long dwNumberOfBytesSent = 0;

while(dwNumberOfBytesSent < dwSize /*size of the buffer pszBuf*/)
{
    unsigned long dwNumberOfBytesWritten;

    if(WriteFile(m_hSerialComm, &pszBuf[dwNumberOfBytesSent], 1, 
                            &dwNumberOfBytesWritten, NULL) != 0)
    {
        if(dwNumberOfBytesWritten > 0)
            ++dwNumberOfBytesSent;
        else
            //Handle Error Condition
    }

    else
        //Handle Error Condition
}

V. Close

After we finish all our communication with the serial port, we have to close the connection. This is achieved by using the CloseHandle function and passing in the serial port HANDLE we obtained from the CreateFile function call. Failure to do this results in hard to find handle leaks. The follow code snippet explains the use of this function:

if(m_hSerialComm != INVALID_HANDLE_VALUE)
{
    CloseHandle(m_hSerialComm);
    m_hSerialComm = INVALID_HANDLE_VALUE;
}

Conclusion

I hope my demonstration of the use of Win32 functions in serial port communication will serve as a starting point. I am sure as you browse through MSDN looking for these function definitions, you will come across more sophisticated functions that might be better suited for your application needs.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Web Developer
United States United States
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
QuestionHow to add your serial library on my project Pin
zhjnzu22-Apr-13 17:35
zhjnzu22-Apr-13 17:35 
AnswerRe: How to add your serial library on my project Pin
PiligrimJob23-Mar-14 23:39
PiligrimJob23-Mar-14 23:39 
BugRead method assumes that dwSize parameter is zero initialized Pin
kungjohan_uppsala16-Apr-13 22:44
kungjohan_uppsala16-Apr-13 22:44 
SuggestionSome modification to read method Pin
ankur@codeblocks19-Mar-13 18:43
ankur@codeblocks19-Mar-13 18:43 
GeneralRe: Some modification to read method Pin
kungjohan_uppsala17-Apr-13 4:59
kungjohan_uppsala17-Apr-13 4:59 
GeneralMy vote of 4 Pin
ankur@codeblocks19-Mar-13 18:31
ankur@codeblocks19-Mar-13 18:31 
QuestionRead file-question Pin
Pradeep Abeygunawardhana11-May-12 21:24
Pradeep Abeygunawardhana11-May-12 21:24 
Questionhow to read the received bytes one by one Pin
nathasion24-Mar-11 4:05
nathasion24-Mar-11 4:05 
QuestionDoEvents equivalent function in C Pin
pmk_196911-Jan-11 1:34
pmk_196911-Jan-11 1:34 
GeneralMy vote of 1 Pin
M. Orcun Topdagi10-Jun-10 5:19
M. Orcun Topdagi10-Jun-10 5:19 
GeneralLicense Pin
dyadcat26-Apr-10 15:25
dyadcat26-Apr-10 15:25 
Questionworks in windows 7? Pin
kat8888-Jan-10 3:23
kat8888-Jan-10 3:23 
Questionhow to send send and receive a file through serial port using VC++ Pin
ramesh25513-Oct-08 0:47
ramesh25513-Oct-08 0:47 
Questionreading input frm serial port!!!! Pin
akhshay gandhi1-Jul-07 22:22
akhshay gandhi1-Jul-07 22:22 
Generalserial/parallel port communication using Pin
Rahoo6-Dec-06 2:01
Rahoo6-Dec-06 2:01 
Questionsilly question - pointer of pointer Pin
ansi_c11-Jun-06 23:58
ansi_c11-Jun-06 23:58 
JokeExample to make things easier: Pin
isthisfuckingnametaken15-Mar-06 12:29
isthisfuckingnametaken15-Mar-06 12:29 
Generalfile instead of port Pin
ARadauer14-Nov-05 13:19
ARadauer14-Nov-05 13:19 
GeneralRe: file instead of port Pin
Eshwar14-Nov-05 13:55
Eshwar14-Nov-05 13:55 
GeneralLNK2001 link error Pin
87918-Jul-05 6:16
87918-Jul-05 6:16 
Hi, I try to compile and run the sample program above.
I create from empty pfoject of MS VC++ 6.0, and copied both of SyncSerialComm.cpp and SyncSerialComm.h.
I can compile SyncSerialComm.cpp but when try to "build all"
the error message has come out.
"LNK2001 unresolved external symbol_main"
"LNK1120 1 unresolved external"

Does anybody help to how can I solve this problem??
Please repy.
GeneralRe: LNK2001 link error Pin
Anonymous18-Jul-05 8:44
Anonymous18-Jul-05 8:44 
GeneralRe: LNK2001 link error Pin
87919-Jul-05 0:58
87919-Jul-05 0:58 
GeneralEfficency Pin
Franck HERESON23-May-05 5:55
Franck HERESON23-May-05 5:55 
GeneralRe: Efficency Pin
Anonymous9-Jul-05 20:24
Anonymous9-Jul-05 20:24 
GeneralChecking if Windows buffer is empty Pin
nirishere22-May-05 20:03
nirishere22-May-05 20:03 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.