Asynchronous Serial Communication Port of ATmega328 Microcontroller

7.1 Introduction to UART Terminologies

The ATmega328 Microcontroller has a ‘Communication Port’ known as Universal Synchronous Asynchronous Receiver Transmitter (USART), which is used to exchange data with Personal Computer (PC) and other Microcontroller (MCU). The port operates in two modes: synchronous and asynchronous. In this book, we will deal with the studies of the asynchronous part of the USART port; hence, we will address it as an asynchronous receiver transmitter (UART) port. It is an asynchronous port; because, there is no timing relationship between the transmitter and receiver on data transmit/receive issue; it is a serial port; because, data transfer takes place bit-by-bit and one-after-another. It is a universal port; because of what?

(1) Serial Communication Protocol: Protocol refers to a set of rules which two or more parties have agreed to follow for a certain period of time. Serial Communication Protocol is a set of rules that regulate the definitions of various operational parameters of the serial data communication system. For example: It is a protocol that the data transmit/receive between ATmega328 and PC will occur on Asynchronous Serial Mode at 4800 Bd, 10-bit Frame Length, No-parity, and 1-Stop Bit.

(2) Asynchronous Serial Mode (AS): This mode defines that:
(a) There would be absolutely no timing relationship (means asynchronous) between the transmitter
and receiver as to who is transmitting (receiving) at what times.

(b) The basic data item is the 8-bit code for an ASCII character which could be a member of the English Language alphabet (A – Z, a – z, 0 – 9, and Punctuation Marks) or Non-printable Control Characters.

(c) The data transmission/reception will happen bit-by-bit with LS-bit first (Fig-7.2).

(d) At idle state (no transmission mode), the transmission line (TX Line) will remain at LH-state (Fig-7.2).

(e) At the beginning of data transmission, TX line will drop to LL-state for 1-bit period to alert the receiver (RX Line) for accepting the forth coming data bits (Fig-7.2).

(f) After the transmission of 8-bit data (the ASCII code), the TX line is pulled up to LH-state (Fig-7.2) for 1-bit period indicating the end-of-transmission. If parity bit is added, the receiver will be collecting 9-data bits instead of 8.

(3) Baud Rate (Bd): In communication theory, Baud Rate (Bd) refers to quantitative measure of information being transmitted/received by a carrier. A carrier is said to be conveying information when the modulating signal (the information) brings changes in its amplitude, frequency or phase. Every change in the carrier is an information bit (the baud). In asynchronous serial communication, there is no carrier. The bits being carried out over the TX-line are all information bits. So, the Baud Rate is equal to the Bit Rate.

There are cases where Baud Rate is different from Bit rate. For example: The Bell 212A type modem uses 1200 Hz sine wave carrier for transmission. It uses the so called ‘dibit encoding’, where ‘2 consecutive bits’ in the data stream is treated together. In this scheme, the value of these two bits determines the amount of phase shift to be occurred in the carrier. The relationship is:

dibit value phase shift
00 00
01 900
11 1800
10 2700

Now, assume that the bit pattern 00 11 01 01 11 01 would be transmitted using the dibit encoding scheme. The relationship between the values of the dibits and the phase shifts of the carrier is depicted below in Fig-7.1. The value of the 1st dibit is 00, so there is no phase shift of the carrier. The value of the 2nd dibit is 11, so the phase shift of the carrier is 1800 and it has occurred at the elapse of 1800 from point B. In a similar way, we have indicated the phase shift points for the remaining dibits of the data stream.

Figure-7.1: Waveforms for simple phase-shift modulation

Now, we are in a position to explain the difference between the Bit Rate and the Baud Rate. At 1200 Hz carrier frequency, one cycle period is required for the shifting of 1-bit data into the phase-shift keying modulator. In the example of Fig-7.1, we have 12-bit data; we need 12 clock cycles to shift them into the modulator. So, the Bit Rate: 1200 bits/sec.

Now, let us look at the carrier; we observe that there are only 6 changes in the carrier. The 12-bit data have brought only 6 changes in phases of the carrier. The information content is 6 Baud. The Baud Rate is half of the Bit Rate and it is: 600 Bd.

(4) Graphical Representation of the Asynchronous Data Frame (TTL Logic)

Figure-7.2: Waveforms for asynchronous data frame for character A (TTL Logic)

(a) Assume Bd = 4800; Even-parity (number of 1s in the data field is even).
(b) Frame Length : 11 (1-Start Bit, 8-Data bit, 1-parity bit, and 1-Stop bit)
(c) Bit Rate = Baud Rate = 4800. Bit Period = 1/4800 = 208 µs.

