Interfacing the Keyboard to 8051 Micro Controller

38
Interfacing the Keyboard to 8051 microcontroller By Nagabhooshan S.Shet The key board here we are interfacing is a matrix keyboard. This key board is designed with a particular rows and columns. These rows and columns are connected to the microcontroller through its ports of the micro controller 8051. We normally use 8*8 matrix key board. So only two ports of 8051 can be easily connected to the rows and columns of the key board. When ever a key is pressed, a row and a column gets shorted through that pressed key and all the other keys are left open. When a key is pressed only a bit in the port goes high. Which indicates microcontroller that the key is pressed. By this high on the bit key in the corresponding column is identified. Once we are sure that one of key in the key board is pressed next our aim is to identify that key. To do this we firstly check for particular row and then we check the corresponding column the key board. To check the row of the pressed key in the keyboard, one of the row is made high by making one of bit in the output port of 8051 high . This is done until the row is found out. Once we get the row next out job is to find out the column of the pressed key. The column is detected by contents in the input ports with the help of a counter. The content of the input port is rotated with carry until the carry bit is set. The contents of the counter is then compared and displayed in the display. This display is designed using a seven segment display and a BCD to seven segment decoder IC 7447. The BCD equivalent number of counter is sent through output part of 8051 displays the number of pressed key.

Transcript of Interfacing the Keyboard to 8051 Micro Controller

Page 1: Interfacing the Keyboard to 8051 Micro Controller

Interfacing the Keyboard to 8051 microcontroller

 By Nagabhooshan S.Shet     

           The key board here we are interfacing is a matrix keyboard. This key board is designed with a particular rows and columns. These rows and columns are connected to the microcontroller through its ports of the micro controller 8051. We normally use 8*8 matrix key board. So only two ports of 8051 can be easily connected to the rows and columns of the key board.

          When ever a key is pressed, a row and a column gets shorted through that pressed key and all the other keys are left open.  When a key is pressed only a bit in the port goes high.  Which indicates microcontroller  that the key is pressed. By this high on the bit key in the corresponding column is identified.

          Once we are sure that one of key in the key board is pressed next our aim is to identify that key.   To do this we firstly check for particular row and then we check the corresponding column the key board.

          To check the row of the pressed key in the keyboard, one of the row is made high by making one of bit in the output port of 8051 high .  This is done until the row is found out.  Once we get the row next out job is to find out the column of the pressed key. The column  is detected by contents in the input ports with the help of a counter. The content of the input port is rotated with carry until the carry bit is set.

          The contents of the counter is then compared and displayed in the display. This display is designed using a seven segment display and a BCD to seven segment decoder IC 7447.

          The BCD equivalent number of counter is sent through output part of 8051 displays the number of pressed key.

          Circuit diagram of INTERFACING  KEY BOARD TO 8051.

The programming algorithm, program and the circuit diagram is as follows. Here program is explained with comments.

Page 2: Interfacing the Keyboard to 8051 Micro Controller

Circuit diagram of INTERFACING  KEY BOARD TO 8051.

Keyboard is organized in a matrix of rows and columns as shown in the figure. The microcontroller accesses both  rows and columns through the port. 

1. The 8051 has 4 I/O ports P0 to P3 each with 8 I/O pins, P0.0 to P0.7,P1.0 to P1.7, P2.0 to P2.7, P3.0 to P3.7. The one of the port P1 (it understood that P1 means P1.0 to P1.7) as an I/P port for microcontroller 8051, port P0 as an O/P port of microcontroller 8051 and port P2 is used for displaying the number of pressed key.

2.  Make all rows of port P0 high so that it gives high signal when key is pressed.

3.  See if any key is pressed by scanning the port P1 by checking all columns for non zero condition.

4.  If any key is pressed, to identify which key is pressed make one row high at a time.

5.  Initiate a counter to hold the count so that each key is counted.

6.  Check port P1 for nonzero condition. If any nonzero number is there in [accumulator], start column scanning by following step 9.

7.  Otherwise make next row high in port P1.

8.  Add a count of 08h to the counter to move to the next row by repeating steps from step 6.

Page 3: Interfacing the Keyboard to 8051 Micro Controller

9.  If any key pressed is found, the [accumulator] content is rotated right through the carry until carry bit sets, while doing this increment the count in the counter till carry is found.

10.  Move the content in the counter to display in data field or to   memory location

11.  To repeat the procedures go to step 2. 

Program to interface matrix keyboard to microcontroller 8051

Start of main program:   

to check that whether any key is pressed

                        start:   mov a,#00h                                    mov p1,a             ;making all rows of port p1 zero                                    mov a,#0fh                                         mov p1,a             ;making all rows of port p1 high                        press:   mov a,p2                                    jz press                ;check until any key is pressed after making sure that any key is pressed                                     mov a,#01h         ;make one row high at a time                                      mov r4,a                                     mov r3,#00h        ;initiating counter                        next:    mov a,r4                                    mov p1,a             ;making one row high at a time                                     mov a,p2             ;taking input from port A                                    jnz colscan          ;after getting the row jump to check                                                                      column                                    mov a,r4                                    rl a                       ;rotate left to check next row                                    mov r4,a                                    mov a,r3                                    add a,#08h         ;increment counter by 08 count                                    mov r3,a                                    sjmp next           ;jump to check next row after identifying the row to check the colomn following steps are followed                   colscan:    mov r5,#00h                           in:    rrc a               ;rotate right with carry until get the carry                                    jc out             ;jump on getting carry                                    inc r3             ;increment one count                                    jmp in                                    out:    mov a,r3                                    da a                ;decimal adjust the contents of counter                                                                     before display                                    mov p2,a                                    jmp start       ;repeat for check next key.

Page 4: Interfacing the Keyboard to 8051 Micro Controller

Interfacing 7-segment display using 7447 decoder

by Ranjith | August 17th, 2009.

