Serial Communication 8051 Microcontroller using KEIL

In this tutorial, we will see the serial communication programming of the 8051 microcontroller. When electronic devices communicate with each other, they can transfer data in two different ways. One way of communicating is serial, and the other is parallel. When we transfer digital data in serial mode, this mode transmits the data bit by bit. Whereas in parallel mode, the digital data bits transmit at the same time. Though the parallel transfer of data is much faster, it requires more wires. while a serial transfer is slower as compared to a parallel transfer but requires fewer wires. Serial communication may be synchronous or asynchronous. In synchronous communication, the transmitter also transmits a clock along with data. This clock synchronizes the transmitter and receiver devices. In an asynchronous transfer of data, there is no clock.

Introduction to Serial Communication with 8051 Microcontroller

Serial communication may be simplex, half-duplex, or full-duplex. Simplex communication means that data transmission will be in one direction only, while half-duplex means data transmission will be in both directions, but at one time only one device can transmit, whereas full-duplex means data transmission may be in both directions at one time, and while one device is transmitting, it can also receive data transmitted from other devices at the same time. We did mention before that the transmitter and receiver need configuration to communicate at some data transfer rate before communication starts. This data transfer rate, or the transmission per second of the number of bits, is the baud rate for handling serial communication.

serial communication with microcontroller

Parallel communication is fast, but it is not applicable for long distances (for printers). Moreover, it is also expensive. Serial communication is not as fast as parallel communication, but it can deal with the transmission of data over longer distances (for telephone lines, ADCs, and DACs). It is also cheaper and requires fewer physical wires, which is why we use serial communication. This article also deals with how to serially communicate with an 8051 microcontroller.

Methods of Serial Communication

There are two methods of Serial Communication:

  • Synchronous
  • Asynchronous
serial communication types ASYNCHRONOUS and SYNCHRONOUS

Synchronous: Transfer the block of data (characters) between sender and receiver, spaced by a fixed time interval. This type of transmission requires an external clock for synchronization.

Asynchronous: There is no clock involvement here, and synchronization of transmission is done by special signals along the transmission medium. It transfers a single byte at a time between sender and receiver, along with inserting a start bit before each data character and a stop bit at its termination to inform the receiver where the data begins and ends. An example is the interface between a keyboard and a computer. The keyboard is the transmitter, and the computer is the receiver. We use USART and UART for serial communications. USART and UART are microcontroller peripherals that convert incoming and outgoing bytes of data into a serial bit stream. Both do the same work but with different methods, which are explained below.

Difference between USART and UART

USART

USART stands for Universal Synchronous/Asynchronous Receiver-Transmitter. It uses an external clock, so it needs a separate line to carry the clock signal. The sending peripheral generates a clock, and the receiving peripheral recovers from the data stream without knowing the baud rate ahead of time. By using an external clock, USART’s data rate can be much higher (up to rates of 4 Mbps) than that of a standard UART.

UART

It stands for Universal Asynchronous Receiver-Transmitter. A UART generates its internal data clock for the microcontroller. It synchronizes that clock with the data stream by using the start-bit transition. The receiver needs to know the baud rate ahead of time to properly receive the data stream.

8051 Serial Communication Programming Registers 

The 8051 microcontroller has a built-in serial port called UART. We can easily read and write values to the serial port. For using the serial port, we simply need to configure the serial port:

  • Operation mode (how many data bits we want)
  • Baud rate

There are 21 Special function registers (SFR) in the 8051 microcontrollers, and there are 21 unique locations for these 21 SFR. Each of these registers is 1 byte in size. The “Serial Control” (SCON) is the SFR, which we can use to configure the serial port.

8051 serial communication SCON register
SCON SFRModeFunction
SM0Serial port modeBit 0 of serial port mode.
SM1Serial port modeBit 1 of serial port mode.
SM2Enable multiprocessorEnable multiprocessor communication in modes 2 and 3 (for 9-bit UART).
RENReceiver enableSet/clear by software to enable/disable receive operations.
TB8Transmit 8-bitSet or cleared by software. The 9 bits will be transmitted in modes 2 and 3.
TB8 = 1, a value is written to the serial port, and the 9th bit of data is 1.
TB8 = 0, 9th bit of data = 0, RI will not be set.
RD8Receive 8-bitSet or cleared by software. The 9 bits will be received in modes 2 and 3. The first eight bits are the data received, and the ninth bit received will be placed in RB8.
TITransmit interrupt flagSet by hardware when a byte is transmitted completely. Now the port is free and ready to send the next byte. This bit must be cleared by software.
RIReceive interrupt flagSet by hardware when a byte has been completely received. This lets the program know that it needs to read the value quickly before another byte is read. This bit must be cleared by software.

