Lonewolff
Posts: 144
Joined: Fri Dec 28, 2012 11:13 pm

Send/Recieve data on the RS232 port

Sun Dec 30, 2012 9:29 pm

Hi Guys,

I am just wondering how to send and receive data from the RS232 port (TX/RX pins on the header plug) on the Raspberry PI in C++.

I am pretty fluent in programming in Win32 but am a complete newb when programming under Linux.

Any help would be awesome. 8-)
Loving my peice of the Pi

User avatar
[email protected]
Posts: 2020
Joined: Tue Feb 07, 2012 2:14 pm
Location: Devon, UK
Contact: Website

Re: Send/Recieve data on the RS232 port

Sun Dec 30, 2012 11:37 pm

Lonewolff wrote:Hi Guys,

I am just wondering how to send and receive data from the RS232 port (TX/RX pins on the header plug) on the Raspberry PI in C++.

I am pretty fluent in programming in Win32 but am a complete newb when programming under Linux.

Any help would be awesome. 8-)
It's not hard - have a look at the serial stuff in wiringPi: https://projects.drogon.net/raspberry-p ... l-library/

It's all C, but callable from C++ without any issues. If you want an example, look in: http://unicorn.drogon.net/serialTest.c

-Gordon
--
Gordons projects: https://projects.drogon.net/

Lonewolff
Posts: 144
Joined: Fri Dec 28, 2012 11:13 pm

Re: Send/Recieve data on the RS232 port

Mon Dec 31, 2012 10:30 pm

Hi Gordon,

Thanks for the link. Your site looks very informative. 8-)

If I get a chance, I'll have a crack at this over the next few days. :D
Loving my peice of the Pi

dairon
Posts: 28
Joined: Sat Dec 15, 2012 12:17 pm

Re: Send/Recieve data on the RS232 port

Fri Jan 04, 2013 2:36 pm

Hi guys,

I'm also having some questions about serial Tx/Rx. I want to send a self build binary string (only some bytes). when i send a one then i want a high on the serial port. It then should be also possible to read that one and print it out for verification. In the future a string will be send fia RF to another device which should then receive the string. At the moment i shortcut the Rx and Tx on my RasPi for testing. I confirmed and tested this and serial is working.

Is this possible? Really appreciate your help :)

cheers,
dai

User avatar
joan
Posts: 14473
Joined: Thu Jul 05, 2012 5:09 pm
Location: UK

Re: Send/Recieve data on the RS232 port

Fri Jan 04, 2013 2:49 pm

The serial link transmits bytes of data at a time. Each byte is sent as a preamble (start bit), the data bits, and then a postamble (optional check and stop bits). The preamble/postamble are handled by the hardware at each end and will not be visible to you. Treat it as a byte stream, not a bit stream.

dairon
Posts: 28
Joined: Sat Dec 15, 2012 12:17 pm

Re: Send/Recieve data on the RS232 port

Fri Jan 04, 2013 3:19 pm

ok i see what you mean. but nevertheless when i have a stream (01010101111010001) it will be seperated, header and checksum information will be added and send out. after receiving it these extra information is chopped off again so i should see my stream again, right? the question is now how do i send a self made bitstream (or bytestream however you would call it, if I havent enough bits to get the byte full i will fill it up with zeros) via the serial interface? code samples would be great! :D

cheers,
dai

User avatar
joan
Posts: 14473
Joined: Thu Jul 05, 2012 5:09 pm
Location: UK

Re: Send/Recieve data on the RS232 port

Fri Jan 04, 2013 3:55 pm

I'm going to assume this is a 433 wireless tx/rx pair connected to the serial link.

I'd package your bits up into a whole number of bytes and then encapsulate them in a message such as follows,

Code: Select all

0xAA start message token
mlen message data bytes (1.255)
dat1 data byte 1
...
datN data byte N
cksm byte xor of message bytes
Transmission is straightforward

Code: Select all

#include <string.h>

void tx_message(int fd, int mlen, char * dat)
{
   char buf[300];
   int i;
   char cksm;

   buf[0] = 0xAA;
   buf[1] = mlen;

   memcpy(buf+2, dat, mlen);

   cksm = 0;
   for (i=0; i<(mlen+2); i++)  cksm ^= buf[i];
   buf[mlen+2] = cksm;

   write(fd, buf, mlen+3);
}
The reception code is more complicated as you'll have to scan for the start byte, accumulate, and check the message. If the checksum is corrupt the start byte might have been erroneous so you'd need to rescan the input from that point forward for another start byte.