The Light Emitting Diode (LED), finds its place in many applications in this modern electronic fields. One of them is the Seven Segment Display. Seven-segment displays contains the arrangement of the LEDs in “Eight” (8) passion, and a Dot (.) with a common electrode, lead (Anode or Cathode). The purpose of arranging it in that passion is that we can make any number out of that by switching ON and OFF the particular LED’s. Here is the block diagram of the Seven Segment LED arrangement.

Pin configuration of a seven segment display:

LED’s are basically of two types:

1. Common Cathode (CC)All the 8 anode legs uses only one cathode, which is common.

2. Common Anode (CA)The common leg for all the cathode is of Anode type.

For the discussion purpose, we use CC LED, where by just reversing the logical voltages we can implement the same for CA LED also.

In a CC LED, all the 8 legs (’a’ through ‘h’) are of anode type and the common cathode will be connected to the GND of the supply. By energizing any of the legs with +5 Volts will lead to switch the correspondent segment ON. In the microprocessor binary system, 0Volts will be considered as Binary 0, and 5Volts will be considered as Binary1. Considering these two condition, we can make an arrangement as the microcontroller gives OUT the 0s and 1s through its ports, which is connected to the 8 legs of the LED.

Page 5: Interfacing the Keyboard to 8051 Micro Controller

Of course, we can control the Port Output; implicitly we can Switch-ON required legs of the display.

There 2 methods of interfacing LED with the Microcontroller Intel 8051/8951.

1. Using lookup table. This uses 7 output pins of microcontroller 2. Using 7447 decoder. This method uses 4 output pins of microcontroller

The difference between the two main methods is simple and clear. In both the cases, microcontroller communicates with external world through its ports. But, in the 1st case, we connect all the 8 pins of the port directly to the LED and control the voltage through the ports manually to display the desired number. But, in the second case, we send the BCD of the number that we wanted to display to a middleware IC 7447, the BCD to LED code converter, which by itself gives out the correspondent 7 segment codes to the LED.

Here we explain using lookup table. Click here for the method “using 7447 decoder”

Using 7447 decoder:

The IC7447 is a BCD to 7-segment pattern converter. This setup is the advanced form of the <previous> setup where we entered the patterns manually to display the desired character. Here in this case, the IC7447 takes the Binary Coded Decimal (BCD) as the input and outputs the relevant 7 segment code. We connect first four pins of the microcontroller Port 2  to the 7447 and the Output 8 pins of 7447 to the 8 legs of the LED as shown in the figure. Te circuit diagrams are shown below, the first figure is interfacing the CA LED where as the second is of CC LED. The number required to display is sent as the lower nibble of the Port 2 of the Microcontroller. The 7447 converts the four input bits (BCD) to their corresponding 7-segment codes. The outputs of the 7447 are connected to the 7-segment display.

Page 6: Interfacing the Keyboard to 8051 Micro Controller

Circuit diagram for interfacing Common Anode 7-Segment Display

Circuit diagram for Common Cathode 7-Segment Display

Program:

This program displays characters 0 through 9 on seven-segment display using IC 7447 as the middle wear.  again: mov a,#00h ; Start form zero

Page 7: Interfacing the Keyboard to 8051 Micro Controller

up: mov p2, a ; Move to Port 2 mov r3,#255 ; Delay D1: mov r1,#255 D: djnz r1,D djnz r3,D1 inc a cjne a,#0ah,up sjmp again

Interfacing 7-segment display using 7447 decoder

by Ranjith | August 17th, 2009.

The Light Emitting Diode (LED), finds its place in many applications in this modern electronic fields. One of them is the Seven Segment Display. Seven-segment displays contains the arrangement of the LEDs in “Eight” (8) passion, and a Dot (.) with a common electrode, lead (Anode or Cathode). The purpose of arranging it in that passion is that we can make any number out of that by switching ON and OFF the particular LED’s. Here is the block diagram of the Seven Segment LED arrangement.

Pin configuration of a seven segment display:

LED’s are basically of two types:

1. Common Cathode (CC)All the 8 anode legs uses only one cathode, which is common.

2. Common Anode (CA)The common leg for all the cathode is of Anode type.

For the discussion purpose, we use CC LED, where by just reversing the logical voltages we can implement the same for CA LED also.

Page 8: Interfacing the Keyboard to 8051 Micro Controller

In a CC LED, all the 8 legs (’a’ through ‘h’) are of anode type and the common cathode will be connected to the GND of the supply. By energizing any of the legs with +5 Volts will lead to switch the correspondent segment ON. In the microprocessor binary system, 0Volts will be considered as Binary 0, and 5Volts will be considered as Binary1. Considering these two condition, we can make an arrangement as the microcontroller gives OUT the 0s and 1s through its ports, which is connected to the 8 legs of the LED. Of course, we can control the Port Output; implicitly we can Switch-ON required legs of the display.

There 2 methods of interfacing LED with the Microcontroller Intel 8051/8951.

1. Using lookup table. This uses 7 output pins of microcontroller 2. Using 7447 decoder. This method uses 4 output pins of microcontroller

The difference between the two main methods is simple and clear. In both the cases, microcontroller communicates with external world through its ports. But, in the 1st case, we connect all the 8 pins of the port directly to the LED and control the voltage through the ports manually to display the desired number. But, in the second case, we send the BCD of the number that we wanted to display to a middleware IC 7447, the BCD to LED code converter, which by itself gives out the correspondent 7 segment codes to the LED.

Here we explain using lookup table. Click here for the method “using 7447 decoder”

Using 7447 decoder:

The IC7447 is a BCD to 7-segment pattern converter. This setup is the advanced form of the <previous> setup where we entered the patterns manually to display the desired character. Here in this case, the IC7447 takes the Binary Coded Decimal (BCD) as the input and outputs the relevant 7 segment code. We connect first four pins of the microcontroller Port 2  to the 7447 and the Output 8 pins of 7447 to the 8 legs of the LED as shown in the figure. Te circuit diagrams are shown below, the first figure is interfacing the CA LED where as the second is of CC LED. The number required to display is sent as the lower nibble of the Port 2 of the Microcontroller. The 7447 converts the four input bits (BCD) to their corresponding 7-segment codes. The outputs of the 7447 are connected to the 7-segment display.

