Setting Serial Data, Parity and Stop bits.

Hi all, I've just started working with the Arduino and have not been able to find a way to set the Data, Parity and Stop bits for the serial libraries. I've got a motor controller that needs 7-E-1, not 8-N-1.

Thanks!

I wrote a library for this, I put off posting it because I wanted to add some more interesting stuff for error checking. Its short so I am putting the code in line. I didnt find this elsewhere, but its pretty simple so it may be on the site already. Note if you dont want to use the library, you can simply lift the setserial sub.
FYI - I have worked out a couple of tricks to check for parity errors if you get into that. The best one requires editing wiring_serial.c, but I found a kluge that can be done from a program.

File must be named SerialExtension.cpp

#include <SerialExtension.h>

void SetSerial(long baud, char parity, int wordlength, int stop)
{
// set baud rate
// code lifted straight from wiring_serial.c
#if defined(__AVR_ATmega168__)
      UBRR0H = ((F_CPU / 16 + baud / 2) / baud - 1) >> 8;
      UBRR0L = ((F_CPU / 16 + baud / 2) / baud - 1);
      
      // enable rx and tx
      sbi(UCSR0B, RXEN0);
      sbi(UCSR0B, TXEN0);
      
      // enable interrupt on complete reception of a byte
      sbi(UCSR0B, RXCIE0);

#else
      UBRRH = ((F_CPU / 16 + baud / 2) / baud - 1) >> 8;
      UBRRL = ((F_CPU / 16 + baud / 2) / baud - 1);
      
      // enable rx and tx
      sbi(UCSRB, RXEN);
      sbi(UCSRB, TXEN);
      
      // enable interrupt on complete reception of a byte
      sbi(UCSRB, RXCIE);
#endif
      // defaults to 8-bit, no parity, 1 stop bit

//clear parity, stop bits, word length
//UCSR0B bit 2=0 for all wordlengths except 9
//Note: Serial.read routines wont work with 9 bit data as written
UCSR0C = UCSR0C & B11000001;
UCSR0B = UCSR0B & B11111011;  

//set parity 
if ((parity == 'O')|(parity == 'o')) 
  {
    UCSR0C = UCSR0C | B00110000; 
  } 
else if ((parity == 'E')|(parity == 'e')) 
  {
    UCSR0C = UCSR0C | B00100000;
  }
else // ((parity == 'N')|(parity == 'n'))) 
  {
    UCSR0C = UCSR0C | B00000000;
  }

//set word length
if (wordlength == 5)
  {
    UCSR0C = UCSR0C | B00000000;
  }
else if (wordlength == 6)
  {
    UCSR0C = UCSR0C | B00000010;
   }
else if (wordlength == 7)
  {
    UCSR0C = UCSR0C | B00000100;
  }
else if (wordlength == 9)
  {
    UCSR0C = UCSR0C | B00000110;
    UCSR0B = UCSR0B | B00000100;
  }
else // (wordlength == 8)
  {
    UCSR0C = UCSR0C | B00000110;
  }

//set stop bits
if (stop == 1) 
  {
    UCSR0C = UCSR0C | B00000100;
  }
else // (stop == 2)
  {
    UCSR0C = UCSR0C | B00000000;
  }
}

File must be named SerialExtension.h

#include <WConstants.h>
//#include <wiring_private.h>

#ifndef cbi
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
#endif
#ifndef sbi
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
#endif

void SetSerial(long baud,char parity, int wordlength, int stop);

#endif

The #endif at the bottom of SerialExtension.h is missing the associated if, and if I remove it there are a few other errors because it looks like something is missing or redefining something. What is the #if line at the top of the file?

I'm getting this error now:

In file included from /Applications/arduino-0015/hardware/cores/arduino/WProgram.h:4,

/Applications/arduino-0015/hardware/tools/avr/bin/../lib/gcc/avr/4.3.2/../../../../avr/include/stdlib.h:111: error: expected unqualified-id before 'int'

/Applications/arduino-0015/hardware/tools/avr/bin/../lib/gcc/avr/4.3.2/../../../../avr/include/stdlib.h:111: error: expected `)' before 'int'

/Applications/arduino-0015/hardware/tools/avr/bin/../lib/gcc/avr/4.3.2/../../../../avr/include/stdlib.h:111: error: expected `)' before 'int'

