Register forum user name Search FAQ

Gammon Forum

Notice: Any messages purporting to come from this site telling you that your password has expired, or that you need to "verify" your details, making threats, or asking for money, are spam. We do not email users with any such messages. If you have lost your password you can obtain a new one by using the password reset link.
 Entire forum ➜ Electronics ➜ Microprocessors ➜ Async (Serial) peripheral interface - for Arduino

Async (Serial) peripheral interface - for Arduino

Postings by administrators only.

Refresh page


Posted by Nick Gammon   Australia  (23,070 posts)  Bio   Forum Administrator
Date Tue 25 Jan 2011 06:20 AM (UTC)

Amended on Sat 28 Sep 2013 07:11 AM (UTC) by Nick Gammon

Message
This post describes how the Serial interface works, with particular reference to the Arduino Uno which is based on the ATmega328P microprocessor chip. A lot of the details however will be of more general interest.

Serial comms is used to send serial data from a microprocessor to another one, or a peripheral, for example an LCD display.

More information about serial (RS-232) comms at:

    http://en.wikipedia.org/wiki/RS-232


More information about the Arduino Serial interface at:

    http://arduino.cc/en/Reference/Serial


For a discussion about reading serial data without blocking, see:




Other protocols





Sending data


Let's start with an image - this is a screenshot taken with a logic analyser. It shows the 3-character sequence "Fab" being sent from the Arduino at 9600 baud.



From the above graphic note that the Tx (transmit) data line is normally high (1) until it drops low to indicate the start of a character (byte). This is the start bit. Then the 8 data bits (indicated by dots) appear at the baud rate (9600 samples per second). After that the line is brought high again. This is the stop bit. Then we see the start bit for the next character, and so on.

More detail for the first character (the letter "F" or 0x46 or 0b01000110) can be seen here:





  • A - no data (Tx is high)

  • B - The "start bit". The line is taken low to tell the receiver that a character (byte) is commencing to be sent. The receiver waits for one and a half clock times before sampling the line.

  • C - First character arrives (the letter "F" or 0x46 or 0b01000110). There is no clock bit as such, the incoming data is simply sampled at the baud (transmission) rate. In contrast to SPI communication the data arrives least-significant bit first (in case you are not sending 8 bits per byte). Thus we see 01100010 (rather than 01000110).

  • D - The stop bit. This is always high, to ensure that we can distinguish between the end of this byte, and the start of the next one. Since the start bit is a zero, and the stop bit is a one, there is always a clear transition from one byte to the next.

  • E - The start bit for the next character.