Page 9: Interfacing the Keyboard to 8051 Micro Controller

Circuit diagram for interfacing Common Anode 7-Segment Display

Circuit diagram for Common Cathode 7-Segment Display

Program:

This program displays characters 0 through 9 on seven-segment display using IC 7447 as the middle wear.  again: mov a,#00h ; Start form zero

Page 10: Interfacing the Keyboard to 8051 Micro Controller

up: mov p2, a ; Move to Port 2 mov r3,#255 ; Delay D1: mov r1,#255 D: djnz r1,D djnz r3,D1 inc a cjne a,#0ah,up sjmp again

ADC-DAC InterfacingAnalog signals are very common inputs to embedded systems .Most transducers and sensors

such as temperature ,pressure ,velocity ,humidity are analog. Therefore we need to convert

these analog signals in to digital so that 8051 can read it.

 

 ANALOG DIGITAL TO CONVERTER - ADC

Commonly used ADC device – ADC804

 

ABOUT IC

  PinOut

 • CS – Chip Select , active low

 • RD – Read Digital data from ADC, H-L edge triggered

 • WR -- Start conversion, L-H pulse edge triggered

 • INTR -- end of conversion, Goes low to indicate conversion done

 • Data bits -- D0-D7

 • CLK IN & CLK R

–  CLK IN is an input pin connected to an external clock source when an external clock is used

for timing. However, ADC804 has an internal clock  

   generator.

   To use the internal clock generator of the ADC804, the CLK IN and CLK R pins are connected

to a capacitor and a resistor. In that case, the  

   clock frequency is determined by the equation.

 

   f = 1/1.1RC

   R=10K and C=150pF f=606Hz

   the conversion time is 110us. 

Page 11: Interfacing the Keyboard to 8051 Micro Controller

 

 Input Voltage range

• Default 0-5V. Can be changed by setting

different value for Vref/2 pin.

   Vin=Vin(+) – Vin (-)

• Range = 0 to 2x Vref/2.

    for Vin = 2x Vref/2. we get 256 as a digital output on D0-D7. (Refer Table)

•Step Size a Smallest change

– (2 x Vref/2)/ 256 for ADC804

for eg for  step size 10mv ,digital output on D0-D7 changes by one count for every 10mv

change of  the input analog

voltage.

 Data Out

 Dout = Vin / Step Size

for input vtg. of 2.56 volts

(Vref=1.28 volts)  and

stepsize of 10mv Dout

=2560/10 =256  or FF that is

full scale output.

Conversion Time

 Greater than 110us for

ADC804 

Resolution

 8 bits for ADC804

 

INTERFACING ADC804 TO 8051

Signals to be interfaced (on the ADC804)

– D0-D7, RD, WR, INTR, CS

 Can do both Memory mapping and IO mapping

 

Vref/2

(Volts)

Vin

(Volts)

Step size (mV)

Open (2.5) 0 to 5 5/256 = 19.53

2.56 0 to 5.12 5.12/256 =20

1.28 0 to 2.56 2.56/256 = 10

0.5 0 to 1 1/256=3.90

Page 12: Interfacing the Keyboard to 8051 Micro Controller

Memory Mapping (timing is critical)

– Connect D0-D7 of ADC804 to the data bus of the 8051 system

– Connect RD, WR of the ADC804 to the 8051 system (ensure polarity)

– Connect CS of ADC804 to an appropriate address decoder output

– Connect INTR of ADC804 to an external interrupt Pin on the 8051 (INT0 or INT1) 

IO Mapping (easiest - I prefer )

– Connect D0-D7, RD, WR, CS, INTR to some port bits on the 8051 (12 in all).

 

 

Algorithm

• Make CS=0 and send a low-to-high to pin WR to start the conversion.

• Keep monitoring INTR

– If INTR =0, the conversion is finished and we can go to the next step.

– If INTR=1, keep polling until it goes low.

• After INTR=0, we make CS=0 and send a high-to-low pulse to RD to get the data out of the

ADC804 chip.

 

ASSEMBLY LANGUEGE       (A51)

 

 

 

 

 

 

 

ADC_IO:

mov P1, #0xff ; To configure as input

 

AGAIN

clr p3.7 ;Chip select

setb P3.6 ;RD=1

clr P3.5 ;WR=0

setb P3.5 ;WR=1- low to high transition

 

WAIT:

 jb P3.4, WAIT ;wait for INTR

clr p3.7 ;generate cs to ADC

clr P3.6 ;RD=0 -High to low transition

mov A, P1 ;read digital o/p

Page 13: Interfacing the Keyboard to 8051 Micro Controller

sjmp AGAIN

 

 

 

INTERFACING ADC804 TO 8051

 

ADC808/809 Chip with 8 analog channel. This means

this kind of chip allows to monitor 8 different

transducers.

• ADC804 has only ONE analog input: Vin(+).

• ALE: Latch in the address

• Start : Start of conversion (same as WR in 804)

• OE: output enable (same as RD in 804)

• EOC: End of Conversion (same as INTR in 804)

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Channel C B A

IN0 000

IN1 001

IN2 010

IN3 011

IN4 100

IN5 101

IN6 110

IN7 111

Page 14: Interfacing the Keyboard to 8051 Micro Controller

Algorithm

Notice that the ADC808/809 that there is no self-clocking and the clock must be provided from

an external source to the CLK pin. (you can use programmable clock oscillator to enable or

disable clock by programmable bit. )

 

• Select an analog channel by provide bits to A, B, C.

• Enable clock

• Activate ALE with a low-to-high pulse.

• Activate SC with a high-to-low pulse (start conversion) The conversion is begun on the falling

edge of the start conversion pulse. you can use circuit like

• Monitor EOC Pin .After conversion this pin goes high.

• Activate OE with a high-to-low pulse to read data out of the ADC chip.

 

 

 

DIGITAL TO ANALOG CONVERTER - DAC

 Commonly used DAC808 (MC1408)

– R/2R ladder