In file included from /Applications/arduino-0015/hardware/cores/arduino/WProgram.h:6,

Thanks!

Solved using the info from this thread: http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1237653105

Sorry for the syntax error. I dont know if I grabbed a bad version from my archive or if it somehow compiled as-is. Either way thanks for the catch.

Also, you can test as follows. 1) initialize the serial port as usual 2) set the baud/parity/stop bits 3) loop and send a string repeatedly, (delay a second each time makes it a little easier)

4) start your sketch, then EXIT the Arduino GUI. Start Hyperterm you should receive your test string. You should have to set hyperterm to match your serial settings. Make sure you select the right com port in hyperterm.

Hi,

I hope you can help… What you have here looks like the solution to my problems.

I need to interface to a device that uses 2 stop bits, I went searching and found this post.

I fixed SerialExtension.h as shown here:

#include <WProgram.h>

#ifndef cbi
   #define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
#endif
#ifndef sbi
   #define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
#endif

void SetSerial(long baud,char parity, int wordlength, int stop);

The corresponding SerialExtension.cpp is as follows:

#include <SerialExtension.h>

void SetSerial(long baud, char parity, int wordlength, int stop)
{
// set baud rate
// code lifted straight from wiring_serial.c
#if defined(__AVR_ATmega168__)
      UBRR0H = ((F_CPU / 16 + baud / 2) / baud - 1) >> 8;
      UBRR0L = ((F_CPU / 16 + baud / 2) / baud - 1);

      // enable rx and tx
      sbi(UCSR0B, RXEN0);
      sbi(UCSR0B, TXEN0);

      // enable interrupt on complete reception of a byte
      sbi(UCSR0B, RXCIE0);

#else
      UBRRH = ((F_CPU / 16 + baud / 2) / baud - 1) >> 8;
      UBRRL = ((F_CPU / 16 + baud / 2) / baud - 1);

      // enable rx and tx
      sbi(UCSRB, RXEN);
      sbi(UCSRB, TXEN);

      // enable interrupt on complete reception of a byte
      sbi(UCSRB, RXCIE);
#endif
      // defaults to 8-bit, no parity, 1 stop bit

//clear parity, stop bits, word length
//UCSR0B bit 2=0 for all wordlengths except 9
//Note: Serial.read routines wont work with 9 bit data as written
UCSR0C = UCSR0C & B11000001;
UCSR0B = UCSR0B & B11111011;  

//set parity
if ((parity == 'O')|(parity == 'o'))
  {
    UCSR0C = UCSR0C | B00110000;
  }
else if ((parity == 'E')|(parity == 'e'))
  {
    UCSR0C = UCSR0C | B00100000;
  }
else // ((parity == 'N')|(parity == 'n')))
  {
    UCSR0C = UCSR0C | B00000000;
  }

//set word length
if (wordlength == 5)
  {
    UCSR0C = UCSR0C | B00000000;
  }
else if (wordlength == 6)
  {
    UCSR0C = UCSR0C | B00000010;
   }
else if (wordlength == 7)
  {
    UCSR0C = UCSR0C | B00000100;
  }
else if (wordlength == 9)
  {
    UCSR0C = UCSR0C | B00000110;
    UCSR0B = UCSR0B | B00000100;
  }
else // (wordlength == 8)
  {
    UCSR0C = UCSR0C | B00000110;
  }

//set stop bits
if (stop == 1)
  {
    UCSR0C = UCSR0C | B00000100;
  }
else // (stop == 2)
  {
    UCSR0C = UCSR0C | B00000000;
  }
}

But I’m getting (kinda expected, from code inspection) the following compile errors:

SerialExtension.cpp: In function 'void SetSerial(long int, char, int, int)':
SerialExtension.cpp:19: error: 'UBRRH' was not declared in this scope
SerialExtension.cpp:20: error: 'UBRRL' was not declared in this scope
SerialExtension.cpp:23: error: 'UCSRB' was not declared in this scope
SerialExtension.cpp:23: error: 'RXEN' was not declared in this scope
SerialExtension.cpp:24: error: 'TXEN' was not declared in this scope
SerialExtension.cpp:27: error: 'RXCIE' was not declared in this scope
E:\Internet Downloads\arduino-0015-win\arduino-0015\hardware\cores\arduino\SerialExtension.cpp: In function 'void SetSerial(long int, char, int, int)':


