OFF-the-wall idea for momentary ON switch

MrDEB

Well-Known Member
Looking to build a digital kitchen timer that shuts off after timing out and/or a 10 second delay waiting for user input.
Here is the screenshot of the on/off section of the kitchen timer. Going to use an 18Fxxxx pic
maybe need a diode on the pic output pin to prevent applying voltage to the unpowered pic. unpowered pic?
 
browsers remove extraneous spaces and tabs

No, the forum software removes spaces and tabs, else when I edited my post, I wouldn't have seen the original line with the spacers.

Anyway, I was mostly surprised that the spaces were in fact saved so they were visible when I edited. And yes, I have experienced this before and understand the use of code tags, but trying to decipher MrDEB 's code can lead to a confused state.
 
No, the forum software removes spaces and tabs, else when I edited my post, I wouldn't have seen the original line with the spacers.
Browsers remove it - but obviously not when you're entering data, only when displaying it.

If you've ever written web pages you WILL have come across it (fallen foul of it )
 
Looking at the previous posts. it seems to me that it's a lot easier just keeping track of the total number of seconds instead of always screwing around with hours/min/secs.

Here's an (untested) example, complete with a timer event that's called every second
EDIT - fix hours calc

Code:
program KitchenTimer

device = 18F43K22
clock = 16

// int osc and IO pin libraries
include "intosc.bas"
#option DIGITALIO_INIT = true       // automatically call setalldigital
include "setdigitalio.bas"

#option LCD_DATA = PORTD.4
#option LCD_RS = PORTD.2
#option LCD_EN = PORTD.3
include "LCD.bas"

include "convert.bas"
include "utils.bas"
include "ISRTimer.bas"

//SWITCHES
dim SelKey   as PORTB.0
dim PlusKey  as PORTB.1
dim MinusKey as PORTB.2
dim StartKey as PORTB.3    //start countdown
dim SWT_4 as PORTB.4
dim SWT_5 as PORTB.5
dim SWT_6 as PORTB.6
dim SWT_7 as PORTB.7

//LEDS
dim led0 as PORTC.0  //HOURS+
dim led1 as PORTC.1  //HOURS-
dim led2 as PORTC.2  //MINUTES+
dim led3 as PORTC.3  //MINUTES-
dim led4 as PORTC.4  //SECONDS+
dim led5 as PORTC.5  //SECONDS-
dim led6 as PORTC.6
dim led7 as PORTC.7

dim sel_focus as byte       // used to set Plus/Minus key increment (H:M:S)
dim total_secs as word      // user input (total H:M:S in secs)
dim timer_secs as word      // timer counter
dim t_secs as word          // interrupt-safe timer value used for display

// timer index number (one timer)
const Timer1 = 0

// display H:M:S on the LCD
sub DisplayTime(secs as word)
    dim t_hours, t_mins, t_secs as byte
    dim t_total as word
 
    // convert total secs to individual H,M,S for display
    t_total = secs                  // time to convert

    t_hours = t_total / 3600                 // number of hours
    t_total = t_total - (t_hours * 3600)     // subtract hours from total

    t_mins = t_total / 60                   // number of minutes
    t_total = t_total - (t_mins * 60)       // subtract minutes from the total

    t_secs = t_total                        // what's left is seconds

    //               123456789012345
    LCD.WriteAt(1,1,"HRS   MIN   SEC")
    LCD.WriteAt(2,1, DecToStr(t_hours), 3, " ")     // print 3 chars, pad w/space
    LCD.WriteAt(2,7, DecToStr(t_mins), 3, " ")
    LCD.WriteAt(2,13, DecToStr(t_secs), 3, " ")
end sub

// timer event called by ISRTimer to keep track of elapsed time
event OnTimer1()
    if (timer_secs > 0) then
        timer_secs = timer_secs - 1
    endif
end event

// key debounce delay
sub Debounce()
    delayms(100)
end sub