– Iout = Iref (D7/2 + D6/4 + D5/8 + …… + D0/256)

– Iout converted to voltage by a resistive load or op-amp based isolator (Rf from Vout to V- and

V+ to GND)

 

PinOut

– D0-D7 à Connected to the Processor’s IO port

– Vref+, Vref-, Vee

 

Usage:

– Just write a byte to the IO port and the DAC converts it to an

   analog value

   Some 8051 clones have ADCs and DACs in built

 

Page 15: Interfacing the Keyboard to 8051 Micro Controller

PROGRAM TO INTERFACE ADC

 

   

The ADC804 is an analog to digital converter, which converts analog voltage to its digital equivalent. Resolution of this IC is 8 bits and works with +5V. If input voltage 5V then converted digital output is FF.

Pin description is as follows:

CS : Chip Select:

It is an active low input used to activate the ADC804 IC. To activate ADC804, this pin must be low.

RD : Read:

It is an active low input used to get the converted data out of the ADC chip. The ADC converts the analog input to its binary equivalent and holds in an internal register. When a CS = 0 and high-to-low pulse is applied to the RD pin, then 8-bit digital output is available at the D0-D7 data pins.

WR : Write:

This is an active low input used to inform the ADC to start the conversion process. ADC starts converting analog input to digital, when CS = 0 and a low-to-high pulse is applied to WR pin. The amount it takes to convert varies depending on the CLK IN and CLK R values. When the data conversion is complete, the INTR pin is forced low by the ADC804.

Page 16: Interfacing the Keyboard to 8051 Micro Controller

Here ADC 0804 is connected to port1 of 8051.WR and INTR of ADC is connected to P3.4 and P3.5 respectively. Analog input is applied to pin 6 of ADC. Here WR is the start of conversion and INTR is the end of conversion. In this program if input voltage accedes certain range then 8255 sets corresponding bits 

             mov a,#80h        

             mov p2,#ffh                    ; configuring port 2 as i/p

    start: clr p3.4                            ; low to high signal to WR, start of conversion

             setb p3.4

   here3: jb p3.5,here3                    ; check whether conversion is over, pin-INTR

             mov a,p2

             mov r5,a

             mov r6,a

             subb a,#cch                    ; check whether i/p is greater than 4V

             jc L4v                             ; jump if input is less than 4V              mov P3,#10h                    ; send high signal to 5th line

             jmp last

     L4v: mov a,r5

             subb a,#99h                    ; check whether i/p is greater than 3V

             jc L3v                             ; jump if input is less than 3V

             mov P3,#08h                    ; send high signal to 4th line

             jmp last

     L3v: mov a,r5

             subb a,#66h                    ; check whether i/p is greater than 2V

             jc L2v                             ; jump if input is less than 2V

Page 17: Interfacing the Keyboard to 8051 Micro Controller

             mov P3,#04h                     ; send high signal to 3rd line

             jmp last

     L2v: mov a,r5

             subb a,#33h                    ; check whether i/p is greater than 1V

             jc L1v                             ; jump if input is less than 1V

             mov P3#02h                     ; send high signal to 2nd line

             jmp last

    L1v: mov a,r5

            mov P3,#01h                      ; send high signal to 1st line

    last: mov r1,#0ffh  

   here: djnz r1,here

            mov r2,#0ffh

 here1: djnz r2,here1

            jmp start

            .end

Related source codes :

Interrupts       Revision of Timers   In an earlier section we looked at the 8051 timers and how we could use them to generate a pulse train of a particular frequency on a port pin (for example).   Below is a program for generating a pulse train of 10KHz on port 1 pin 0.      

MOV TMOD, #02H ;initialize timer 0 as 8-bit auto-reload timerMOV TH0, #0CEH ;set timer 0 high-byte to produce 50us delay (assuming system clock frequency of 12MHz)SETB TR0 ;start timer 0waitForOverflow:

JNB TF0, waitForOverflow ;if timer 0 overflow bit is not set, repeat this instructionCLR TF0 ;reset timer 0 overflow bitCPL P1.0 ;invert (complement) port 1 pin 0JMP waitForOverflow      Busy Waiting   The above program implements what is known as busy waiting. In the line JNB TF0, waitForOverflow the CPU is continuously executing the same instruction - testing the overflow bit of timer 0 and waiting for it to change to 1. In other words, the CPU is busy testing the bit while waiting for its value to change.   Last year, when we wrote programs to exercise the timers and the serial port, we always used busy waiting. The CPU would sit in a loop, testing a bit (the timer overflow bit, the data received bit, the data transmitted bit) waiting for it to be set. The setting of the bit announced an event. If it was a timer overflow bit it announced the timer's overflow to zero, if it was the serial port transmit interrupt bit it announced the complete transmission

Page 18: Interfacing the Keyboard to 8051 Micro Controller

of a byte, if it was the serial port receive interrupt bit it announced the arrival of an entire byte of data. All of these are events. The CPU waits for these events, continuously testing the appropriate bit and waiting for it to be set.       Advantages of busy waiting:  

Easy to implement. Relatively easy to test - step through the program and at each point it can be

determined what the next instruction to be executed will be.

  Disadvantages of busy waiting:   The CPU is tied up with a mundane task when it could be off doing something

more useful. Continuous CPU operation is heavy on power consumption - not good for battery

operated devices. If more than one event needs to be tracked busy waiting becomes difficult to

implement (need to test more than one bit in the busy waiting loop and deal with whichever event occurs. While dealing with this event, another event may occur and be missed because the CPU was not in its busy waiting loop).

