You are on page 1of 21

Chapter 11 Embedded System Design

11. AT89C52 Based System Design


This chapter deals with system design involving both hardware and software. The first part of a design is the hardware connections with the microcontroller and peripheral ICs/components. The second part is the software development. The software can be written using assembly or a higher level language like C. Because of extensive use of microcontrollers in system development, some third party vendors has come out with powerful C compilers with integrated development environment that would produce the machine codes optimally. Using C compilers help reducing the program development time and rapid prototyping. In this chapter the readers would get flavors of both assembly and C based program development.

11.1 System Design Involving Timers and Interrupts


Embedded systems use timers/counters extensively for real time control purposes. The interrupts related to timers/counters allow the programmer to accommodate multiple tasks that gives a flavor of multitasking. In this section we would examine the timer operation in different modes and generate real time pulses in a port pin.

11.1.1

13 bit Timer using Timers 0 and 1

For writing programs involving Timers 0 and 1 needs configuration of TMOD, TCON and IE registers. Summary of these registers are shown in Table 11-1. Table 11-1 Summary of configuration bits for TMOD, TCON and IE registers Bits 7 6 TMOD register GATE1 C/T1# TCON register TF1 TR1 Interrupt Enable (IE) Register EA TCON and IE registers are bit addressable 5 M11 TF0 ET2 4 M01 TR0 ES 3 GATE0 IE1 ET1 2 C/T0# IT1 EX1 1 M10 IE0 ET0 0 M00 IT0 EX0

Program Task 1 Write an assembly program that sets up Timer 0 in Mode 0 (as a 13 bit timer) with software gate and toggles state of pin P0.0 of AT89C52 at every Timer 0 interrupt.

Listing 11-1

Assembly Program Listing Timer 0 in Mode 0 (Software Gate)

$INCLUDE (reg52.inc) org 000h ljmp begin org 00Bh ljmp it_timer0 org 0100h begin: ANL TMOD,#0F0h ; Timer 0 mode 0 with software gate ; GATE0=0; C/T0#=0; M10=0; M00=0; MOV TH0,#00h MOV TL0,#00h SETB ET0 SETB EA SETB TR0 JMP $ ; init values ; ; enable timer0 interrupt ; enable interrupts ; timer0 run ; endless loop ; Main program starts at 100h ; ISR location for Timer 0 interrupt

; FUNCTION_PURPOSE: timer0 interrupt ; FUNCTION_OUTPUTS: P0.0 toggle period ; = 2 * 12* 8192 crystal Hz it_timer0: CLR TF0 CPL P0.0 ; reset interrupt flag (already done by hardware) ; P0.0 toggle when interrupted

RETI end

Program Task 2 Write an assembly program that sets up Timer 1 in Mode 0 (as a 13 bit timer) with software gate and toggles state of pin P0.0 of AT89C52 at every Timer 1 interrupt. Listing 11-2 Assembly Program Listing Timer 1 in Mode 0 (Software Gate) $INCLUDE (reg52.inc) org 000h ljmp begin org 01Bh ljmp it_timer1 org 0100h begin: ANL TMOD,#0Fh ; Timer 1 mode 0 with software gate ; GATE1=0; C/T1#=0; M11=0; M01=0; MOV TH1,#00h MOV TL1,#00h SETB ET1 SETB EA SETB TR1 JMP $ ; init values ; ; enable timer0 interrupt ; enable interrupts ; timer0 run ; endless loop ; Main program starts at 100h ; ISR location for Timer 1 interrupt

; FUNCTION_PURPOSE: timer 1 interrupt

; FUNCTION_OUTPUTS: P0.0 toggle period ; = 2 * 12* 8192 crystal Hz it_timer1: CLR TF1 CPL P0.0 RETI end ; reset interrupt flag (already done by hardware) ; P0.0 toggle when interrupted

Note that in Program Tasks 1 and 2, the ISR location for Timer 0 and Timer 1 are different. Recall the vector addresses of different interrupts as shown in Table 11-2. When interrupts occur, the processor address pointer (instruction pointer) loads the processor assigned vector address and jumps to that address. In the main program body, the respective interrupt is enabled (ET0 = 1 or ET1 = 1) and than the global interrupt (EA = 1) by using the SETB instruction. Next the timer is enabled by setting TR0 or TR1 to 1. Table 11-2 Vector addresses of different interrupts External 0 Timer 0 (IE0) (TF0) 0003H 000BH External 1 Timer 1 (IE1) (TF1) 0013H 001BH Serial Port (RI or TI) 0023H Timer 2 (TF2 or EXF2) 002BH System Reset (RST) 0000H

Interrupt Vector Address