// start of main program
main:
    // set switch port to inputs and enable pullups
    TRISB = $ff                // set as inputs
    WPUB = $ff                // enable pullups on all PORTB pins
    INTCON2.bits(7) = 0        // set bit RBPU = 0 turns on pullups

    // set led port to outputs, all low
    LATC = 0
    TRISC = 0

    // init variables
    total_secs = 0
    timer_secs = 0
 
    // init LCD
    LCD.Cls()

    // activate the timer module for one timer...
    Timer.Initialize(1)

    // wait for START button
    // the SEL button is used to select H:M:S for PLUS/MINUS buttons
    // each press increments sel_focus
    //  sel_focus = 0   PLUS/MINUS Secs
    //  sel_focus = 1   PLUS/MINUS Mins
    //  sel_focus = 2   PLUS/MINUS Hrs

    while (true)
        DisplayTime(total_secs)
        sel_focus = 0                   // default to Secs
        repeat
            if (SelKey = 0) then           // Sel button
                sel_focus = sel_focus + 1
                if (sel_focus > 2) then     // wrap back to Secs
                    sel_focus = 0
                endif
                Debounce()
            elseif (PlusKey = 0) then      // Plus button
                select (sel_focus)
                    case 0                  // incr by secs
                        total_secs = total_secs + 1  
                    case 1                  // incr by mins (60 secs)
                        total_secs = total_secs + 60     
                    case 2                  // incr by hours (3600 secs)
                        total_secs = total_secs + 3600
                end select
                DisplayTime(total_secs)
                Debounce()
            elseif (MinusKey = 0) then     // Minus button
                select (sel_focus)
                    case 0                  // decr by secs
                        if (total_secs > 0) then
                            total_secs = total_secs - 1
                        endif
                    case 1                  // decr by mins (60 secs)
                        if (total_secs > 60) then
                            total_secs = total_secs - 60
                        endif
                    case 2                  // decr by hours (3600 secs)
                        if (total_secs > 3600) then
                            total_secs = total_secs - 3600
                        endif
                end select
                DisplayTime(total_secs)
                Debounce()
            endif
        until (StartKey = 0)

        // Start timer running
        // set timer total seconds counter from user input
        timer_secs = total_secs
     
        // initialise the timers - refreshes every 1000Hz (1ms)...
        Timer.Items(Timer1).Interval = 1000        // call event every 1 sec
        Timer.Items(Timer1).OnTimer = OnTimer1     // timer event handler
        Timer.Items(Timer1).Enabled = true
        // start processing all timers...
        Timer.Start

        // wait for timer total secs to count down
        repeat
            delayms(100)                // wait a bit... no sense in hammering the lcd
            repeat                      // get an interrupt-safe copy of the timer seconds
                t_secs = timer_secs
            until (t_secs = timer_secs)
            DisplayTime(t_secs)
        until (t_secs = 0)

        Timer.Stop
    end while

end program
 
Last edited:
After all this time I know better than that.

btw, the code in post 124 will max out at about 18 hours since it uses a word to store the secs data (65535 secs = 18.2 hours). If you want a longer time then change all the 'as word' declarations to 'as longword'. That extends it to years worth of seconds.

It's not meant to be a complete program... you'll probably want to add better button debounce handling, LED indicators for what's going on, etc.
 
I ran the program code and yes it has a few hickups, I need to pour over the code again and change the debounce and figure out what it is displaying when finished.
Seems to run good otherwise.
 
For the "debounce" routine you might want to try something like this instead
Code:
// key debounce delay
sub Debounce()
    delayms(50)
    // wait for all keys to be released
    while (PORTB <> $FF)
    end while
    delayms(50)
end sub
That'll wait for all buttons to be released before continuing.
There are better ways to handle buttons, but that's probably the simplest.

...and figure out what it is displaying when finished.
The LCD should display "0 0 0" when the timer finishes, after which it'll go back to the beginning of the 'while (true)' loop and display the last entered time again ( DisplayTime(total_secs) ). Add a 'delayms(1000)' after the timer.stop if you want to see the "0 0 0" better
Code:
        Timer.Stop
         // timer is done... wait a bit
        delayms(1000)
    end while

You could add LED indicators for what's going on, such as 'running/stopped', which H:M:S has focus (sel_focus), etc.
 
Here's an updated version that includes using some of the LEDs for status indicators.
It also lets you choose the max time supported (18hrs/99hrs), and has 'improved' button handling

Code:
program KitchenTimer

device = 18F43K22
clock = 16

// this option sets the longest time for the timer
// select either 'word' (18 hours) or 'longword' (99 hours)
#option MAX_TIME_TYPE = word
#if not(MAX_TIME_TYPE in (word, longword))
  #error "MAX_TIME_TYPE option must be 'word' or 'longword'"