(5) Graphical Representation of the Asynchronous Data Frame (RS232 Logic)
The raw TTL signal of Fig-7.2 can travel over 10ft to 15ft without much appreciable distortion and after that it becomes heavily distorted. The receiver fails to detect the incoming signal and the information is lost. In an effort to allow the serial data traveling over a distance of 100ft or more without any modulation or amplification and without suffering appreciable distortion, the Electronic Industries Association introduced the RS232 scheme in 1960. In this scheme, TTL signal is transformed into RS232 logic (Fig-7.3) and vice versa with suitable logic converters like MAX232. The TTL Logic and its counterpart RS232 Logic states are shown below:

TTL Logic RS232 Logic
LL = 0V LL = 3V to 10V (under loading)
LH = 5V LH = -3V to -10V (under loading)

Figure-7.3: Asynchronous serial data format in TTL  RS232

L71.doc (832 KB)

7.2 Conceptual View of the Hardware Structure of the Asynchronous Serial Port

The Arduino IDE provides as many as 10 high level instructions/functions to support data exchange activities of the UART port of the ATmega328 Microcontroller. At design time, the functional behaviors of these functions have been determined looking at the actual hardware of the UART port. Unfortunately, the structures of these functions are of so high level abstractions that they do not convey much information as to their relationships with the hardware. For example: the if(serial) function checks if the UART port is available or not for data communication. It is difficult to understand from the name of the function as to which resource of the UART port is being tested to take the decision. We have depicted below (Fig-7.4) a conceptual view of a typical UART port, which might help the readers to understand the functionalities of the Arduino IDE functions in a better way.

Figure-7.4: Conceptual view of the hardware structure of the asynchronous serial port

(1) By default, Pin-3 of the ATmega328 works as a digital IO line under the name PD1. As we can see in Fig-7.4, the same IO line is changed to work as an ‘Asynchronous Serial Data Transmission Line, TXD Line’ by closing the switch S7 and opening the switch S9. The new name of the line is TXD Line, and the direction of this line is always outgoing. Similarly, the PD0 line is configurable to work as ‘Asynchronous Serial Data Reception Line, RXD Line’ by closing switch S8 and opening switch S10. In the programming section of the UART port, we will see the mechanism of opening/closing of these switches using instructions.

(2) Transmission Section
(a) Tx Register (M1): This is a write only UDR0-register of the ATmega328. When the user mind wants to transmit a character (say, A) to a remote computer, he executes the pseudo code 0x41 ----> UDR0. In response, the MCU writes the data 0x41 (the ASCII code of A) in parallel format (0100 0001) into the UDR0-register (Tx Register). The module M1 accepts this parallel data and converts into serial format and then passes to module M2 with LS-bit first. Once the Tx Register module M1 has finished transmitting data to the next module, it generates the 'Tx Register Empty' signal (the software name is UDRE0). The user program can poll this signal or being interrupted by this signal in order to write the next data byte into the Tx-register.

(b) Frame Formatter (M2): It is a programmable module; its functionalities can be changed using software instructions. The module creates a serial data frame. In a typical example, it makes a frame by putting 1-startbit (LL), then 8-databit, then 1-paritybit (optional), and then 1-stopbit (LH). Identical time slots (bit-period) are allocated for every bit of the frame. The frame length refers to the number of bits in the data frame including the startbit and stopbit. The graphical representation of the asynchronous data frame in TTL logic (ASTTL) for character A has been depicted in Fig-7.2.

(c) Transmitter (M3): This is the module which provides necessary current to drive the transmission cable with the bit streams of the data frame. When all the data bits of the frame have actually been shifted out from the Transmitter, the 'TX Complete (TXC0)' is generated. The user program may poll this signal/bit or being interrupted by this signal for writing next data byte into the TX-register.

(3) Reception Section
(a) Receiver (M6): This module performs necessary signal amplification on the incoming digital data by boosting the logic levels up to TTL if needed. It also performs (optional) some digital filtering to reduce noise level form the incoming data, which helps better signal detection.

(b) Frame Conditioner (M5): This module strips out start, stop, and parity (optional) bits from the incoming data frame. It also performs necessary error checking, and then it passes the valid data to the Rx Register.

(c) Rx Register (M4): This is a read only UDR0-register of the ATmega328. It converts the received serial data into parallel format and makes it ready for the MCU. It also creates the 'Rx Complete (RXC0)' signal. The MCU can poll this signal or being interrupted by this signal in order to read the incoming data byte from the Rx-register.

L72x.doc (51 KB)

7.3 IO Registers involved in the Operation of UART Port

The following IO registers play important role in the initialization, operation, and maintenance of the UART port of the ATmega328 MCU. We will see the applications of the various bits of these registers in the data read/write procedures described elsewhere in this chapter. In the following write-up, we have described only those bits which are primarily used for the initialization and operation of the UART port; the readers are referred to Atmel data sheets for the definitions of the remaining bits. The readers will notice, in the description of the registers' bit, that many lines have been copied from Atmel data sheets, which the author acknowledges.