User avatar
rurwin
Forum Moderator
Forum Moderator
Posts: 4258
Joined: Mon Jan 09, 2012 3:16 pm
Contact: Website

Re: Send/Recieve data on the RS232 port

Fri Jan 04, 2013 4:16 pm

I'd guess a checksum (actually that code produces longitudinal parity) is a little weak for that application. If it's a 433MHz data link with no other error checking, I'd use at least a CRC16. Algorithm and source code is only a Google away. You don't have to understand it. SECDED is probably overkill, but worth Googling if you get too many errors.

Adding redundancy to the message helps, so if you code your message in hexadecimal, or even binary with "1" and "0" characters, you'll get fewer undetected errors and you can have a message start byte that doesn't appear in the data-stream so resynchronisation is easier. Debugging is much easier too if the data-stream is human-readable.
Last edited by rurwin on Fri Jan 04, 2013 4:22 pm, edited 1 time in total.

User avatar
[email protected]
Posts: 2020
Joined: Tue Feb 07, 2012 2:14 pm
Location: Devon, UK
Contact: Website

Re: Send/Recieve data on the RS232 port

Fri Jan 04, 2013 4:20 pm

Also watch out for those really cheap tx/rx units that just take raw data to modulate the carrier - some are not good at detecting long streams of 1's or zeros, so an additional encoding scheme may be needed.

Personally I've always used the "designed for rs232" type modules - they cost a few £ more, but "just work" - e.g. ciseco xrf/urf, xbee, etc.

-Gordon
--
Gordons projects: https://projects.drogon.net/

User avatar
joan
Posts: 14473
Joined: Thu Jul 05, 2012 5:09 pm
Location: UK

Re: Send/Recieve data on the RS232 port

Fri Jan 04, 2013 4:45 pm

When I was playing with the serial link and the RF tx/rx pair I bought it looked stable at 2400bps. A VirtualWire solution seems a bit over the top. Frankly I'd try the simplest reasonable solution first and only ditch it if it is not reliable.

User avatar
cyrano
Posts: 714
Joined: Wed Dec 05, 2012 11:48 pm
Location: Belgium

Re: Send/Recieve data on the RS232 port

Fri Jan 04, 2013 4:46 pm

Found this a couple of days ago:

http://shop.ciseco.co.uk/erf-0-1-pin-sp ... io-module/

Looks good. Haven't tried it yet.

Lonewolff
Posts: 144
Joined: Fri Dec 28, 2012 11:13 pm

Re: Send/Recieve data on the RS232 port

Fri Jan 04, 2013 9:01 pm

Great info on this thread guys :D

BTW, I am going to use infrared RS232 communications for my project. I designed and built a couple of TX/RX modules about 10 years back using the MC1488 & MC1489 line drivers. This was designed for the PC so it will be even easier to refactor for the Raspberry Pi as we are dealing directly with 5v highs (instead of +/- RS232 voltages) from the TX/RX pins. 8-)

I also just recieved my second Raspberry Pi. So, let the fun begin :lol:
Loving my peice of the Pi

User avatar
rurwin
Forum Moderator
Forum Moderator
Posts: 4258
Joined: Mon Jan 09, 2012 3:16 pm
Contact: Website

Re: Send/Recieve data on the RS232 port

Fri Jan 04, 2013 11:44 pm

3.3V, not 5V

Lonewolff
Posts: 144
Joined: Fri Dec 28, 2012 11:13 pm

Re: Send/Recieve data on the RS232 port

Sat Jan 05, 2013 12:52 am

3.3v is it? Thanks for the heads up ;)

Is that the same for all I/O on the GPIO port?
Loving my peice of the Pi

User avatar
rurwin
Forum Moderator
Forum Moderator
Posts: 4258
Joined: Mon Jan 09, 2012 3:16 pm
Contact: Website

Re: Send/Recieve data on the RS232 port

Sat Jan 05, 2013 1:12 am

Yes. The 5V is only used by the USB chip and the USB bus IIUC. There is 5V (and 3.3V) power on the GPIO connector, but all the signals are 3.3V

