Serial Port Programming Using Win32 API
Serial Port Programming Using Win32 API
In this tutorial we will learn How to communicate with an external device like a microcontroller
board or modem using the Serial port of a windows PC(Windows XP,7). The software is written
using C language and communicates with the Serial Port using Win32 API.
In Windows ,Serial ports are named as COM1,COM2 ,COM3.. etc .COM1 and COM2 usually
refer to the hardware serial ports present in the PC while COM numbers in double digits like
COM32,COM54,COM24.. etc are given to USB to Serial Converters or PCI serial port extenders.
If your PC does not have any hardware serial ports (RS232 DB9 ports), you can use USB to
Serial Converter's like USB2SERIAL.
If you are interested in setting up an RS485 network controlled by your PC to control a robot or a
sensor network ,you can use USB2SERIAL board (buy here).
Sourcecodes
All the C sourefiles used in this tutorial can be downloaded from our GitHub Page.
Please note that the sourcecodes on the website show only the relevant sections to highlight
the process of programming the serial port.
Please use the complete sourcecodes from our github repo when building your own program.
After opening a serial port using the CreateFile() function you should close it with
CloseHandle() function, otherwise port will become unavailable to other programs.
Now let's write a small program to open and close a serial port on Windows. Open a text editor
like notepad or Notepad++ and type the below code and save it as “serial.c”.If you are using IDE
like VS Express, use the one integrated with it.
#include<windows.h>
#include<stdio.h>
int main()
{
HANDLE hComm;
hComm = CreateFile(“\\\\.\\COM24”, //port
name
GENERIC_READ |
GENERIC_WRITE, //Read/Write
0, // No
Sharing
NULL, // No
Security
OPEN_EXISTING,// Open existing port
only
0, // Non Overlapped I/O
NULL); // Null for Comm
Devices
if (hComm == INVALID_HANDLE_VALUE)
printf(“Error in opening serial port”);
else
printf(“opening serial port successful”);
return 0;
}
Find out the COM port corresponding to your system and substitute in CreateFile() instead
of COM24.
Next we open a connection to serial port using CreateFile() function. The CreateFile() function on
success, returns a valid handle to the hComm variable.
If the function succeeds in opening the serial port, it returns a valid handle to hcomm which is then
used for error checking.
CloseHandle(hComm);
Please note that in Windows, COM port numbers from COM1 to COM9 are reserved by the
system. If you are using a serial port whose COM port number falls in that range, you don’t need
the back slashes (\\\\.\\)shown in the above code.
First you declare a new structure of type DCB and initializes it.
After that retrieve the current settings of the serial port using the GetCommState() function.
and set the values for Baud rate, Byte size, Number of start/Stop bits etc.
if you want to change the Baud rate values prefix standard values with CBR like
this CBR_4800,CBR_9600,CBR_192600 etc.
Now its time to configure the serial port according to the DCB structure using SetCommState()
function.
SetCommState(hComm, &dcbSerialParams);
Setting Timeouts
Timeouts helps to prevent your program from waiting endlessly till data arrives. It helps the read
or write calls to return after a set time period has elapsed.
COMMTIMEOUTS timeouts = { 0 };
timeouts.ReadIntervalTimeout = 50; // in milliseconds
timeouts.ReadTotalTimeoutConstant = 50; // in milliseconds
timeouts.ReadTotalTimeoutMultiplier = 10; // in milliseconds
timeouts.WriteTotalTimeoutConstant = 50; // in milliseconds
timeouts.WriteTotalTimeoutMultiplier = 10; // in milliseconds
All values are in milliseconds.
ReadIntervalTimeout Specifies the maximum time interval between arrival of two bytes. If the
arrival time exceeds these limits the ReadFile() function returns.
ReadTotalTimeoutConstant is 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.
After this you have to set the values using SetCommTimeouts() function.
char lpBuffer[] = "A";
DWORD dNoOFBytestoWrite; // No of bytes to write
into the port
DWORD dNoOfBytesWritten = 0; // No of bytes written to
the port
dNoOFBytestoWrite = sizeof(lpBuffer);
lpBuffer[] character array containing the data to write into the serial port.
dNoOFBytestoWrite is the total number of bytes to be written into the serial port.Here we
are using the sizeof() operator to find out that .
dNoOFBytestoWrite = sizeof(lpBuffer);
dNoOfBytesWritten is the total number of bytes written successfully to the port by the
WriteFile() operation.
Now in the Zip File containing the source codes you can find “USB2SERIAL_Write_W32.c” which
contains the complete code for writing into serial port. You can compile the code using Visual
Studio Express or GCC.
If your PC does not have any hardware serial ports you can use any USB to Serial
Converters(I am using USB2SERIAL).
I have interfaced a microcontroller board(MSP430G2553 on Launch Pad) to the serial port using
a null modem cable like this
You can use any microcontroller of your choice like 8051,AVR or ARM(LPC2148).The Controller
waits for a character to be received and lights up the corresponding LED. The code for MSP430
is included in the zip file.If you want to know how to configure the MSP430 controller UART you
can check this tutorial.
Please note that if you are using a DB9 RS232 Serial Port of your PC, you will have to build a
RS232 signal level converter at the microcontroller side to decode the RS232 signal.
Directly connecting the PC's RS232 Serial port to MSP430 's pins will damage the chip.
Here is the screen shot of the Program writing into serial port.
One way to do that is to use polling where the ReadFile() continuously reads from the serial port
and checks for any received characters.
Other way is to setup an event and let windows notify us when a character is received.
We are going to use the second method here, following are the steps.
1. Create an Event for a particular action like character reception, change in modem lines etc
using SetCommMask() function .
2. Ask windows to wait for the event set by SetCommMask() function using WaitCommEvent()
and notify us when the condition happens.
3. Call ReadFile () to read the received data from the Serial port.
SetCommMask() is used to set the events to be monitored for a communication device. Here
we are going to set the event as character received (EV_RXCHAR).The function takes two
arguments, Handle of the serial port (hComm) and the code for the event (EV_RXCHAR) to be
monitored.
Status = SetCommMask(hComm, EV_RXCHAR);
WaitCommEvent() is used to wait for the events set by SetCommMask() to happen, in this
case reception of a character. The flow of execution of the program stops and the program waits
until a character is received.
DWORD dwEventMask;
Status = WaitCommEvent(hComm, &dwEventMask, NULL);
dwEventMask contains a hex value indicating the event, which has caused WaitCommEvent()
to return.
After WaitCommEvent() has returned, call ReadFile() function to read the received
characters from the Serial Port Buffer.
do
{
ReadFile( hComm, //Handle of the Serial port
&TempChar, //Temporary character
sizeof(TempChar),//Size of TempChar
&NoBytesRead, //Number of bytes read
NULL);
ReadFile() function is similar to the WriteFile() function we had seen earlier,instead of writing we
are reading from the serial port.
&TempChar Temporary variable used to store the byte read from serial port buffer.
Now in the Zip File containing the source codes you can find “USB2SERIAL_Read_W32.c” which
contains the complete code for writing into serial port. You can compile the code using Visual
Studio Express or GCC.
Check out our next section, If you want to know how to control the RTS and DTR pins of the
serial port .