If some events have higher priorities than others and must be dealt with before lower priority events, busy waiting becomes almost impossible to implement.

          Interrupts   An interrupt is the occurrence of an event that causes a temporary suspension of a program while the event is serviced by a section of code known as the interrupt service routine.   Modern operating systems use interrupts to produce the illusion of a multiprocessor computer. A computer may be running many applications at the same time, say a word processor, a CD player and a web server. All of the applications think they have sole access to the CPU. However, since there is only one processor in the computer (in most cases) then this cannot be the case.   In reality, they are all sharing the CPU. The operating system (OS) hands the CPU to one process (in OS terms, an programs or applications are known as processes) for a set amount of time (perhaps milliseconds) and then hands it over to the next process for a set amount of time, and so on until it gets back to the initial process. This form of CPU sharing is known as round robin scheduling and we will talk about it more when we deal with the section on real-time operating systems.       How is one process stopped so that another can get the CPU? After all, the process has the CPU, therefore the operating system itself is not running and therefore it cannot stop the running process. The answer is an interrupt. The running process is interrupted after its allotted CPU time has elapsed and the operating system takes the CPU so that it can then hand the CPU over to the next process. The interrupt is generated by the hardware.   The operating system uses a hardware timer to generate this interrupt. The sequence is as follows:  

1. The OS initializes the timer to count for a specified time.2. The OS starts the timer.3. The OS hands the CPU over to the next process in the list (ie; the list of processes

that are waiting to use the CPU). The OS is now no longer running.4. The timer overflows and generates an interrupt.5. The interrupt forces the program counter to jump to the interrupt service routine

(ISR).6. The ISR jumps to step 1 above.

Page 19: Interfacing the Keyboard to 8051 Micro Controller

      Desktop operating systems are not the only software systems to make use of interrupts. They are heavily used in embedded systems. Most systems deal with external events through interrupts. For example, when you press a key on your mobile phone, the keypad sends an interrupt signal to the microcontroller. The microcontroller is then forced to jump to the ISR, regardless of what it was doing in its main program.   The diagram below illustrates a system program flow with interrupts.  

      Interrupt events can internal or external. The interrupt described in the OS above is an internal interrupt generated by a timer overflow. An example of an external interrupt is a signal generated by a key press on a keypad.       8051 Interrupts   The 8051 has five interrupt sources.  

Two external interrupts are provided through pins INTO-bar and INT1-bar, which are the alternate functions of port 3 pin 2 and port 3 pin 3, respectively.

Two internal interrupts are generated by timer 0 overflow and by timer 1 overflow.

The serial port on the 8051 can generate an interrupt when a byte has been transmitted or when a byte is received.

  The interrupt flag bits are detailed below.  

Interrupt Flag Location

External 0 IE0 TCON.1

External 1 IE1 TCON.3

Timer 0 TF0 TCON.5

Timer 1 TF1 TCON.7

Serial Port Receive RI SCON.0

Serial Port Transmit TI SCON.1

     

When an interrupt occurs the following happens:

  The current instruction completes execution. The PC is saved on the stack (ie; the address of the next instruction). The address of the ISR for the interrupt is loaded into the PC.

Page 20: Interfacing the Keyboard to 8051 Micro Controller

  Interrupt Vectors   When an interrupt occurs the address of the interrupt service routine is loaded into the PC. This address is known as the interrupt vector.   The table below details the interrupt vectors for the 8051.      

Interrupt Flag Vector

System reset RST 0000H

External interrupt 0 IE0 0003H

Timer 0 TF0 000BH

External interrupt 1 IE1 0013H

Timer 1 TF1 001BH