E:\Internet Downloads\arduino-0015-win\arduino-0015\hardware\cores\arduino\SerialExtension.cpp:19: error: 'UBRRH' was not declared in this scope


E:\Internet Downloads\arduino-0015-win\arduino-0015\hardware\cores\arduino\SerialExtension.cpp:20: error: 'UBRRL' was not declared in this scope


E:\Internet Downloads\arduino-0015-win\arduino-0015\hardware\cores\arduino\SerialExtension.cpp:23: error: 'UCSRB' was not declared in this scope


E:\Internet Downloads\arduino-0015-win\arduino-0015\hardware\cores\arduino\SerialExtension.cpp:23: error: 'RXEN' was not declared in this scope


E:\Internet Downloads\arduino-0015-win\arduino-0015\hardware\cores\arduino\SerialExtension.cpp:24: error: 'TXEN' was not declared in this scope


E:\Internet Downloads\arduino-0015-win\arduino-0015\hardware\cores\arduino\SerialExtension.cpp:27: error: 'RXCIE' was not declared in this scope

I get the same results in versions 15 & 16 of the Arduino environment.

Help would be greatly appreciated.

Cheers,

Darren

The stop bits code I posted is wrong anyway.......

Quick and dirty just 1) set baud rate with the usual command 2) add the following to your setup code: UCSR0C = UCSR0C | B00001000;

I am pretty sure UCSR0C is predefined (note that is a ZERO not an O). Word length is also UCSR0C (except for 9 bit).

I double checked with the AVR datasheet and the code I posted doesnt set stop bits right anyway. Pretty embarrasing. Between the compile errors and that I am going to go retest.

Hey drspectro,

Thank you !!!!!!!!!!!!!!!!

I'm posting very simple code here for anyone else who hits this problem. You don't need any other library, just the code below.

This is working built using Arduino 16 talking to hyper-terminal on Windows XP.

byte high = 0;

void setup()
{
  Serial.begin(9600); 
  // 2 Stop-bits please!
  UCSR0C = UCSR0C | B00001000;
  pinMode(13, OUTPUT);
}

void loop()
{
  if (high == 0)
  {
    digitalWrite(13, HIGH);
    high = 1;
  }
  else
  {
    digitalWrite(13, LOW);
    high = 0;
  }
  if (high == 0)
  {
    Serial.print("HELLO"); // The text
  }
  else
  {
    Serial.print("WORLD"); // The text
  }
  delay(500);
}

glad it worked

I still want to get the library fixed because it covers all the parameters at once. I would hope that would be easier in the long run..... Also dont be afraid to go straight to the AVR datasheet for stuff like this. It is usually pretty clear which registers to mess with and you can look at the wiring code to figure out the syntax.

Hey all, I have a device that communicates on 1200-8-N-0. All of that is possible minus the 0 stop bits. Anyway to get the arduino to do this?

I have a device that communicates on 1200-8-N-0. All of that is possible minus the 0 stop bits. Anyway to get the arduino to do this?

Are you really sure about the 0 stop bit requirement? I say that because asynchronous communication hardware is built around the requirement for the stop bit and start bit to determine the ending of one character and the starting of the next, it just doesn't work without the stop bit. I've worked with the RS-232 asynchronous comm links for many decades and I've never heard of a zero stop bit ability. Now there are synchronous communications links that use no start or stop bits but rather either an independent or impeded clock to keep the sender and receiver in step for character transmission.

So might you be working with a serial synchronus communicating device?

Note: the AVR processor can be programmed to use synchronous communications, however with the standard Arduino serial software commands and a new clock wire would have to be wired between the Arduino and the external device.

Lefty

I'm trying to read data that is coming in with 2 stop bits. Now I see that the Atmel datasheet says that on page 198, BIT3 of USBSn sets the stop bits, but only the transmitter cares. From my rough knowledge of how asynchronous communications work, is that because the receiver sees a single stop bit and doesn't care what happens after that until the next start (low) bit? If not, how would I go about changing the receiver settings for stop bits? Thanks!

is that because the receiver sees a single stop bit and doesn't care what happens after that until the next start (low) bit? If not, how would I go about changing the receiver settings for stop bits? Thanks!

That's exactly right. Remember that after a single character with a proper stop bit detected, there may be no further characters for several seconds or even mins depending on the application.

