Posts Tagged 8051

8051-Programmable Counter Array

Hello people…its been quite some time since i ve posted anything here. Well let me fix that…. this is a post on the programmable counter array functionality in 8051. To be clear, the 8051 core as such does not have this functionality but if you have an 8051 board which is not too old, you should have it. Referring the data sheet might be helpful. For the description below i ll be using AT89c51ed2. But you can extend the ideas to other boards too.

A few words on programmable counter array…its there to expand the timing capabilities of 8051. It requires comparatively low software overhead and is more accurate. It has an array of 5 counter/capture modules. They can be programmed in any of the following modes:

  • Rising or falling edge timer
  • Software timer
  • High speed output
  • PWM

If you ve read my previous post on controlling the servo motor using 8051..i wrote about one way PWM can be achieved. Here i ll demonstrate a much simpler approach. I ll be using the module 0 here to generate a PWM wave. We ll set the frequency as 100kHz and the duty cycle to 20%. The output will be available on Pin1.3/CEX0. I ll be using the Keil simulator to see the output.

The modules that i mentioned above require a timer of their own to function properly, this is achieved by what is called a PCA timer. Its a common base timer for all the modules. This timer is itself sourced by :

  • Freq (clk-peripheral) / 2
  • Freq(clk-peripheral) / 6
  • Timer 0 overflow
  • Input on ECI pin (Pin 1.2)

A better way to say this is….lets assume that we have programmed it to use Timer 0 overflow as a source. This means every time timer0 overflows the PCA timer increments by 1.

Okay then lets get started with it.

Since the output frequency is 100kHz, Freq(clk-peripheral)/ 6  seems to be a good enough choice .To program that we need the CPS1 and the CPS0 bits in the CMOD register.

MOV 0D9H, #00H

Next we ll fix the contents of CCAPM0 register. This is where we tell the microcontroller that we are going to use it in the PWM and enable the comparison.

MOV 0DAH, #42H

The next step is loading the CH & CL registers with appropriate values such that CH/CL overflows at the rate of 100kHz.

The oscillator frequency here is 33MHz. The F(clk-peripheral) is (Oscillator / 2) in this case..i.e 16.5MHz. Further more the clock to PCA is F(clk-peripheral)/6….i.e. 2.75MHz. As a result the number of increments the CH/CL register should go through to get a frequency of 100kHz is 27.5 ~ 28. So CH can be initialized with 0xFF and CL with 0xE4. Everytime the timer overflows an interrupt is raised. Thus in the interrupt service routine reload the CH/CL registers with the above values.

Once we have taken care of the frequency, the next step is setting the duty cycle. How this works is,  we store a value in the CCAPL0 SFR. This value is compared with the value in CL. As long as the count in CL is less than the value in CCAPLo, the output remains LOW, it then toggles to HIGH when the CL count exceeds the value in CCAPL0.

Finally start the timer and enable the PCA interrupt. After debugging and running the program, the plot the output.

Here is the final code for 100kHz and 20 % duty cycle. I ve loaded the CH/CL with values other than what I mentioned above since 28 increments was giving me a frequency of around 80kHz. After experimenting a bit the value of 235 in CL worked out perfectly.

Advertisements

, , , , , , , , ,

Leave a comment

Servo motor, Serial COM and 8051

In this project I control the angular position of a servo motor by using the serial communication ability of the 8051 microcontroller. To state it a bit more simply ..I control the angle by which the shaft of the servo motor rotates by pressing keys on my laptop. This project might be helpful to you, if you are planning to build a robotic arm someday and want to control it using your computer.

List of things I am using here:

  • 8051 microcontroller board.
  • A Servo motor.
  • Connecting wires.
  • Computer (..obviously :P)

The connections are really very simple. Choose any of the 32 input/output pins available on your microcontroller board and connect it to signal wire of the servo motor.

A servo motor has just three wire. One for Vcc, one for GND and a signal wire. They are generally colour coded. On the motor which I have, the colour codes are as follows:

  • Red – Vcc
  • Brown – GND
  • Yellow – Signal

In case you have any confusion regarding the colour codes for your motor,  it is always a good idea to just google the model of your motor and clear your doubt.

Once you are done with these connections, thats it  .. now all that needs to be done is to program the microcontroller.