#endif  
#if (MAX_TIME_TYPE = word)
  type time_t = word
  const MAX_SECS = 18 * 3600        // limit timer to 18 hours
#else
  type time_t = longword
  const MAX_SECS = 99 * 3600        // limit timer to 99 hours
#endif

// int osc and IO pin libraries
include "intosc.bas"
#option DIGITALIO_INIT = true       // automatically call setalldigital
include "setdigitalio.bas"

#option LCD_DATA = PORTD.4
#option LCD_RS = PORTD.2
#option LCD_EN = PORTD.3
include "LCD.bas"

include "convert.bas"
include "utils.bas"

#option TIMER_AVAILABLE = 1     // we only use one timer
include "ISRTimer.bas"

//SWITCHES
dim AllKeys  as PORTB
dim SelKey   as PORTB.0
dim PlusKey  as PORTB.1
dim MinusKey as PORTB.2
dim StartKey as PORTB.3    //start countdown
dim SWT_4 as PORTB.4
dim SWT_5 as PORTB.5
dim SWT_6 as PORTB.6
dim SWT_7 as PORTB.7

//LEDS
dim ALL_LEDS    as PORTC
dim SEC_LED     as PORTC.0  // sel_focus = 0 (secs)
dim MIN_LED     as PORTC.1  // sel_focus = 1 (mins)
dim HOUR_LED    as PORTC.1  // sel_focus = 2 (hours)
dim START_LED   as PORTC.2  // waiting for START key
dim RUN_LED     as PORTC.3  // timer running
dim led4 as PORTC.4
dim led5 as PORTC.5
dim led6 as PORTC.6
dim led7 as PORTC.7

dim sel_focus as byte         // used to set Plus/Minus key increment (H:M:S)
dim total_secs as time_t      // user input (total H:M:S in secs)
dim timer_secs as time_t      // timer counter
dim t_secs as time_t          // interrupt-safe timer value used for display

// timer index number (one timer)
const Timer1 = 0

// display H:M:S on the LCD
sub DisplayTime(secs as time_t)
    dim t_hours, t_mins, t_secs as byte
    dim t_total as time_t
    
    // convert total secs to individual H,M,S for display
    t_total = secs                  // time to convert

    t_hours = t_total / 3600                 // number of hours
    t_total = t_total - (t_hours * 3600)     // subtract hours from total

    t_mins = t_total / 60                   // number of minutes
    t_total = t_total - (t_mins * 60)       // subtract minutes from the total

    t_secs = t_total                        // what's left is seconds

    //               123456789012345
    LCD.WriteAt(1,1,"HRS   MIN   SEC")
    LCD.WriteAt(2,1, DecToStr(t_hours), 3, " ")     // print 3 chars, pad w/space
    LCD.WriteAt(2,7, DecToStr(t_mins), 3, " ")
    LCD.WriteAt(2,13, DecToStr(t_secs), 3, " ")
end sub

// timer event called by ISRTimer to keep track of elapsed time
event OnTimer1()
    if (timer_secs > 0) then
        timer_secs = timer_secs - 1
    endif
end event

// key debounce/ wait for all released
sub WaitForRelease()
    delayms(50)

    // wait for all keys to be released
    while (AllKeys <> $FF)
    end while

    delayms(50)
end sub

