Continue to Site

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.

  • 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.

Interrupt not working....

Status
Not open for further replies.

S.K

New Member
Hi Guys, Im new to this forum...

I'm currently using a timer and a external interrupt to detect heartrate.
The board that I'm using is Silabs C8051F226 and a 8*2 LCD.
The program can vector to the timer interrupt after 5 secs (I set it to 5 secs) but it cannot vector to the external interrupt. I have set the external interrupt pin to detect falling edge of the signal. This is my Interrupts routines and configurations...

Code:
;*****************************************
;-----------INTERRUPTS CONFIGURATIONS----------
;****************************************
MOV IE,#8CH
MOV SWCINT,#000H
MOV EIE1,#000H
MOV EIE2,#000H
MOV EIP1,#000H
MOV EIP2,#000H
MOV IP,#08H

;**************************************
;-------------TIMER 1 CONFIGURATIONS----------
;**************************************
SETB TCON.2
MOV TMOD,#10H
MOV CKCON,#000H

;**********
;-Start Timer-
;**********
START: 	MOV 40H,#000H
	MOV TH1,#0D0H		
	MOV TL1,#0A0H		; Program timer to run for 5 seconds
	SETB TR1		; Start timer

WAIT:	JNB TF1,WAIT
	
;****************************
;-Timer 1 Overflow Interrupt-
;****************************
T1_INT: RETI

;**********************
;-External Interrupt 1-
;**********************
EX_INT:    INC 40H			; Increment 40H
	  RETI

Does the input signal to the external interrupt pin need to be digital?
 
Last edited:
If your processor is an 8051, then yes the interrupt input needs to be a digital signal. It can be configured for edge or level triggering AFAIK.

I see several problems:
1. No stack pointer initialization. It probably defaults to 0x07 which is OK
2. You're not clearing the bank select bits in the PSW to guarantee that you are in register bank #0 Probably OK if PSW is cleared on RESET
3. You have not enabled the global interrupt flag, bit EA(IEN0.7 @ 0xA8). I bet you can't prove that you are getting timer interrupts either.
 
Last edited:
Thanks Brevor and Papabravo.

Code:
MOV IE,#8CH
Isn't this instruction enable the EA bit?
So clearing the bank select bit in the PSW is this instruction?
Code:
CLR RS1
          CLR RS0
and the instruction to stack pointer initialistion is:
Code:
MOV SP,#07H

Am i right?
Sorry to ask such a noob question, but i'm new to 8051. Learning along the way.
 
Declaration of bytes in internal RAM
Code:
Main_RAM_Byte	segment data
Stack		segment data

		SEG Main_RAM_Byte
Variable_1:	ds 1         ;declare 1 byte in internal RAM
Variable_2:           ds 2         ;declare two consecutive bytes in RAM

		SEG Stack
		ds 10	;declare 10 bytes for stack

Initialisation stackpointer; must be first instruction in code
Code:
mov  sp,#Stack-1         ;initialize stack

Remark:
You must be sure that the "Stack" bytes are located AFTER all other RAM bytes so leave at the end of the list. Even then check that in the LST file that is normally generated.

Part of a lst file from a project
First all internal RAM stuff
Then external data (parallel E²PROM)
Then different segments in code memory

TYPE BASE LENGTH RELOCATION SEGMENT NAME
---- ---- ------ ---------- ------------

REG 0000H 0008H "REG BANK 0"
DATA 0008H 0010H UNIT MATH_RAM_BYTE
DATA 0018H 0008H UNIT TMR0_RAM_BYTE
DATA 0020H 0001H BIT_ADDR LCD_BYTE_BIT
DATA 0021H 0001H BIT_ADDR MATH_RAM_BYTEBIT
BIT 0022H 0002H.6 UNIT MAIN_RAM_BIT
BIT 0024H.6 0001H UNIT TMR0_RAM_BIT
BIT 0025H.6 0000H.1 UNIT LCD_BIT
0025H.7 0000H.1 *** GAP ***
DATA 0026H 001DH UNIT MAIN_RAM_BYTE
DATA 0043H 0005H UNIT LCD_BYTE
DATA 0048H 000AH UNIT STACK

XDATA 0000H 0212H UNIT EEPROM

CODE 0000H 0003H ABSOLUTE
0003H 0008H *** GAP ***
CODE 000BH 0003H ABSOLUTE
CODE 000EH 1546H UNIT MAINPROG
CODE 1554H 0345H UNIT MATH_CODE
CODE 1899H 0317H UNIT LCD_CODE
CODE 1BB0H 02E5H UNIT LCD_TEKSTEN
CODE 1E95H 0199H UNIT TMR0_CODE
CODE 202EH 000CH UNIT PARAMETERS