In case you have used an Arduino board before, you might know that there already exists a library for controlling the Servo motor which makes the task trivial. But in the case of 8051 the it is a bit more complicated. Its easy but some math needs to be done.

The position of the servo motor depends on the width of the pulses that it receives on the signal wire.And these pulses need to have a time period of approximately 20ms. After doing some research on the web i found the “on” time of the pules required for various positions(.. applicable to my servo).

  • 0.388 ms – 0 degrees
  • 1.25ms – 90 degrees
  • 2.14ms -180 degrees

Next we need to create a loop that runs for a fixed amount of time and depending upon what is the width of the pulses required we can run it multiple number of times. The following code accomplishes it.

To give an example of how i use this code, say I want to set the angular position of the servo to 0 degrees. In that case i need to provide the pulses with the width of 0.388 ms.So i do it this way.

  • Set the output 1
  • Call set_timer(8) 8 * 50 = 400usec = 0.4ms ~0.388ms
  • Set the output 0
  • Call set_timer(400 – 8) // because 400* 50us = 20000us = 20ms.

And since the calling function is itself inside a loop that goes on forever unless you receive a character serially, we are able to provide the pulses every 20ms on the signal line that sets the servo at angular position zero.

The following function receives the angle that needs to be written on the servo and calls the set_timer() function shown above from within.

0,90 & 180 are the constants denoting different angles.

RI = 0 when no data is received  on the serial line and RI = 1 when data has been received successfully. So once data is received, it breaks out from the loop and exits to return to the main() function, as the write_pos() was called from main.

Now in the main function we do all the initializations, like setting the baud rate etc needed for serial communication.

To decide what value needs to be put in TH1 for a particular baud rate there is the following formula if the mode is 1:

TH1 = 255 – ((Crystal freq / 384)/baudrate).

Thats it then..when you load this program onto the microcontroller you ll be able to control the position of servo motor using the keys ‘1’, ‘2’ and ‘3’ on your keyboard.Check out the video here

Here is the final code:

//Servo motor position control using serial    communication

#include <reg52.h>
#include <stdio.h>

void write_pos(int position);
void set_timer(int x);

sbit servo_signal1 = P1^0;

int main (void){

unsigned char ch;

SCON = 0x50; //
TMOD = 0X22; //
TH1 = 244;   //
TR1 = 1;     //
TI = 1;      //
RI = 0;      //

while(!RI);
ch = SBUF;
RI = 0;

printf(“%c “,ch);
while (1){

switch(ch){
case ‘1’:
write_pos(0); // Set Servo position to 0 degrees
break;
case ‘2’:
write_pos(90); // Set Servo position to 90 degrees
break;
case ‘3’:
write_pos(180); // Set Servo position to 180 degrees
break;
default:
while(!RI); // wait till you get a valid input
RI = 0;

}
ch = SBUF;
printf(“%c “,ch);

}

}

void write_pos(int position){
int msec;
switch(position){
case 0:
msec = 8;
while(!RI){
servo_signal1 = 1;
set_timer(msec);
servo_signal1 = 0;
set_timer(400 -msec);}
RI = 0;
break;
case 90:
msec = 25;
while(!RI){
servo_signal1 = 1;
set_timer(msec);
servo_signal1 = 0;
set_timer(400 -msec);}
RI = 0;
break;
case 180:
msec = 40;
while(!RI){
servo_signal1 = 1;
set_timer(msec);
servo_signal1 = 0;
set_timer(400 -msec);
}
RI = 0;
break;
default:
;
}
}

void set_timer(int x){

int i;
// To run the loop given below once it takes approx 50us
// Since I have already used the timer 1 for serial communication, I use
// the timer 0 to give PWM signal to the servo motor.
for(i=0;i<x;i++)
{
TMOD=0x22;
TH0=0x0FF;
TL0=0x0D1;

TR0=1;
while(TF0==0);
TF0=0;
TR0=0;
}
}

, , , , ,

Leave a comment

Blink LED using 8051

8051… this is historically one of the most important microcontroller the world has seen so far. To say it in one sentence..Its a piece of beauty.

the microcontroller p89v51rd2