// start of main program
main:
    // set switch port to inputs and enable pullups
    TRISB = $ff                // set as inputs
    WPUB = $ff                // enable pullups on all PORTB pins
    INTCON2.bits(7) = 0        // set bit RBPU = 0 turns on pullups

    // set led port to outputs, all low
    ALL_LEDS = 0
    TRISC = 0

    // init variables
    total_secs = 0
    timer_secs = 0
    
    // init LCD
    LCD.Cls()

    // activate the timer module for one timer...
    Timer.Initialize(1)

    // wait for START button
    // the SEL button is used to select H:M:S for PLUS/MINUS buttons
    // each press increments sel_focus
    //  sel_focus = 0   PLUS/MINUS Secs
    //  sel_focus = 1   PLUS/MINUS Mins
    //  sel_focus = 2   PLUS/MINUS Hrs

    while (true)
        DisplayTime(total_secs)
        sel_focus = 0                   // default to Secs
        ALL_LEDS = 0
        SEC_LED = 1
        START_LED = 1
        repeat
            if (SelKey = 0) then           // Sel button
                sel_focus = sel_focus + 1
                if (sel_focus > 2) then     // wrap back to Secs
                    sel_focus = 0
                endif
                select (sel_focus)
                    case 0:
                        SEC_LED = 1
                        MIN_LED = 0
                        HOUR_LED = 0
                    case 1:
                        SEC_LED = 0
                        MIN_LED = 1
                        HOUR_LED = 0
                    case 2:
                        SEC_LED = 0
                        MIN_LED = 0
                        HOUR_LED = 1
                end select                        
                WaitForRelease()
            elseif (PlusKey = 0) then      // Plus button
                select (sel_focus)
                    case 0                  // incr by secs
                        if (total_secs < (MAX_SECS-1)) then
                            total_secs = total_secs + 1
                        endif     
                    case 1                  // incr by mins (60 secs)
                        if (total_secs < (MAX_SECS-60)) then
                            total_secs = total_secs + 60
                        endif
                    case 2                  // incr by hours (3600 secs)
                        if (total_secs < (MAX_SECS-3600)) then
                            total_secs = total_secs + 3600
                        endif
                end select
                DisplayTime(total_secs)
                WaitForRelease()
            elseif (MinusKey = 0) then     // Minus button
                select (sel_focus)
                    case 0                  // decr by secs
                        if (total_secs > 0) then
                            total_secs = total_secs - 1
                        endif
                    case 1                  // decr by mins (60 secs)
                        if (total_secs > 60) then
                            total_secs = total_secs - 60
                        endif
                    case 2                  // incr by hours (3600 secs)
                        if (total_secs > 3600) then
                            total_secs = total_secs - 3600
                        endif
                end select
                DisplayTime(total_secs)
                WaitForRelease()
            endif
        until (StartKey = 0)

        // Start timer running
        // set timer total seconds counter from user input
        ALL_LEDS = 0
        RUN_LED = 1
        timer_secs = total_secs
        
        // initialise the timers - refreshes every 1000Hz (1ms)...
        Timer.Items(Timer1).Interval = 1000        // call event every 1 sec
        Timer.Items(Timer1).OnTimer = OnTimer1     // timer event handler
        Timer.Items(Timer1).Enabled = true
        // start processing all timers...
        Timer.Start

        // wait for timer total secs to count down
        repeat
            delayms(100)                // wait a bit... no sense in hammering the lcd
            repeat                      // get an interrupt-safe copy of the timer seconds
                t_secs = timer_secs
            until (t_secs = timer_secs) // re-read until two successive reads are the same
            DisplayTime(t_secs)
            toggle(RUN_LED)
        until (t_secs = 0)

        // timer is done
        Timer.Stop
        RUN_LED = 0
        
        // wait a bit before looping
        delayms(1000)
    end while

end program
 
just ran the code in post#132
won't accept any input.
NOTE I like the way your calling subroutes DisplayTime(total_secs) instead of just DisplayTime()
going to work with it and improve the input of desired time.
After some research, my code in post#117 is missing lots of code after while true
BUT running the complete code in #117 it still outputs hexadecimal (not binary)
 
After some research, my code in post#117 is missing lots of code after while true
BUT running the complete code in #117 it still outputs hexadecimal (not binary)

You need to explain exactly what is being displayed. Pictures of the display would help.

Bur tumbleweed's code is probably your best bet. His code should work, so please explain what you're doing exactly.
 
just ran the code in post#132
won't accept any input.
So the code in post#124 worked but the code in post#132 doesn't?
Are you leaving the programmer attached? If so, try running it with the programmer disconnected.

The code would have to be modified to ignore RB6 and RB7. The PICkit has pulldowns on those two pins, so it could get stuck in the WaitForRelease() routine.

If that's not the problem let me know...