Inside the ISR routine (it_timer0 or it_timer1), the interrupt flag (TF0 or TF1) is cleared to reset the interrupt. This is already done by hardware, however, to ensure that the system is ready for next interrupt, clear it inside the ISR. The last instruction in the ISR is the RETI (return from interrupt) that will popup all the necessary addresses/data from the stack. Assignments Exercise 11-1 Implement the program tasks 1 and 2, and determine the frequency of the pulses at P0.0 for a 20MHz crystal clock. Also verify the theoretical frequency output. See the waveform pattern using an oscilloscope and draw the waveform with time scale. Exercise 11-2 Configure Timer 0 as a 16 bit timer and toggle the state of P0.0 using Timer 0 interrupt. Measure the frequency and duty cycle of the pulses at P0.0 for a 20MHz crystal clock.

Also verify the theoretical frequency output. See the waveform pattern using an oscilloscope and draw the waveform with time scale. Exercise 11-3 Repeat Exercise 11-2 for Timer 1.

11.1.2

16-bit Timer using Timers 0 and 1

Timers 0 or 1 can be configured as a 16-bit Timer/Counter in Mode 1. For Timer 0, in mode 1 M10 = 0, M00 = 1. For Timer 1, in mode 1 M11 = 0 and M01 = 1. Lets use Timer 0 in mode 1 for the 16-bit timer. The assembly program for 16-bit timer and toggling pin P1.0 with timer 0 interrupt is shown in program task 3. Program Task 3 Write an assembly program that sets up Timer 0 in Mode 1 (as a 16 bit timer) with software gate and toggles state of pin P2.0 of AT89C52 at every Timer 0 interrupt. Listing 11-3 Assembly Program Listing Timer 0 in Mode 1 (Software Gate) and generating square wave pulses at P2.0 with Timer 0 interrupt. $INCLUDE (reg52.inc) org 000h ljmp begin org 00Bh ljmp it_timer0 org 0100h begin: ANL TMOD,#0Fh ORL TMOD,#01h MOV TH0,#00h MOV TL0,#00h SETB ET0 SETB EA ; Timer 0 mode 1 with software gate ; GATE0=0; C/T0#=0; M10=0; M00=1; ; init values ; ; enable timer0 interrupt ; enable interrupts ; Main program starts at 100h ; ISR location for Timer 0 interrupt

SETB TR0 JMP $

; timer0 run ; endless loop

; FUNCTION_PURPOSE: timer 0 interrupt ; FUNCTION_OUTPUTS: P2.0 toggle period ; = 2 * 12* 65536 crystal Hz it_timer0: CLR TF0 CPL P2.0 RETI end ; reset interrupt flag (already done by hardware) ; P2.0 toggle when interrupted

With a 20 MHz crystal, the output frequency at P1.0 would be Program Task 4 Write an assembly program that sets up Timer 1 in Mode 1 (as a 16 bit timer) with software gate and toggles state of pin P2.0 of AT89C52 at every Timer 1 interrupt. Listing 11-4 Assembly Program Listing Timer 1 in Mode 1 (Software Gate) and generating square wave pulses at P2.0 with Timer 1 interrupt.

$INCLUDE (reg52.inc) org 000h ljmp begin org 01Bh ljmp it_timer1 org 0100h ; Main program starts at 100h ; ISR location for Timer 1 interrupt

begin: ANL TMOD,#0Fh ORL TMOD,#10h MOV TH1,#00h MOV TL1,#00h SETB ET1 SETB EA SETB TR1 JMP $ ; Timer 1 mode 1 with software gate ; GATE1=0; C/T1#=0; M11=0; M01=1; ; init values ; ; enable timer0 interrupt ; enable interrupts ; timer1 run ; endless loop

; FUNCTION_PURPOSE: timer 1 interrupt ; FUNCTION_OUTPUTS: P2.0 toggle period ; = 2 * 12* 65536 crystal Hz it_timer1: CLR TF1 CPL P2.0 RETI end ; reset interrupt flag (already done by hardware) ; P2.0 toggle when interrupted

11.1.3

C-Example

13-bit Timer Developing programs using C is comparatively easy and takes less time than assembly language. The SFR definitions are available in reg52x2.h header file.

Listing 11-5

C-program listing of 13-bit timer at Timer 0 in Mode 0.

#include "reg52x2.h" /** * FUNCTION_PURPOSE: This file set up timer 0 in mode 0 (13 bits timer) * with a software gate. */ void main(void) { TMOD &= 0xF0; /* Timer 0 mode 0 with software gate */ /* GATE0=0; C/T0#=0; M10=0; M00=0; */ TH0 = 0x00; TL0 = 0x00; ET0=1; EA=1; TR0=1; while(1); } /** * FUNCTION_PURPOSE: timer0 interrupt * FUNCTION_OUTPUTS: P2.0 toggle period = 2 * 12* 8192 Crystal Hz */ void it_timer0(void) interrupt 1 /* interrupt address is 0x000b */ { /* enable timer0 interrupt */ /* enable interrupts */ /* timer0 run */ /* endless loop*/ /* init values */

