/*
THE ULTIMATE SOFTWARE DEBOUNCER
Program: debounce.asm
Version: 1.0
Date: 5/5/2005
Author: Elio Mazzocca
E-mail:
jnz9876@adam.co.uk
micro used: ATmega8 with internal 4 MHz oscillator
assembled with: AVR Studio 4.0
Timer0 interrupt period: 4 mSEC
Description: This is a 1st order recursive digital filter
with Schmitt trigger output that filters noisy
digital inputs to ATmega8 microcontroller.
The formula employed for the recursive filter:
ynew = 1/4 xnew + 3/4 yold
Formula for an inverting Schmitt trigger:
if(ynew>hi) and (flag=0) then flag=1; vout=1;
if(ynew<lo) and (flag=1) then flag=0; vout=0;
Use: The code is placed in Timer0 interrupt routine
with a 4 mSEC period. The output of the trigger
is continuously checked in the main program loop
The interrupt routine checks the PORT bit and
applies either 0 (keypress) or $3F to the digital
filter, the output value is then applied to a
Schmitt trigger with thresholds of 15, 240 for
an effective "time constant" of 11 interrupts.
Program requires 11 ints, 19/18 machine cycles,
6 ints if schmitt threshold is $3C instead of $0F
;
.NOLIST
.INCLUDE "AvrAssembler2\appnotes\m8def.inc"
.LIST
; Register defines
.DEF yold = R17 ; old/new filter output value, share same reg
.DEF tmp = R18 ; new input to filter value/threshold reg
.DEF flag = R19
.DEF VOUT = R20
.CSEG
.ORG $0000
rjmp Reset
.ORG OVF0addr
rjmp tim0_ovf ; Timer0 overflow handler
Reset:
ldi R16, LOW(RAMEND) ; Initiate Stackpointer
out SPL, R16 ; for use by interrupts
ldi R16, HIGH(RAMEND)
out SPH, R16
ldi R16, (1<<CS01)|(1<<CS00) ; Fosc = 4 MHz
out TCCR0, R16 ; set Timer/Counter0 Prescaler=64, int = 16x256 uSEC
ldi R16, (1<<TOIE0) ; set timer0 interrupt enable
out TIMSK, R16 ; in the Timer Interrupt Mask Register
ldi R16, (1<<TOV0) ; clr pending interrupts
out TIFR, R16
ser tmp
out DDRB, tmp ; set PORTB = output
clr tmp
out DDRD, tmp ; set PORTD = input
ser tmp
out PORTD, tmp ; turn on PORTD pull-ups
ldi yold, $FF ;optional
sei ; enable interrupts
loop: ; main program loop
sbrs VOUT, 0 ; if schmitt out = 1
rjmp a1
sbi PORTB, 0 ; then set PORTB, bit 0 - LED on
rjmp loop
a1:
cbi PORTB, 0 ; else clear PORTB, bit 0 - LED off
rjmp loop
;------------------------------------------------------------------------
tim0_ovf:
mov tmp, yold
lsr tmp
lsr tmp ; tmp = 1/4 yold
sub yold, tmp ; 3/4 yold is in left in reg yold
ldi tmp, $3F ; re-use tmp register for xnew
sbis PIND, 0 ; if PIND bit 0 = 0, then input = 1/4 xnew
clr tmp
add yold, tmp ; yold same as ynew, saves 1 instruction/register !
.UNDEF tmp ; re-use tmp register as threshold reg.
.DEF thresh = R18
; now apply filter output to schmitt trigger
ldi thresh, $0F ; load lo thresh into threshold register
sbrc flag, 0 ; test bit 0 of flag register
rjmp s1
cp yold, thresh
brsh s1
sbr flag, (1<<0) ; set bit 0 of register flag
sbr VOUT, (1<<0)
s1:
swap thresh ; to test hi thresh, swap nibbles
cp yold, thresh
brlo s2
cbr flag, (1<<0)
cbr VOUT, (1<<0) ; clear bit 0 of register VOUT
s2:
reti ; 19/18 (nokeypress/keypress) machine cycles
;------------------------------------------------------------------------
.EXIT