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:
#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
}
#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.
#ifndef LISTPORTS_H
#define LISTPORTS_H
#define VERSION_LISTPORTS 0x00020000
#ifdef __cplusplus
extern "C"{
#endif
#include <windows.h>
typedef struct
{
LPCTSTR lpPortName;
LPCTSTR lpFriendlyName;
LPCTSTR lpTechnology;
}LISTPORTS_PORTINFO;
typedef BOOL (CALLBACK* LISTPORTS_CALLBACK)(LPVOID lpCallbackValue,
LISTPORTS_PORTINFO* lpPortInfo);
BOOL ListPorts(LISTPORTS_CALLBACK lpCallback,LPVOID lpCallbackValue);
#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
typedef BOOL (CALLBACK* LISTPORTS_CALLBACK)(LPVOID lpCallbackValue,
LISTPORTS_PORTINFO* lpPortInfo);
definition. In the example, I'm providing:
string comPorts[4]; int port_cnt=0;
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.
#include <iostream>
#include "rs232.h"
#include "timerclass.h"
#include "listports.h"
#include <tchar.h>
using namespace std;
string comPorts[4]; int port_cnt=0;
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;
string outBuffer;
ListPorts(callback,NULL);
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--;
if(RS232_OpenComport(cport_nr, bdrate)) {
cout << "Can not open com port " << comPorts[cport_nr];
return(0);
}
while(1)
{
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.
RS232_SendBuf(cport_nr, (unsigned char*) outBuffer.c_str(), outBuffer.size());
Wait for 100 milliseconds and poll the port for the response:
n = RS232_PollComport(cport_nr, buf, 4096);
If there is any message, it is displayed on the screen:
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.