Don't boder about the length now, the Stack can now use all remaining bytes from internal RAM.

Now you can use
Code:
mov a,Variable_1
instead of
Code:
MOV 40H,#000H
that way your code will be more readable to eveyone :D


About the timer initialisation
Code:
Time_0	equ 65535-10000   ;10ms interrupt


mov  TH0,#HIGH Time_0      ;load timer value
mov  TL0,#LOW  Time_0
mov  TMOD,#01H          	;timer 0 mode 1
setb ET0                           ;enable interrupt timer 0
setb EA           
setb TR0                           ;start timer 0
 
Code:
Main_RAM_Byte	segment data
Stack		segment data

		SEG Main_RAM_Byte
Variable_1:	ds 1         ;declare 1 byte in internal RAM
Variable_2:           ds 2         ;declare two consecutive bytes in RAM

		SEG Stack
		ds 10	;declare 10 bytes for stack

I do not understand this.
Does Stack-1 means 10-1?
 
As you probably knows the Stack is located in internal RAM.
By declaring a "Stack" segment, you reserve an amount of bytes for the stack.
Since you don't know how many bytes to reserve you need to be sure that the stack is located behind your last internal RAM byte, that is after the register banks, bit addressable bytes and variables you declared.

The length of the segment "Stack" is unimportend, I choose 10 you could also write 4 or 8.

What is important is the location in internal RAM. Where does the stack starts? That changes when you add or delete variables in you code.

Depending on the number of variables used, the Stack can start @ any address in internal RAM, theoreticaly from 07h to FFh.

Like Papabravo already said if you don't initialize your stack it will be initialzed at 07h, first address after reg bank 0.

Now comes the very important part.
If in your code you wrote "MOV 07H,#000H" instead of "MOV 40H,#000H" you overwrite the stack!!!!!!!!!!!!!

So I will never say it again:
***********************************************************************************************
Be sure that the stack is located behind your last internal RAM byte, that is after the register banks, bit addressable bytes and variables you declared.
***********************************************************************************************


With the instruction
Code:
mov  sp,#Stack-1         ;initialize stack
you place the StackPointer one address before the Stack.
Why -1?
Because when something needs to be placed on the stack, the StackPointer is first incremented then the data is placed onto the stack.

So if your Stack starts at 045h the StackPointer wil be initialized at 044h.
That instruction has nothing to do with the length of the stack only the first address of the stack.

Clear now?
No :(
Ask... :)
 
Another problem in your code is the location of the ISR routines.
One thing you know for sure is the location of the ISR in code memory, see datasheet for correct addresses.
Each possible ISR starts at a known location. Two examples below

Code:
CSEG AT 0000h
jmp StartMain

CSEG AT 000bh
jmp ISR_Timer0

CSEG AT 0023h
jmp ISR_SerialInterrupt

Depending on the assembler you use, you can also use predefined labels
Code:
CSEG AT RESET 
jmp MainProg

CSEG AT TIMER0
jmp Timer_0


You can write

;****************************
;-Timer 1 Overflow Interrupt-
;****************************
T1_INT: RETI

;**********************
;-External Interrupt 1-
;**********************
EX_INT: INC 40H ; Increment 40H
RETI

but it won't work since the code is at a wrong location!!!

What I would do is:
Complement an output in each ISR (timer & external)
Run the code
Hook a scoop to both outputs and check for square wave signal

and of course let us know the outcome :):D:)
 
I have one question... 2 actually... lol...

1) How do i start a timer when it detect the 1st pulse and stop the timer when it detect the 4th pulse?
I have tried using a timer and an external interrupt to do this.. But I'm stuck at the start timer and stop timer pocedure.

2) After i got the number of overflows, i need to multiply with 0.39, how do i do that in asm?
 
Last edited:
This time you won't get any code from me just some hints how I should do it :(
Build your own code, share it here and we can check it :):)

For your first question
1) Start and stop timer should happen in ISR from EX1
2) EX1 should be enabled from the start of your code
3) You need one byte to count the edges on EX1, call that byte EdgeCounter
4) In the EX1 ISR
4a) increment the counter
4b) check if its equal to 1
4c) if yes start the timer "setb TR1" and quit ISR
4d) if not check if its equal to 4
4e) if yes stop the timer "clr TR1", do what you want to do with the timed value, reset EdgeCounter and Timer1 and quit ISR
4d) if not nothing to do :)
5) You need no code in the T1 ISR since you just use the timer to time between pulse 1 and 4.

That is if your expted time never exceed 2^16 * 12/fosc in µs, with fosc in MHz
If that's not the case you have to work in another way.
Which way depends on the maximum time expected and needed accuracy.
What will the max expected time be and how accurate do you want it?