Serial port RI or TI 0023H

  A system reset is a special type of interrupt. It interrupts the running program and loads the PC with the vector address 0000H. This is the address the microcontroller begins with on power-up. Therefore, reset is similar to powering down and the powering up the system.   When an interrupt in the 8051 occurs, the vector address, as shown above, is loaded into the PC. For example, if timer 1 overflows (and interrupts are enabled; we'll talk more about enabling and disabling interrupts shortly) the PC is loaded with the value 001BH. The programmer must ensure the ISR for timer 1 is placed at this address.       Not much room for the ISRs   When you examine the vector table above you will notice there are only eight memory locations between the vectors. If our ISRs are short, this is not a problem. For example, if we need an ISR for dealing with timer 1 and we also need one for dealing with the serial port, then the timer 1 ISR, placed at location 001BH, cannot take up more than eight memory locations because it would then take up the space reserved for the serial port ISR.   The solution is simple. At location 001BH we put a jump to somewhere else in code memory and at this point we put our timer 1 ISR.       Enabling and Disabling Interrupts   As can be seen from the interrupt vector table above, the timer interrupt flags are TF0 and TF1 and the serial interrupt flags are RI and TI. We used these flags during the second year of the course. For example, we waited for timer 0 to overflow by testing the state of the timer overflow flag, TF0. If this is the case, why didn't the timer overflowing (setting TF0) cause an interrupt?   The answer is simple: we did not enable interrupts.   On power-up or reset all interrupts are disabled. To enable interrupts we set the appropriate bits in the interrupt enable SFR. This register is detailed below.  

SymbolBit Number

Description

EA 7

Enable/disable all interrupts. If this bit is cleared all interrupts are disabled. If it is set each interrupt source is individually enabled or disabled by setting or clearing the appropriate enable bit, as detailed below.

-- 6  

-- 5  

ES 4 Enable/disable serial port interrupts (set to enable,

Page 21: Interfacing the Keyboard to 8051 Micro Controller

clear to disable).

ET1 3Enable/disable timer 1 overflow interrupt (set to enable, clear to disable).

EX1 2Enable/disable external 1 interrupt (set to enable, clear to disable).

ET0 1Enable/disable timer 0 overflow interrupt (set to enable, clear to disable).

EX0 0Enable/disable external 0 interrupt (set to enable, clear to disable).

  To enable an interrupt we must set the EA bit and then set the appropriate interrupt enable bit. For example, to enable the timer 0 overflow interrupt we would write the following code:  

SETB EASETB ET0  To disable an interrupt we simply clear the appropriate interrupt enable bit. For example, to disable the timer 0 overflow interrupt:  

CLR ET0      Why is there a global enable bit (EA)?   You may be curious as to why the EA bit exists at all. It seems pointless to have to set it and then set the individual enable bit to enable an interrupt. However, there is a very good reason for having the EA bit. There are sections of code known as critical sections (we will deal with these when we discuss operating systems in the Embedded Software class) that must not be interrupted. In other words, a critical section of code must be allowed to complete in entirety without being interrupted. To ensure this, when entering a critical section, all interrupts are disabled (CLR EA). Then, when leaving the critical section, the global enable bit is set (SETB EA). In this way, whatever interrupts were enabled prior to entering the critical section are again enabled when the critical section has been complete.   Take a look at the code below for an example.  

SETB EA ;enable all interrupts SETB ET0 ;enable timer 0 interruptSETB EX1 ;enable external 1 interrupt (remaining 3 interrupt sources remain disabled)...; entering a critical sectionCLR EA ;disable interrupts; execute critical section codeSETB EA; exit critical section; interrupts ET0 and EX1 are again enabled (remaining 3 interrupt sources

Page 22: Interfacing the Keyboard to 8051 Micro Controller

remain disabled)      If we take the above code as an example, the programmer writing the critical section code doesn't need to know which interrupts are enabled. He/she simply disables all interrupts at the start of the critical section and then sets the global enable bit on exiting the critical section, therefore re-enabling whichever interrupts had been enabled in the first place.       Polling Sequence   What happens if two interrupts of the same priority occur at the same time? (We will deal with interrupt priority in a moment - for now take it that all interrupts have the same priority.) The 8051 has a definite polling sequence that deals with simultaneous interrupts. Each interrupt is serviced in the following order:   External 0 followed by Timer 0 Overflow followed by External 1 followed by Timer 1 Overflow followed by the Serial Port.   Therefore, if for example an interrupt occurs on timer 1 and external 1 at the same time, external 1 will be serviced before timer 1.       Interrupt Priority   In most systems, some events are more important than others. For example, imagine a microwave oven in operation (ie; heating food). Let's also imagine a user presses a key on the keypad and opens the oven door at the same time. The interrupt caused by opening the door is more important than the interrupt caused by the key press (when the oven door is opened the microwave must immediately shut down, regardless of what's being pressed on the keypad) and it should be serviced first.   Therefore, microcontrollers are designed so that interrupts can be prioritized. The 8051 has only two interrupt priority levels, 0 and 1, with 1 being the high priority. On reset, all interrupts are set at the low priority. To set an interrupt to high priority we set the appropriate bit in the interrupt priority (IP) SFR, as detailed below.  

SymbolBit Number

Description

-- 7  

-- 6  

-- 5  

PS 4Serial port interrupt priority level.

PT1 3Timer 1 interrupt priority level.

PX1 2External interrupt 1 priority level.

PT0 1Timer 0 interrupt priority level.

PX0 0External interrupt 0 priority level.

  An interrupt service routine (ISR) can itself be interrupted. If a low priority interrupt is being serviced while a high priority interrupt occurs, the low priority ISR is interrupted (in exactly the same way as the main program is interrupted) and the high priority interrupt is serviced. Once the high priority ISR completes execution begins again at the next instruction in the low priority ISR.   An ISR cannot be interrupted by an interrupt of

Page 23: Interfacing the Keyboard to 8051 Micro Controller

the same or lower priority.   The 8051 has only two priority levels, but some microcontrollers/microprocessors have more than two levels. If we imagine for a moment a microcontroller that has eight priority levels 0 to 7, with 7 as the highest priority. In this case a level 5 ISR (for example) can only be interrupted by interrupts at levels 6 and 7.     Some Examples   Generating a 10KHz pulse train on port 1 pin 0 using interrupts.   A 10KHz signal has a cycle of 100us. Therefore we need an interrupt to occur every 50us (pulse train of 50% duty cycle - 50us at 1, 50us at 0). To achieve this we will enable timer 0 overflow interrupt and set up timer 0 so that it overflows every 50us.   Assuming a 12MHz system clock implies the timer will step once every 1us - we need the timer to count from (256 - 50) 206 to overflow. We can do this with the 8-bit auto-reload mode.  

ORG 0 ; reset vectorJMP main ; jump above interrupt vectorsORG 000BH ; timer 0 interrupt vectorCPL P1.0 ; invert port 1 pin 0RETI ; return from interruptORG 0030H ; main program entry pointmain:MOV TMOD, #02H ; timer 0 in 8-bit auto-reload timer modeMOV TH0, 0CEH ; put 206 decimal into TH0SETB TR0 ; start timer 0SETB EA ; global interrupt enableSETB ET0 ; enable timer 0 interruptJMP $ ; do nothing but wait for interrupt      The code in boldface is the ISR. When timer 0 overflows (every 50us) the following occurs:  

PC is saved on the stack PC gets 000BH (interrupt vector for timer 0) Execution begins in ISR (in this case it simply inverts P1.0) RETI takes the PC off the stack - execution beings again in the main program

where it left off (in this case the JMP $ instruction)

  The ORG statements are assembler directives. They are not part of the 8051 code. They simply tell the assembler where in code memory to place the following section of code. The reset vector for the 8051 is 0. Therefore, when the 8051 powers up or is reset, the PC is loaded with 0 and the first instruction executed is that stored at location 0.   When using interrupts we do not want our main program to write over the area reserved for the ISRs. Therefore, our first instruction (at location 0) is a jump to somewhere in code memory above the ISR vectors (in the above example we jump to 0030H).   The ORG 000BH directive causes the assembler to place the following piece of code (our timer 0 ISR) at location 000BH. This is the timer 0 interrupt vector, ie; this is the address automatically placed in the PC (by hardware) when an interrupt occurs on timer 0 (and timer 0 interrupt is enabled).       Servicing More Than One Interrupt   Let's say we wish to generate two pulse trains of differing frequencies. For example, to generate a 7KHz pulse train on P1.7 and a 500Hz pulse train on P1.6, we could use the following code:  

Page 24: Interfacing the Keyboard to 8051 Micro Controller

ORG 0 ; reset vectorJMP main ; jump above interrupt vectorsORG 000BH ; timer 0 interrupt vectorCPL P1.7 ; invert port 1 pin 7RETI ; return from interruptORG 001BH ; timer 1 interrupt vectorJMP timer1ISR ; jump to timer 1 ISRORG 0030H ; main program entry pointmain:

MOV TMOD, #12H ; timer 0 in 8-bit auto-reload timer mode, timer 1 in 16-bit modeMOV TH0, #0B9H ; put (256 - 71) 185 decimal into TH0SETB TR0 ; start timer 0SETB TF1 ; force timer 1 interruptSETB ET0 ; enable timer 0 interruptSETB ET1 ; enable timer 1 interruptSETB EA ; global interrupt enableJMP $ ; do nothing but wait for interrupttimer1ISR:CLR TR1 ; stop timer 1MOV TH1, #0FCHMOV TL1, #18H ; initialize timer 1 with (65536 - 1000) 64536 (FC18HSETB TR1 ; start timer 1CPL P1.6 ; invent port 1 pin 6RETI   A 7KHz pulse train has a cycle of 143us. With a duty cycle of 50% the time delay required for generating the 7KHz pulse train is 71us. This can be achieved using one of the timers in mode 2 (8-bit auto reload). The code above uses timer 0 to generate the 7KHz pulse train on P1.7.   A 500Hz pulse train has a cycle of 2ms. Again, with a duty cycle of 50% this results in a time delay of 1ms (1000us). This is too long of a delay to be achieved using the 8-bit auto reload mode. Therefore, timer 1 is put into 16-bit mode. However, this requires the timer be initialized with the starting value (64536) each time it overflows. To achieve this, the timer is first stopped in the ISR and the value FC18H is loaded, the timer started again and the pin (P1.6) is inverted.   Notice in the main program a timer 1 interrupt is forced through software. This is to start the timer initially. Once the interrupts are enabled execution will jump to the timer 1 ISR and the timer is initialized and started. Then, 1ms later, a timer 1 overflow interrupt will occur and the timer will be initialized again.   Also note that timer 0 ISR is left at the reset vector since it is such a short ISR. However, since there are only 8 bytes between each vector, timer 1 ISR is moved elsewhere in code memory (after the main program in this example) and a jump to the ISR is placed at timer 1's reset vector.       What if both interrupts occur simultaneously?   If it happens that both timer 0 and timer 1 overflow at the same time, the polling sequence says the interrupt on timer 0 will be serviced before timer 1. This is acceptable in this situation because timer 0 is being used to generate the higher frequency

Page 25: Interfacing the Keyboard to 8051 Micro Controller

signal. If the P1.6 pin is not inverted exactly every 1ms (because a few microseconds are lost while servicing timer 0) then this is not very noticeable in the low frequency signal.   However, if timer 1 is being serviced when timer 0 overflows, timer 0 will have to wait because both interrupt sources are at the same priority level (low level) and no ISR can be interrupted by an interrupt of the same priority. This could present a problem because the microseconds that are lost while servicing timer 1 would be noticeable in the higher frequency signal on P1.7. Therefore, the main program should be altered as shown below: main:

MOV TMOD, #12H ; timer 0 in 8-bit auto-reload timer mode, timer 1 in 16-bit modeMOV TH0, 0B9H ; put (256 - 71) 185 decimal into TH0SETB TR0 ; start timer 0SETB TF1 ; force timer 1 interruptSETB PT0 ; set timer 0 overflow to high priority interruptSETB ET0 ; enable timer 0 interruptSETB ET1 ; enable timer 1 interruptSETB EA ; global interrupt enableJMP $ ; do nothing but wait for interrupt  Timer 0 is set to high priority. Therefore, if timer 1 is being serviced and an overflow occurs on timer 0, timer 1 ISR will be suspended and timer 0 will be serviced. Timer 0 ISR is very short (just invert P1.7 and return) so the time lost there will not be noticed on the P1.6 signal, while at the same time the higher frequency signal on P1.7 is kept accurate.           Serial Port Interrupts   There is only one serial port interrupt vector in the 8051, at address 0023H. However, there are two serial port interrupt sources - TI and RI.  

TI is set by hardware when an entire character has been transmitted from SBUF down the serial line.

RI is set by hardware when an entire character has been received on the serial line and is waiting in SBUF to be read by the program.

  Since the serial port can be used to transmit and receive data at the same time, the serial port ISR must first check to see which source caused the interrupt.       The serial port flags are not automatically cleared when vectoring to the ISR.   As we saw when dealing with interrupts on the timers, the timer overflow flag is cleared by hardware when the CPU vectors to the interrupt vector address. In other words, if the timer's interrupt is enabled, when an overflow occurs the hardware automatically resets the interrupt flag.   It is very important to note that this is NOT the case with the serial port interrupt flags. Since the same vector is used for both TI and RI, the ISR must first check to see which of the two flags actually caused the interrupt and then clear this interrupt flag. Clearing the serial port interrupt flags is the responsibility of the software, not the hardware.       Repeatedly Sending the ASCII Character Set on the Serial Line   The program below shows how to send the ASCII character set (excluding the control characters) down the serial line, starting with the space character (20H) and progressing through the set to the last character (7EH) and back to the start again. This program will loop indefinitely.   A

Page 26: Interfacing the Keyboard to 8051 Micro Controller

Baud rate of 9600 with a system clock frequency of 12MHz is generated (see notes on the 8051 serial port for more information on setting the serial port Baud rate).  

ORG 0JMP main ORG 0023H ; serial port interrupt vectorJMP serialPortISR ; jump to serial port ISRORG 0030H ; main program entry pointmain:

MOV TMOD, #20H ; timer 1 in 8-bit auto-reload timer modeMOV TH1, 0FDH ; high byte value to generate baud rate of 9600SETB TR1 ; start timer 1CLR SM0SETB SM1 ; clearing SM0 and setting SM1 puts serial port into mode 1SETB TI ; force serial port transmit interruptMOV A, #20H ; send ASCII space character first by initializing A to 20HSETB ES ; enable serial port interruptsSETB EA ; global interrupt enableJMP $ ; do nothing but wait for interruptserialPortISR:CJNE A, #7FH, skip ; if A does not contain 7FH (the end of the ASCII sequence) skip next lineMOV A, #20H ; if A contains 7FH replace it with the start of the sequence (20H - the space character) skip:MOV SBUF, A ; send character to serial portINC A ; increment to next character in ASCII sequenceCLR TI ; clear the transmit interrupt flagRETI       In the above example, since we are only transmitting data, when a serial port interrupt occurs we know it has been caused by the transmission of an entire byte. Therefore, our serial port ISR does not need to test to see whether the interrupt was caused by TI or RI. It simply transmits the next character and then clears TI.       Transmitting and Receiving on the Serial Port   If our system transmits and receives data on the serial port at the same time then we need to first check to see which flag (TI or RI) actually caused the interrupt.   A typical serial port ISR for dealing with this is shown below.   serialPortISR:JNB RI, testTI ; if RI is not set jump to testing TICLR RI ; if RI is set clear itCALL dataReceived ; and call subroutine for dealing with received byte testTI:JNB TI, endSerialPortISR ; if TI is not set jump to endCLR TI ; if TI is set clear itCALL dataSent ; and call subroutine that deals with an entire byte sent (most likely to send another byte)

Page 27: Interfacing the Keyboard to 8051 Micro Controller

endSerialPortISR:RETI  In the above ISR, RI is tested to see if the interrupt was caused by a received byte. If so it jumps to the subroutine for dealing with this case, after first clearing RI. It then checks to see if TI is set. Take note, a byte may have been sent at the same time as a byte was received and therefore both RI and TI may be set together. Therefore, the ISR must test TI even if it found RI was set. If TI is set it jumps to the subroutine for dealing with this case, after first clearing TI.   It is important to test RI before testing TI. If RI is set then we must deal with this received byte as soon as possible because another byte may be on the way, whereas it is less critical if some time is lost between transmitting bytes.           External Interrupts   External interrupts occur as a result of a low-level or negative edge on the INT0-bar or INT1-bar pins on the 8051 (INT0-bar is at P3.2 while INT1-bar is at P3.3).   The flags that generate these interrupts are IE0 and IE1 in the TCON register.  

As stated above, the interrupt may be caused by either a low-level or a negative edge on the INTx-bar pin. The choice of low-level activation or edge activation can be programmed through the IT0 and IT1 bits in the TCON register. For example, to set external interrupt 0 as low-level activated and external interrupt 1 as edge activated we could write the following:

  CLR IT0SETB IT1  The external interrupt pins are sampled (ie; tested) once every machine cycle. If the interrupts are level activated, the external source (the peripheral, such as a keypad, that causes the interrupt) must ensure the interrupt pin is kept low for at least one machine cycle. With the basic 8051 running at 12MHz the machine cycle is 1us.   If the external interrupt is set to edge activation then the external source must ensure the pin is kept high for one complete machine cycle and then low for one complete machine cycle. In this way, the CPU will see a negative edge on the interrupt pin and set the flag accordingly (IE0 or IE1).       Controlling the Level of Liquid in a Tank   The diagram below shows a tank interfaced (via suitable electronic circuitry) to the 8051. The output value is controlled via P1.0; a logic 0 opens the valve while a logic 1 closes it.   The input value is similarly controlled via P1.1; a logic 0 on this port pin opens the valve while a logic 1 cloeses it. Since, on reset, all 8051 port pins are at logic 1, both valves will initially be closed.   A liquid level sensor is connected to the external 1 interrupt (INT1). This sensor produces a logic 0 when the liquid level is higher than max (red line).   Similarly, a level sensor connected to the external 0 interrupt (INT0) produces a logic 0 when the liquid is lower than min (green line).  

Page 28: Interfacing the Keyboard to 8051 Micro Controller

      There is some process, controlled by the 8051, that makes use of the liquid in this tank. Whenever the process requires liquid from the tank, P1.0 is cleared and when enough liquid has been taken from the tank the output valve is closed by setting P1.0. However, for this example of the use of external interrupts, this process is of no concern to us. We simply wish to write the code for handling the two interrupts.       When the liquid in the tank drops below the minimum level, the INT0 line will go from HIGH to LOW: a negative edge. The external 0 ISR should then open the input value in order to start filling the tank.   When the level in the tank reaches the maximum, the INT1 line will go from HIGH to LOW: a negative edge. The external 1 ISR should then close the input value in order to stop filling the tank.      

ORG 0JMP mainORG 0003H ; external interrupt 0 vectorCLR P1.1 ; open input valveRETIORG 0013H ; external interrupt 1 vectorSETB P1.1 ; close input valveRETIORG 0030Hmain:

SETB IT0 ; set external interrupt 0 as edge activatedSETB IT1 ; set external interrupt 1 as edge activated SETB EX0 ; enable external interrupt 0SETB EX1 ; enable external interrupt 1SETB EA ; global interrupt enable JB P3.2, skip ; if INT0-bar (P3.2) is logic 1 then the liquid level is above min, therefore skip next instructionCLR P1.1 ; if INT0-bar is logic 0 the liquid level is below min, therefore turn open input valve

Page 29: Interfacing the Keyboard to 8051 Micro Controller

skip:... ; continue with main program (the process that makes use of the liquid in the tank)       The ISRs are very simple. An external 0 interrupt occurs when the liquid level is too low, therefore the ISR at vector 0003H simply opens the input valve. An external 1 interrupt occurs when the liquid level is too high, therefore the ISR at vector 0013H simply closes the input valve.   It should be noted that the choice of applying the min-liquid sensor to INT0-bar and the max-liquid sensor to INT1-bar is completely arbitrary; the system would work exactly the same if we swapped the sensors from one external interrupt pin to the other, as long as we also swapped the ISRs.   The main program performs the initialization. However, if the liquid level is already too low we will never see a negative edge on INT0-bar (it is already at 0, and will remain at 0, because the temperature is too low). We therefore need to check to see if INT0-bar (which is at P3.2) is at logic 1. If it is logic 1 it means the liquid level is not too low and we can jump to the end of the initialization. However, if P3.3 is 0 then we must open the input valve and then proceed with the main program.