Interrupts

8051 derivatives acknowledges an interrupt request by executing a hardware generated LCALL to the appropriate servicing routine ISRs.
ISRs are organized in IVT. ISR is defined as a standard function but with the iv directive afterwards which connects the function with specific interrupt vector.

For example, 0x000B is IVT address of Timer 0 Overflow interrupt source of the AT89S8253, and the symbolic name for this interrupt vector in mikroPascal PRO for 8051 is IVT_ADDR_ET0.
Symbolic interrupt name list can be accessed by using Code Assistant, i.e. by typing the IVT and pressing Ctrl+Space in the Code Editor.

For more information on interrupts and IVT refer to the specific datasheet.

Interrupt Handling

For the sake of interrupt handling convenience, new keyword, iv, is introduced. It is used to declare IVT address for a defined interrupt routine :

procedure interrupt(); iv IVT_ADDR_ET0; ics ICS_OFF;
begin
  // Interrupt service routine code
end;

where :

Now it is possible to explicitly declare interrupt routine address :

procedure Timer0_Interrupt(); org 0x600; iv IVT_ADDR_ET0;  // Interrupt routine will be placed on the address 0x600
begin
   asm nop;
end;

For the sake of backward compatibility, user may write also :

procedure Timer0_Interrupt(); org IVT_ADDR_ET0;
begin
   asm nop;
end;

which is equivalent to :

procedure Timer0_Interrupt(); iv IVT_ADDR_ET0;
begin
   asm nop;
end;

Is is recommended that interrupts are handled in this way for the sake of better readability of the user projects.

Function Calls from Interrupt

Calling functions from within the interrupt routine is allowed. The compiler takes care about the registers being used, both in "interrupt" and in "main" thread, and performs "smart" context-switching between them two, saving only the registers that have been used in both threads. It is not recommended to use function call from interrupt. In case of doing that take care of stack depth.

Disable Context Saving

Use the DisableContextSaving to instruct the compiler not to automatically perform context-switching. This means that no regiser will be saved/restored by the compiler on entrance/exit from interrupt service routine.
This enables the user to manually write code for saving registers upon entrance and to restore them before exit from interrupt.

Interrupt Priority Level

8051 MCUs has possibilty to assign different priority level trough setting appropriate values to coresponding SFRs. You should also assign ISR same priority level by ilevel keyword followed by interrupt priority number.
Available interrupt priority levels are: 0 (default), 1, 2 and 3.

Interrupt Example

Here is a simple example of handling the interrupts from Timer1 (if no other interrupts are allowed) :

program Timer1_Interrupt;

//-------------- Interrupt handler routine
procedure Timer1InterruptHandler(); org IVT_ADDR_ET1;
begin
  EA_bit := 0;        // Clear global interrupt enable flag

  TR1_bit := 0;       // Stop Timer1
  TH1 := 0x00;        // Reset Timer1 high byte
  TL1 := 0x00;        // Reset Timer1 low byte

  P0 := not P0;       // Toggle PORT0

  EA_bit := 1;        // Set global interrupt enable flag
  TR1_bit := 1;       // Run Timer1
end;

begin
  P0  := 0;           // Initialize PORT0

  TF1_bit := 0;       // Ensure that Timer1 interrupt flag is cleared
  ET1_bit := 1;       // Enable Timer1 interrupt
  EA_bit  := 1;       // Set global interrupt enable

  GATE1_bit := 0;     // Clear this flag to enable Timer1 whenever TR1 bit is set.
  C_T1_bit  := 0;     // Set Timer operation: Timer1 counts the divided-down systam clock.
  M11_bit   := 0;     // M11_M01 = 01    =>   Mode 1(16-bit Timer/Counter)
  M01_bit   := 1;

  TR1_bit := 0;       // Turn off Timer1
  TH1 := 0x00;        // Set Timer1 high byte
  TL1 := 0x00;        // Set Timer1 low byte
  TR1_bit := 1;       // Run Timer1
end.

Most of the MCUs can access interrupt service routines directly, but some can not reach interrupt service routines if they are allocated on addresses greater than 2K from the IVT. In this case, compiler automatically creates Goto table, in order to jump to such interrupt service routines.

These principles can be explained on the picture below :

Accessing interrupt service routines

Direct accessing interrupt service routine and accessing interrupt service routine via Goto table.

Copyright (c) 2002-2013 mikroElektronika. All rights reserved.
What do you think about this topic ? Send us feedback!
Want more examples and libraries? 
Find them on LibStock - A place for the code