For your second question
Fractional numbers have to be converted to integers.
0.39 * 2^16 = 25559.04
We definitely can forget the 0.04 :D
Multiply your overflows (which overflows anyway? T1? then the above is mayby unusable:eek:) with 25559 and use only the upper two bytes of the result(devide again by 2^16).
16 bit OpA * 16 bit OpB = 32 bit result
By using the 16 upper bits you divide your result again by 2^16.
Need a 16 bit multiplication?
Lots to find on the web, Google is your friend.
 
Hmm...

Code:
CONFIG: 		MOV R7,#00H
                          MOV R3,#04H
		MOV TH0,#00H
		MOV TL0,#00H

WAIT:		CJNE R3,#00H,WAIT
		CLR TR0

INT_T1:               INC R7             ; Timer 1 ISR
                          RETI

EX_INT:               SETB TR1         ; External ISR
                          DEC R3
                          RETI

Can i use the above code to count the number of overflows for 4 pulse? :p

About the math routine, I'm still abit blur... :confused:

I know the concept, the only problem is to write it in code.
Lets say,

x = 0.39 * R7
y = 1 / x
z = y * 60

Than display z :D
 
Last edited:
Please first answer the question:
mcs51mc said:
What will the max expected time be and how accurate do you want it?

With your code R7 will increment every 65536µs assuming you have a 12MHz xtal. Is that what you want? I bet not :D

If you want to count 10ms interval then you need to setup the timer to a specific value and reload that value at each interrupt.

Main code
Code:
Time_1	equ 65535-10000   ;10ms interrupt assuming 12MHz xtal

mov  TH1,#HIGH Time_1      ;load timer value
mov  TL1,#LOW  Time_1
mov  TMOD,#10H          	;timer 1 mode 1
setb ET1                           ;enable interrupt timer 1
setb EA

EndlessLoop:

;Do your main code stuff here


jmp EndlessLoop

Timer 1 ISR
Code:
mov  TH1,#HIGH Time_1      ;reload timer value
mov  TL1,#LOW  Time_1

push acc                    ;save some registers used in ISR
push psw

inc  OverflowConter      ;Count number of timer overflows Max 255


;Do other timed stuff here

pop psw                   ;restore registers used in ISR
pop acc
reti
 
S.K said:
About the math routine, I'm still abit blur... :confused:

I know the concept, the only problem is to write it in code.
Lets say,

x = 0.39 * R7
y = 1 / x
z = y * 60

Than display z :D
Hmm... :D:D

You have to think in a byte-based system instead of decimal system.
You can simplify your three "formulas" into one Z = 153.8461 / Overflowcounter (R7).

You can't use 153.8461 so multipy it by let say 256 then divide it by the OverflowCounter.
Will you have enough accuracy? Check that in Excel by simulating your formula!

Did you check the web for math routines for 8051?
Check 8052.com...
 
With your code R7 will increment every 65536µs assuming you have a 12MHz xtal. Is that what you want? I bet not

I got what you mean, meaning i have to set the value in TH1 and TL1 10ms so that after the 4th pulse, the math routine will be easier to do isn't it?

just use R7 * 10ms... :D :D

Also, how do you get 153.8461???

Yeah.. been to 8052.com... still trying to figure out what the tutorial is talking about...
 
Last edited:
S.K said:
I got what you mean, meaning i have to set the value in TH1 and TL1 10ms so that after the 4th pulse, the math routine will be easier to do isn't it?

just use R7 * 10ms... :D :D
Yep

The assembler calculate the timer preset value for you with
Code:
Time_1	equ 65535-10000   ;10ms interrupt assuming 12MHz xtal
If you need 2ms interrupt then write
Code:
Time_1	equ 65535-2000   ;2ms interrupt assuming 12MHz xtal

But please please please answer the question:
mcs51ms said:
What will the max expected time be and how accurate do you want it?
because 10ms is a bad choice if you need 1ms accuracy or want to measure several minutes!!
Also: Are you using a 12MHz xtal?



S.K said:
Also, how do you get 153.8461???
Elementary math ... :eek: :eek:
Z = 60 / (0.39 * R7) Your three formulas in one
Z = 60 / 0.39 * 1 / R7
Z = 153.8461 * 1 / R7
Z = 153.8461 / R7



S.K said:
Yeah.. been to 8052.com... still trying to figure out what the tutorial is talking about...
One thing for sure, it's not about baking cookies :D:D:D:D
 