TF0 = 0;

/* reset interrupt flag (already done by hardware)*/ /* P2.0 toggle when interrupt */

P2_0 = ~P2_0; }

Although the SFR symbols used in example 11-5 are same as in assembly program, few things are new here. The shorthand &= is performing the AND immediate operation. Also look at the interrupt service routine and interrupt declaration. The interrupt declaration depends upon the compiler (the example is following RIDE compiler). The port bits are defined as Portname_bitname (Example: P2.0 is defined in reg52x2.h as P2_0). Large and complicated applications are difficult to manage using assembly as the file size becomes large. In such situations, the user can explore the power of C language that can easily manage complicated tasks with lesser text lines.

11.1.4

Auto Reload Mode (Mode 2) of Timers 0 and 1

The 13-bit and 16-bit timer modes have limited applications. As modes 0 or 1 produces very low frequency, these modes are not suitable for generating variable width pulses at high frequency. The auto reload mode in fact can configure the timer with flexibility of output frequency. In mode 2 with software gate, the interrupt frequency is

For a crystal of 12 MHz, finterrupt can be varied from 3.9 kHz to 1 MHz. The following program will produce a PWM pulse train at P2.0 with a duty of 80% at 1 kHz. The PWM frequency is obtained from the equation

... 11-1

... 11-2 For fPWM = 1 kHz and N = 30, reload_value = 201. Listing 11-6 80% duty. C program listing of PWM pulse generated at P2.0 of AT89C52 at 1 kHz and

#define reload_value

201

#include "reg52x2.h" /** * PURPOSE: This file set up timer 0 in mode 2 with a software gate */ unsigned char count = 0, count_max = 30; void main(void) { TMOD &= 0xF0; TMOD |= 0x02; TH0 = reload_value; TL0 = reload_value; ET0=1; EA=1; TR0=1; P2_0 = 0; while(1); } /* enable timer0 interrupt */ /* enable interrupts */ /* timer0 run */ /* Initialize P2.0 */ /* endless */ /* Timer 0 mode 0 with software gate */ /* GATE0=0; C/T0#=0; M10=1; M00=0; */ /* init values */

void it_timer0(void) interrupt 1 /* interrupt address is 0x000b */ { TF0 = 0; /* reset interrupt flag*/ count++;

if (count == 6)P2_0 = 1; /* 6 to 30 on */ if (count == 30) { P2_0 = 0; count = 0; } } /* 1 to 6 off */

Examine output of program 11-6 at P2.0 (pin 21) of AT89C52 with a 20 MHz crystal. It is supposed to produce a PWM waveform of 80% duty at 1 kHz. Exercise 11-4 Write an assembly program that would a generate a PWM waveform at P2.0 of AT89C52 with a variable duty. A low signal at P1.0 would increase the duty whereas a low signal at P1.1 would decrease the duty. The PWM switching frequency should remain constant at 1 kHz.

11.2 Pulse Width Modulation


New generation microcontrollers are normally equipped with PWM channels because of extensive motor control applications. Pulse width modulation needs continuous pulse train with adjustable widths but fixed frequency. Normally, the PWM frequency is set above the audible range (more than 4 kHz). AT89C52 does not have any built in PWM module. However, a timer can be used in auto reload mode to produce PWM waveforms of fixed frequency. For this purpose the auto reload value will have to be changed between two values circularly. Suppose timer 0 is loaded with a reload value RL_ON. After (256-RL_ON) counts it will produce a timer 0 interrupt. This interrupt will be used to reset the state of P2.0 (P2.0 = 0) and load the timer 0 with a reload value of RL_OFF. Then after (256-RL_OFF) counts, there will be another timer 0 interrupt. This interrupt will be used to set P2.0 (P2.0 = 1) and load timer 0 with a reload value of RL_ON. This will repeat circularly and produce a PWM pulse train at P2.0.

Reload value = RL_ON, P2.0 = 1 Reload value = RL_OFF, P2.0 = 0 T1

T2

Figure 11-1 PWM waveform generation technique using timer interrupt in auto reload mode PWM frequency and Duty Cycle Calculations In auto reload mode of Timer 0 or Timer 1, the interrupt occurs at the end of 256auto_reload_value. The time duration is given by,

... 11-3

... 11-4

... 11-5

... 11-6 From equation 11-5 and 11-6, it is evident that for constant switching frequency, the sum of RL_ON and RL_OFF should be kept constant. The duty cycle adjustment can be done by adjusting the vale of RL_ON and RL_OFF but the sum should be a constant value.

11.2.2

DC Motor Speed Control

