Can Interrupts Cause Permanent Branching in 8051 Microcontrollers?

  • Thread starter Thread starter Jiggy-Ninja
  • Start date Start date
Click For Summary
The discussion focuses on implementing interrupts in an 8051 microcontroller (DS89C450) to control music playback from a program written in Assembly. The user aims to use two push buttons connected to interrupt pins to either repeat the current song or load a new one, requiring a permanent jump to specific code locations after an interrupt. There is a concern about managing the state of registers and memory upon entering the interrupt, as well as the need for debouncing the buttons to avoid multiple triggers. The user acknowledges that while polling could be a simpler solution, they prefer to explore the intricacies of interrupts for better understanding. Overall, the goal is to manipulate the program flow effectively using hardware interrupts without nesting or excessive complexity.
Jiggy-Ninja
Messages
309
Reaction score
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
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.
 
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?
 
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.
 
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.
 
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.
 
I am trying to understand how transferring electric from the powerplant to my house is more effective using high voltage. The suggested explanation that the current is equal to the power supply divided by the voltage, and hence higher voltage leads to lower current and as a result to a lower power loss on the conductives is very confusing me. I know that the current is determined by the voltage and the resistance, and not by a power capability - which defines a limit to the allowable...

Similar threads