1. Welcome to our site! Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.
    Dismiss Notice
Ian Rogers

Simple interrupts on the 8051

Interrupts on 8051

  1. Ian Rogers
    Following on from the Simple Interrupts on the mid range PIC's found here..
    http://www.electro-tech-online.com/articles/simple-interrupts-on-mid-range-pics.640/
    (Notice the title change )

    I have done the similar article on the humble 8051... I've kept it generic so the code will work on every variation...

    So you can get started there is an IDE that I use as a test bed.. Its quite a good IDE / Simulator for the 8051.. you can download it here.. http://mcu8051ide.sourceforge.net/

    The C compiler I use for the 8051 is SDCC ( Small Device C Compiler ).. Again you can download it here..
    http://sdcc.sourceforge.net/

    You can use Kiel free version to compile these small code snippets. There are other free compilers, but I haven't used them... MPU8051IDE compiles the C code as well..

    We start with timer 0 as I did with the pic example, I'll show you in ASM and in C how to setup and use the interrupts so you can use them in your code... As with the PIC the 8051 has registers that need attention to get your interrupts up and working..

    The IE register is that register...

    ie reg.png

    As you can see Timer 0 is bit 1 ET0.. Set this bit to logic 1 and the interrupt will fire when timer 0 overflows... Bit 5 and bit 6 are not used on the basic 8051..

    There is also a global interrupt EA that controls all the interrupts!!

    Now! Unlike the PIC's the 8051 has several interrupt vectors instead of the single vector on the mid range PIC.. Vector is the name given to jump position allocated to each interrupt... For example here are the 8051 interrupt vectors..

    0x00 = Reset vector... You can insert a AJMP ( absolute jump ) to the beginning of your main code routine..
    0x03 = EXO vector.. Jump to the code that deals with an external change on the INT0 ( pin 12 )..
    0x0B = ETO vector.. Jump to the code that deals with an overflow on the timer 0 register..
    0x13 = EX1 vector.. Jump to the code that deals with an external change on the INT1 ( pin 13 )..
    0x1B = ET1 vector.. Jump to the code that deals with an overflow on the timer 1 register..
    0x23 = ES vector.. Jump to the code that deals with a character received or transmitted on the serial port..

    Heres the code for setting up and using timer 0 as an interrupt.
    Code (asm):

    $mod51

    ISRvar    equ    0x30        ; Reserve a byte to hold a count

        org    0x0
        sjmp    Main        ; Short jump to our main code

        org    0x0B
        ajmp    ISR        ; Absolute jump to the ISR
    Main:
        mov    TMOD,#0x03    ; 8 bit counter no reload
        mov    TH0,#0x00    ; Clear
        mov    TL0,#0x0    ; timer regs
        setb    TR0        ; start timer 0
        setb    ET0        ; set timer 0 interrupt
        setb    EA        ; Set global interrupts
        clr    ISRvar        ; clear count byte

    while:
        mov    P0, ISRvar    ; Put the count
        sjmp    while        ; On PORT 0

    ISR:
        mov    A, ISRvar    ; Get variable into Acc
        inc    Acc        ; inrease by one
        mov    ISRvar,Acc    ; stick it back

        reti

        end
     
    A couple of points to go over here! I have used the TMOD register..
    The TMOD register controls the way the timer is implemented..

    M01 and M00.. ( bits 1 and 0 ) Mode.
    00 = 8 bit Timer with pre-scaler (TLO = pre-scale)
    01 = 16 bit timer.
    10 = 8 bit timer with re-load. (TH0 = reload value )
    11 = 8 bit timer with no pre-scaler.

    CT0.. ( bit 2 ) Counter / timer .
    1 = increment timer on pulses on the T0 ( pin 14).
    0 = increment timer from system clock.

    G0.. ( bit 3 ) Gate control.
    1 = INT0 and TR0 controls timer..
    0 = TR0 controls timer.

    Bits 4~7 are the same but for timer 1..

    Here is the C equivalent...
    Code (c):

    #include <mcs51reg.h>

    volatile int ISRvar;    // ISR counter variable.

    void Timer0_ISR(void) __interrupt (1)
        {
        ISRvar++;        // Increment counter variable.
        }

    void main(void)
        {
        TMOD = 0x3;        // Timer mode.
        TL0 = 0;        // Clear
        TH0 = 0;        // Reg's.
        TR0 = 1;        // Set timer to run.
        ET0 = 1;        // Set interrupt.
        EA = 1;            // Set global interrupt.
        while (1)
            {
            P0 = ISRvar;    // P0 display's counter.
           }
        }
     
    With C you need to specify the interrupt number.. Here I have used __interrupt (1)
    This can be found in the C documentation....


    There are priority settings... You can select each interrupt to a high or low setting.. High priority take precedent over the low priority interrupts. This can be found in the IP0 register..

    1p0 reg.png

    1 = High priority
    0 = low priority

    The precedence of importance ( if they are all set high / low ) is as the register itself. EX0 is the highest and ES is the lowest.

    As with the other tutorial I will do the external interrupt.

    Here is the asm code.
    Code (asm):

        org    0x0
        sjmp    Main        ; Short jump to our main code

        org    0x03
        ajmp    ISR        ; Absolute jump to the ISR
    Main:
        setb    EX0        ; set INT0 interrupt
        setb    EA        ; Set global interrupts
        clr    ISRvar        ; clear count byte

    while:
        mov    P0, ISRvar    ; Put the count
        sjmp    while        ; On PORT 0

    ISR:
        mov    A, ISRvar    ; Get variable into Acc
        inc    Acc        ; increase by one
        mov    ISRvar,Acc    ; stick it back

        reti

        end
     
    And of course for completeness here is the C version
    Code (c):

    #include <mcs51reg.h>

    volatile int ISRvar;    // ISR counter variable.

    void INT_ISR(void) __interrupt (0)
        {
        ISRvar++;        // Increment counter variable.
        }

    void main(void)
        {
        EX0 = 1;        // Set interrupt.
        EA = 1;            // Set global interrupt.
        while (1)
            {
            P0 = ISRvar;    // P0 display's counter.
           }
        }
     
    Finally we put them together to have two interrupts running at the same time.
    Code (asm):

    $mod51

    ISRvar    equ    0x30        ; Reserve a byte to hold a count

        org    0x0
        sjmp    Main        ; Short jump to our main code

        org    0x03
        ajmp    ISRint        ; Absolute jump to the ISR for int0

        org    0x0B
        ajmp    ISRtim        ; Absolute jump to the ISR for timer
    Main:
        mov    TH0,#0x00       ; Clear
        mov    TL0,#0x0       ; timer regs
        setb    TR0           ; start timer 0
        setb    ET0           ; set timer 0 interrupt
        setb    ET0        ; set Tmer interrupt
        setb    EX0        ; set INT0 interrupt
        setb    EA        ; Set global interrupts
        clr    ISRvar        ; clear count byte

    while:
        mov    P0, ISRvar    ; Put the count
        sjmp    while        ; On PORT 0

    ISRint:
        clr    ISRvar
        reti

    ISRtim:
        mov    A, ISRvar    ; Get variable into Acc
        inc    Acc        ; increase by one
        mov    ISRvar,Acc    ; stick it back

        reti

        end
     
    And the same again in C...

    Code (c):

    #include <mcs51reg.h>

    volatile int ISRvar;    // ISR counter variable.

    void int_ISR(void) __interrupt (0)
        {
        ISRvar = 0;        // Reset counter variable.
        }

    void Timer0_ISR(void) __interrupt (1)
        {
        ISRvar++;        // Increment counter variable.
        }

    void main(void)
        {
        TMOD = 0x3;        // Timer mode 3
        TH0 = 0;        // Clear
        TL0    = 0;        // registers
        TR0    = 1;        // Start timer
        ET0 = 1;        // Set timer interrupt
        EX0 = 1;        // Set int0 interrupt.
        EA = 1;            // Set global interrupt.
        while (1)
            {
            P0 = ISRvar;    // P0 display's counter.
           }
        }
     
    Notice that in C, the level precedence is 0 ( highest )
    Also remember that there is no debounce function on the INT0 pin so if this were to be used in a real device, this must be taken into account..

    This concludes this little example... I am going to do more tutorials for the 8051 in a similar fashion as this..

    If you have any questions, or you would like me to concentrate on a specific piece of code then leave a comment and I'll reply as soon as I can.

    Cheers
    Ian
    RonaldB likes this.

Recent Reviews

  1. RonaldB
    RonaldB
    5/5,
    Nice tutorial. Started late on 8051, but I'll give it a try. Good thing the C code was included...bit readable than the ASM.