Once a receiver detects that a expected stop bit is proper, it is willing to wait forever for only one further event, a start bit. That's why it's called asynchronous communications because the receiving end has no advance information on when and if the next character may be sent.

Interesting the purpose for more then a single stop bits (1&1/2 stop bits was an option in older times as well as 2 stop bits) dates back to the old mechanical teletype machines that used asyn communications. It allowed a little more time for receiving machines to "catch up" in case the transmitter was sending slightly faster then the agreed on baud rate.

Lefty

The half bit in the old 5 data bit standards also allowed synchronisation to a continuous stream of data. For example a standard way of keeping the channel open (free from other signals) was to transmit a continuous string of "RYRYRYRYRYRY....". These characters were chosen because they were at each end of the mechanical rotation limit of the print head. This was transmitted over short wave. Now if you tuned into this continuous stream you could start anywhere in it. If you had a stop bit time of exactly one or two bits you could tap into this stream and miss read it mistaking start bits and stop bits for data bits. The half period stop bit prevented this from happening.

I do recall a lot of RYRYRYRY test tapes as well as a lot of the "THE QUICK BROWN FOX JUMPED OVER THE LAZY DOGS BACK" tapes back in my Air Force days in the late 60s.

I was taught that the RYRYRY sequence was sent because it used and tested alternate bit combinations in the old 5-bit code used at the time.

Around Christmas time every year the data centers would be streaming and passing along wonderful graphic art work, kind of the predecessor of today's ASCII art and drawings. If the Russkies ever managed to break the crypto codes in the day and decoded one of these long 'art' messages (some were 10ft long when hung on a wall) I wonder what they would have thought of that. ;)

Lefty

After a few tests on my arduino, it seems to me that the proposed code solves only one half of the problem. It indeed changes the parity on the arduino, but I am afraid the Serial library does not check for parity errors.

For example, using a PC and an Arduino2009 with Even parity, I sent a message from the PC and expected and answer from the arduino (using modbus RTU):
PC (8N1) <-> Ard (8E1): communication erros (expected behaviour)
PC (8E1) <-> Ard (8E1): communication correct (just as expected)
PC (8O1) <-> Ard (8E1): the arduino interprets the message as correct (it should not) and replies accordingly, however the PC reports the arduino message is wrong (parity error).
If I change the arduino to 8O1, I will get similar results (does not work with PC-8N1, works with PC-8O1, half works with PC-8E1).

It looks like the parity errors are never checked on the Arduino serial library (for example, by reading the UPEn flag on register UCSRnA).
Am I missing something?
If the serial library is indeed not checking for parity erros, any ideas how to solve it (preferably, without messing with the library)?

If the serial library is indeed not checking for parity erros, any ideas how to solve it (preferably, without messing with the library)?

I think that would pretty much require a complete redo of the serial library as it is a very low level function and would have to have a standard interface to the user to let know when such errors occur (parity errors, framing errors, etc).

When reliable and rugged communications is required it's more common to do it at a higher level protocol instead of at a character at a time basis. Adding and checking for error free message can be done using CRC generation/error detection and message ack/nak handshaking between the two nodes.

It can be a complex subject and a lot depends on if one can dictate what standards will be used on both sides of the comm link. If not, one just has to adapt as best as they can.

Lefty

I think that would pretty much require a complete redo of the serial library as it is a very low level function and would have to have a standard interface to the user to let know when such errors occur (parity errors, framing errors, etc).

At the low level: I was thinking to just "ignore" a character when a parity error occurs. According to the ATmega's manual, the parity is checked by the hardware, and it raises a flag everytime such an error occurs. I am rather new to the arduino, therefore I was not sure if there was something missing on the library side.

At a higher level: I am using Modbus RTU, so the CRC is there already.

Thanks for your response.

If you are sending/receiving seven data bits, even or odd parity, you can always generate and check parity in your program. Let the serial library default to eight data bits, no parity, set the parity bit in bytes you send, and check the parity bit in bytes you receive.

The parity bit is the high order bit in the byte. For even parity, the high order bit is set to 0 or 1 as appropriate to make the total number of 1 bits in the byte (including the parity bit) an even number of bits. For odd parity, the goal is an odd number of total bits in the byte.

You can shift and mask bits to count them, but a faster way is to use a lookup table. If you use just one bit per table entry, your table will only be 16 bytes long.

Regards,

-Mike