(1) USDR0: USART IO Data Register 0

The USDR0 is the software name (at assembly and assignment levels) for the Tx- and Rx-registers of the UART port of the ATmega328 MCU.

Referring to Tx-register, it is a write-only register; execution of the instructions: ldi r16, 0x42; out USDR0, r6 (in Arduino it is Serial.write(0x41) writes 8-bit into the Tx-register for onward transmission.

Referring to Rx-register, it is a read-only register; execution of the instructions: in r16, UDR0 (in Arduino it is int x= Serial.read()) reads 8-bit data from the Rx-register which it has just received from the host computer.

(2) UCSRA0A: USART Control and Status Register 0 A

(a) RXC0 (Receive Complete): This is a status bit and also a flag bit; it assumes LH-state when the Rx-register (Fig-7.4) contains a valid data item which is ready for the MCU to read. As a status bit, the RXC0-bit could be polled by the MCU to check if the Rx-register holds valid data; if so, the MCU can read the data item. As a flag bit, the RXC0-bit can interrupt the MCU for vectoring at location 0024h provided that the switches S1 and S2 (Fig-7.4) were kept at closed conditions during initialization.

The RXC0 is a read-only bit; it cannot be reset (to bring 0 inside it) by writing LH at this bit like TOV1 bit of TC1. If the Receiver is disabled, the receive buffer will be flushed and consequently the RXC0 bit will become zero.

The RXC0 bit will automatically become zero (reset) when this bit is allowed to interrupt the MCU, and the MCU vectors at the interrupt sub routine.

(b) TXC0 (Transmit Complete): This is a status bit and also a flag bit; it assumes LH-state when the final Transmitter (M3 of Fig-7.4) finishes shifting out all the bits of the data frame. As a status bit, the TXC0-bit could be polled by the MCU to take decision as to writing new data byte into the Tx-register (the write-only UDR0-register). The user can reset this bit by writing LH at this bit executing the instruction bitSet(UCSR0A, 6).

As a flag bit, the TXC0-bit can interrupt the MCU for vectoring at location 0028h provided that the switches S5 and S6 (Fig-7.4) were kept at closed conditions during initialization. The TXC0 bit will automatically become zero (reset) when this bit is allowed to interrupt the MCU, and the MCU vectors at the interrupt sub routine.

(3) UCSRA0B: USART Control and Status Register 0 B

(a) RXCIE0 (Receive Complete Interrupt Enable 0): This bit, when written LH, closes switch S5 (Fig-7.4); as a result, the Rx Register can interrupt the MCU to read the data item that it has just received. We have assumed that the switch S6 is at closed condition (S6 becomes closed when LH is written at bit-7 of SREG-register.) When there are many simultaneous sources of interrupts in the ATmega328 system, the user can isolate only the Rx-register from the interrupt chain by writing LL at the RXCIE0-bit of the UCSRA0-register.

(b) TXCIE0 (Transmit Complete Interrupt Enable 0): This bit, when written LH, closes switch S3 (Fig-7.4); as a result, the Transmitter can interrupt the MCU to write data item into the Tx-register. We have assumed that the switch S4 is at closed condition (S4 becomes closed when LH is written at bit-7 of SREG-register.) When there are many simultaneous sources of interrupts in the ATmega328 system, the user can isolate only the Transmitter from the interrupt chain by writing LL at the TXCIE0-bit of the UCSRA0-register.

(c) RXEN0 (Receiver Enable 0): In Fig-7.4, we notice that Pin-2 of the MCU has two possible functions: Digital IO line and RXD Line. In UART application, the Pin-2 must be configured as a RXD line, and it is done by writing LH at the RXEN0 bit of the UCSR0B register. When LL is written to disable the receiver, three things happen: the RXC0-bit becomes zero, and the receive buffer is flushed out.

(d) TXEN0 (Transmitter Enable 0): In Fig-7.4, we notice that Pin-3 of the MCU has two possible functions: Digital IO line and TXD Line. In UART application, the Pin-3 must be configured as a TXD line, and it is done by writing LH at the TXEN0 bit of the UCSR0B register. When LL is written to disable the transmitter, the disabling will come into action once the ongoing and pending transmissions are completed.

(e) UCSZ02 (Frame Character Size 0; bit2): The UCSZ02 bit combined with the UCSZ0[1:0] bit in UCSR0C sets the number of data bits (Character Size) in a frame the Receiver and Transmitter use.

(4) UCSRA0C: USART Status and Control Register 0 C

(a) UMSEL[1:0] (USART Mode Select 0): These two bits, when written to 00, select the asynchronous mode operation of USART port of the ATmega328.

(b) UPM[:0](USART Parity Mode 0): These two bits, when written to 00, insert no parity bit in the data frame; when written to 10, they select even parity bit in the data frame; when written to 11, they select odd parity bit in the data frame.

(c) USBS0 (USART Stop Bit Select 0): This bit, when written to 0, inserts 1-stop bit in the data frame; when written to 1, it inserts 2-stopbit in the data frame.

(d) UCSZ01[1:0] (UDORD0: USART Character Size: These two bits being combined with UCSZ02 bit of UCSRA0B-register set the number of data bits (Character Size) in a frame the Receiver and Transmitter use. These two bits and UCSZ02-bit of UCSR0B-register, when written to 010, set the data bits to 7; when written to 011; they set the data bits to 8.

(5) UBRR0L: USART Baud Rate Register 0 Low

The 8-bit of this register being combined with the lower 4-bit of the UBBR0H-register, select the baud rate (Bd) of the UART port. In asynchronous mode of operation, the Bd is same as the bit rate of data transmission. It is due to the fact that there is no carrier in the asynchronous mode, and all the bits in the data frame are the information bits.

The Bd is calculated, as per data sheets of Atmel, using the following formula:

Buad Rate (Bd) = clkSYS/16(UBBRn + 1); where UBBRn = <UBRR0H, UBBR0L = 12-bit>

(6) UBBR0H: USART Baud Rate Register 0 High

The lower 4-bit of this register being combined with the 8-bit of the UBBR0L-register, select the baud rate (Bd) of the UART port. The Bd is calculated, as per data sheets of Atmel, using the following formula:

Buad Rate (Bd) = clkSYS/(16(UBBRn + 1); where UBBRn = <UBRR0H, UBBR0L = 12-bit>

For example: You want to operate the UART port at 4800 Bd; then you need to load the following data into UBBR0H and UBBR0L resisters respectfully.
(a) 00h into UBBR0H
(b) CFh into UBBR0L
(c) Calculation: clkSYS = 16 MHz
UBBRn + 1 = 1000 000 /4800 = 208
===> UBBRn = 208 - 1 = 207 = 00CFh // n stnads for 0H and 0L
(d) At 4800 Baud Rate, the error is only 0.2%. [Table 24-7 of ATmel data sheets, P243)

L73.doc (97 KB)

7.4 Data Communication between UART Port of Arduino UNO and PC

Figure-7.5: Conceptual link between real UART port of ATmega328 and virtual UART port of PC

When we say ‘UART Port of Arduino UNO’, we want to mean that this is the UART Port of the ATmega328 Microcontroller which the Arduino UNO Learning Kit contains. The ATmega328 contains a real UART port which means that the port exits physically in respect of its hardware electronics. On the other hand, the UART port of the PC is a virtual port (U31, Fig-7.5 upper), which means that the hardware electronics of the port does not exist physically. The UART port is automatically created when we connect the Arduino Kit in a USB port of the PC (the PC must have the Arduino IDE Interface installed). The virtual UART port at the PC comes after the name COMX (X = 1, 2, 3, …). The older PCs were equipped with physical UART Ports, and they were known as COM0/COM1 Ports. With the advent of new PCs and USB ports, those hardware UART ports had been removed; but, provision were kept to generate them using software as writing programs for UART port is much simpler compare to writing program for USB ports.

(1) Let us make the following Setup.
(a) Connect the Arduino UNO Kit with the PC using a USB port. Open the IDE Interface and check that (Tools  Port  COMX  Click) the virtual COMX port is allocated at the PC side to establish communication with the Arduino UNO.

(b) In the Arduino IDE perform: Tools  Serial Monitor  Click. Observe that the following window has appeared on the Desktop of the PC. This window is known as ‘Serial Monitor’. It is an ASCII-type display unit, and is very similar to the LCD panel that we have connected with the Arduino. This Serial Monitor can receive and display data/messages that will be sent from the Arduino; it can also take commands (in the form of ASCII characters) from the PC and send them to the Arduino using the virtual UART Port.

Figure-7.6: Snapshot of Serial Monitor at the PC side

(c) Connect an LCD panel with the Arduino as per diagram of Fig-7.5. In this ASCII display, we will show all the data/messages that will come from the PC.

(d) Connect the switch K1 at DPin-8 (PB0-pin of ATmega328) of the Arduino UNO.

(3) Conditions to be satisfied to exchange data between Arduino and PC using UART Port
(a) At the Arduino side, we need a program to acquire data from the user, and then send them to the PC. We have a switch (K1) connected at DPin-8 by which user can give command/data to the MCU.

(b) At the Arduino side, we need a program to receive data from the PC, and show them on the LCAD Pane.

(c) The Arduino should be connected with the PC using a USB Port.

(d) At the APC side, we need a program to acquire data from the Arduino and show them on the Serial Monitor. This program is automatically invoked when the Serial Monitor option is activated from the Arduino IDE Interface.

(e) At the PC side, we need a program to acquire data from user via keyboard of the PC, and then send them to the Arduino. This program is automatically invoked when the Serial Monitor option is activated from the Arduino IDE Interface

L74.pdf (173 KB)

7.5 Pseudo Codes for Data Exchange between Arduino UART and PC under the Setup of Fig-7.5/Fig-7.6 (Polling Method)

The Polling Method of data exchange between Arduino and PC consists of the following events:
(1) The initialization is done in terms of Baud Rate, Frame Length, non-Interrupts.

(2) At power up reset, the TX Register (write-only UDR0 Register) becomes ready to accept data byte from user; it means that the TX Empty signal is at LH-state. When the user writes a data byte into the TX Register, the TX Empty signal (UDRE0 bit of UCSR0A) assumes LL-state. It becomes HIGH when the TX Register finishes shifting all data bytes into the next module (M2, Fig-7.4). The user program checks again and again (this is known as polling) if the TX Empty signal has assumed LH-state so that he can write the next data byte into the TX Register. The TX Empty signal can be employed to interrupt the MCU (Fig-7.4) by enabling the associated interrupt logic.

The user can also write data byte into the TX Register by polling the TX Complete signal (TXC0 bit of UCSR0A Register). At power up, the TX Complete signal is at LL-state (not ready state). If we want to write data into TX Register by polling the TX Complete signal, a LH signal is to be written in this bit first. When the user writes a data byte into the TX Register, the TX Complete signal (TXC0 bit of UCSR0A) assumes LL-state. It becomes HIGH when the Transmitter (M3 of Fig-7.4) has finished shifting out all the data bits and there is no new data byte present in the TX Register. The user program checks again and again (this is known as polling) if the TX Complete signal has assumed LH-state so that he can write the next data byte into the TX Register. The TX Complete signal can be employed to interrupt the MCU (Fig-7.4) by enabling the associated interrupt logic.

(3) When the RX Register contains a valid data byte that has arrived from the PC, the RX Complete (RXC0 bit of UCSR0A Register) assumes LH state. The user program checks again and again (this is known as polling) if the RX Complete signal has assumed LH-state so that he can read the data byte from the RX Register (read-only UDR0 Register). The RX Complete signal (RXC0 bit) assumes LL-state (reset) when the user program reads data from the RX Register. The RX Complete signal can be employed to interrupt the MCU (Fig-7.4) by enabling the associated interrupt logic.

(4) The Pseudo Codes:

//--------- Initialization Tasks/Codes for Arduino UART Port ---------------------------------------------

L11: //changing PD1 Port Line (Fig-7.4) to work as TXD Line. Open S3 and Close S1 (Fig-7.4). This is done by:
 LH ----> TXEN0 bit of UCSRA0B (bit-3)

L12: //changing PD0 Port Line (Fig-7.4) to work as RXD Line. Open S4 and Close S2 (Fig-7.4). This is done by:
 LH ----> TXEN0 bit of UCSRA0B (bit-4)

L13: //select asynchronous mode of operation for UART port. This is done by:
 00 ----> UMSEL[1:0] of UCSRA0C (bit – 7, 6)
L14: //select operating speed of the Port (the Baud Rate = Bit Rate = clkSYS / 16(UBBRn + 1)) to 4800.
// This done by solving: 4800 = 16 MHz/((16(Contents of UBBR0H, UBBR0L) + 1). The solution says that we have //to do the following::
 0x00 ----> UBBROH
 0xCF ----> UBBR0L

L15: //select Frame Length at 10: 1-statrtbit + 8-databits + No-paritybit + 1-stoppbit. This is done by:
 0 ----> UCSZ02 bit of UCSR0B (bit-2) 
 11 ----> UCSZ0[1:0] of UCSR0C (bit-2, 1)

//---------- Initialization Tasks/Codes for the Virtual UART Port/Serial Monitor at PC Side----------
The port is automatically initialized when the Serial Monitor option is invoked from the Arduino IDE Interface (Tools ---->Serial Monitor ----> Click). The Serial Monitor is an interactive window which provides the facilities to configure the Baud Rate of the Virtual UART Port, acquiring data from the keyboard, and then send them to the Arduino.

//--- Codes to transmit A from Arduino to PC by Polling the URDE0 bit (TX Register Empty) ----

L16: //By Polling UDRE0 flag (Transmit Data Register is empty. At power up, it is ready.)
 AGNCK: if (UDRE0 != LH)        //bit-5 of UCSR0A
                     Goto AGNCK
L17: Write character A into Tx Register via write-only UDRE0 register.

//--------- Codes to transmit Z from Arduino to PC by Polling the TXC0 bit (TX Complete) ---------
At reset, the TXC0 bit contains LL-state. Let us first make it to contain LH by writing 

L18: // putting LH into TXC0 bit (bit-6 of UCSR0A)
 LH ---->TXC0 (bit-5 of UCSRA0A)

L19: //now poll the TCX0 biy for LH
 AGNCK1: if (TXC0 != LH)
 Goto AGNCK1

L20: Write character Z into Tx Register via write-only UDRE0 register.

//---- Codes to receive an ASCII character by Arduino from PC by polling RXC0 bit (RX Ready)--
L01: AGNCHK2: if (RXC0 != HIGH)     //bit-7 of UCSR0A
 Goto AGNCHK2
L22: Read data from Rx Register and save in a variable
L23: Show the character on LCD

L75.doc (45.5 KB)

7.6 Standard C++ Codes for Data Exchange between Arduino UART and PC under the Setup of Fig-7.5/Fig-7.6 (Polling Method)

#include <LiquidCrystal.h>
//LiquidCrystal lcd(RS, E, D4, D5, D6, D7);   //declaration of LCD wiring function
LiquidCrystal lcd (5, A0, A1, A2, A3, A4);      //definition of LCD wiring function

void setup()
{
  lcd.begin(16, 2);       // 16x2 LCD ; 2-line; each line has 
  lcd.setCursor(1, 0);     // Cursor at DP1 position of Top Line
  //---- start of intialisation of ARduino UART-------
  bitSet(UCSR0B, 3);       //L11 of Section-7.5 ; Transmitter Enable
  bitSet(UCSR0B, 4);       //L12 of section-7.5; Receiver Enable

  bitClear(UCSR0C, 7);     //L13 of Section-7.5  ; Asynchronous Mode
  bitClear(UCSR0C, 6);     //L13  of Section-7.5;  "

  UBRR0H = 0x00;           //L14  of Section-7.5; Baud Rate 4800
  UBRR0L = 0xCF;           //L14 of Section-7.5 ; Baud Rate 4800

  bitWrite(UCSR0B, 2, 0);   //L15  of Section-7.5; Data size 8
  bitWrite(UCSR0C, 2, 1);   //L15  of Section-7.5; Data size 8
  bitWrite(UCSR0C, 1, 1);   //L15  of Section-7.5; Data size 8 
  //--------end of initialization -------------------------

  //--send A by polling UDRE0 bit (Tx Register Ready) of UCSR0A register------
  while (bitRead(UCSR0A, 5) != HIGH)   //L16 of Section-7.5
    ;
  UDR0 = 0x41;                       //L17 of Section-7.5  ; send ASCII of A
  
  while (bitRead(UCSR0A, 5) != HIGH)   //
    ;
  UDR0 = 0x0D;                       // Carriage Retuen code
  
  while (bitRead(UCSR0A, 5) != HIGH)   //
    ;  
  UDR0 = 0x0A;                   // Line Feed code
  
  //--send Z by polling TXC0 bit (Tx Complete) of UCSR0A register------
  bitSet(UCSR0A, 6);                   //L18 of section-7.5 putting LH at TXC0 bit
  while (bitRead(UCSR0A, 6) != HIGH)   //L19 of Section-7.5
    ;
  UDR0 = 'Z';                       //L20 of Section-7.5 ; send ASCII 
  character Z
  
  while (bitRead(UCSR0A, 5) != HIGH) //
    ;
  UDR0 = 0x0D;                     // Carriage Return code
  
  while (bitRead(UCSR0A, 5) != HIGH)  //
    ;  
  UDR0 = 0x0A;                     //Line Feed code 
  //--receive Q from PC by polling RXC0 bit (Rx Ready signal)---------------
  while (bitRead(UCSR0A, 7) != HIGH) //L20 of Section-7.5
     ;
  byte x = UDR0;                     //L21 reading 8-bit data from PC  
  lcd.write(x);                     //L22 of Section-7.5
}

void loop()
{
      
}

(a) Let us create the above program in the Arduino IDE and save it as P76.

(b) Compile and upload P76 program.

(c) At the PC side, open the Serial Monitor of Fig-7.6 (Tools  Serial Monitor  Click).

(d) Press the RST button of the Arduino Kit.

(e) Check that the characters A and Z have appeared on the Serial Monitor.

(f) In the input box of the Serial Monitor, type the character Q; press the Send button; observe that the character has appeared on the LCD attached with the Arduino.

L76.doc (42.5 KB)

7.7 Standard C++ Codes for Data Exchange between Arduino UART and PC under the Setup of Fig-7.5/Fig-7.6 (Interrupt Method)

(1) Data Receive on Interrupt
When valid data is present in RX Register (read-only UDR0 Register), the RX Complete signal (RCX0) becomes HIGH. This RX Complete signal will interrupt the MCU if the switches S5 and S6 (Fig-7.4) are in closed conditions. As a result, the MCU vectors at location 0x0024; automatically clears the RXC0 bit; reads the data byte from RX Register; returns to Main Line Program from ISR(USART_RX_vect) subroutine.

(2) Data Transmit on Interrupt
The scheme of data transmit on interrupt is chosen when the MCU has a Main Line Program that demands considerable amount of processing time from the MCU. It is also true that there is a large amount of data to be transmitted when the time of transmission comes. Transmit of one byte or two or at best a series of characters are usually done by polling.

The TX Empty (UDRE0 Bit) signal will interrupt the MCU if the switches S1 and S2 are kept in close conditions. As a result, the MCU vectors at location 0x0026; automatically clears the UDRE0 bit; transmits the character; returns to MLP from ISR(USART_UDRE_vect) subroutine.

The TX Complete (TXC0 bit) signal will interrupt the MCU if the switches S3 and S4 are kept in close conditions. As a result, the MCU vectors at location 0x0028; automatically clears the TXC0 bit; transmits the character; returns to MLP from ISR(USART_TX_vect) subroutine.

(3) The Standard C++ Codes

//UART Operaton on Interrupt 
#include <LiquidCrystal.h>
//LiquidCrystal lcd(RS, E, D4, D5, D6, D7);   //declaration of LCD wiring function
LiquidCrystal lcd (5, A0, A1, A2, A3, A4);      //definition of LCD wiring function

void setup()
{
  lcd.begin(16, 2);       //16x2 LCD ; 2-line; each line has 
  lcd.setCursor(1, 0);    //DP1 postion of TopLine


  //---- start of intialisation of ARduino UART-------
  bitSet(UCSR0B, 3);      //L11 of Section-7.5 ; Transmitter Enable
  bitSet(UCSR0B, 4);       //L12 of Sec-7.5 ; Receiver Enable

  bitClear(UCSR0C, 7);    //L13 of Sec-7.5 ; Asynchronous Mode
  bitClear(UCSR0C, 6);    //L13 of Sec-7.5 ;  "

  UBRR0H = 0x00;          //L14 of Sec-7.5 ; Baud Rate 4800
  UBRR0L = 0xCF;          //L14 of Sec-7.5 ; Baud Rate 4800

  bitWrite(UCSR0B, 2, 0);  //L15 of Sec-7.5 ; Data size 8
  bitWrite(UCSR0C, 2, 1);  //L15 of Sec-7.5 ; Data size 8
  bitWrite(UCSR0C, 1, 1);  //L15 of Sec-7.5 ; Data size 8 

 bitSet(SREG, 7);         //Global Interrupt Enable Bit is made active switch S5 of Fig-7.4)
 bitSet(UCSR0B, 7);       //RXCIE0 is enabled; RX Complete will now interrupt (switch S6 of Fig-7.4)
  //--------end of initialization -------------------------

  //--send A by polling UDRE0 bit (Tx Register Ready) of UCSR0A register------
  while (bitRead(UCSR0A, 5) != HIGH)  //L16 of Sec-7.5
    ;
  UDR0 = 0x41;                      //L17 of Sec-7.5 ; send ASCII of A
  
  while (bitRead(UCSR0A, 5) != HIGH)  //
    ;
  UDR0 = 0x0D;                      // Carriage Retuen code
  
  while (bitRead(UCSR0A, 5) != HIGH)  //
    ;  
  UDR0 = 0x0A;                   // Line Feed code
  
  //--send Z by polling TXC0 bit (Tx Complete) of UCSR0A register------
  bitSet(UCSR0A, 5);                  //L18 putting LH at TXC0 bit
  while (bitRead(UCSR0A, 6) != HIGH)  //L19 of Sec-7.5
    ;
  UDR0 = 'Z';                      //L19 of Sec-7.5 ; send ASCII character Z
  
  while (bitRead(UCSR0A, 5) != HIGH)  //
    ;
  UDR0 = 0x0D;                      // Carriage Retuen code
  
  while (bitRead(UCSR0A, 5) != HIGH)  //
    ;  
  UDR0 = 0x0A;                      //Line Feed code 

}

void loop()
{
      
}


ISR(USART_RX_vect)			//ISR due to RX Complete signal.
{
 
  byte x = UDR0;                    //L21 reading 8-bit data from PC  
  lcd.write(x);                     		//L22 of Section-7.5
 // reti();                         		//with this, the ISR does not work
}

(a) Let us create the above program in the Arduino IDE and save it as P77.

(b) Compile and upload P77 program.

(c) At the PC side, open the Serial Monitor of Fig-7.6 (Tools  Serial Monitor  Click).

(d) Press the RST button of the Arduino Kit.

(e) Check that the characters A and Z have appeared on the Serial Monitor.

(f) In the input box of the Serial Monitor, type the character Q; press the Send button; observe that the character has appeared on the LCD attached with the Ar

L77.doc (44 KB)

7.8 Arduino C++ Codes for Data Exchange between Arduino UART and PC under the Setup of Fig-7.5/Fig-7.6 (Interrupt Method)

(1) By saying Arduino C++, we have wanted to mean that the Arduino IDE contains UART related few functions which could be used for data exchange between Atmega328 and PC. These functions are documented in Section-7.9. Four of them are mentioned here.

(a) Serial.begin(arg1, arg2); This function 
• Converts PD0 and PD1 lines into RXD and TXD lines by enabling Receiver and Transmitter;
• Sets Baud Rate to the desired value by arg1;
• Sets Frame Length to the desired value by arg2;
• Enables RX Complete interrupt logic by placing LH  RXCIE0 bit (the I-bit has been enabled by
the Boot Loader Program of the ATmega328.);
• Declares within itself (user cannot see it) a 64-byte wide FIFO type data array (say, rxArray[ ])
for the storage of data read form RX Register byte by byte;
• Declares within itself (user cannot see) ISR(USART_RX_vect) subroutine which the MCU
automatically executes when RX Complete signal becomes active and interrupts the MCU; reads
data from RX Register one byte at a time; puts the data into FIFO type array (rxArray[ ]). The
int x = Serial.read() function is designed to read data from this array (the rxArray[ ]).

(b) int x = Serial.available(): This function 
• Returns the number of bytes available to read from the Arduino declared FIFO type array
(rxArray[ ]).
• If the return value is 0 after the execution of the function, it means that the RX Register has not
yet received any data from the Host PC.

(c) Serial.write(arg1); This function ---
Writes an 8-bit data (numerical value or ASCII code of a character) as defined by arg1 into the TX Register (write-only UDR0 Register).

(d) byte x = Serial.read(); This function reads byte-by-byte data from rxArray[ ].

(2) Arduino C++ Codes:

#include <LiquidCrystal.h>
//LiquidCrystal lcd(RS, E, D4, D5, D6, D7);//declaration of LCD wiring function
LiquidCrystal lcd (5, A0, A1, A2, A3, A4); //definition of LCD wiring function

void setup()
{
  lcd.begin(16, 2);       //16x2 LCD ; 2-line; each line has 
  lcd.setCursor(1, 0);     //Cursor DP1 postion of TopLine

  //---- Arduino UART init: Bd = 4800, 8-databit, No-parity, 1-stopbit-------
  Serial.begin(4800, SERIAL_8N1); //cover L11-L15 of Section-7.5 + enables RX Complete interrupt logic
  //bitSet(SREG, 7);         //Global Interrupt Enable Bit is made active; done by Boot Loader 
 // bitSet(UCSR0B, 7);       //RXCIE0 is enabled; RX Complete will now interrupt; done by Serial.begin(). 
  
  //--send A by polling UDRE0 bit (Tx Register Ready) of UCSR0A register------
  while (bitRead(UCSR0A, 5) != HIGH)   //L16 of Sec-7.5
    ;
  UDR0 = 0x41;                         //L17 of Sec-7.5 ; send ASCII of A
  //--------send new line charcater by polling TX Complete signal-------
  bitSet(UCSR0A, 6);                   //L18 Sec-7.5; making TXC0 bit active
  while (bitRead(UCSR0A, 5) != HIGH) //L19 of Sec-7.5 
    ;
  Serial.write('\n');                 L20 send to PC a newline= CR(0x0D) + LF(0x0A)   
  while(Serial.available()==0x00)   //wait here until data comes from PC
       ;
  lcd.write(Serial.read()); //show the received character on LCD
}

void loop()
{
      
}

(a) Let us create the above program in the Arduino IDE and save it as P78.

(b) Compile and upload P78 program.

(c) At the PC side, open the Serial Monitor of Fig-7.6 (Tools----> Serial Monitor ----> Click).

(d) Press the RST button of the Arduino Kit.

(e) Check that the characters A and Z have appeared on the Serial Monitor.

(f) In the input box of the Serial Monitor, type the character Q; press the Send button; observe that the character has appeared on the LCD attached with the Arduino.

L78x.doc (46.5 KB)