11. Serial Port Programming
11. Serial Port Programming
1
1. Basics of Serial Communication
• Data transfer between sender and receiver occurs in two ways: parallel and serial
• In parallel data transfer (shown below), many lines of wires (buses), eight or more
are used to transfer data between sender and receiver over a short distance
(inches)
D0
Sender Receiver
D7
• Although a lot of data can be transferred in short amount of time using many
wires in parallel, parallel transmission has the following disadvantages:
o Not applicable over long distances
o More expensive in terms of cables and connectors
o Cross-talk between lines at longer distances
2
• Serial communication (shown below) is used to transfer data between devices
separated by longer distances (metres away)
Sender Receiver
3
• Serial data communication uses two methods: synchronous and asynchronous
• The synchronous method (shown below) transfers a block of data (characters) at
the same time
• Synchronous communication happens when messages can only be exchanged in
real time
• It requires the transmitter and receiver to be present at the same time and/or
space
• Examples of synchronous communication are phone calls or video meetings
4
• Asynchronous communication happens when information can be exchanged
independent of time, allowing the recipient to respond to a message later, e.g., emails
Transmitter Receiver
Transmitter Receiver
Receiver Transmitter
5
• In full-duplex transmission, data is transmitted both ways at the same time
(requiring two wires) as shown below:
Transmitter Receiver
Receiver Transmitter
7
• In asynchronous serial communication, chips can be programmed for data that is
7 or 8 bits wide, in addition to 1 or 2 stop bits
• The parity (even or odd parity) is included in the data frame to maintain data
integrity
• In case of even parity, the number of 1’s in the data bits, including parity bit, is
even, while in odd parity, the number of 1’s is odd
• For example, the ASCII code for A (0100 0001) has 0 for even parity bit
5V
1 0 1 1 0
0V
Binary signalling
11
6V
10 10
4V
01
2V
00
0V
Multi-level signalling
9
2. ATmega328P USART
• The ATmega328P has one built in USART (universal synchronous-asynchronous
receiver-transmitter) for serial data communications
• The USART has the following features:
o Full Duplex Operation (Independent Serial Receive and Transmit Registers)
o Asynchronous or Synchronous Operation
o Master or Slave Clocked Synchronous Operation
o Baud Rate Generator
o Supports Serial Frames with 5, 6, 7, 8, or 9 Data Bits and 1 or 2 Stop Bits
o Odd or Even Parity Generation and Parity Check Supported by Hardware
o Data OverRun Detection
o Framing Error Detection
o Noise Filtering Includes False Start Bit Detection and Digital Low Pass Filter
o Three Separate Interrupts on TX Complete, TX Data Register Empty and RX Complete
o Multi-processor Communication Mode
o Double Speed Asynchronous Communication Mode
• The ATmega328P uses TXD (PD1) and RXD (PD0) for serial data transfer
• A block diagram of the USART is shown in the next page:
10
11
• The USART has three main parts: clock generator, transmitter and receiver
• Here, we consider the asynchronous mode only (UART)
• There are three groups of registers in the UART: 1) configuration (control)
registers, 2) transmit and receive registers, and 3) status register
• Configuration (control) registers: before using the UART, control registers must be
initialized – setting parameters like baud-rate, word-length, stop bit, interrupts (if
used)
• The configuration registers in ATmega328P are UBRR0, UCSR0A, UCSR0B and
UCSR0C
• Transmit and receive registers: to send data, the transmit register is written into
and the UART sends out the contents transmit register through the TXD pin
• The received data is stored in the receive register
• The transmit and receive registers are named UDR: UDR(transmit) and
UDR(receive)
12
• Status register: the status register (UCSR0A) contains flags which show the state
of sending and receiving data including: transmitter has sent out entire byte;
transmitter is ready for another byte; receiver has received entire byte; etc.
Mode Selection
• The UMSELn bit in USART Control and Status Register C (UCSRnC), shown below,
selects between asynchronous and synchronous operation as shown in the table
in the next slide
13
Baud-rate generation
• The ATmega328P sends and receives data serially at different baud-rates, i.e., the
transmitter unit has a clock input as well as the receiver unit as shown below:
14
• Some of the standard baud rates are shown in the table below:
15
• The baud-rate is programmable using the USART Baud Rate Registers shown below:
• For a given crystal oscillator frequency, the value loaded into UBRR0[H:L] decides the
baud-rate
• The value is 12 bits: 4 most significant bits contained by UBRR0H and 8 least
significant bits by UBRR0L
• The table in the next slide contains equations for calculating the baud rate (in bits per
second) and for calculating the UBRR0[H:L] value for each mode of operation
16
17
• The U2X0 bit is contained in the USART Control and Status Register 0 A (UCSR0A)
register
• This bit must be 0 for asynchronous normal mode
• Writing this bit to one will double the transfer rate for asynchronous communication
Example 1
With oscillator frequency of 16 MHz, find the UBRR value to have a baud rate of 9600 bps
𝐹𝑜𝑠𝑐 1000000
UBRR = 16 ×𝐵𝑎𝑢𝑑−𝑟𝑎𝑡𝑒
− 1 = 9600
−1 =103 (67𝐻)
18
Frame formats
• A frame (as shown below) is one character (ASCII code) data bits with
synchronisation bits (start and stop bits, and optionally a parity bit for error
checking
19
• The UART accepts a combination of the following:
o 1 start bit
o 5, 6, 7, 8, 9 data bits
o No parity, even or odd parity
o 1 or 2 stop bits
• The frame format is set by the UCSZ02:0, UPM01:0 and USBS0 bits in the UCSR0B
and UCSR0C registers shown below:
20
• The character size in bits is selected using the USART Character Size (UCSZ) bits in
the UCSR0B and UCSR0C registers as follows:
21
• The parity mode is selected using the USART Parity Mode (UPM) bits in UCSR0C
register as follows:
• The UPM01:0 bits enable and set type of parity generation and check
• If enabled, the transmitter will automatically generate and send the parity of the
transmitted data bits within each frame
• The Receiver will generate a parity value for the incoming data and compare it to
the UPM0 setting
• If a mismatch is detected, the UPE0 Flag in UCSR0A will be set
• Note that by default, the parity mode is disabled
22
• The number of stop bits is selected using the USART Stop Bit Select (USBS) bit in
the UCSR0C register as follows:
23
Data transmission – the UART transmitter
• The Transmit Shift Register has a buffer called the Transmit Data Buffer Register
as shown below:
24
• The Transmit Data Buffer Register makes use of the USART I/O Data Register
(UDR0) (shares it with Receive Data Buffer Register), shown below:
• Data to be transmitted is written into the UDR0 register, and it will be transferred
to the Transmit Data Buffer Register (TXB)
• For 5-, 6-, or 7-bit characters, the upper unused bits will be ignored by the
Transmitter
• The transmit buffer can only be written into when the USART Data Register Empty
(UDRE0) flag in the UCSR0A Register is set (indicating that the buffer is empty,
and, therefore, ready to be written into)
25
• The UCSR0A register is shown below:
• Data written to UDR0 when the UDRE0 flag is not set will be ignored by the
USART Transmitter
• Data written to the transmit buffer, when the transmitter is enabled, will be
loaded into the Transmit Shift Register (when it is empty) and serially transmitted
on the TxD pin
26
Steps to program the ATmega328P to transmit data serially
1. The UCSR0B Register is loaded with the value 08H to enable the USART
Transmitter, setting the Transmit Enable (TXEN0) bit - the normal port operation
of the TxDn pin is overridden by the transmitter
2. The UCSR0C register is loaded with value 06H, indicating asynchronous mode,
8-bit data frame, no parity and one stop bit
3. The UBRR0 register is loaded with a value to set the baud-rate for serial
transmission
4. The UDRE0 bit of the UCSR0A register is monitored (polling method) to make
sure UDR0 is ready for the next byte
5. The character byte (ASCII code) to be transmitted is written into the UDR0
register
6. Step 4 is repeated to transmit the next character
27
Example 2
Write a program for the ATmega328P to transfer letter ‘G’ serially at 9600 baud,
continuously. Use 8-bit data and 1 stop bit. Assume XTAL = 16 MHz.
Solution
#include <avr/io.h>
int main()
{
UCSR0B = (1 << TXEN0); //enable transmitter
UCSR0C = (1 << UCSZ01) | (1 << UCSZ00); //select character size 8
UBRR0L = 103; //generate baud-rate
while(1)
{
while( ! (UCSR0A & (1 << UDRE0))); wait until UDR0 is empty - polling
UDR0 = ‘G’; //transmit character
}
return 0;
}
28
Example 3
Write a program for the ATmega328P to send a message “The Earth is but One Country”. Use 9600 baud, 8-bit data and 1 stop bit.
Assume XTAL = 16 MHz.
Solution
#include <avr/io.h>
int main()
{
unsigned char str[30] = “The earth is but one country”;
unsigned char i = 0;
UCSR0B = (1 << TXEN0); //enable transmitter
UCSR0C = (1 << UCSZ01) | (1 << UCSZ00); //select character size 8
UBRR0L = 103; //generate baud-rate
while(1)
{
while( ! (UCSR0A & (1 << UDRE0))); wait until UDR0 is empty - polling
if (str[i] != ‘\0’) //transmit characters before null character
UDR0 = str[i++];
else
i = 0;
}
return 0;
}
29
Exercise 1
Write a program for the ATmega328P to send an integer number 2897. Use 9600
baud, 8-bit data and 1 stop bit. Assume XTAL = 16 MHz.
Exercise 2
Write a program for the ATmega328P to send a floating-point number 197.895. Use
9600 baud, 8-bit data and 1 stop bit. Assume XTAL = 16 MHz.
30
Steps to program the ATmega328P to receive data serially
1. The UCSR0B register is loaded with 10H to enable the USART receiver, setting
the Receive Enable (RXEN0) bit – the normal port operation of RxD pin is
overridden by the receiver
2. The UCSR0C register is loaded with value 06H, indicating asynchronous mode,
8-bit data frame, no parity and one stop bit
3. The UBRR0 register is loaded with a value to set the baud-rate for serial
transmission
4. The USART Receive Complete (RXC0) flag bit of the UCSR0A register is
monitored for a HIGH to see if a byte has been received in the receive buffer
5. When RXC0 is raised, the UDR0 has the byte, and its contents are read
6. Step 4 is repeated to receive the next byte
31
Example 4
Write a program for the ATmega328P to receive bytes of data serially and put them
on PORTB. Set the baud rate at 9600, 8-bit data and 1 stop-bit.
Solution
#include <avr/io.h>
int main()
{
DDRB = 0xFF;
UCSR0B = (1 << RXEN0); //enable receiver
UCSR0C = (1 << UCSZ01) | (1 << UCSZ00); //select character size 8
UBRR0L = 103; //generate baud-rate
while(1)
{
while( ! (UCSR0A & (1 << RXC0))); wait until character is received - polling
PORTB = UDR0; //read character
}
return 0;
}
32
Exercise 3
Write a program for the user to manually enter a byte at a terminal and the
ATmega328P to display the byte on PORTB
33
Exercise 4
Write a program with the following parts: (a) the ATmega328P sends a message
“YES” once to the PC screen, (b) the ATmgea328P gets data from the switches and
sends it to the PC’s screen and (c) the ATmega328P receives any key press sent by
the terminal program and puts it on LEDs.
Steps:
1. Enable both transmitter and receiver by UCSR0B = (1 << TXEN0) | (1 << RXEN0);
2. Select 8-bit data, no parity, 1 stop bit
3. Use 9600 baud rate
4. Transmit once one character after another of “YES” - send after UDRE0 is set
5. Read PORTB into UDR0 to send; wait until UDRE0 flag is set (data transmitted);
when UDRE0 is set, proceed to Step 6
6. Check if RXC0 flag is set to see if there is data received from the PC; if there is
data received, read it to PORTC and repeat Step 5; if there is no data received,
repeat this step (Step 6)
34
Interrupt-based data transmit
• To transmit data using the interrupt method, set HIGH the USART Data Register
Empty Interrupt Enable (UDRIE0) bit in UCSR0B
• Setting this bit enables the interrupt when the UDRE0 flag is set (indicating ready
to accept new data)
• When UDRE0 flag is set, the CPU will jump to the USART Data Register Empty
(USART_UDRE_vect) interrupt vector
• To transmit data serially, another source of interrupt is the Transmit Complete
Interrupt, which uses the USART Transmit Complete (USART_TX_vect) interrupt
vector
35
• When RXC0 flag is set, the CPU will jump to the USART Receive Complete
(USART_RX_vect) interrupt vector
Example 5
Write a program for the ATmega328P to transfer letter ‘G’ serially at 9600 baud,
continuously. Use 8-bit data and 1 stop bit. Assume XTAL = 16 MHz. Use the
interrupts method.
36
Solution
#include <avr/io.h>
#include <avr/interrupt.h>
int main()
{
UCSR0B = (1 << TXEN0) | (1 << UDRIE0); //enable transmitter and data register empty interrupt
UCSR0C = (1 << UCSZ01) | (1 << UCSZ00); //select character size 8
UBRR0L = 103; //generate baud-rate
sei(); //enable interrupts
while(1) ; wait forever
return 0;
}
ISR ( USART_UDRE_vect )
{
UDR0 = ‘G’; //transmit character
}
37
Example 6
Write a program for the ATmega328P to receive bytes of data serially and put them
on PORTB. Set the baud rate at 9600, 8-bit data and 1 stop-bit. Use interrupts
Solution
#include <avr/io.h>
#include <avr/interrupt.h>
int main()
{
DDRB = 0xFF;
UCSR0B = (1 << RXEN0) | (1 << RXCIE0); //enable receiver and receive complete interrupt
UCSR0C = (1 << UCSZ01) | (1 << UCSZ00); //select character size 8
UBRR0L = 103; //generate baud-rate
sei(); //enable interrupts
while(1); // wait forever
return 0;
}
ISR ( USART_RX_vect)
{
PORTB = UDR0; //read character
}
38