What I present in this article is the first assembly language program that I ran on the 8051 microcontroller. If you have seen my “Blinking LED using Arduino”, we do a very similar thing here. However the difference is, blinking an LED using an Arduino board is just too easy and for the most part of it we are unaware of what is happens in the various registers. Although there is an easier way to program an 8051 using the C language, I intend to program it using the assembly language here simply because it gives me a better sense of control over the registers and also it is a fairly easy program to be implemented in assembly. Also programming in assembly makes you think a bit harder which can be fun if you want it to be.

Okay enough of the intro .. lets start.

The following components are required in this project:

  • An 8051 board. I am using the 89V51RD2 starter kit. I got it from here: 8051 Starter Kit
  • LEDs
  • A programmer
  • Programs like Keil and flashmagic to write the program and upload it to the microcontroller.
  • Connecting wires.

First things first, the objective. Our aim here is to connect  LEDs to one of the i/o ports and program the microcontroller such that the LEDs glow for 1 sec and turn off for the next second and they keep doing until the end of time (.. or as long as we supply power to the microcontroller)

Now.. the crystal that is used in my 8051 board oscillates at 11.0592MHz frequency. In other words there are 11.0592 million crystal pulses every second.

Next we look at the two timers (T0 & T1). Irrespective of which mode they are used in, the timers in the 8051 only keep incrementing and they increment by 1 every “machine cycle”. A machine cycle in 8051 requires 12 crystal pulses always. So although different instructions in the “Instruction set” require different number of machine cycles, a timer increments after every machine cycle.

So doing some math here a timer increments

11059200/12 = 921600 times every second

In other words it increases by 1 in 1.085 micro seconds. Here we will be using Timer 0 and will be using it in the 16 bit mode( Timer 0 and Timer 1 each are actually a combination of two 8 bit registers. Timer 0 -TH0 & TL0, Timer 1 – TH1 & TL1). Okay so 16 bits… which means it can count from 0 to (2^16) – 1 i.e from 0 to  65535, after which it will overflow, reset itself to 0 and start all over again. So lets check how much time does it take to do that:

65536 / 921600 = 0.07 sec

Well this is an odd value and it might be a bit tedious to work with such a number. So lets go the other way round. Lets check how many times does it increment in 0.05sec

0.05 * 921600 = 46080 increments.

Since it takes 1/20 th of a second to have 46080 increments, what we need to do is carry out 46080 increments of the timer 20 times to have a delay of 1 sec.

All right then now that we have an algorithm to measure time, now all we have to do is implement it in the timers.

This is done using two Special Function Registers ( SFRs), TCON and TMOD registers. Each one of them has eight bits and every bit has a particular function. The details of the TMOD timer are given below:

TMOD register

Timer modes

Next is the TCON register. In this register only two bits are useful for us at the moment and both of them can be accessed by specially assigned names.

TF0 – This bit sets when the timer 0 overflows.

TR0 – This bit must be set by us to enable the timer.

In our earlier derivation, we said that we need the timer to increment 46080 times  to introduce a delay of 0.05s. So we need to determine the starting point for the timer which is (65535 – 46080) = 19455( which in hexadecimal is 4BFFh) i.e. this is the value with which the timer needs to be initialized.

Now that we have all the bits and pieces, here is the algorithm for blinking an led every two seconds(“on” for 1 sec and “off” for the next second)

  • Set a flag bit ..say the bit at 20h and set the timer in mode1.
  • Store 20 (14 hex) in R0. This is the initialization step.
  • Initialize timer0 to 4BFF hex
  • Start the timer ( Set TR0)
  • Check the TF0 bit. Every time it overflows decrement R0 by 1.
  • If R0 is not zero jump back to the initialization process. Else  if it is zero depending upon the flag jump to instructions that turn on the led or turn off the led. Change the flag bit to the other state(if flag = 0 initially set it to 1 and vice verse)
  • Jump back to the point of initialization.

Here is the final code that I came up with and it appears to be working all right:

I must confess though, that the time delay is not exactly 1 sec. There is an error of a few milliseconds but even then its a pretty good result. Now all that needs to be done is to convert this asm file to a hex file and upload it onto the microcontroller.

There you have it.. blinking LED using 8051. Here is the video Video

, , , , , ,

Leave a comment