The AT89C52 can be used for dc motor speed control using pulse width modulation technique. The hardware schematic is shown in Figure 11-2. The scheme is an open loop control that would give variable duty PWM pulses at the Darlington transistor U2. Speed control is done by pressing switches SW1 and SW2. Pressing SW1 will increase the speed, while, pressing SW2 will decrease the speed. Because of using interrupts, on line control is possible without system interruption.

Figure 11-2 DC motor control using pulse width modulation driven from AT89C52 microcontroller

Listing 11-7

C program for PWM pulse generation at P2.0 with fixed switching frequency but variable duties depending on control inputs at P1.0 and P1.1.

#include "reg52x2.h"

/* * FUNCTION_PURPOSE: This file set up timer 0 in mode 2 * with a software gate.

duty = (256-RL_OFF)/[512-(RL_ON+RL_OFF)] */ unsigned char RL_ON = 192, RL_OFF = 64; bit flag = 1; unsigned int count = 0;

void main(void) { TMOD &= 0xF0; TMOD |= 0x02; TH0 = RL_ON; TL0 = RL_ON; ET0=1; EA=1; TR0=1; P2_0 = 0; while(1); } /* enable timer0 interrupt */ /* enable interrupts */ /* timer0 run */ /* Initialize P2.0 */ /* endless */ /* Timer 0 mode 0 with software gate */ /* GATE0=0; C/T0#=0; M10=1; M00=0; */ /* init values */

void it_timer0(void) interrupt 1 { TF0 = 0; if (flag == 1) { P2_0 = 0; TH0 = RL_OFF; } if (flag == 0) { P2_0 = 1; TH0 = RL_ON; } count++; if (count == 1000) {

/* interrupt address is 0x000b */

/* reset interrupt flag*/

if (P1_0 == 0) RL_ON++; if (RL_ON >240) RL_ON = 240; // Upper limit if (P1_1 == 0) RL_ON--; if (RL_ON < 16) RL_ON = 16; // Lower Limit RL_OFF = RL_total - RL_ON; count = 0;

} flag = ~flag;

11.2.3

Assignments for Exercise


Write a C program to generate PWM pulses on pin P2.0 of AT89C52 at a frequency of 10 kHz with variable duty capability. Assume crystal frequency of 20 MHz. The PWM output from P2.0 would drive a permanent magnet dc motor. The controls for the program would be Increase duty if P1.0 = 0 Decrease duty if P1.1 = 0 Stop the motor if P1.2 = 0 Restart the motor if P1.3 = 0

Exercise 11-5

Exercise 11-6

Add the following features to the problem of Exercise 11-5: On reset or a new start, the motor will start with a low duty and gradually attain the set duty

11.2.4

DC Servo Motor Speed Control

In most applications there is a need for bidirectional speed/position control of DC motor. A dc motor drive capable of moving in both directions is often called a dc servo. A simple dc servo drive is shown in Figure 11-3. The scheme in this form can be used for bidirectional speed control. However, a position feedback would make it a servo. There are four inputs given from push buttons for controlling the motor. SW1 SW2 SW3 SW4 Forward or Reverse selection Increase Speed Decrease Speed Start/Stop Button

The fifth switch SW5 is for reset purpose. The DPDT relay controls the direction of motion of the motor by providing +Ve or Ve voltage across the dc motor armature. Motor speed is controlled by adjusting the PWM signal obtained from P2.1, with the Darlington transistor U5 acting as a chopper switch.

Figure 11-3 Bidirectional speed control of a dc motor using AT89C52 C Program Listing for Bidirectional Speed Control #include "reg52x2.h" bit onoff_flag = 1, Direction_old = 1,Direction_new = 1; bit ONOFF_old = 1, ONOFF_new = 1; unsigned int K1 = 500, K2 = 500, Kmax = 1000; void delay (unsigned int i) { while (i--); }

void main(void) { P2 = 0; while(1) /* endless */ { if (P1_1 == 0)K1++; if (K1 > 900) K1= 900; if(P1_2 == 0)K1--; if(K1 < 100) K1 = 100; K2 = Kmax - K1; P2_1 = onoff_flag; // PWM pattern sent to P2_1 delay(K1);

P0_0 = ~P0_0; P2_1 = 0; delay(K2); Direction_new = P1_0; if (Direction_new == 0 && Direction_old == 1) // PB1 pressed ? { P0_1 = ~P0_1; // Toggle if PB1 toggled P2_0 = ~P2_0; // Toggle Direction Relay } Direction_old = Direction_new;

ONOFF_new = P1_3; // Check state of on/off button if (ONOFF_new == 0 && ONOFF_old == 1) // PB4 pressed ? { onoff_flag = ~onoff_flag; /* Change Start/Stop state of the Motor if PB4 is pressed */ } ONOFF_old = ONOFF_new; } }

You might also like