Lonewolff
Posts: 144
Joined: Fri Dec 28, 2012 11:13 pm

Re: Send/Recieve data on the RS232 port

Sat Jan 05, 2013 11:02 pm

How many bytes does the RS232 buffer hold?

I would imagine that if you developed an app (without handshaking) incoming bytes would be discarded if the recieve buffer was full. Am I right?
Loving my peice of the Pi

User avatar
[email protected]
Posts: 2020
Joined: Tue Feb 07, 2012 2:14 pm
Location: Devon, UK
Contact: Website

Re: Send/Recieve data on the RS232 port

Sat Jan 05, 2013 11:57 pm

Lonewolff wrote:How many bytes does the RS232 buffer hold?

I would imagine that if you developed an app (without handshaking) incoming bytes would be discarded if the recieve buffer was full. Am I right?
Yes, however I don't know the answer to that one. The hardware will have a small FIFO (8 bytes is typical) and the linux kernel driver will have a bigger buffer, but you'd need to look at the code to find out...

Best not rely on it, and read the port if you're expecting data from it...

-Gordon
--
Gordons projects: https://projects.drogon.net/

Lonewolff
Posts: 144
Joined: Fri Dec 28, 2012 11:13 pm

Re: Send/Recieve data on the RS232 port

Sun Jan 06, 2013 1:22 am

That's the plan, to poll the port at regular intervals. Each loop might be overkill but I'll see what works best for my application.

The plan is to make a couple of 'laser tag' units. So, in the scheme of of things (700Mhz) the packets will be few and far between, in reality. Also, the packets will be pretty small. I am thinking something like the following;

Packet type | Data | Checksum

Parity is all well and good but if you get two bits incorrect over a byte the parity will still show the packet to be valid. And dealing with infrared over a distance the packets will be somewhat prone to errors.
Loving my peice of the Pi

User avatar
[email protected]
Posts: 2020
Joined: Tue Feb 07, 2012 2:14 pm
Location: Devon, UK
Contact: Website

Re: Send/Recieve data on the RS232 port

Sun Jan 06, 2013 9:13 am

Lonewolff wrote:That's the plan, to poll the port at regular intervals. Each loop might be overkill but I'll see what works best for my application.

The plan is to make a couple of 'laser tag' units. So, in the scheme of of things (700Mhz) the packets will be few and far between, in reality. Also, the packets will be pretty small. I am thinking something like the following;

Packet type | Data | Checksum

Parity is all well and good but if you get two bits incorrect over a byte the parity will still show the packet to be valid. And dealing with infrared over a distance the packets will be somewhat prone to errors.
There are many types of checksum and error correcting codes (ECC) out there. I'd try it first before adding in checksums/ecc just to see how bad (or good!) it might be...

-Gordon
--
Gordons projects: https://projects.drogon.net/

Lonewolff
Posts: 144
Joined: Fri Dec 28, 2012 11:13 pm

Re: Send/Recieve data on the RS232 port

Sun Jan 06, 2013 9:26 am

Yeah, I am aware of a couple of EEC methods. Predominantly, 'Hamming Code' which does a pretty god job. 8-)
Loving my peice of the Pi

User avatar
joan
Posts: 14473
Joined: Thu Jul 05, 2012 5:09 pm
Location: UK

Re: Send/Recieve data on the RS232 port

Sun Jan 06, 2013 9:36 pm

I've spent some more time playing with my cheap radio modules connected to the serial ports (one Pi transmitting, another receving).

I used the following code.

Code: Select all

#include <stdio.h>   /* Standard input/output definitions */
#include <stdlib.h>  /* exit */
#include <string.h>  /* String function definitions */
#include <unistd.h>  /* UNIX standard function definitions */
#include <fcntl.h>   /* File control definitions */
#include <errno.h>   /* Error number definitions */
#include <termios.h> /* POSIX terminal control definitions */
#include <ctype.h>   /* isxxx() */

/* ------------------------------------------------------------------------

cc -o 433 433.c

Usage ./433 [option] ...

   -r, receiver (default)

   -t, transmitter

   -s BPS, bits per second, default 2400
      (300, 600, 1200, 1800, 2400, 4800, 9600, 19200)

   -m COUNT, test messages, default 1000

./433 -t -s4800 -m500 run as transmitter send 500 messages at 4800 bps
./433 -r -s4800       run as receiver (default), receive at 4800 bps

-------------------------------------------------------------------------- */