Sorry for the late reply.:(

Originally Posted by mcs51ms
What will the max expected time be and how accurate do you want it?

Well, i'm measuring heart rate, thats about 60 secs. I don't need so much accuracy. About 1sec should be ok. Nah.. I'm using 2MHz xtal... :p

Elementary math ...
Z = 60 / (0.39 * R7) Your three formulas in one
Z = 60 / 0.39 * 1 / R7
Z = 153.8461 * 1 / R7
Z = 153.8461 / R7

Oh... that is if its just one pulse. If its between 4 pulses, will it be like this?

Z = 60/((0.39)*R7/4)
Z = 60 * 4/(0.39*R7)
Z = 240 / 0.39*R7
Z = 615 / R7

Am i correct?

Also, how do i change my signal to digital, cause the senor that i'm using have a op-amp of 100 gain which i think gives me analog signal. I cannot use the ADC in my chip as i have already used it for another function which is to display the peak value of the signal. :confused:

So the timer code will be:
Code:
TIME_0 EQU 65535
MOV TMOD,#01H
SETB EA
SETB ET1

MOV TH0,#HIGH TIME_0
MOV TLO,#LOW TIME_0
Am i right? Since i want the timer to run for the whole of 65535 ticks.

And for the math routine, i need to use 16-bit division? Cause 615 is greater than 255.

Must i need the remainder of the division since i do not need so much accuracy? If i used 2MHz, R7 won't be greater than 0FFH and it will be easier to do the math routine:D
 
Last edited:
Good code starts with good knowledge of the hardware and well defined specifications!

So please let's clear some things out:
1) How many sensors do you have and what are their outputs?

2) You wrote:
"I cannot use the ADC in my chip as i have already used it for another function which is to display the peak value of the signal."
Do you mean you digitalized the sensor output and search for the maximum value? Did you use on chip hardware or code to do that?
Now you want to measure time between 4 pulses, are these 4 pulses from the same signal? Four maximums you already measured?
If that is the case you need to revise your analysis.
If you have only one signal, digitalized by the on chip ADC, then you can do all the job with only the ADC values you read.
The sensor output, is it something like we all know from ecg's (**broken link removed** If that's the case you can tell a lot from the signal analysis if it's well sampled.
3) What is the ADC scan rate? How many readings/sec?

4) If your opamp is used as a comparator it will produce a digital signal 0V and 5V only. If it's used as an amplifier, what is most likely the case since you talk about a gain of 100, it's output is analog and need to be processed by an ADC.

5) Are you sure about what you wrote: "Well, i'm measuring heart rate, thats about 60 secs. I don't need so much accuracy. About 1sec should be ok."
Human heartbeat is about 1 to 1.33 bps, you need to measure 1sec accurately. So please redefine the accuracy needed, it's not one second :(.
 
1) How many sensors do you have and what are their outputs?

I have 1 sensor and their output is an analog output.

2) Do you mean you digitalized the sensor output and search for the maximum value? Did you use on chip hardware or code to do that?

I managed to get the external interrupt working without digitalized the output.
The chip hardware ADC have been use for another function. Yea, the output is something like ECG. About the 4 pulses, I'm measuring the time between them and averaging them. So that 1 / Time = Frequency. Therefore, Frequency * 60 = BPM.

3) What is the ADC scan rate? How many readings/sec?

The ADC scan rate is 100ksps.

4) Yea... Its used as an amplifer.

5) I'm measuring the beats per min. Hmm... Not one sec? :confused: Hmm. :rolleyes: 100ms?
 
S.K said:
So the timer code will be:
Code:
TIME_0 EQU 65535
MOV TMOD,#01H
SETB EA
SETB ET1

MOV TH0,#HIGH TIME_0
MOV TLO,#LOW TIME_0
Am i right? Since i want the timer to run for the whole of 65535 ticks.
Please review the datasheet concerning the timer stuff!
When is an interrupt generated?
Once you know that, what is the time between 2 interrupts with the above code?

Now you maybe also understand the meaning of the substraction in the code below
Code:
Time_1	equ 65535[b]-10000[/b]   ;10ms interrupt assuming 12MHz xtal
Time_1	equ 65535[b]-2000[/b]   ;2ms interrupt assuming 12MHz xtal

S.K said:
And for the math routine, i need to use 16-bit division? Cause 615 is greater than 255.
Must i need the remainder of the division since i do not need so much accuracy? If i used 2MHz, R7 won't be greater than 0FFH and it will be easier to do the math routine:D
Like I already said do some evaluations in Excel to determine what is best suited for you application! Use the "Integer" function to calculate the way a µC do, that is without fractional numbers.
Don't worry about the division, make sure you have the correct data first.
I have math routines for
div_32x16_signed, div_32x16_unsigned, div_32x16_signed_op1
but one thing at the time :D
 
Status
Not open for further replies.

Latest threads

New Articles From Microcontroller Tips

Back
Top