Configuration Settings

In this section, we will discuss the configuration settings for serial communication on the 8051 microcontroller.

Setting Operation Mode of Serial Port:

The Upper four bits are configuration bits. SM0 and SM1 set the serial mode between 0 and 3. In modes 0 and 2, the 8051 has a fixed baud rate, which depends on the oscillator frequency. In modes 1 and 3, the baud rate is variable, which depends on how often Timer 1 overflows. The list of four modes, along with the baud rates, is in the table below.

SM0SM1ModeDescriptionBaud rate
000shift register(Fosc./12)
0118 bit UARTVariable (set by Timer 1)
1029 bit UART(Fosc./64)
1139 bit UARTVariable (set by Timer 1)

SM2 is a flag bit for Multiprocessor communication. When we enable SM2, the 8051 microcontroller sets the RI (Receive Interrupt) flag whenever it receives a byte (if the 9th bit received is “1”). This way, the program knows that a byte has been received and needs to be processed. If the 9th bit is clear, the 8051 never sets the RI flag. We will clear this RI bit so that the flag sets upon reception of any character.

If SM2 = 1, RI = 1 (only if the 9th bit of the received byte is 1).
REN is the Receiver Enable bit. Set this bit if we want to receive data through the serial port.
REN = 1 (for serial communication)

Setting the Baud Rate of Serial Port

Baud Rate

It is defined as the number of bits transmitted or received per second and is usually expressed in Bits per second (bps). After setting the operation mode of the serial port, the program must configure the serial port’s baud rate, which is only applicable to Serial Port modes 1 and 3. For modes 0 and 2, the oscillator frequency determines the Baud Rate.

For Mode 0

The baud rate always divides the oscillator frequency by 12. For a crystal with a frequency of 11.059 MHz, the baud rate will be 921,583 baud.

Baud rate = (11.0592 MHz/12) = 921,583 baud

For Mode 2

The baud rate always divides the oscillator frequency by 64. For a crystal with a frequency of 11.059 MHz, the baud rate will be 172,797 baud.

Baud rate = (11.0592 MHz/64)  = 172,797 baud

For Modes 1 and 3

The baud rate determines the frequency at which timer 1 overflows. The more frequently timer 1 overflows, the higher the baud rate. There are many ways in which timer 1 overflows at a rate that determines a baud rate. The most common method is:

  • We put timer 1 in 8-bit auto-reload mode (timer mode 2).
  • This 8-bit timer allows only values of 00 to FFH to be loaded in timer register TH1.
  • Set a reload value in TH1 that causes Timer 1 to overflow at a frequency appropriate to generate a baud rate.
  • If PCON.7 is clear (SMOD=0), then to generate a given baud rate, the value to be put in TH1 can be determined from an equation:
    • TH1 = 256 – ((Crystal / 384) / Baud)
  • If we try to load the value in TH1 using the above equation, which is not a whole number, then we can’t get an accurate baud rate. For that case, set PCON.7 (SMOD=1). This doubles the baud rate, and the equation becomes:
    • TH1 = 256 – ((Crystal / 192) / Baud)

Calculate Baud Rate for Serial Communication in 8051 Microcontroller

Let’s take an example. If we have a crystal oscillator with a frequency of 11.059 MHz and we want to configure the serial port to a 19,200 baud rate, first we try equation 1. By using equation 1, we get:

TH1 = 256 – ((Crystal / 384) / Baud)
TH1 = 256 – ((11.059 MHz/ 384) / 19200 )
TH1 = 256 – 1.5 = 254.5

By setting 254 and 255, we don’t achieve an accurate baud rate, so we need to set PCON.7 (SMOD=1). This doubles the baud rate, and we will use equation 2 for determining the TH1 value. By using equation 2, we get:

TH1 = 256 – ((Crystal / 192) / Baud)
TH1 = 256 – ((11.059 MHz/ 192) / 19200)
TH1 = 256 – 3 = 253

Thus, by setting TH1 to 253, we get the correct frequency for the 19,200 baud rate.

Example of Serial Communication Programming using Mikro C for 8051

If you do not want to do complicated programming using serial communication registers, you can simply use the Mikro C compiler, which has built-in libraries for UART communication. Now I will explain UART programming through Mikro C, and after that, I will provide an example of UART in the Keil compiler. We can use the built-in UART library for handling 8051 serial communication; there are several functions. In this library.

  • UART_init() is used for initializing the 8051 UART module.
  • The UART_data_read() function checks if some data has been received on the serial port. UART_read() reads one byte from the serial port.
  • whereas UART_Read_Text() can read multiple bytes.
  • UART_Write() writes one byte to serial port. UART_Write() writes one byte to serial port
  • while UART_Write_Text() can write multiple bytes.
  • The UART_Set_Active() function is only used on microcontrollers that support more than one UART port.

Code

sbit LCD_RS at P2_0_bit; // Port 2, Pin 0
sbit LCD_EN at P2_1_bit; // Port 2, Pin 1
sbit LCD_D7 at P2_5_bit; // Port 2, Pin 2
sbit LCD_D6 at P2_4_bit; // Port 2, Pin 3
sbit LCD_D5 at P2_3_bit; // Port 2, Pin 4
sbit LCD_D4 at P2_2_bit; // Port 2, Pin 5

void main() {
  unsigned int sum;
  char txt[6];
  P0 = 0xFF; // Sets all pins of P0 to high
  P1 = 0xFF; // Sets all pins of P1 to high

  uart1_init(9600); // Initializing UART
  PCON.SMOD = 0;

  Lcd_init(); // Initializing LCD
  lcd_cmd(_LCD_CURSOR_OFF); // Turning LCD cursor off
  lcd_out(1, 1, "****************"); // Displaying output on LCD

  uart1_write_text("Uart OK"); // Uart message

  while (1) {
    sum = P0 + P1;
    wordToStr(sum, txt);

    lcd_out(2, 1, "P0+P1=");
    lcd_out(2, 7, txt);

    uart1_write_text("P0+P1=");
    uart1_write_text(txt);
    uart1_write_text("\r\n");
    delay_ms(500);
  }
}

In the above, we are transmitting data through the UART port and also displaying the same data on the LCD. If you don’t know how to display data on an LCD, you can check out this tutorial here. Now let’s see the explanation of the code.

  • First, we initialize the serial port at a 9600 baud rate using the UART_Init() function.
  • Next we need to Clear SMOD bit of PCON register
  • Actually there is some bug in uart_init() function of UART library, it writes HIGH to SMOD bit that causes erroneous baud rate.
  • We can send some string to serial port with uart_write_text() function.
  • Now in while(1) loop, we are sending “P0+P1” string to serial port with uart_write_text function.
  • Now we can send the same text array to the serial port that is being displayed on the character LCD.
  • At the end, we are sending a new line character. OK, the code is now ready. We can compile and test it.
  • It is recommended to select 11.0592 MHz crystal frequency for using the serial port. 11.0592 MHz crystal frequency can give exact clock rates for most of the common baud rates for the UART.
  • We can use a virtual terminal in Proteus for testing serial communication.
  • The TX pin of 8051 will be connected to the RX of the virtual terminal.
  • In the virtual terminal of Proteus, you have to enter the same baud rate as configured in your code.
  • When we run the code, we will see the sum of P0 and P1 appear on the virtual terminal.

Example of serial communication 8051 microcontroller with Keil IDE

The schematic uses an 8051 microcontroller. Its crystal frequency is set at 11.059 MHz. The Baud rate used is 9600. We will use a virtual terminal. The data coming from the transmitter pin of the controller is displayed on a virtual terminal. The send to the microcontroller is also received on the receiver pin of the controller, which is sent through a virtual terminal by pressing a specific key. The program’s baud rate is 9600.

For 9600 baud rate:

TH1 = 256 – ((Crystal / 384) / Baud)
TH1 = 256 – ((11.59MHz/ 384) / 9600 )
TH1 = 256 – 3 = 253

