Maths routine problem???

asm_lan

Joined Jul 30, 2007
9
Hi all,
I'm currently doing a project on measuring heart rate using a sensor.
I have tried programming to display the beats per min(BPM) on a LCD but to no avail. I'm using Silabs C8051F226 development kit. The LCD only displays 2 values either "77 BPM" or "154 BPM". I'm using a timer and an external interrupt. In the external ISR, when the 1st pulse comes in, i'll start the timer and stop the timer at the 2nd pulse. And in the timer ISR, i count the number of overflows. I suspect that my overflows counter always count from 1-2 only... Thats why in my maths routine, it gave me the 2 values.

My code are as follows:
Rich (BB code):
;***************************************
;-----------INTERRUPT CONFIGURATIONS-----------
;***************************************
SETB EA		 ; Enable Global Interrupts
SETB ET0	 ; Enable Timer 0 Interrupt
SETB EX0	 ; Enable External Interrupt 0
SETB PX0	 ; External Interrupt 0 High Priority

;***************************************
;------------TIMER 0 CONFIGURATIONS------------
;***************************************
TIMER_0 EQU 65535
SETB IT0	                                     ; External Interrupt 0 detect falling-edge
MOV TMOD,#01H                           ; Set Timer 0 to Mode 1
MOV A,CKCON                               ; Move CKCON to Accumualtor
CLR ACC.3                                     ; Set system clock to divided by 12
MOV 70H,#00H                               ; Move 0 to 70H
MOV R7,#02H			 ; Move 4 to R7
MOV 62H,#01H			 ; Move 1 to 62H
MOV TH0,#HIGH TIMER_0		; Set High Byte of Timer 0
MOV TL0,#LOW TIMER_0		; Set Low Byte of Timer 0

;**********************
;-Wait Until 4th Pulse-
;**********************
WAIT:	CJNE R7,#00H,WAIT  ; Compare and jump to subroutine "WAIT" if R7 != 0
CLR TR0			; Stop Timer 0

;******
;-Math-
;******
MATH:	MOV A,#9AH      ; Move 154 to A
MOV B,70H
DIV AB
MOV R6,A

;**********************
;-External Interrupt 0-
;**********************
EX_INT0:	DJNZ 62H,COUNT  ; Decrement 62H and jump if != 0
SETB TR0	; Start Timer 0

COUNT:	DEC R7		; Decrement R7
RETI		; Return from Interrupt

;***********************
;-Timer 0 Overflow Flag-
;***********************
T0_INT:	INC 70H			; Overflow Counter
MOV TH0,#HIGH TIMER_0	; Reloads Timer 0 with High Byte
MOV TL0,#LOW TIMER_0	; Reloads Timer 0 with Low Byte
RETI			; Return from Interrupt

beenthere

Joined Apr 20, 2004
15,819
Accumulate the beats in a register. Use the timer to mark an interval - say 15 seconds. When it times out, multiply the register count by 4 for BPM. Don't forget to clear the count before the next interval.

asm_lan

Joined Jul 30, 2007
9
Meaning i start the timer to run for 15 secs and count the number of pulses for 15 secs and multiply by 4 to get the result?

EDIT: I have tried the method, but it is not accurate. Like when i input 1.2Hz, it gave me a value of 80BPM. The higher the frequency, the more it is not accurate...

beenthere

Joined Apr 20, 2004
15,819
How certain are you that the input is clean? It might be helpful to know what interface circuitry is inputting the heart rate.

asm_lan

Joined Jul 30, 2007
9
I test the program using a fuction generator... Since its from the function gen, shouldn't it be clean enough for the 8051 to detect?

I have another question:

Does the 8051 have a range for detecting pulses?
For example: below/above certain frequencies or below/above certain amplitudes, it cannot detect?

beenthere

Joined Apr 20, 2004
15,819
It can't count pulses that come faster than the counting register can increment. I believe it is necessary to use external circuitry to introduce the signals to the 8051 - an interface circuit. What are you using to do this function?

asm_lan

Joined Jul 30, 2007
9
I'm using a timer and an external interrupt pin to do this function... I start the timer for 10 secs. Whenever, there is a falling edge on the external interrupt pin, the counter will increase...

beenthere

Joined Apr 20, 2004
15,819
If the levels of the pulse satisfy the electrical requirement of the 8051's input, then the interrupt should get generated.

By the way, your code shows that you initialize R7 with 02h. The interrupt routine has you decrementing the value in R7. How is this going to count the number of inputs? Shouldn't you set the register to 0 and then increment it with each interrupt?

asm_lan

Joined Jul 30, 2007
9
I see.... Thanks...

EDIT: I have tried the code below to start the timer for 5 secs and count the number of pulses than multiplying by 12 to get the result. But it is not accurate. I have to multiply it by 11 to make it more accurate... It still have a error of -8 to 8 BPM...

This is the code that i used:

Rich (BB code):
;**********
;-Definitions-
;**********
COUNTER EQU 70H
START_TIMER EQU 60H

;***************************************
;-----------INTERRUPT CONFIGURATIONS-----------
;***************************************
SETB EA		 ; Enable Global Interrupts
SETB ET0	 ; Enable Timer 0 Interrupt
SETB EX0	 ; Enable External Interrupt 0
SETB PX0	 ; External Interrupt 0 High Priority

;**********************************************
;-------------TIMER 0 CONFIGURATIONS-----------
;**********************************************
SETB IT0		; External Interrupt 0 detect falling-edge
MOV TMOD,#01H	; Set Timer 0 to Mode 1
MOV A,CKCON	; Move CKCON to Accumualtor
CLR ACC.3            ; Set system clock to divided by 12
MOV START_TIMER,#01

;********************
;-Initialize Timer 0-
;********************
INIT: 	MOV COUNTER,#00H	; Initialize counter to count pulses to zero.
MOV TH0,#3CH		; Initialize Timer 0 to run for 50ms
MOV TL0,#0B0H

;****************
;-Wait for pulse-
;****************
WAIT:	JNB EX0,WAIT		; Wait for pulses to generate interrupt
ACALL DELAY2		; Make Timer 0 loop for 100 times to get 5 secs

;**********************
;-External Interrupt 0-
;**********************
EX_INT0:	DJNZ START_TIMER,COUNT	; Start Timer 0 only once
SETB TR0		; Start Timer 0

COUNT:	INC COUNTER		; Count number of pulses
RETI

;***********************
;-Timer 0 Overflow Flag-
;***********************
T0_INT:	NOP			; Do nothing
RETI
;**************
;-Delay for 5 secs-
;**************
DELAY2:   MOV R0,#100D
D7:	CLR TF0
MOV TH0,#3CH			; Loop Timer 0 using 12 MHz
MOV TL0,#0B0H			; crystal to run for 5 secs
D8:	JNB TF0,D8
DJNZ R0,D7
CLR TR0
RET

beenthere

Joined Apr 20, 2004
15,819
At this point, about all I can suggest is to insestigate why the count varies so much. If you can set your function generator to accurately run at an accurate frequency and the accumulated count does not agree, then something must be wrong. If the value in the counter is not always the same, then the timing loop must be incorrect.

If you do 10 runs with the function generator and the 10 values in the counter are not accurate, then you will need to tinker with your code. This can be frustrating, but the accumulated count should be repeatable.