Showing posts with label 8051 tutorial. Show all posts
Showing posts with label 8051 tutorial. Show all posts

Friday, June 15, 2012

Using the UART

Universal  Asynchronous Receive/Transmit is a form of serial communications used in conjunction with RS-232, RS-485 or RS-422. The 89S52 has one UART port, and the important registers that we will look are TMOD, SCON and SBUF registers. More info regarding this registers can be found on the datasheet.

Initializing Serial Port

1. Set Timer1 as Mode 2, Timer1 then acts as the baudrate generator.
    To do this, load TMOD with 0x20.
2. Load TH1with the desired value according to the baudrate.
    To calculate the value of TH1 we use the formula:

        TH1 = -((Crystal Frequency/12)/32) /desired Baud Rate

       Example: Value of TH1 for a baud rate of 9600 and a crystal frequency of 3.579545MHz

           Divide crystal frequency by 12

                       3579545 / 12 = 298295.4167

          As you can see, if we divide the crystal frequency by 12, the result is not a whole number, if the error is so little, then we can disregard it else choose a crystal frequency that is divisible by 12 to come up with 0% error such as 11.0592MHz or 22.1184MHz.

     Divide resulting value by 32
             
                      298295.4167/32 = 9321.731771

   Divide the resulting value by the desired baud rate

                       9321.731771/9600 = -0.971013726 ~= -1

         We have about 3% error with this crystal frequency

To get the value of TH1

     Subtract computed value from 0xFF and add 1

 TH1 = 0xFF

3. Load the SCON register with the standard 8-bit UART parameters, Mode1 with 8-bits data, no parity, 1 start bit, 1 stop bit and receive enabled.

4. Start Timer 1
5. Load SBUF with the character to be transferred
6. Check if TI is set, if set, clear it.

The Code


#include <at89x52.h>

void UARTputch (unsigned char ch)
{
    TI = 0;                //Clear TI
    SBUF = ch;        //Load data to SBUF
    while(!TI);          //Wait for transmission to finish
}

unsigned char UARTgetch()
{
     while(!RI);        //wait for a byte to receive
     RI = 0;             //Clear RI
     return(SBUF);  //return the contents of SBUF
}

void main (void)
{
  unsigned char rx_byte;
  TMOD = 0x20;     //Timer1 Mode2 Auto Reload
  TH1 = 0xFF;         //9600 baud at 3.579545MHz
  SCON = 0x50;     //UART parameters
  TR1 = 1;               //Start timer

   while(1)
    {
       rx_byte = UARTgetch();
       UARTputch(rx_byte);
   }  
}

The code presented above will echo a single byte that has been sent to the 8051 back to the sender.


                   


Hardware Delay

This tutorial is all about using the internal timers/counters of the 8051 to produce a delay. The AT89S52 has three (3) 16-bit Timers/Counters that can be used to produce a more accurate delay, rather than approximation like that of the software based delay. These timers has different modes, and functions that can be set thru the SFR registers.

In this tutorial, we will be concerned of Timer0 operating at Mode 1. The important registers that we will look at are the TMOD, THx, TLx and TCON registers.

I. The TMOD Register

      The TMOD register is the one responsible for the operation of Timer0 and Timer 1, the lower nibble is for Timer 0 and upper nibble for Timer1.

Figure 1: TMOD Register
a. Gate - Clear to enable Timer x whenever the TRx bit is set. Set to enable Timer x only while the INTx pin is high and TRx bit is set.
b. C/T - Clear for timer operation: timer 1x counts the divided-down system clock. Set for Counter operation: timer x counts negative transitions on external pin Tx.
c. M1/M0 - Timer x mode bits

II. TCON Register
    The TCON register is the one responsible for the control of TIMER0 and TIMER1.

Figure 2: TCON Register

