Sometimes we require to communicate with an external device like a printer, microcontroller board or any serial device using the serial port of a windows machine. There is a lot of serial application available like Hercules, HyperTerminal, Docklight, ..etc.
We can use any one of them for serial communication but sometimes we require to create our own custom serial application for communication. In windows, it is easy to create the custom serial application using the win32 API.
In this blog post, we will learn serial port programming using the Win32 API. In Windows, serial port programming is very easy, MSDN provide all the required win32 API information which require for the serial port programming.
You can also see the below articles that how to change the properties of com-port like baud rate, parity using the Windows API.
- Change properties of COM Port Using win32 API
- Get COM PORT of USB Serial Device using the VID and PID
Finding COM port Number of a Device
In windows, the serial device will display in com port section of device manager with name as COM1, COM2, COM3, COM4.. etc. Generally, COM1 and COM2 refer to the hardware serial ports present in the PC and another com port number is export when any serial device or USB to serial device attached to PC. It also possible that com id could be virtual ( for example static virtual com port).
In my laptop, I have attached an Arduino board (Atmega 2560) and its COM id would be shown in com port section (Control Panel > Device Manager > Ports).
Compilers and IDE’s used
Here I have used Visual Studio 2013. You can also use MinGW (Minimalist GNU for Windows) an Open Source programming tool. Here I am assuming that you know how to create the console application using the visual studio and familiar with win32 API.
Opening a Serial Port
In Windows using the CreateFile(), we can open the serial port. The CreateFile() is a Win32 API that creates or opens a file or I/O device.
On success CreateFile() returns a handle that can be used to access the file or device depending on the flags and attributes specified.
HANDLE CreateFile( LPCTSTR lpFileName, // pointer to name of the file DWORD dwDesiredAccess, // access (read-write) mode DWORD dwShareMode, // share mode LPSECURITY_ATTRIBUTES lpSecurityAttributes, // pointer to security attributes DWORD dwCreationDisposition, // how to create DWORD dwFlagsAndAttributes, // file attributes HANDLE hTemplateFile // handle to file with attributes to // copy );
Closing a Serial Port
You should remember that after opening the com port using the CreateFile(), you have to close it by calling the CloseHandle() otherwise it will be unavailable to other applications.
BOOL CloseHandle( HANDLE hObject );
On success CloseHandle() returns zero.
Serial port communication Application
Let see an example code where I am talking with a Mega2560 Arduino device. I have written a small code for mega2560 in which it receives serial data. If received data is “aticleworld” then it will send a message “Welcome to AticleWorld !” or otherwise it will send the message “Please Send Correct Message”.
Mega2560 serial code,
#include <SoftwareSerial.h> void setup() { // initialize serial ports Serial.begin(9600); // USB serial port 0 } void loop() { String msg = ""; // check for data byte on USB serial port if (Serial.available()) { // get byte from USB serial port while(Serial.available()) { msg = Serial.readString();// read the incoming data as string } if( msg == "aticleworld") { //Send data to usb serial port Serial.write(" Welcome to AticleWorld !"); } else { //Send data to usb serial port Serial.write("Please Send Correct Message"); } } }
You can purchase Mega2560 from Amazon, Click here
Serial Application for the console,
In the below console application, I am using the win32 API to open the com port and sending the data to the open COM port. See the below video where I have downloaded the Arduino code in the Arduino board and communicating with this board using the console application.
#include "stdafx.h" #include <Windows.h> #include <stdio.h> #include <string.h> int main(void) { HANDLE hComm; // Handle to the Serial port BOOL Status; // Status DCB dcbSerialParams = { 0 }; // Initializing DCB structure COMMTIMEOUTS timeouts = { 0 }; //Initializing timeouts structure char SerialBuffer[64] = { 0 }; //Buffer to send and receive data DWORD BytesWritten = 0; // No of bytes written to the port DWORD dwEventMask; // Event mask to trigger char ReadData; //temperory Character DWORD NoBytesRead; // Bytes read by ReadFile() unsigned char loop = 0; wchar_t pszPortName[10] = { 0 }; //com port id wchar_t PortNo[20] = { 0 }; //contain friendly name //Enter the com port id printf_s("Enter the Com Port: "); wscanf_s(L"%s", pszPortName, (unsigned)_countof(pszPortName)); swprintf_s(PortNo, 20, L"\\\\.\\%s", pszPortName); //Open the serial com port hComm = CreateFile(PortNo, //friendly name GENERIC_READ | GENERIC_WRITE, // Read/Write Access 0, // No Sharing, ports cant be shared 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_s("\n Port can't be opened\n\n"); goto Exit2; } //Setting the Parameters for the SerialPort dcbSerialParams.DCBlength = sizeof(dcbSerialParams); Status = GetCommState(hComm, &dcbSerialParams); //retreives the current settings if (Status == FALSE) { printf_s("\nError to Get the Com state\n\n"); goto Exit1; } dcbSerialParams.BaudRate = CBR_9600; //BaudRate = 9600 dcbSerialParams.ByteSize = 8; //ByteSize = 8 dcbSerialParams.StopBits = ONESTOPBIT; //StopBits = 1 dcbSerialParams.Parity = NOPARITY; //Parity = None Status = SetCommState(hComm, &dcbSerialParams); if (Status == FALSE) { printf_s("\nError to Setting DCB Structure\n\n"); goto Exit1; } //Setting Timeouts timeouts.ReadIntervalTimeout = 50; timeouts.ReadTotalTimeoutConstant = 50; timeouts.ReadTotalTimeoutMultiplier = 10; timeouts.WriteTotalTimeoutConstant = 50; timeouts.WriteTotalTimeoutMultiplier = 10; if (SetCommTimeouts(hComm, &timeouts) == FALSE) { printf_s("\nError to Setting Time outs"); goto Exit1; } printf_s("\n\nEnter your message: "); scanf_s("%s", SerialBuffer, (unsigned)_countof(SerialBuffer)); //Writing data to Serial Port Status = WriteFile(hComm,// Handle to the Serialport SerialBuffer, // Data to be written to the port sizeof(SerialBuffer), // No of bytes to write into the port &BytesWritten, // No of bytes written to the port NULL); if (Status == FALSE) { printf_s("\nFail to Written"); goto Exit1; } //print numbers of byte written to the serial port printf_s("\nNumber of bytes written to the serail port = %d\n\n", BytesWritten); //Setting Receive Mask Status = SetCommMask(hComm, EV_RXCHAR); if (Status == FALSE) { printf_s("\nError to in Setting CommMask\n\n"); goto Exit1; } //Setting WaitComm() Event Status = WaitCommEvent(hComm, &dwEventMask, NULL); //Wait for the character to be received if (Status == FALSE) { printf_s("\nError! in Setting WaitCommEvent()\n\n"); goto Exit1; } //Read data and store in a buffer do { Status = ReadFile(hComm, &ReadData, sizeof(ReadData), &NoBytesRead, NULL); SerialBuffer[loop] = ReadData; ++loop; } while (NoBytesRead > 0); --loop; //Get Actual length of received data printf_s("\nNumber of bytes received = %d\n\n", loop); //print receive data on console printf_s("\n\n"); int index = 0; for (index = 0; index < loop; ++index) { printf_s("%c", SerialBuffer[index]); } printf_s("\n\n"); Exit1: CloseHandle(hComm);//Closing the Serial Port Exit2: system("pause"); return 0; }
Recommended Posts for you:
- Best 5 C Books.
- Get COM PORT of USB Serial Device using the VID and PID.
- Reading And Writing Windows Registry Using WinAPI
- Install the port monitor silently without user interaction.
- C++ Interview Questions with Answers.
- C-Sharp Interview Questions.
- Python Interview Questions with Answer.
- Memory Layout in C.
- 100 C interview questions, your interviewer might ask.
- C Interview Questions for the experience.
- 10 questions about dynamic memory allocation
- File handling in C, in few hours.