The Hex value of 253 is FD, which should be loaded to TH1.

  • Port 3 pin 0 receiver pin connects to the TX of the virtual terminal.
  • Port 3 pin 1 transmitter pin connects to the RX of the virtual terminal.
  • Port 1’s lower four pins connect with four LEDs.

Proteus Schematic Diagram

Working of Serial Communication 8051 Microcontroller

  • When we press key 1, the first LED will glow, and when we press the “a” key, it goes off.
  • Now, If we press key 2, the second LED will glow, and when we press the “b” key, it goes off.
  • If we press key 3, the third LED will glow, and if we press the “c” key, it goes off.
  • By pressing key 4, the fourth LED will glow, and when we press the “d” key, it goes off.

The virtual terminal will also show the ON and OFF status of LEDs.

Code

#include <REGX51.H>

void cct_init(void);

void SerialInitialize(void);

void uart_msg(unsigned char * c);

void uart_tx(unsigned char);

sbit led1 = P1 ^ 0;
sbit led2 = P1 ^ 1;
sbit led3 = P1 ^ 2;
sbit led4 = P1 ^ 3;

void main()
{
  cct_init();
  SerialInitialize();

  EA = 1;
  ES = 1;

  uart_msg("Initializing Serial Communication");
  uart_tx(0x0d);

  uart_msg("1,2,3,4 key can on leds and a,b,c,d can off them respectively.");
  uart_tx(0x0d); //next line

  uart_msg("Press the key for particular LED");
  uart_tx(0x0d);

  while (1);
}

void cct_init(void) //initialize cct
{
  P0 = 0x00; //not used
  P1 = 0x00; //output port used for leds
  P2 = 0x00; //not used
  P3 = 0x03; //used for serial communication
}

void SerialInitialize(void) //Initialize Serial Port
{
  TMOD = 0x20; //Timer 1 In Mode 2 -Auto Reload to Generate Baud Rate
  SCON = 0x50; //Serial Mode 1, 8-Data Bit, REN Enabled

  TH1 = 0xFD; //Load Baud Rate 9600 To Timer Register
  TR1 = 1; //Start Timer
}

void uart_msg(unsigned char * c)
{
  while ( * c != 0)
  {
    uart_tx( * c++);
  }
}

void uart_tx(unsigned char serialdata)
{
  SBUF = serialdata; //Load Data to Serial Buffer Register

  while (TI == 0); //Wait Until Transmission To Complete

  TI = 0; //Clear Transmission Interrupt Flag
}

void serial_ISR(void) interrupt 4
{
  char chr; //receive character

  if (RI == 1)
  {
    chr = SBUF;
    RI = 0;
  }

  P0 = ~P0; //Show the data has been updated

  switch (chr)
  {

  case '1':
    led1 = 1;
    uart_msg("1st on");
    uart_tx(0x0d);
    break;

  case '2':
    led2 = 1;
    uart_msg("2nd on");
    uart_tx(0x0d);
    break;

  case '3':
    led3 = 1;
    uart_msg("3rd on");
    uart_tx(0x0d);
    break;

  case '4':
    led4 = 1;
    uart_msg("4th on");
    uart_tx(0x0d);
    break;

  case 'a':
    led1 = 0;
    uart_msg("1st off");
    uart_tx(0x0d);
    break;

  case 'b':
    led2 = 0;
    uart_msg("2nd off");
    uart_tx(0x0d);
    break;

  case 'c':
    led3 = 0;
    uart_msg("3rd off");
    uart_tx(0x0d);
    break;

  case 'd':
    led4 = 0;
    uart_msg("4th off");
    uart_tx(0x0d);
    break;

  default: ;
    break; //do nothing
  }
  RI = 0;
}

Code Explanation

In this section, we will discuss the workings of the code

#include <REGX51.H>

void cct_init(void);

void SerialInitialize(void);

void uart_msg(unsigned char * c);

void uart_tx(unsigned char);

sbit led1 = P1 ^ 0;
sbit led2 = P1 ^ 1;
sbit led3 = P1 ^ 2;
sbit led4 = P1 ^ 3;

