Can Interrupts Cause Permanent Branching in 8051 Microcontrollers?

  • Thread starter Jiggy-Ninja
  • Start date
In summary, an interrupt can cause a branch to a specific location in code, but you need to be careful to initialize the state of everything after the interrupt jumps.
  • #1
Jiggy-Ninja
309
1
I'm messing around with an 8051 microcontroller (DS89C450 if it makes a difference) and I'm trying to get a handle on how interrupts work, and what they can and can't do.

I'm working with Assembly right now, not C.

The program I made has a few songs in it's memory (very simple ones like "We Three Kings" and "Star-Spangled Banner"), and will start playing one at start up. Which one it plays depends on how a couple switches are set.

What I want to do is hook a pair of push buttons to the interrupt pins on P3; INT0 will reset and repeat the current song from the beginning regardless of the switch settings, and INT1 will reset and reload a new song.

Details aside, the essence of what I want to do is to make the interrupts cause a permanent branch to a specific location, at which point the interrupt ends and the program keeps running from that point. I don't want it to pick up where it left off after the interrupt is done.

So far, the only way I can think of doing this is something rather kludgy, like this:
Code:
mov     DPTR, #Song
pop     R1
pop     R1                    ;  Popping the original return address from stack
push   DPH                   ;  Push the new address onto the stack
push   DPL                   ;  or whatever order these two need to be in
reti
* Song is a label in the code.

Needs to be modified a bit to protect the original value of DPTR, but you should get the basic concept.

For the record, I understand that polling the buttons might be a better solution,and would be trivially easy to do in my program. I already have a main loop that polls the timers (Though I might change one of them to an interrupt), so adding two more polls isn't much of a hassle. I'm not trying to do this for the most efficient or workable program, I'm trying to do this in order to understand interrupts better.
 
Engineering news on Phys.org
  • #2
This one has a nice description of the interrupt structure:
http://www.dcc.ttu.ee/LAP/LAP5760/MCS51Manual.pdf

The best way I can think of to do this would be just to set a flag in the hardware interrupt that keeps the status of the pin that caused the last interrupt.

I would try to avoid having excessively large interrupts as well - I might be mistaken, but that's what it sounds like you are intending to do. Nesting interrupts can get very frustrating, very quickly.

Bear in mind that you will have to adequately debounce your switches, or you may experience multiple interrupts with undesired results. A simple hardware LPF filter might help a bit as well.
 
  • #3
I'm not trying to have an excessively large interrupt. I want to interrupts to act kind of like RESET, except I want them to reset to different addresses, not just 0000h. I'm not sure how to do that with the "flag" thing you're talking about. I'm not trying to nest them either.

Perhaps "branch" is the wrong word. I meant I wanted it to jump to the specified location and keep going from there.

Debouncing shouldn't be an issue if I can get them working right. All that would happen is it would jump to the same place each time it bounces, which isn't problematic.

And isn't the phrase "LPF filter" redundant?
 
  • #4
Jiggy-Ninja said:
Perhaps "branch" is the wrong word. I meant I wanted it to jump to the specified location and keep going from there.

The thing about hardware interrupts that makes this more tricky than jumping out of a normal subroutine or software interrupt is that, pretty much by definition, you don't know at what point in your "main loop" code that the interrupt was called from. So this usually means you won't have full knowledge of the state of memory and registers (including SP) when you enter the interrupt. So you'll probably have to be careful to re-initialize the state of everything , including the stack, after the interrupt jumps. Other than that it should work.
 
  • #5
uart said:
The thing about hardware interrupts that makes this more tricky than jumping out of a normal subroutine or software interrupt is that, pretty much by definition, you don't know at what point in your "main loop" code that the interrupt was called from. So this usually means you won't have full knowledge of the state of memory and registers (including SP) when you enter the interrupt. So you'll probably have to be careful to re-initialize the state of everything , including the stack, after the interrupt jumps. Other than that it should work.
This is a fairly simple program that only uses 6 registers + DPTR for data storage, and doesn't use the stack for anything.

Here, I'll post the code:
Code:
;"We Three Kings" Music Program
;"Pallet Town"
;"The Star-Spangled Banner"
;"Route 1"
;by Mark Dowd
;


;	Double Whole	: 128
;	Whole Note	: 64
;	Half Note	: 32
;	Quarter Note	: 16
;	Eighth Note	: 8
;	16th Note	: 4

;	F4	FAD7
;	Eb4	FA35
;	D4	F9DD
;	C4	F91D
;	Bb3	F845
;	A3	F7D0
;	G3	F6CF
;	F3	F5AF
;	E3	F513
;	Eb3	F46C
;	D3	F3BC
;	C3	F23C
;	B2	F16A
;	Bb2	F08C
;	A2	EFA1
;	G2	EDA0

;	E4	FA89
;	F#4	FB21
;	G4	FB67
;	A4	FBE7
;	B4	FC59
;	C5	FC8E
;	D5	FCEE
;	E5	FD44
;	F#5	FD90
;	G5	FDB3

	org	0000h
Begin:	mov	TMOD, #11h
	mov	P1, #0FFh
	mov	R2, #0BEh   	;32Hz, 16 reps = 120 bpm
	mov	R3, #0C7h
	mov	TL1, R2
	mov	TH1, R3
Song:	mov	A, P1
	anl	A, #03h		;Masking all but the imporant swiches.
	mov	DPTR, #WeThreeKings
	jz	Repeat
	dec	A
	mov	DPTR, #PalletTown
	jz	Repeat
	dec	A
	mov	DPTR, #TheStarSpangledBanner
	jz	Repeat
	dec	A
	mov	DPTR, #Route1
	jz	Repeat
	sjmp	Song
