AN506

Domino 1 & Domino 2

Interrupt Handler for INT1

04/01/01

Introduction: This application note will illustrate how to create an interrupt handler for External Interrupt 1 on the Domino 1 and Domino 2 controllers.

 

Background: The user has the option of using the BASIC-52 interrupt instruction (ONEX1) or writing their own interrupt handler to service the interrupts. While the Basic instructions are convenient, they are much slower than an assembly language interrupt handler. If speed is important in your program, a custom assembly language interrupt service routine is the way to go.

 

How it works: Upon power-up of the Domino controllers, the BASIC interpreter disables all interrupts. External Interrupt 1 (INT1), is enabled by setting bit 7 and bit 2 in the Interrupt Enable (IE) register. The interrupt can be programmed to be level-activated or transition-activated by setting or clearing bit IT1 (bit 2 in the TCON Register). If IT1=0, external interrupt 0 is triggered by a detected low at the INT1 pin. If IT1=1, external interrupt 1 is edge triggered. For this application IT1=0. INT1 is located on Port 3 pin 3 (P3.3). Port 3 on the 80C52 processor is a multi-functional port. Upon power-up, P3.3 is cleared enabling its primary function (bi-directional I/O). Bit P3.3 needs to be set to enable the secondary function (INT1). This is done in line 50 of the sample Basic code provided.

In the 80C52, the interrupts are vectored to specified address locations. The vector address for External Interrupt 1 is 13H. When an interrupt occurs, a hardware LCALL instruction pushes the contents of the Program Counter onto the stack, and then loads the appropriate vector address. At the vector address, BASIC-52 checks to see if it should respond to the interrupt. If BASIC-52 isn’t going to handle the interrupt, it pushes the Program Status Word onto the stack and LJMPs to the handler vector, which is located at 04013H. The user needs to place a LJMP in the handler vector that points to the address of the handler routine.

When the jump is made to the Interrupt Service Routine (ISR) a few important register values need to be saved so that when the return is made to BASIC the program can pick up exactly where it was interrupted. If the serial port is being used the first thing that needs to be done is to check and see if there is a transmission in progress. If there is, then the ISR should wait for the transmission to finish. Then the SCON, ACC, DPH and DPL registers should be pushed onto the stack (the ACC, DPH and DPL only need to be saved if the user wants to preserve them, saving isn’t always necessary). BASIC-52 pushed the Program Counter and the Program Status Word (PSW) onto the stack when the interrupt was generated. When the ISR is finished the user must pop off all the registers placed on the stack. The last register that was pushed must be the first register popped off. Even though BASIC pushed the PSW onto the stack the user is responsible for popping it off. The Program Counter is popped off when the RETI is executed.

The sample program listed illustrates how to write an ISR. This particular program counts from 0 to 50 and then displays the number. The program is interrupted when a logic low is present on INT1. When the interrupt is generated the words ‘Program Interrupt’ are transmitted out the serial port. The start address (ORG address) of the ISR is 0C000H. The ISR was assembled using the ASEM_51 assembler and was stored using Micromints STOREHEX.BAS routine. The LJMP pointing to the ISR was stored into 04013H using the XBY instruction

Program Listing:

Assembly Language ISR:

ORG 0C000H

 

JNB SCON.1,$ ; Wait for serial transmission to finish

PUSH SCON ; Save SCON to stack

PUSH ACC ; Save ACC to stack

CLR SCON.1 ; CLR Transmit interrupt flag

LCALL XM ; Transmit "Program Interrupted"

POP ACC ; Retrieve ACC from stack

POP SCON ; Retrieve SCON pushed by user

POP PSW ; Pop PSW pushed by BASIC

RETI ; Return from interrupt

XM: MOV A,#0DH ; "CR"

LCALL SND

MOV A,#0AH ; "LF"

LCALL SND

MOV A,#050H ; "P"

LCALL SND

MOV A,#072H ; "r"

LCALL SND

MOV A,#06FH ; "o"

LCALL SND

MOV A,#067H ; "g"

LCALL SND

MOV A,#072H ; "r"

LCALL SND

MOV A,#061H ; "a"

LCALL SND

MOV A,#06DH ; "m"

LCALL SND

MOV A,#020H ; "ASCII FOR SPACE"

LCALL SND

MOV A,#049H ; "I"

LCALL SND

MOV A,#06EH ; "n"

LCALL SND

MOV A,#074H ; "t"

LCALL SND

MOV A,#065H ; "e"

LCALL SND

MOV A,#072H ; "r"

LCALL SND

MOV A,#072H ; "r"

LCALL SND

MOV A,#075H ; "u"

LCALL SND

MOV A,#070H ; "p"

LCALL SND

MOV A,#074H ; "t"

LCALL SND

MOV A,#0DH ; "CR"

LCALL SND

MOV A,#0AH ; "LF"

LCALL SND

RET

 

SND: MOV SBUF,A ; Move contents out Serial Port

JNB SCON.1,$ ; Wait until buffer is empty

CLR SCON.1 ; CLR Transmit interrupt flag

RET ; Return

END

Basic sample program:

10 XBY(04013H)=02H REM** Poke LJMP to ISR into memory

20 XBY(04014H)=0C0H REM** MSByte of ISR address

30 XBY(04015H)=00H REM** LSByte of ISR address

40 IE=84H REM** Enables external interrupt 0

50 DBY(0B3H)=1 REM** Enables P3.2 secondary function

60 FOR X = 0 TO 100 REM** Counter

70 PRINT X

80 FOR Y = 0 TO 50 : NEXT Y REM** Delay

90 NEXT X