#define PREAMBLE 0x21
#define SYNC     0xAA

int     rx       = 1;     /* defaults to receiver end */
int     messages = 1000;  /* default send 1000 test messages */
speed_t speed    = B2400; /* default to 2400 bps */

struct termios orig;
int filedesc;

/* prototypes */

int  openSerialPort (char * device, int bps);
void tx_message     (int fd, int mlen, char * dat);
int  rx_message     (int fd, char * dat);
int  initOpts       (int argc, char *argv[]);
void tidyup(void);

int main(int argc, char *argv[])
{
   int i, c;
   char buf[512];

   initOpts(argc, argv);

   filedesc = openSerialPort("/dev/ttyAMA0", speed);

   if (filedesc == -1) exit(1);

   atexit(tidyup);

   if (rx)
   {
      while(1)
      {
         usleep(100);
         c = rx_message(filedesc, buf);
         if (c > 0)
         {
            buf[c]=0;
            printf(buf);
         }
      }
   }
   else
   {
      for (i=1; i<=messages; i++)
      {
         sprintf(buf, "message #%d\n", i);
         tx_message(filedesc, strlen(buf), buf);
         usleep(500); /* delay between messages */
      }
   }

}

void tidyup(void)
{
   fflush(NULL); /* flush output */

   /* important to use TCSAFLUSH, otherwise buffered messages will be lost */
   tcsetattr(filedesc, TCSAFLUSH, &orig); /* restore original serial settings */
}

int openSerialPort(char * device, int bps)
{
   int fd;
   struct termios new;
   char buf[128];

   fd = open(device, O_RDWR | O_NOCTTY | O_NDELAY | O_NONBLOCK);

   if (fd == -1)
   {
      sprintf(buf, "openSerialPort %s error", device);
      perror(buf);
   }
   else
   {
      tcgetattr(fd, &orig); /* save current serial settings */
      tcgetattr(fd, &new);
      cfmakeraw(&new);
      fprintf(stderr, "speed=%d\n", bps);
      cfsetispeed(&new, bps);
      cfsetospeed(&new, bps);
      tcsetattr(fd, TCSANOW, &new); /* set new serial settings */
      fcntl (fd, F_SETFL, O_RDWR);
   }
   return fd;
}

int checksum(int len, char * dat)
{
   int cksm;
   int i;

   cksm = 0;
   for (i=0; i<len; i++)  cksm ^= dat[i];

   return cksm;
}

void tx_message(int fd, int mlen, char * dat)
{
   char buf[300];
   char cksm;
   int wrote;

   buf[0] = SYNC; /* gives time for the receiving uart to sync */
   buf[1] = SYNC; /* gives time for the receiving uart to sync */
   buf[2] = PREAMBLE;
   buf[3] = mlen;

   memcpy(buf+4, dat, mlen);

   cksm = checksum(mlen+2, buf+2);
   buf[mlen+4] = cksm;

   wrote = write(fd, buf, mlen+5);
   if (wrote != (mlen+5)) printf("short write %d\n", wrote);
}

void printBuf(char * buf, int bufLen)
{
   int i;

   for (i=0; i<bufLen; i++)
   {
      if (isprint(buf[i])) printf("%c ", buf[i]);
      else                 printf("%02X ", buf[i]);
   }

   printf("\n");
}