a. IT0 - Interrupt 0 Type Control Bit - Clear to select low level active (level triggered) for external interrupt 0 (INT0#). Set to select falling edge active (edge triggered) for external interrupt 0.
b. IE0 - Interrupt 0 Edge Flag - Cleared by hardware when interrupt is processed if edge-triggered (see IT0). Set by hardware when external interrupt is detected on INT0# pin.
c. IT1 - Interrupt 1 Type Control Bit - Clear to select low level active (level triggered) for external interrupt 1 (INT1#).Set to select falling edge active (edge triggered) for external interrupt 1.
d. IE1 - Interrupt 1 Edge Flag - Cleared by hardware when interrupt is processed if edge-triggered.
Set by hardware when external interrupt is detected on INT1# pin.
e. TR0 -Timer 0 Run Control Bit - Clear to turn off timer/counter 0. Set to turn on timer/counter 0.
f. TF0 - Timer 0 Overflow Flag - Cleared by hardware when processor vectors to interrupt routine.
Set by hardware on timer/counter overflow, when the timer 0 register overflows.
g. TR1 - Timer 1 Run Control Bit - Clear to turn off timer/counter 1. Set to turn on timer/counter 1.
h. TF1 - Timer 1 Overflow Flag - Cleared by hardware when processor vectors to interrupt routine.
Set by hardware on timer/counter overflow, when the timer 1 register overflows.

III. THx and TLx Register
    The THx and TLx registers represent the value of the timer count. The 16 bit count is divided between THx which represents upper byte and TLx which represents lower byte.

Figure 3: THx and TLx Register

Steps in using Mode 1


1. Load TMOD register a value indicating which timer to be used.
2. Load THx and TLx with initial values.
    To calculate
     
     XXYY(hex) = 65536 - (delay / (12/xtal freq.))

   XX = THx Value
   YY = TLx Value
   Crystal Frequency is in Hertz.
3. Start timer by setting TRx (TRx = 1).
4. Monitor the Timer flag TFx to see if it is set.
5. Stop timer (TRx = 0)
6. Clear the timer flag for the next round
7. Go back to step 2.

Example: You want to make a 10ms delay with a 3.58MHz crystal using TIMER0.

Lets compute for the value of THx and TLx

XXYY = 65536 - (10x10^-3 / (12/3.58x10^-6)
XXYY = 62553.04
 since we have a decimal point, we will drop it
 so XXYY = 62553 = 0xF459
 THx = 0xF4
 TLx = 0x59

Implementation:


    #include <at89x52.h>
void delay (void)
{
   TMOD = 0x01;   //Timer0 Mode 1
   TL0 = 0x59;    //Computed Value of TLx
   TH0 = 0xF4;    //Computed Value of THx
   TR0 = 1;       //Start timer 0
   while(!TF0);   //Wait for overflow
   TR0 = 0;       //Stop Timer 0
   TF0 = 0;       //Clear interrupt flag
}
 
void main (void)
{
   while(1)
    {
        P2_0 ^= 1;
        delay();
     }
}
 
The program above will create a 100Hz square wave at P2.0.



Sunday, May 20, 2012

More LED's: Binary Counter

In this example we will display the binary values to LEDs connected to PORT2. P2_0 represents the least significant bit (LSB) and P2_3 represents the most significant bit (MSB).

For example, if we want to display binary count from 0(0x00) to 15(0x0F), we can hard code the values or another approach is use a variable and increment its value by 1 and display its value to PORT2.


Example 1: Hard Coded values

#include <at89x52.h>

void delay (void)
{
    unsigned int i;
     for(i=0; i<0x7FFF; i++);
}

void main (void)
{
   P2 = 0; //initially turn LEDS off

      while(1)
         {
                P2 = 0x00;
                delay();
                P2 = 0x01;
                delay();
                P2 = 0x02;
                delay();
                P2 = 0x03;
                delay();
                P2 = 0x04;
                delay();
                P2 = 0x05;
                delay();
                P2 = 0x06;
                delay();
                P2 = 0x07;
                delay();
                P2 = 0x08;
                delay();
                P2 = 0x09;
                delay();
                P2 = 0x0A;
                delay();
                P2 = 0x0B;
                delay();
                P2 = 0x0C;
                delay();
                P2 = 0x0D;
                delay();
                P2 = 0x0E;
                delay();
                P2 = 0x0F;
                delay();
         } 
}

Example 2: Improved version

#include <at89x52.h>

void delay (void)
{
    unsigned int i;
     for(i=0; i<0x7FFF; i++);

}

void main (void)
{
   unsigned char val = 0  //the value of this variable will be transferred to P2
   P2 = 0; //initially turn off all LEDs


    while(1)
       {
            P2 = val;  //transfer val to P2
                 val++; //increment val by 1
            if(val>=0x0F) //if we reach 0x0F then reset value
               val = 0;

             delay();

       }

}


Saturday, May 19, 2012

Working With GPIO

Now that we have our tools, we are now ready to start! For our first lesson we will learn how to turn an LED on and off. Writing and reading a port in SDCC can be directly done. So to write to a PORT is simply writing 1 to turn it on or 0 to turn it off.

To write to the whole 8 bits of the PORT, its simply "Px = value;" where x is the port number and value is an 8 bit data, and to write to a specific pin its "Px_y", where x is the port number and y is bit number.

   Examples:

     Write 0x05 to Port 1
  
                    P1 = 0x05;

     Make Port3.4 high

                     P3_4 = 1;


Now that we know the basic syntax, Lets keep going!

For the following examples, we will be using the following connections to the microcontroller.


Example 1:

   Turn on LED connected at Port 2-0.

  1. Open M-IDE and create a new file called led.c and save to your working folder.
  2. Copy and paste the following codes:
 #include <at89x52.h>

void main (void)
{

  P2 = 0; //initially turn off PORT2
 
         while(1)
         {
            P2_0 = 1;
         }
}
 3. Build the program and load the hex to the microcontroller to see the result.

 Example 2:

  1. Create a new file called blink.c and save to your working folder.
  2. Copy paste the following codes:

      To blink a LED we turn it on and off, but since the microcontroller is running fast that we cannot see, we will introduce a delay in between.We will introduce a software delay. This delay routine is just a counter that will waster CPU process before doing another instruction. Now lets make the LED connected to P2_0 blink.

#include <at89x52.h>

void delay (void)
{
    unsigned int i;                 //this for loop will just count up to 0xFFFF

     for(i=0; i<0xFFFF; i++)
     
}

void main (void)
{
    P2 = 0; //initially turn off all LEDs

    while(1)
       {
              P2_0 = 1;
              delay();
              P2_0 = 0;
              delay();
      }
}
 3. Build the program and load the hex to the microcontroller to see the result.


Led Blink Demo









Getting Started: The Tools

In order to learn, we need tools, to learn a microcontroller we need the microcontroller itself, some I/O modules, a programmer and an IDE to compile our program.

The IDE

      M-IDE for the 8051 can be downloaded freely from opcube packed with ASEM-51 assembler and SDCC C compiler. This IDE is easy to use, free and also comes with a simulator. It can be downloaded from here


Input/Output Modules

    This is a microcontroller independent Microcontroller Training Module proudly designed and made in the Philippines by e-Gizmo Mechatronix Central. It features almost all the peripherals needed for learning such as Buttons, LED's, Seven Segment, LCD, RS232, Analog sources, relay, motor drivers, Temp Sensor, RTC, matrix keypad, I/O expander and a Rotary Encoder. Any arduino compatible board can be plugged-in.



The Microcontroller
   For use with my trainer, I made an Arduino compatible board for the 8051, though the small breadboard on the center can also be used for plugging in any MCU for experiment.



Programmer
  This is my DIY programmer for programming 8051 and AVR via ISP. It is based on USBASP with modified firmware to support the 8051. Project files for the programmer can be found at 8051projects.info