Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / C

Simple Serial Communication Utilities

4.80/5 (9 votes)
29 Aug 2014CPOL2 min read 49.3K  
A simple serial communication library, with a serial ports enumerator

Introduction

In embedded designing, it is very common to need a communication channel with a PC. The simplest way is the serial communication because every microcontroller has UART ports to make serial communication with the world. But on the computer, it's not always that easy.

Here, I present a very simple serial communnication library, with non blocking reading and no-event-dependant which can be an advantage denpending on the type of software we need.

Along with this, I provide a serial port enumerator, which is very useful, and a simple Timer class which will allow us to measure intervals and automate some actions. This timer class is not event-driven so you have to poll the state of the interval to know if it's time to do something.

In future articles, I will explain how to use event-driven timers to really automate a function. But for now, this simple timer is enough for our aplication.

Using the Code

In the code, I use three separate libraries. One for the serial communication, one for the timing and one for the summary of the available comports in the PC. I upload each library separately and an example project using them.

RS232 Library

This library brings a simple and easy to use interface with the COM ports of the PC. The header presents these functions:

C++
#ifndef rs232_INCLUDED
#define rs232_INCLUDED

#ifdef __cplusplus
extern "C" {
#endif

#include <stdio.h>
#include <string.h>


#ifdef __linux__

#include <termios.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <limits.h>

#else

#include <windows.h>

#endif

int RS232_OpenComport(int, int);
int RS232_PollComport(int, unsigned char *, int);
int RS232_SendByte(int, unsigned char);
int RS232_SendBuf(int, unsigned char *, int);
void RS232_CloseComport(int);
void RS232_cputs(int, const char *);
int RS232_IsDCDEnabled(int);
int RS232_IsCTSEnabled(int);
int RS232_IsDSREnabled(int);
void RS232_enableDTR(int);
void RS232_disableDTR(int);
void RS232_enableRTS(int);
void RS232_disableRTS(int);

#ifdef __cplusplus
} /* extern "C" */
#endif

#endif

This library was writen by Teunis van Beelen, more information here.

Com Ports Enumerator

This library brings a simple method for enumerating the available serial ports in the PC. It isn't perfect but it works fine.

C++
#ifndef LISTPORTS_H
#define LISTPORTS_H

#define VERSION_LISTPORTS 0x00020000

#ifdef __cplusplus
extern "C"{
#endif

#include <windows.h>

typedef struct
{
  LPCTSTR lpPortName;     /* "COM1", etc. */
  LPCTSTR lpFriendlyName; /* Suitable to describe the port, as for  */
                          /* instance "Infrared serial port (COM4)" */
  LPCTSTR lpTechnology;   /* "BIOS","INFRARED","USB", etc.          */
}LISTPORTS_PORTINFO;

typedef BOOL (CALLBACK* LISTPORTS_CALLBACK)(LPVOID              lpCallbackValue,
                                            LISTPORTS_PORTINFO* lpPortInfo);
/* User provided callback funtion that receives the information on each
 * serial port available.
 * The strings provided on the LISTPORTS_INFO are not to be referenced after
 * the callback returns; instead make copies of them for later use.
 * If the callback returns FALSE, port enumeration is aborted.
 */

BOOL ListPorts(LISTPORTS_CALLBACK lpCallback,LPVOID lpCallbackValue);
/* Lists serial ports available on the system, passing the information on
 * each port on succesive calls to lpCallback.
 * lpCallbackValue, treated opaquely by ListPorts(), is intended to carry
 * information internal to the callback routine.
 * Returns TRUE if succesful, otherwise error code can be retrieved via
 * GetLastError().
 */

#ifdef __cplusplus
}
#endif

#elif VERSION_LISTPORTS!=0x00020000
#error You have included two LISTPORTS.H with different version numbers
#endif
To use it, just define in your code what you want to do with the listed ports inside the
C++
typedef BOOL (CALLBACK* LISTPORTS_CALLBACK)(LPVOID              lpCallbackValue,
                                            LISTPORTS_PORTINFO* lpPortInfo);