This version allows you to ignore the buttons on RB6 and RB7 (#option IGNORE_RB6_RB7 = true)
Code:
program KitchenTimer

device = 18F43K22
clock = 16

// this option sets the longest time for the timer
// select either 'word' (18 hours) or 'longword' (99 hours)
#option MAX_TIME_TYPE = word
#if not(MAX_TIME_TYPE in (word, longword))
  #error "MAX_TIME_TYPE option must be 'word' or 'longword'"
#endif 
#if (MAX_TIME_TYPE = word)
  type time_t = word
  const MAX_SECS = 18 * 3600        // limit timer to 18 hours
#else
  type time_t = longword
  const MAX_SECS = 99 * 3600        // limit timer to 99 hours
#endif

// this option allows you to ignore the buttons on RB6 and RB7
#option IGNORE_RB6_RB7 = true

// int osc and IO pin libraries
include "intosc.bas"
#option DIGITALIO_INIT = true       // automatically call setalldigital
include "setdigitalio.bas"

#option LCD_DATA = PORTD.4
#option LCD_RS = PORTD.2
#option LCD_EN = PORTD.3
include "LCD.bas"

include "convert.bas"
include "utils.bas"

#option TIMER_AVAILABLE = 1     // we only use one timer
include "ISRTimer.bas"

//SWITCHES
dim AllKeys  as PORTB
dim SelKey   as PORTB.0
dim PlusKey  as PORTB.1
dim MinusKey as PORTB.2
dim StartKey as PORTB.3    //start countdown
dim SWT_4 as PORTB.4
dim SWT_5 as PORTB.5
dim SWT_6 as PORTB.6
dim SWT_7 as PORTB.7

//LEDS
dim ALL_LEDS    as PORTC
dim SEC_LED     as PORTC.0  // sel_focus = 0 (secs)
dim MIN_LED     as PORTC.1  // sel_focus = 1 (mins)
dim HOUR_LED    as PORTC.1  // sel_focus = 2 (hours)
dim START_LED   as PORTC.2  // waiting for START key
dim RUN_LED     as PORTC.3  // timer running
dim led4 as PORTC.4
dim led5 as PORTC.5
dim led6 as PORTC.6
dim led7 as PORTC.7

dim sel_focus as byte         // used to set Plus/Minus key increment (H:M:S)
dim total_secs as time_t      // user input (total H:M:S in secs)
dim timer_secs as time_t      // timer counter
dim t_secs as time_t          // interrupt-safe timer value used for display

// timer index number (one timer)
const Timer1 = 0

// display H:M:S on the LCD
sub DisplayTime(secs as time_t)
    dim t_hours, t_mins, t_secs as byte
    dim t_total as time_t
   
    // convert total secs to individual H,M,S for display
    t_total = secs                  // time to convert

    t_hours = t_total / 3600                 // number of hours
    t_total = t_total - (t_hours * 3600)     // subtract hours from total

    t_mins = t_total / 60                   // number of minutes
    t_total = t_total - (t_mins * 60)       // subtract minutes from the total

    t_secs = t_total                        // what's left is seconds

    //               123456789012345
    LCD.WriteAt(1,1,"HRS   MIN   SEC")
    LCD.WriteAt(2,1, DecToStr(t_hours), 3, " ")     // print 3 chars, pad w/space
    LCD.WriteAt(2,7, DecToStr(t_mins), 3, " ")
    LCD.WriteAt(2,13, DecToStr(t_secs), 3, " ")
end sub

// timer event called by ISRTimer to keep track of elapsed time
event OnTimer1()
    if (timer_secs > 0) then
        timer_secs = timer_secs - 1
    endif
end event

// key debounce/ wait for all released
sub WaitForRelease()
  #if (IGNORE_RB6_RB7)
    const KEY_MASK = %11000000
  #else
    const KEY_MASK = 0
  #endif
         
    delayms(50)

    // wait for all keys to be released
    while ((AllKeys or KEY_MASK) <> $FF)
    end while
 
    delayms(50)
end sub

// start of main program
main:
    // set switch port to inputs and enable pullups
    TRISB = $ff                // set as inputs
    WPUB = $ff                // enable pullups on all PORTB pins
    INTCON2.bits(7) = 0        // set bit RBPU = 0 turns on pullups

    // set led port to outputs, all low
    ALL_LEDS = 0
    TRISC = 0

    // init variables
    total_secs = 0
    timer_secs = 0
   
    // init LCD
    LCD.Cls()

    // activate the timer module for one timer...
    Timer.Initialize(1)

    // wait for START button
    // the SEL button is used to select H:M:S for PLUS/MINUS buttons
    // each press increments sel_focus
    //  sel_focus = 0   PLUS/MINUS Secs
    //  sel_focus = 1   PLUS/MINUS Mins
    //  sel_focus = 2   PLUS/MINUS Hrs

    while (true)
        DisplayTime(total_secs)
        sel_focus = 0                   // default to Secs
        ALL_LEDS = 0
        SEC_LED = 1
        START_LED = 1
        repeat
            if (SelKey = 0) then           // Sel button
                sel_focus = sel_focus + 1
                if (sel_focus > 2) then     // wrap back to Secs
                    sel_focus = 0
                endif
                select (sel_focus)
                    case 0:
                        SEC_LED = 1
                        MIN_LED = 0
                        HOUR_LED = 0
                    case 1:
                        SEC_LED = 0
                        MIN_LED = 1
                        HOUR_LED = 0
                    case 2:
                        SEC_LED = 0
                        MIN_LED = 0
                        HOUR_LED = 1
                end select                       
                WaitForRelease()
            elseif (PlusKey = 0) then      // Plus button
                select (sel_focus)
                    case 0                  // incr by secs
                        if (total_secs < (MAX_SECS-1)) then
                            total_secs = total_secs + 1
                        endif    
                    case 1                  // incr by mins (60 secs)
                        if (total_secs < (MAX_SECS-60)) then
                            total_secs = total_secs + 60
                        endif
                    case 2                  // incr by hours (3600 secs)
                        if (total_secs < (MAX_SECS-3600)) then
                            total_secs = total_secs + 3600
                        endif
                end select
                DisplayTime(total_secs)
                WaitForRelease()
            elseif (MinusKey = 0) then     // Minus button
                select (sel_focus)
                    case 0                  // decr by secs
                        if (total_secs > 0) then
                            total_secs = total_secs - 1
                        endif
                    case 1                  // decr by mins (60 secs)
                        if (total_secs > 60) then
                            total_secs = total_secs - 60
                        endif
                    case 2                  // decr by hours (3600 secs)
                        if (total_secs > 3600) then
                            total_secs = total_secs - 3600
                        endif
                end select
                DisplayTime(total_secs)
                WaitForRelease()
            endif
        until (StartKey = 0)

        // Start timer running
        // set timer total seconds counter from user input
        ALL_LEDS = 0
        RUN_LED = 1
        timer_secs = total_secs
       
        // initialise the timers - refreshes every 1000Hz (1ms)...
        Timer.Items(Timer1).Interval = 1000        // call event every 1 sec
        Timer.Items(Timer1).OnTimer = OnTimer1     // timer event handler
        Timer.Items(Timer1).Enabled = true
        // start processing all timers...
        Timer.Start

        // wait for timer total secs to count down
        repeat
            delayms(100)                // wait a bit... no sense in hammering the lcd
            repeat                      // get an interrupt-safe copy of the timer seconds
                t_secs = timer_secs
            until (t_secs = timer_secs) // re-read until two successive reads are the same
            DisplayTime(t_secs)
            toggle(RUN_LED)
        until (t_secs = 0)

        // timer is done
        Timer.Stop
        RUN_LED = 0
       
        // wait a bit before looping
        delayms(1000)
    end while

end program
 
Last edited:
Thanks, Mike.

Since 'timer_secs' is a multi-byte variable modified by the ISR in the callback event OnTimer1, something has to be done to protect accessing it, otherwise you could get invalid data.

The simple way to do this is to just disable/enable interrupts around it...
Code:
disable_intr()
t_secs = timer_secs
enable_intr()
which is way less code, but that requires knowing whether or not you should be screwing around with the GIE bit.

Re-reading it until you get two reads that are the same lets you leave interrupts alone.
 
My (C) version has a flag but yours is much simpler.
Code:
uint32_t getMs(void){
    uint32_t retVal;
    flagISR=0;
    retVal=tickMs;
    if(flagISR)             //if Interrupt occurred
        retVal=tickMs;      //fetch milli seconds again
    return(retVal);
}
As I already have a variable to hold the value (retVal), I can get rid of the flag completely.
I also don't like playing around with GIE.

My modified version,
Code:
uint32_t getMs(void){
    uint32_t retVal;
    retVal=tickMs;
    if(retVal!=tickMs)       //if Interrupt occurred
        retVal=tickMs;      //fetch milli seconds again
    return(retVal);
}
It will, of course, be slower but I've got oodles of time to spare.

Mike.
P.S. note, lack of braces around subject of if statement. Uni lecturers will have a fit.
 
he code in post#136 works THANKS
need to redo the menu nput / leds. could be confusing IMO
going to attempt using my menu from post#100 and integrate it into post#100
 
Cookies are required to use this site. You must accept them to continue using the site. Learn more…