int rx_message(int fd, char * dat)
{
   static int  posBuf=0;
   static char msgBuf[512];

   int i, scanning, mlen, validMessage;
   char cksm;
   char * ptr;

   validMessage = 0;

   i = read(fd, msgBuf+posBuf, sizeof(msgBuf)-posBuf);

   if (i>0)
   {
      posBuf += i;

      scanning = 1;

      while (scanning)
      {
         if (msgBuf[0] != PREAMBLE)
         {
            /* find message start */

            ptr = memchr(msgBuf, PREAMBLE, posBuf);

            if (ptr != NULL)
            {
               /* preamble found, discard previous junk */

               i = ptr - msgBuf;
               posBuf -= i;
               memmove(msgBuf, ptr, posBuf);
            }
            else
            {
               /* no preamble found, discard junk */

               posBuf = 0;
               scanning = 0;
            }
         }

         if (posBuf > 2)
         {
            /* we have enough to calculate size */

            mlen = msgBuf[1];

            if (posBuf > (mlen+2))
            {
               /* we have enough for a message */

               cksm = checksum(mlen+2, msgBuf);

               if (msgBuf[mlen+2] == cksm)
               {
                  /* valid message received */
                  validMessage = 1;

                  /* copy message to callers buffer */
                  memmove(dat, msgBuf+2, mlen);

                  /* remove from receive buffer */
                  posBuf -= (mlen+3);
                  if (posBuf) memmove(msgBuf, msgBuf+mlen+3, posBuf);
                  scanning = 0;
               }
               else
               {
                  /* corrupt message or invalid preamble.
                     Delete preamble and search for another
                  */
                  msgBuf[0] = 0;
               }
            }
            else scanning = 0;
         }
         else scanning = 0;
      }
   }

   if (validMessage) return mlen; else return 0;

}

int initOpts(int argc, char *argv[])
{
   int opt;

   while ((opt = getopt(argc, argv, "m:rs:t")) != -1)
   {
      switch (opt)
      {
         case 'm':
            opt = atoi(optarg);
            if (opt>0) messages = opt;
            break;

         case 'r':
            rx = 1;
            break;

         case 's':
            opt = atoi(optarg);

            if      (opt ==   300) speed =   B300;
            else if (opt ==   600) speed =   B600;
            else if (opt ==  1200) speed =  B1200;
            else if (opt ==  1800) speed =  B1800;
            else if (opt ==  2400) speed =  B2400;
            else if (opt ==  4800) speed =  B4800;
            else if (opt ==  9600) speed =  B9600;
            else if (opt == 19200) speed = B19200;

            break;

         case 't':
            rx = 0;
            break;
      }
   }
   return 0;
}
I ran a series of tests with bps of 1200, 1800, 2400, 4800, 9600, and 19200.

On the transmitter I used the command ./433 -t -s<bps> -m5000
On the receiver I used the command ./433 -s<bps>

Results

Code: Select all

bps  1200: good 4998 discarded    1 bad  1
bps  1800: good 4995 discarded    5 bad  0
bps  2400: good 4999 discarded    1 bad  0
bps  4800: good 4999 discarded    1 bad  0
bps  9600: good 4945 discarded   55 bad  0
bps 19200: good  711 discarded 4211 bad 78
good = message received ok
discarded = message failed checksum and was discarded
bad = message passed checksum but was corrupt

I discovered it was important to send a couple of dummy bytes before each message proper. This gave the receiving uart a proper bit stream to synchronise against. Without those bytes the receiving uart would be synced against any old wireless static.

Lonewolff
Posts: 144
Joined: Fri Dec 28, 2012 11:13 pm

Re: Send/Recieve data on the RS232 port

Tue Jan 08, 2013 9:02 pm

Going to have a play with this today 8-)

I read somewhere that you could bridge the TX and RX pins (for test purposes). But, I can't track down that post now.

How do you 'terminal in' to the port to test that transmitted characters are being recieved back? Is there something like 'hyperterm' (Windows equivalent)?
Loving my peice of the Pi

User avatar
joan
Posts: 14473
Joined: Thu Jul 05, 2012 5:09 pm
Location: UK

Re: Send/Recieve data on the RS232 port

Tue Jan 08, 2013 9:12 pm

I use minicom. Others have a fit and say it's so outdated and use something called screen.

sudo apt-get install minicom

User avatar
[email protected]
Posts: 2020
Joined: Tue Feb 07, 2012 2:14 pm
Location: Devon, UK
Contact: Website

Re: Send/Recieve data on the RS232 port

Tue Jan 08, 2013 9:40 pm

joan wrote:I use minicom. Others have a fit and say it's so outdated and use something called screen.

sudo apt-get install minicom
Minicom is good.

-Gordon
--
Gordons projects: https://projects.drogon.net/

Lonewolff
Posts: 144
Joined: Fri Dec 28, 2012 11:13 pm

Re: Send/Recieve data on the RS232 port

Tue Jan 08, 2013 9:49 pm

Sorry for the newbie posts. But what is the serial device called (within /dev)?

I see posts reffering to it as /dev/ttyS0 but that doesn't exist on my Pi.
Loving my peice of the Pi

Return to “C/C++”