Repeat:mov	R1, #0		;Note data offset
Main:	mov	A, R1
	movc	A, @A+DPTR		;Load Freq LOW byte
	mov	R4, A
	mov	TL0,A
	inc	R1
	mov	A, R1
	movc	A, @A+DPTR		;Load Freq HIGH byte
	mov	R5, A
	mov	TH0, A
	inc	R1
	mov	A, R1
	movc	A, @A+DPTR		;Load duration byte
	mov	R0, A
	inc	R1
	orl	A, R4			;Check all the bytes retreived. 
	orl	A, R5			;If they are all 0 (end of song), repeat.
	jz	Repeat
	setb	TR1
	setb	TR0
	
Loop:	jb	TF1, Note
	jb	TF0, Freq
	sjmp	Loop
	
Note:	clr	TR1		;reset counter, decrement note duration counter, and go 
	clr	TF1		;back to loop. If note is done, go back to main to relead new note.
	mov	TL1, R2
	mov	TH1, R3
	setb	TR1
	djnz	R0, Loop
	clr	TR1
	sjmp	Main
	
;Freq:	clr	TR0		;Flip output, reset counter, go back to loop.
;	cpl	P2.7
;	clr	TF0
;	mov	TL0, R4
;	mov	TH0, R5
;	setb	TR0
;	sjmp	Loop

Freq:	mov	TL0, R4
	mov	TH0, R5
	clr	TF0
	cpl	P2.7
	sjmp	Loop
	
	;org	200h
WeThreeKings:
	DB	013h, 0F5h, 32	;  We
	DB	0BCh, 0F3h, 16	;  three
	DB	03Ch, 0F2h, 32	;  kings
	DB	0A1h, 0EFh, 16	;  of
	DB	06Ah, 0F1h, 16	;  or-
	DB	03Ch, 0F2h, 16	;  -i-
	DB	06Ah, 0F1h, 16	;  -ent
	DB	0A1h, 0EFh, 48	;  are  /
	DB	013h, 0F5h, 32	;  Bear-
	DB	0BCh, 0F3h, 16	;  -ing
	DB	03Ch, 0F2h, 32	;  gifts
	DB	0A1h, 0EFh, 16	;  we
	...
	DB	00, 00, 00          ;   End

PalletTown:
	DB	...
At the label Song, it's the best way I could come up with to select the song based on the value of the switches.

I commented out the first Freq to see if the second freq works better at higher note frequencies.

DPTR contains the location of the song data in the ROM. This must be preserved if the song is to Repeat, but not for a new song.

R0 contains the duration of the note, which is loaded from the ROM. It's the third byte in each line. 16 = quarter note. Does not need to be preserved.

R1 contains the offset, which is incremented each time a value is read from the ROM. It's moved into A to use he movc A, @A+DPTR command. Does not need to be preserved.

Registers 2 & 3 contain the TL1 and TH1 values for Timer 1, which sets the BPM for the song. After initialization, these never change, they are hard-coded in the program. Must be preserved.

Registers 4 & 5 contain the TL0 and TH0 values for Timer 0, which are loaded from the ROM. They set the note frequency. Do not need to be preserved.
_______________________________

What I am trying do is make it so that when INT0 is triggered, the program jumps to the Repeat label, ends the interrupt, and continues from there, or something like that.

As I said in my OP, it would be trivial to add this to the polling loop at "Loop", bu I'm trying to discover the capabilities and limits of interrupts with this right now.
 
  • #6
Jiggy-Ninja said:
What I am trying do is make it so that when INT0 is triggered, the program jumps to the Repeat label, ends the interrupt, and continues from there, or something like that.

As I said in my OP, it would be trivial to add this to the polling loop at "Loop", bu I'm trying to discover the capabilities and limits of interrupts with this right now.
I'm not sure what the etiquette is on bumping, but I still haven't gotten an answer for this.
 

1. What is Interrupt Branching in the context of 8051 microcontrollers?

Interrupt Branching is a feature of the 8051 microcontroller that allows it to temporarily pause its current program execution and handle an external event or request. This allows for real-time responses to critical events without interrupting the main program flow.

2. How does Interrupt Branching work in 8051 microcontrollers?

When an external event or request triggers an interrupt, the 8051 microcontroller will first save the current program counter and status register on the stack. It will then jump to a specific address in memory, known as the Interrupt Vector, to handle the interrupt. Once the interrupt is completed, the microcontroller will retrieve the saved program counter and resume normal program execution.

3. What are the advantages of using Interrupt Branching in 8051 microcontrollers?

By using Interrupt Branching, 8051 microcontrollers can handle critical events or requests in real-time without interrupting the main program. This allows for more efficient use of the microcontroller's resources and faster response times. Additionally, Interrupt Branching allows for easier implementation of multi-tasking and real-time operating systems.

4. Can Interrupt Branching be disabled in 8051 microcontrollers?

Yes, Interrupt Branching can be disabled by clearing the Interrupt Enable Flag (IE) in the 8051's Special Function Register (SFR). This will prevent the microcontroller from responding to any interrupts until the IE flag is set again.

5. How can I use Interrupt Branching in my 8051 microcontroller project?

To use Interrupt Branching in your 8051 microcontroller project, you will need to first identify which external events or requests you want to handle with interrupts. Then, you will need to configure the Interrupt Enable Flag (IE) and Interrupt Priority (IP) in the SFR. Next, you will need to write the code for the interrupt handler, which will be executed when the interrupt is triggered. Finally, you will need to define the Interrupt Vector address in your code and enable the specific interrupt sources.

Similar threads

  • Programming and Computer Science
Replies
6
Views
3K
Replies
5
Views
4K
Back
Top