Firstly, we include the <REGX51.H> header tag to deal with the registers of the 8051 microcontroller. Then we declare four functions. Lastly, we initialize Port 1’s lower four pins as output for LEDs.

void main()
{
  cct_init();
  SerialInitialize();

  EA = 1;
  ES = 1;

  uart_msg("Initializing Serial Communication");
  uart_tx(0x0d);

  uart_msg("1,2,3,4 key can on leds and a,b,c,d can off them respectively.");
  uart_tx(0x0d); //next line

  uart_msg("Press the key for particular LED");
  uart_tx(0x0d);

  while (1);
}

In the void main function, we first call cct_init() and then SerialInitialize(). After this, we set the EA and ES registers high. Next, we print the uart message and shift to the next line using the uart_tx(0x0d) command. We repeat this step two more times. At last, we end the main function with a while loop, so this runs continuously.

void cct_init(void) //initialize cct
{
  P0 = 0x00; //not used
  P1 = 0x00; //output port used for leds
  P2 = 0x00; //not used
  P3 = 0x03; //used for serial communication
}

We set the ports in the cct_init() function. We require Port 1 as output and Port 3 as input. In this tutorial, we will not use Ports 0 and 3.

void SerialInitialize(void) //Initialize Serial Port
{
  TMOD = 0x20; //Timer 1 In Mode 2 -Auto Reload to Generate Baud Rate
  SCON = 0x50; //Serial Mode 1, 8-Data Bit, REN Enabled

  TH1 = 0xFD; //Load Baud Rate 9600 To Timer Register
  TR1 = 1; //Start Timer
}

In this function, we set the serial mode for communication. First, we set the timer to mode 2. Then we set the SCON command for mode 1 with an 8-data bit and REN Enabled. Lastly, we load the baud rate into the timer and start it.

void uart_msg(unsigned char * c)
{
  while ( * c != 0)
  {
    uart_tx( * c++);
  }
}

This function prints the message using the uart_tx function.

void uart_tx(unsigned char serialdata)
{
  SBUF = serialdata; //Load Data to Serial Buffer Register

  while (TI == 0); //Wait Until Transmission To Complete

  TI = 0; //Clear Transmission Interrupt Flag
}

In the uart_tx function, we load the data into the serial buffer register. Then we wait for the transmission to complete.

void serial_ISR(void) interrupt 4
{
  char chr; //receive character

  if (RI == 1)
  {
    chr = SBUF;
    RI = 0;
  }

  P0 = ~P0; //Show the data has been updated

  switch (chr)
  {

  case '1':
    led1 = 1;
    uart_msg("1st on");
    uart_tx(0x0d);
    break;

  case '2':
    led2 = 1;
    uart_msg("2nd on");
    uart_tx(0x0d);
    break;

  case '3':
    led3 = 1;
    uart_msg("3rd on");
    uart_tx(0x0d);
    break;

  case '4':
    led4 = 1;
    uart_msg("4th on");
    uart_tx(0x0d);
    break;

  case 'a':
    led1 = 0;
    uart_msg("1st off");
    uart_tx(0x0d);
    break;

  case 'b':
    led2 = 0;
    uart_msg("2nd off");
    uart_tx(0x0d);
    break;

  case 'c':
    led3 = 0;
    uart_msg("3rd off");
    uart_tx(0x0d);
    break;

  case 'd':
    led4 = 0;
    uart_msg("4th off");
    uart_tx(0x0d);
    break;

  default: ;
    break; //do nothing
  }

The serial interrupt function receives the character, and if RI is 1, it stores the data in the serial buffer. Then, based on the data received, we can shift to cases between LEDs 1, 2, 3, and 4. In each case, we set the LED pin high, then print a message through serial communication, and lastly, we move to the next line and break the case.

Conclusion

Here, we will discuss the topics covered in this tutorial

  • Introduction and methods of serial communication for 8051 microcontroller
  • Serial communication programming registers and configuration settings
  • Calculating baud rate of serial communication of 8051 microcontroller
  • Example of serial communication programming using Mikro c
  • Example and working of serial communication
  • Code and its explanation

Related Articles

You may like to read:

This is for today’s article. In case you face any issues or difficulties while following this tutorial, let us know in the comment section below.

7 thoughts on “Serial Communication 8051 Microcontroller using KEIL”

Leave a Comment