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.

How to make a Momentary switch have multiple functions

Status
Not open for further replies.
non-sequential counter approach

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

This looks like the best idea yet. This might be built as a non-sequential counter ..... Use a momentary switch as an asynchronous clock pulse.
The rising edge of the switch pulse would change states from off to run, and then the next one would turn on the starter. Then use the falling edge of the starter pulse to turn off the starter, as the switch is released, with just one or two logic gates picking up the trailing edge of the switch pulse.

The advantage here is that it is simple.

... Have not actually gone through the design, but this approach seems to be worth looking at.
 
As 3v0 mentioned, I'm also concerned that you might accidentally engage the starter while the engine is running so I modified the code to ignore any 'long' press after one start sequence. That is, if you turn on the ignition with a 'short' press then engage the starter with a 'long' press, additional 'long' presses are ignored. If you have a failed engine start you have to turn the ignition off then back on before you can engage the starter again. This also means that if the engine was running you would have to turn the ignition (and the engine) off before you could engage the starter again.

I'll post the code changes if someone asks. Speaker new press beep and 1-second double beep code has been added (60 words program memory used).

Regards, Mike
ignition-logic-2-png.33959
 

Attachments

  • Ignition logic 2.PNG
    Ignition logic 2.PNG
    9.4 KB · Views: 1,756
Last edited:
Mike, that's some purty lookin code, very well documented and easy on the eyes. As somebody who has to review code once it is in a repository (sometimes affectionately called a suppository), your code is very nice.
 
WOW!.... To be honest I kind of forgot about this project thinking I would never figure it out... Well it came across my mind again and I decided to check this forum! Didn't know so many people had replied! Now I am excited to restart this project.... But I clearly have a LOT of reading ahead of me because I am VERY confused by 98% of what has been said.... lol
Thank you all for the help!
 
Hi guys, i'm currently teaching myself electronics and signed up specifically for this thread. I've built the circuits shown above (with a debounced switch) but used a 12F635 IC instead of the 10F200 and I'm having trouble porting the code over. Any help would be appreciated, im still VERY green when it comes to PICs so please be gentle!
 
Hi Tom,

You should only need a couple simple changes to port the code over to a 12F635. I would recommend you use the version 2 software (below) as a starting point though because it has the additional simple "lock out" safety logic.

I could also probably post a version 2 listing for the 12F635 if you like. Please tell us what pins you're using for the switch and relay outputs.

Regards, Mike

ignition-10f200-png.38690


Code:
;******************************************************************
;*                                                                *
;*  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
 

Attachments

  • Ignition 10F200.PNG
    Ignition 10F200.PNG
    82.4 KB · Views: 1,599
Wow, thanks for the quick reply, I'm using the same pinouts as you detailed in the circuit diagram (GP3 Switch, GP2 Speaker, GP0 Ignition and GP1 for starter)
 
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.
 
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.

Your analysis of the subroutine is incorrect Colin.
 
Last edited:
I still cant get your code to play nice with a 12F635, I'm still very new to programming so am probably missing something fairly obvious :(
 
Here's version 2 software for 12F635. Please note that the GP3 pin on the 12F635 does not have an internal pull-up resistor like the GP3 pin on the 10F200 does so you will need to add an external pull-up.

Regards, Mike

Code:
        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
 
about ignition button

HI to all, It is possible to modify the code and schematic for PIC12F683 ? I have couple of those.
 
Status
Not open for further replies.

Latest threads

New Articles From Microcontroller Tips

Back
Top