CON CLK_FREQ = 200_000_000 ' system freq as a constant MS_001 = CLK_FREQ / 1_000 ' ticks in 1ms US_001 = CLK_FREQ / 1_000_000 ' ticks in 1us _clkfreq = CLK_FREQ ' set system clock #true, ON, OFF #false, NO, YES DAT IR_AC_Max long 0 IR_AC_Min long 0 IR_AC_Signal_Current long 0 IR_AC_Signal_Previous long 0 IR_AC_Signal_min long 0 IR_AC_Signal_max long 0 IR_Average_Estimated long 0 positiveEdge long 0 negativeEdge long 0 ir_avg_reg long 0 cbuf long 0[32] offset long 0 ' Heart Rate Monitor functions takes a sample value and the sample number ' Returns true if a beat is detected ' A running average of four samples is recommended for display on the screen. PUB start() IR_AC_Signal_Current := 0 IR_AC_Signal_min := 0 IR_AC_Signal_max := 0 IR_AC_Max := 20 IR_AC_Min := -20 positiveEdge := 0 negativeEdge := 0 ir_avg_reg := 0 offset := 0 PUB checkForBeat(sample): beatDetected | diff beatDetected := false ' Save current state IR_AC_Signal_Previous := IR_AC_Signal_Current 'This is good to view for debugging 'debug(sdec(IR_AC_Signal_Current)) ' Process next data sample IR_Average_Estimated := averageDCEstimator(@ir_avg_reg, sample) IR_AC_Signal_Current := lowPassFIRFilter(sample - IR_Average_Estimated) 'debug(sdec(IR_Average_Estimated)) 'debug(sdec(sample)) debug(sdec(sample - IR_Average_Estimated)) debug(sdec(IR_AC_Signal_Current)) ' Detect positive zero crossing (rising edge) if ((IR_AC_Signal_Previous < 0) & (IR_AC_Signal_Current >= 0)) debug("**********************************") IR_AC_Max := IR_AC_Signal_max 'Adjust our AC max and min IR_AC_Min := IR_AC_Signal_min debug(sdec(IR_AC_Max - IR_AC_Min)) positiveEdge := 1 negativeEdge := 0 IR_AC_Signal_max := 0 'if ((IR_AC_Max - IR_AC_Min) > 100 AND (IR_AC_Max - IR_AC_Min) < 1000) if ((IR_AC_Max - IR_AC_Min) > 20 AND (IR_AC_Max - IR_AC_Min) < 1000) 'Heart beat!!! beatDetected := true ' Detect negative zero crossing (falling edge) if ((IR_AC_Signal_Previous > 0) AND (IR_AC_Signal_Current <= 0)) positiveEdge := 0 negativeEdge := 1 IR_AC_Signal_min := 0 ' Find Maximum value in positive cycle if (positiveEdge AND (IR_AC_Signal_Current > IR_AC_Signal_Previous)) IR_AC_Signal_max := IR_AC_Signal_Current ' Find Minimum value in negative cycle if (negativeEdge AND (IR_AC_Signal_Current < IR_AC_Signal_Previous)) IR_AC_Signal_min := IR_AC_Signal_Current return beatDetected ' Average DC Estimator PUB averageDCEstimator(p, x): result long[p] += (((x << 15) - long[p]) SAR 4) return result := (long[p] SAR 15) ' Low Pass FIR Filter PUB lowPassFIRFilter(din): result | z, i cbuf[offset] := din z := mul16(FIRCoeffs[11], cbuf[(offset - 11) & $1F]) {{ debug(sdec(offset - 11)) debug(sdec((offset - 11) & $1F)) if ((offset - 11) & $1F) > 31 abort }} i:= 0 repeat while i < 11 z += mul16(FIRCoeffs[i], cbuf[(offset - i) & $1F] + cbuf[(offset - 22 + i) & $1F]) {{ debug(sdec((offset - 22 + i)& $1F)) if ((offset - 22 + i) & $1F) > 31 abort debug(sdec((offset - i) & $1F)) if ((offset - i) & $1F) > 31 abort }} i++ offset++ offset //= 32 'Wrap condition ' debug(sdec(offset)) return result := (z SAR 15) ' Integer multiplier PUB mul16(x, y): result 'debug(sdec(x)) 'debug(sdec(y)) 'debug(sdec(x * y)) return result := (x * y) DAT FIRCoeffs long 172, 321, 579, 927, 1360, 1858, 2390, 2916, 3391, 3768, 4012, 4096