The code to produce this (in Arduino's C++ language) was:


void setup() 
{ 
  Serial.begin(9600); 
  Serial.print("Fab"); 
} 

void loop ()
{
}


[EDIT] See below for slightly different information regarding the Arduino Leonardo.

Timing


As you can see from the Logic analyser timing, the time between each bit is 0.1041667 milliseconds. If we take the inverse of that (1 / 0.0001041667) we get 9599.99, which confirms that the bit rate was 9600 per second (or near enough).

Since each byte consists of 10 bits (start bit + 8 data bits + stop bit) we can transmit 960 bytes per second (a lot less than the 325.5 Kbytes/s we could achieve with SPI communications).

Number of data bits


In order to save transmission time (in the olden days, heh) you were allowed to specify different numbers of data bits. The Atmega hardware supports data bits numbering from 5 to 9. Clearly the less data bits the less information you can send, but the faster it will be.

Parity bits


You can optionally have a parity bit. This is calculated, if required, by counting the number of 1's in the character, and then making sure that this number is odd or even by setting the parity bit to 0 or 1 as required.

For example, for the letter "F" (or 0x46 or 0b01000110) you can see that there are 3 ones there (in 01000110). Thus we already have odd parity. So, the parity bit would be as follows:


  • No parity: omitted
  • Even parity: a 1 (3 + 1 is even)
  • Odd parity: a 0 (3 + 0 is odd)


The parity bit, if present, appears after the last data bit but before the stop bit.

If the receiver does not get the correct parity bit, that is called a "parity error". It indicates that there is some problem. Possibly the sender and receiver are configured to use different baud (bit) rates, or there was noise on the line which turned a zero to a one or vice-versa.

Some early systems also used "mark" parity (where the parity bit was always 1 regardless of the data), or "space" parity (where the parity bit was always 0 regardless of the data).

Number of stop bits


Early equipment tended to be somewhat slower electronically, so to give the receiver time to process the incoming byte, it was sometimes specified that the sender would send two stop bits. This basically adds more time where the data line is held high (one more bit time) before the next start bit can appear. This extra bit time gives the receiver time to process the last incoming byte.

If the receiver does not get a logical 1 when the stop bit is supposed to be, that is called a "framing error". It indicates that there is some problem. Quite possibly the sender and receiver are configured to use different baud (bit) rates.

Notation


Commonly serial communication is indicated by telling you the speed, number of data bits, type of parity, and number of stop bits, like this:


9600/8-N-1


This is telling us:


  • 9600 bits per second
  • 8 data bits
  • No parity (you might see instead: E=even, O=odd)
  • 1 stop bit


It is important that the sender and receiver agree on the above, otherwise communication is unlikely to be a success.


Pinouts on the Arduino Uno





Asynchronous communication


Unlike SPI (described here: http://www.gammon.com.au/forum/?id=10892) serial communications typically allows sending and receiving data independently of each other. This is achieved by having a Tx (transmit data) line at one end (eg. a PC) connected to the Rx (receive data) line on a peripheral. Conversely, the Rx line on the PC would be connected to the Tx line on the peripheral. You would need a third wire at least (the Ground wire), and in some cases additional wires are used to indicate if the peripheral is ready to receive data. Peripherals which used serial communications (such as printers) were common for many years.

It still is a useful way of sending data to small pieces of equipment (like LCD screens) using only a couple of wires, rather than having to have one wire for each bit of data. "Output-only" devices (like LCD screens) would not necessarily need to respond, and thus there would be no need to connect up the Rx line from them.

Arduino Leonardo


The recently-released Arduino Leonardo has a different approach to serial comms, as it connects directly via USB to the host computer, not via the serial port.

Because of this, you must wait for Serial to become "ready" (as the software establishes an USB connection), with an extra couple of lines, like this:


void setup() 
{ 
  Serial.begin(115200); 
  while (!Serial) 
     {}  // wait for Serial comms to become ready
  Serial.print("Fab"); 
} 

void loop ()
{
}


However if you want to actually communicate via pins D0 and D1 (rather than by the USB cable) then you need to use Serial1, rather than Serial, like this:


void setup() 
{ 
  Serial1.begin(115200); 
  Serial1.print("Fab"); 
} 

void loop ()
{
}


Voltage levels


Note that the Arduino uses TTL levels for serial communications. This means that it expects:


  • A "zero" bit is 0V
  • A "one" bit is +5V


Older serial equipment designed to plug into a PC's serial port probably uses RS232 voltage levels, namely:


  • A "zero" bit is +3 to +15 volts
  • A "one" bit is −3 to −15 volts


Not only is this "inverted" with respect to TTL levels (a "one" is more negative than a "zero"), the Arduino cannot handle negative voltages on its input pins (nor positive ones greater than 5V).

Thus you need an interface circuit for communicating with such devices. For input (to the Arduino) only, a simple transistor, diode, and a couple of resistors will do it:



For two-way communication you need to be able to generate negative voltages, so a more complex circuit is required. For example the MAX232 chip will do that, in conjunction with four 1 µF capacitors to act as charge-pump circuits.

- Nick Gammon

www.gammon.com.au, www.mushclient.com
Top

The dates and times for posts above are shown in Universal Co-ordinated Time (UTC).

To show them in your local time you can join the forum, and then set the 'time correction' field in your profile to the number of hours difference between your location and UTC time.


45,609 views.

Postings by administrators only.

Refresh page

Go to topic:           Search the forum


[Go to top] top

Information and images on this site are licensed under the Creative Commons Attribution 3.0 Australia License unless stated otherwise.