You need a "state machine" (consisting of flip-flops) which defines the "next state" (new ones/zeros in the flip-flops) as a function of "present state" (present ones/zeros in the flip-flops) and "how long the button is pushed".
This can be built using discrete logic, e.g. flip-flops/gates, relays, or a micro-controller like a PIC16F84. Regardless of how you build it, you need to start by drawing a "state transition diagram" which defines the behavior. Google all the "quoted" things in this posting, and you will learn more than you ever wanted to know...
;******************************************************************
;* *
;* Filename: Ignition 10F200 v2.asm *
;* Author: Mike McLaren, K8LH (k8lh@arrl.net) *
;* Date: 30-Sep-09 *
;* *
;* *
;* 10F200 Ignition Switch Experiment *
;* *
;* *
;* MPLab: 8.14 (tabs=8) *
;* MPAsm: 5.21 *
;* *
;******************************************************************
include "p10f200.inc"
list st=off
__CONFIG _MCLRE_OFF & _CP_OFF & _WDT_OFF
radix dec
;--< hardware >----------------------------------------------------
#define ignition GPIO,0 ; GP0 = active hi ignition relay
#define starter GPIO,1 ; GP1 = active hi starter relay
;--< variables >---------------------------------------------------
cblock 0x10
temp ; delay subsystem
swnew ; fresh switch sample (b3 bit)
swold ; switch state latch (b3 bit)
mstmr ; msec timer
swtmr ; 1 sec switch timer
endc
#define running swold,0 ; running flag
;--< macros >------------------------------------------------------
clock equ 4 ; 4-MHz clock
usecs equ clock/4 ; cycles/usec multiplier
inDlyCy macro pCycles ; 0..1027 cycle range
local loop ;
if pCycles > 3
movlw pCycles/4 ;
loop movwf temp ; 4-cycle loop
decfsz temp,W ;
goto loop ;
endif
if pCycles%4 >= 2
goto $+1 ; 2 cycles
endif
if pCycles&1 == 1
nop ; 1 cycle
endif
endm
;******************************************************************
; main program *
;******************************************************************
org 0x000
start
movwf OSCCAL ;
movlw b'10011110' ; 10011110
; 1-------, IOC off
; -0------, weak pullups on
; --0-----, T0CS source Fosc/4
; ---1----, T0SE edge hi>lo
; ----1---, PSA prescale WDT
; -----110, PS prescaler 64
option ;
movlw b'00001000' ;
tris GPIO ; GP3 input, all others outputs
clrf GPIO ; set output latches to '0'
clrf swold ; clear switch state latch
clrf swtmr ; clear 1 second timer
clrc ; clear Carry
;
; unsigned char swnew = 0; // fresh switch sample
; unsigned char swold = 0; // switch state latch
; unsigned char mstmr = 0; // 32-msec debounce/beep timer
; unsigned char swtmr = 0; // 1-second switch timer
;
; #define ignition gpio.0 // GP0, active hi relay output
; #define starter gpio.1 // GP1, active hi relay output
; #define running swold.0 // flag
;
; #define newpress swnew.3 == 1 && swold.3 == 0
; #define newrelease swnew.3 == 0 && swold.3 == 1
; #define allowstart ignition == 1 && running == 0
;
; while(1)
; { delay_ms(32); // 32-msec debounce intervals
; swnew = ~gpio; // sample active lo switch GP3
; if(newpress) // if "new press"
; { swold.3 = 1; // update switch state latch
; swtmr = 1000/32; // start 1 second timer
; beep1(); // send a single beep
; }
; if(newrelease) // if "new release"
; { swold.3 = 0; // update switch state latch
; starter = 0; // turn GP1 "starter" off
; if(swtmr) // if "short" press
; { ignition ^= 1; // toggle GP0 "ignition"
; swtmr = 0; // turn 1 second timer off
; running = 0; // clear "running" flag
; } //
; }
; if(swtmr) // if 1 second timer running
; { swtmr--; // decrement it
; if(swtmr == 0) // if timed out
; { beep2(); // send a double beep
; if(allowstart) // if start allowed
; { running = 1; // set "running" flag
; starter = 1; // turn GP1 "starter" on
; } //
; } //
; }
; }
;
newsample
call dbdelay ; 32-msec debounce delay
comf GPIO,W ; sample active lo GP3 switch
movwf swnew ; save fresh sample
newpress
btfsc swnew,3 ; swnew.3 == 1 and
btfsc swold,3 ; swold.3 == 0 (new press)?
goto newrelease ; no, branch, else
bsf swold,3 ; update swold.3 state latch
call beep1 ; do a single 32-msec beep and
movlw 1000/32 ; start 1 second timer
movwf swtmr ;
newrelease
btfss swnew,3 ; swnew.3 == 0 and
btfss swold,3 ; swold.3 == 1 (new release)?
goto timeout ; no, branch, else
bcf swold,3 ; update swold.3 state latch
bcf starter ; turn GP1 'starter' off
movf swtmr,W ; timed out "long" press?
bz newsample ; yes, branch (done), else
clrf swtmr ; turn off 1 second timer
movlw b'00000001' ; use GP0 pin mask to
xorwf GPIO,F ; toggle GP0 'ignition' output
bcf running ; clear "running" flag
timeout
movf swtmr,F ; switch timer running?
bz newsample ; no, branch, else
decfsz swtmr,F ; is it timed out?
goto newsample ; no, branch, else
call beep2 ; do a double beep
btfsc ignition ; ignition == 1 and
btfsc running ; running == 0 (allow start)?
goto newsample ; no, branch, else
bsf running ; set "running" flag
bsf starter ; turn GP1 'starter' on
goto newsample ;
;******************************************************************
; subroutines *
;******************************************************************
beep2
call beep1 ; 32-msec delay with beep
call dbdelay ; 32-msec delay
beep1
setc ; 32-msec delay with beep
dbdelay
movlw 32 ; C = 0, delay, C = 1, beep
movwf mstmr ; mstmr = 32 msecs
dbloop
movlw b'00000100' ; mask for GP2 'spkr' pin
skpnc ; beep task? no, skip, else
xorwf GPIO,F ; toggle the speaker pin
inDlyCy(1000*usecs-6) ; 1-msec minus 6 cycles
decfsz mstmr,F ; done? yes, skip, else
goto dbloop ; loop
clrc ;
retlw 0 ;
;******************************************************************
end
With your very clever coding Mike, K8LH, HTML clipboardbeep2 will actually produce 3 beeps as
call dbdelay is a call and will call the sub-rutine for a third time.
With your very clever coding Mike, K8LH, beep2 will actually produce 3 beeps as
call dbdelay is a call and will call the sub-rutine for a third time.
list p=12F635, b=8, c= 102, n=71, t=on, st=off, f=inhx32
;******************************************************************
;* *
;* Filename: Ignition 12F635 v2.asm *
;* Author: Mike McLaren, K8LH *
;* Date: 16-Feb-10 (last revision 16-Feb-10) *
;* *
;* 12F635 Single Button Ignition/Starter experiment (short *
;* and long switch press detection) *
;* *
;* *
;* MPLab: 8.14 (tabs=8) *
;* MPAsm: 5.15 *
;* *
;******************************************************************
#include <p12f635.inc>
errorlevel -302
radix dec
__config _FCMEN_OFF&_IESO_OFF&_MCLRE_OFF&_WDT_OFF&_INTRC_OSC_NOCLKOUT
;--< hardware >----------------------------------------------------
#define ignition GPIO,0 ; GP0 = active hi ignition relay
#define starter GPIO,1 ; GP1 = active hi starter relay
;--< variables >---------------------------------------------------
swnew equ 0x40 ; fresh switch sample (b3 bit)
swold equ 0x41 ; switch state latch (b3 bit)
mstmr equ 0x42 ; msec timer
swtmr equ 0x43 ; 1 sec switch timer
;--< constants >---------------------------------------------------
#define running swold,0 ; running flag
;--< macros >------------------------------------------------------
;
; uDelay(Tcy) in-line delay macro, range 1..1023 cycles,
; produces 1 to 6 instructions.
;
clock equ 4 ; 4-MHz clock
usecs equ clock/4 ; cycles/usec multiplier
uDelay macro pTime
local dloop
if pTime > 3
movlw (pTime)/4-1 ;
dloop addlw -1 ;
bc dloop ;
endif
if pTime%4 & 1
nop ; 1 cycle
endif
if pTime%4 & 2
goto $+1 ; 2 cycles
endif
endm
;******************************************************************
;* Reset Vector *
;******************************************************************
org 0x0000
v_Reset
clrf STATUS ; |B0
movlw b'00000111' ; |B0
movwf CMCON0 ; comparator off |B0
clrf GPIO ; clear GPIO output latches |B0
bsf STATUS,RP0 ; bank 1 |B1
movlw b'00001000' ; GP3 input, all others outputs |B1
movwf TRISIO ; |B1
;
; setup INTOSC for 4 MHz
;
movlw b'01100000' ; |B1
movwf OSCCON ; 4-mhz INTOSC system clock |B1
Stable btfss OSCCON,HTS ; oscillator stable? |B1
goto Stable ; no, branch, else |B1
bcf STATUS,RP0 ; bank 0 |B0
clrf swold ; clear switch state latch |B0
clrf swtmr ; clear 1 second timer |B0
clrc ; clear Carry |B0
;
; unsigned char swnew = 0; // fresh switch sample
; unsigned char swold = 0; // switch state latch
; unsigned char mstmr = 0; // 32-msec debounce/beep timer
; unsigned char swtmr = 0; // 1-second switch timer
;
; #define ignition gpio.0 // GP0, active hi relay output
; #define starter gpio.1 // GP1, active hi relay output
; #define running swold.0 // flag
;
; #define newpress swnew.3 == 1 && swold.3 == 0
; #define newrelease swnew.3 == 0 && swold.3 == 1
; #define allowstart ignition == 1 && running == 0
;
; while(1)
; { delay_ms(32); // 32-msec debounce intervals
; swnew = ~gpio; // sample active lo switch GP3
; if(newpress) // if "new press"
; { swold.3 = 1; // update switch state latch
; swtmr = 1000/32; // start 1 second timer
; beep1(); // send a single beep
; }
; if(newrelease) // if "new release"
; { swold.3 = 0; // update switch state latch
; starter = 0; // turn GP1 "starter" off
; if(swtmr) // if "short" press
; { ignition ^= 1; // toggle GP0 "ignition"
; swtmr = 0; // turn 1 second timer off
; running = 0; // clear "running" flag
; } //
; }
; if(swtmr) // if 1 second timer running
; { swtmr--; // decrement it
; if(swtmr == 0) // if timed out
; { beep2(); // send a double beep
; if(allowstart) // if start allowed
; { running = 1; // set "running" flag
; starter = 1; // turn GP1 "starter" on
; } //
; } //
; }
; }
;
newsample
call dbdelay ; 32-msec debounce delay |B0
comf GPIO,W ; sample active lo GP3 switch |B0
movwf swnew ; save fresh sample |B0
newpress
btfsc swnew,3 ; swnew.3 == 1 and |B0
btfsc swold,3 ; swold.3 == 0 (new press)? |B0
goto newrelease ; no, branch, else |B0
bsf swold,3 ; update swold.3 state latch |B0
call beep1 ; do a single 32-msec beep and |B0
movlw 1000/32 ; start 1 second timer |B0
movwf swtmr ; |B0
newrelease
btfss swnew,3 ; swnew.3 == 0 and |B0
btfss swold,3 ; swold.3 == 1 (new release)? |B0
goto timeout ; no, branch, else |B0
bcf swold,3 ; update swold.3 state latch |B0
bcf starter ; turn GP1 'starter' off |B0
movf swtmr,W ; timed out "long" press? |B0
bz newsample ; yes, branch (done), else |B0
clrf swtmr ; turn off 1 second timer |B0
movlw b'00000001' ; use GP0 pin mask to |B0
xorwf GPIO,F ; toggle GP0 'ignition' output |B0
bcf running ; clear "running" flag |B0
timeout
movf swtmr,F ; switch timer running? |B0
bz newsample ; no, branch, else |B0
decfsz swtmr,F ; is it timed out? |B0
goto newsample ; no, branch, else |B0
call beep2 ; do a double beep |B0
btfsc ignition ; ignition == 1 and |B0
btfsc running ; running == 0 (allow start)? |B0
goto newsample ; no, branch, else |B0
bsf running ; set "running" flag |B0
bsf starter ; turn GP1 'starter' on |B0
goto newsample ; |B0
;******************************************************************
; subroutines *
;******************************************************************
beep2
call beep1 ; 32-msec delay with beep |B0
call dbdelay ; 32-msec delay |B0
beep1
setc ; 32-msec delay with beep |B0
dbdelay
movlw 32 ; C = 0, delay, C = 1, beep |B0
movwf mstmr ; mstmr = 32 msecs |B0
dbloop
movlw b'00000100' ; mask for GP2 'spkr' pin |B0
skpnc ; beep task? no, skip, else |B0
xorwf GPIO,F ; toggle the speaker pin |B0
uDelay (1000*usecs-6) ; 1-msec minus 6 cycles |B0
decfsz mstmr,F ; done? yes, skip, else |B0
goto dbloop ; loop |B0
clrc ; |B0
return ; |B0
;******************************************************************
end
We use cookies and similar technologies for the following purposes:
Do you accept cookies and these technologies?
We use cookies and similar technologies for the following purposes:
Do you accept cookies and these technologies?