definition. In the example, I'm providing:

C++
string comPorts[4]; // Vector containing available ports
int port_cnt=0;

/* Callback function that list the available ports */
static BOOL CALLBACK callback(LPVOID lpCallbackValue,LISTPORTS_PORTINFO* lpPortInfo)
{
  _tprintf(
    TEXT("\"%s\" \"%s\" \"%s\"\n"),
    lpPortInfo->lpPortName,lpPortInfo->lpTechnology,lpPortInfo->lpFriendlyName);
    comPorts[port_cnt] = lpPortInfo->lpPortName;
    port_cnt++;
  return TRUE;
}

This library was writen by Joaquín Mª López Muñoz.

The Example

The example is just a console aplication emulating a very simple terminal that sends a character or string to the port ad to display the response of the device connected to it. It was written using Code::Blocks over Windows 7.

C++
#include <iostream>
#include "rs232.h"
#include "timerclass.h"
#include "listports.h"
#include <tchar.h>

using namespace std;

string comPorts[4]; // Vector containing available ports
int port_cnt=0;

/* Definition of the Callback function that list the available ports */
static BOOL CALLBACK callback(LPVOID lpCallbackValue,LISTPORTS_PORTINFO* lpPortInfo)
{
  _tprintf(
    TEXT("\"%s\" \"%s\" \"%s\"\n"),
    lpPortInfo->lpPortName,lpPortInfo->lpTechnology,lpPortInfo->lpFriendlyName);
    comPorts[port_cnt] = lpPortInfo->lpPortName;
    port_cnt++;
  return TRUE;
}

int main(int argc, char* argv[])
{

    int n;
    unsigned char buf[4096];
    int cport_nr = 4;
    int bdrate = 9600;

    //unsigned char outBuffer[128];
    string outBuffer;

    ListPorts(callback,NULL); //Calling to the list ports function

    cout << "Available ports: " << endl;
    for(int i=0; i<port_cnt; i++)
    {
        cout << (i+1) << ": " << comPorts[i] << endl;
    }
    cout << endl << "Choose a port ";
    cin >> cport_nr;
    cport_nr--; // according to rs232.h, the port numbers start on 0 for COM1

    if(RS232_OpenComport(cport_nr, bdrate)) //Open the port
    {
        cout << "Can not open com port " << comPorts[cport_nr];

        return(0);
    }

    while(1)
  {
    //n = RS232_PollComport(cport_nr, buf, 4095);
    cout << "Type message to send" << endl << "Type 'quit' to exit" << endl;
    cin >> outBuffer;

    if(outBuffer == "quit")
    {
        RS232_CloseComport(cport_nr);
        return 0;
    }

    RS232_SendBuf(cport_nr, (unsigned char*) outBuffer.c_str(), outBuffer.size());

    Sleep(100);
    n = RS232_PollComport(cport_nr, buf, 4096);
    if(n>0)
    {
        buf[n]=0;
        cout << "Received: " << buf << endl << endl;
    }
    buf[0]=0;

  }
}

After including the libraries is the definition of the callback function of the port lister. It shows the ports available and stores their names on a string.

Then in the main function, first call the ListPort function and show again the available ports. Ask for the desired port and try to open it. If the port is open, the program enters in an infinite loop until the user type 'quit'.

In the loop, the program asks for the message to send and put it on the COM port.

C++
RS232_SendBuf(cport_nr, (unsigned char*) outBuffer.c_str(), outBuffer.size());

Wait for 100 milliseconds and poll the port for the response:

C++
n = RS232_PollComport(cport_nr, buf, 4096);

If there is any message, it is displayed on the screen:

C++
if(n>0)
    {
        buf[n]=0;
        cout << "Received: " << buf << endl << endl;
    }

In the capture is running communicated with an Arduino board acting as an echoer.

Image 1

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)