Starting and stopping an LED chase with a pushbutton

I'd never heard of an Arduino until a few weeks ago, so I'm what you'd call a "new-bee." My next-door neighbor who dabbles in robotics turned me on to it. I have a very rudimentary knowledge of building circuits and some experience writing (mainly adapting) simple expressions in After Effects (computer animation is my profession.)

I'm in the process of building a new version of a Ghostbusters PKE meter I originally made in 1989:

http://www.gbfans.com/fans/props/PKE-meters/2961/

For my new, more-accurate version I plan to use a Teensy 3.1 to drive two servos for the arms and the LED chaser, activated by two touch switches. One switch sends the arms halfway up, the other sends them all the way up. The lights activate whenever either touch switch is engaged, their speed controlled by a pot in the neck of the prop.

I've had a fair amount of luck adapting various existing sketches to create something that mostly works. For now I've got momentary contact switches instead of touch switches (which I still need to figure out).

My prototype mostly works except for the LED chaser, which I adapted from this design:

http://rweather.github.io/arduinolibs/blink_startrek.html

The problem I'm having is that whatever LED was lit when the switch opens stays on. ALL of the LEDs should be off when the arms go down. Here's a 9 MB MPG which shows the setup:

http://marshall-arts.net/PKE/PKE%20Demo.mp4

I'm not sure what I have to do to make all of the lights extinguish. I also need to figure out how to make a single LED blink at the frequency of the wing LEDs (blinking as each LED in the wings sequences).

Here's my code. Sorry if it's horribly inefficient or something:

#include <Servo.h> 
#include <ChaseLEDs.h>
#define NACELLE_RATE         22    // Analog input for reading the nacelle chase rate
#define NACELLE_CHASE_LEN    7     // Length of nacelle chase, 1..6
#define NACELLE_MIN_PERIOD   25    // Minimum time to advance the nacelle chase (milliseconds)
#define NACELLE_MAX_PERIOD   250   // Maximum time to advance the nacelle chase (milliseconds)
#define NACELLE_DIM_VALUE    0      // Value for dimming previous LED in chase, 0..255
// Output pins to use for the nacelle chase
byte nacelleChasePins[7] = {14, 15, 16, 17, 18, 19, 20};
class NacelleChaseLEDs : public ChaseLEDs
{
public:
  NacelleChaseLEDs(const byte *pins, int num)
    : ChaseLEDs(pins, num, 0) {}
protected:
  void advance(byte prevPin, byte nextPin) {
    digitalWrite(previousPin(2), LOW);
    analogWrite(prevPin, NACELLE_DIM_VALUE);
    digitalWrite(nextPin, HIGH);
    setAdvanceTime(map(analogRead(NACELLE_RATE), 0, 1023, NACELLE_MIN_PERIOD, NACELLE_MAX_PERIOD));
  }
};
NacelleChaseLEDs nacelleChase(nacelleChasePins, NACELLE_CHASE_LEN);
 
Servo myservoL;  // create servo object to control a servo 
                // a maximum of eight servo objects can be created 
Servo myservoR; 

void setup()
{
  myservoL.attach(9);
  myservoR.attach(10);
  pinMode(13, OUTPUT);       // LED
  pinMode(12, INPUT_PULLUP); // Pushbutton
  pinMode(11, INPUT_PULLUP); // Pushbutton
}

void loop()
{
  if (digitalRead(12)) // 12 pin is high due to pullup resistor - Returns 1, so this block happens.  If it returns 0 (button pressed, pin goes low), else happens
  {
    digitalWrite(13, LOW);   // LED off
    if (digitalRead(11)) // 11 pin is high due to pullup resistor - Returns 1, so this block happens.  If it returns 0 (button pressed, pin goes low), else happens
  {
    myservoL.write(20);
    myservoR.write(140);
  } 
  
  else
  {
    // Pin is Low - returns 0 - 12 pin is low due to pushbutton pressed
    digitalWrite(13, HIGH);  // LED on
    myservoL.write(80);
    myservoR.write(80);
    nacelleChase.loop();
  }
  } 
  
  else
  {
    // Pin is Low - returns 0 - 12 pin is low due to pushbutton pressed
    digitalWrite(13, HIGH);  // LED on
    myservoL.write(140);
    myservoR.write(20);
    nacelleChase.loop();
  }
}

Any suggestions as to a simple approach to this would be appreciated.

Thanks.

Shawn Marshall
Portland, OR

Would simply sending all of seven wing LED output pins low when the switches are off be the best way to do this?

Shawn

Hi Shawn

The problem I'm having is that whatever LED was lit when the switch opens stays on. ALL of the LEDs should be off when the arms go down.

At the point(s) in your if statements where you stop the chase sequence, try adding this:

digitalWrite(nacelleChase.previousPin(0), LOW);

According to the library documentation, previousPin(0) will return the number of the current pin that was lit the last time that nacelleChase.loop() was called.

Regards

Ray

Hi Ray:

Thanks for the quick reply; I appreciate it.

I tried inserting that snippet of code into the IF statements (so it runs when the buttons are not pressed), but I get this error message when verifying the sketch:

In file included from Pushbutton_Dual_Servos_With_Chase.ino:2:0:
/Applications/Arduino.app/Contents/Resources/Java/libraries/ChaseLEDs/ChaseLEDs.h: In function 'void loop()':
/Applications/Arduino.app/Contents/Resources/Java/libraries/ChaseLEDs/ChaseLEDs.h:34:9: error: 'uint8_t ChaseLEDs::previousPin(int) const' is protected
Pushbutton_Dual_Servos_With_Chase:43: error: within this context
In file included from Pushbutton_Dual_Servos_With_Chase.ino:2:0:
/Applications/Arduino.app/Contents/Resources/Java/libraries/ChaseLEDs/ChaseLEDs.h:34:9: error: 'uint8_t ChaseLEDs::previousPin(int) const' is protected
Pushbutton_Dual_Servos_With_Chase:46: error: within this context

I don't know what the error about 'uint8_t ChaseLEDs::previousPin(int) const' being protected (in the library file, I guess) means.

Here's the sketch with that code inserted:

#include <Servo.h> 
#include <ChaseLEDs.h>
#define NACELLE_RATE         22    // Analog input for reading the nacelle chase rate
#define NACELLE_CHASE_LEN    7     // Length of nacelle chase, 1..6
#define NACELLE_MIN_PERIOD   25    // Minimum time to advance the nacelle chase (milliseconds)
#define NACELLE_MAX_PERIOD   250   // Maximum time to advance the nacelle chase (milliseconds)
#define NACELLE_DIM_VALUE    0      // Value for dimming previous LED in chase, 0..255
// Output pins to use for the nacelle chase
byte nacelleChasePins[7] = {14, 15, 16, 17, 18, 19, 20};
class NacelleChaseLEDs : public ChaseLEDs
{
public:
  NacelleChaseLEDs(const byte *pins, int num)
    : ChaseLEDs(pins, num, 0) {}
protected:
  void advance(byte prevPin, byte nextPin) {
    digitalWrite(previousPin(2), LOW);
    analogWrite(prevPin, NACELLE_DIM_VALUE);
    digitalWrite(nextPin, HIGH);
    setAdvanceTime(map(analogRead(NACELLE_RATE), 0, 1023, NACELLE_MIN_PERIOD, NACELLE_MAX_PERIOD));
  }
};
NacelleChaseLEDs nacelleChase(nacelleChasePins, NACELLE_CHASE_LEN);
 
Servo myservoL;  // create servo object to control a servo 
                // a maximum of eight servo objects can be created 
Servo myservoR; 

void setup()
{
  myservoL.attach(9);
  myservoR.attach(10);
  pinMode(13, OUTPUT);       // LED
  pinMode(12, INPUT_PULLUP); // Pushbutton
  pinMode(11, INPUT_PULLUP); // Pushbutton
}

void loop()
{
  if (digitalRead(12)) // 12 pin is high due to pullup resistor - Returns 1, so this block happens.  If it returns 0 (button pressed, pin goes low), else happens
  {
    digitalWrite(13, LOW);   // LED off
    digitalWrite(nacelleChase.previousPin(0), LOW);
    if (digitalRead(11)) // 11 pin is high due to pullup resistor - Returns 1, so this block happens.  If it returns 0 (button pressed, pin goes low), else happens
  {  
    digitalWrite(nacelleChase.previousPin(0), LOW);
    myservoL.write(20);
    myservoR.write(140);
  } 
  
  else
  {
    // Pin is Low - returns 0 - 12 pin is low due to pushbutton pressed
    digitalWrite(13, HIGH);  // LED on
    myservoL.write(80);
    myservoR.write(80);
    nacelleChase.loop();
  }
  } 
  
  else
  {
    // Pin is Low - returns 0 - 12 pin is low due to pushbutton pressed
    digitalWrite(13, HIGH);  // LED on
    myservoL.write(140);
    myservoR.write(20);
    nacelleChase.loop();
  }
}

Again I wonder whether just manually setting all those LED pins low in the IF statements would work. Probably not as elegant or efficient.

Cheers.

Shawn

Looks like the previousPin() method is not exposed as a public method that you can call. Sorry for the red herrring :blush:

Your idea of writing low to all the LEDs is probably the quickest way to fix the problem

You had another question ...

I also need to figure out how to make a single LED blink at the frequency of the wing LEDs (blinking as each LED in the wings sequences).

Do you mean a different LED from those in the chase sequence? And do you want this LED to go on AND off in the time it takes for one step in the chase? Or go on at one step, off at the next, on at the next, etc?

Hi Ray:

Thanks for the clarification. I'm fuzzy on the concept of public versus protected code in the library.

Regarding the blinking solo LED, it would light every time one of the wing LEDs light, so if it's a slow chase that LED blinks slowly; if it's a fast chase it blinks faster. On my old analog version I had a 555 timer chip driving a 4017 decade counter to create the LED chase on the wings. The solo LED was tied into the pulse generated by the 555.

Maybe it's just some separate non-delay blink code tied to the potentiometer input. I can research that.

Cheers.

Shawn

it would light every time one of the wing LEDs light

So it would go on when the next chase LED comes on. Then go off. Then come on again when the next chase LED comes on?

Or on with the first chase LED and off with the second chase LED?

The library you are using has "blink without delay" style code to time the chase LEDs, but it is hidden away so not that easy to synchronise with your new LED.

Hi:

Thanks again for the quick reply.

The solo LED would NOT go off for every other wing LED. When a wing LED is lit the solo LED is lit. On my analog version the solo LED would only be off for a small fraction of a second, pulsing with each pulse the 555 was sending to the decade counter.

It wouldn't have to be a perfect match between the wings and the solo LED, just as long as the solo blinking rate mimics the speed of the chase.

I've been looking for chase without delay controlled by a pot code snippets I can adapt for this, but I haven't found much else besides this nacelle approach that uses voodoo I don't really comprehend in its library. I'd be up for using another approach that's not as specialized.

I'm also wondering whether it will work to brute force all of those LED pin outputs low when the switches are off. Will it mess up the nacelle chase setup if I later assign pins 14-19 as outputs? Would there be some sort of code conflict? I suppose I could just try it to see what happens.

Thanks again for your attention to my issues; I really appreciate the help. I doubt I'll ever become an expert at this stuff (only so much room in by brain), but I do want to sort of understand the concepts involved.

Shawn

I'm also wondering whether it will work to brute force all of those LED pin outputs low when the switches are off. Will it mess up the nacelle chase setup if I later assign pins 14-19 as outputs? Would there be some sort of code conflict? I suppose I could just try it to see what happens.

Looking at the library code, I don't think you will mess anything up. It uses the advance() function embedded near the top of your program to control the chase LEDs.

Using blink without delay technique, advance() is called by another library function at a rate set by the call to setAdvanceTime() in your program - which is where the connection to the pot setting is made.

To synchronise your other LED, you could add code into the advance() function to do the following:

  1. Store the current time in a global variable - call this lastFlash, say
  2. Turn on the other LED.
  3. Store (in a global variable) the milliseconds calculated by the map() function from reading the pot - call this flashDuration, say - but reduce it to 90% for example (or maybe subtract a fixed number of milliseconds from it)

In the main loop() function of your program, you could then use blink without delay to turn off the other LED after if current time - lastFlash is greater than flashDuration.

Then, the next time that advance() is called, the other LED will come back on in sync with the next change in the chase sequence.

Thanks for the reply. Sorry for the delayed response; I had an issue with my older, analog PKE meter which I think I've corrected (getting ready for the Rose City Comic Con). At some point I'll replace its electronics with a micro controller.

At this point I'm not really comprehending your suggestion. I think I need to go through some more basic examples.

I wish I could find a chaser design that didn't rely on a library, but I'm having trouble finding any I can understand enough to modify for my needs. I don't think I can use one with a delay function since I have to read the button state. Or can I?

One odd thing I'm getting with this current sketch is that if I test the chaser with the pushbutton a few times (running at a slow rate), let is sit a minute or so, then push the button again, all of the LEDs will light up for a fraction of a second, or the lights will do a very fast but brief chase before clicking into its intended slow rate. I don't know if this is a programming glitch or something happening on my breadboard.

Cheers.

Shawn

One odd thing I'm getting with this current sketch is that if I test the chaser with the pushbutton a few times (running at a slow rate), let is sit a minute or so, then push the button again, all of the LEDs will light up for a fraction of a second, or the lights will do a very fast but brief chase before clicking into its intended slow rate. I don't know if this is a programming glitch or something happening on my breadboard.

I think I can see what you mean at the start of the video you posted. Does it still happen if you disconnect the servos completely but leave the servo code in the program?

I don't think I can use one with a delay function since I have to read the button state. Or can I?

Avoid delay().

At this point I'm not really comprehending your suggestion. I think I need to go through some more basic examples.

As a start, try these changes ...

  1. Comment out the three digitalWrite(13, ...) statements in your loop().

  2. Add digitalWrite(13, LOW) in your setup().

  3. Add one line to the function in nacelleChaseLEDs near the top of your program:

  void advance(byte prevPin, byte nextPin) {
    digitalWrite(previousPin(2), LOW);
    analogWrite(prevPin, NACELLE_DIM_VALUE);
    digitalWrite(nextPin, HIGH);
    setAdvanceTime(map(analogRead(NACELLE_RATE), 0, 1023, NACELLE_MIN_PERIOD, NACELLE_MAX_PERIOD));
    digitalWrite(13, !digitalRead(13)); // toggle the LED  <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  }

This should toggle the LED on pin 13 at half the rate of the chase. If that works, we can look at getting the rate the same.

Hi Ray:

Thanks again for the reply.

I tried disconnecting the servos and then removing the servo code in the sketch, but I still get a brief flash on all of the LEDs if the chase is activated after idling unlit for a while. I wonder if there's a small power surge or something happening. Would a decent-size capacitor bridging V+ and ground mitigate that? I don't know whether the Teensy 3.1 already does that when it's pulling power from the USB port.

It took me a few minutes to realize what you meant by "comment out" those digital writes (since I already had comments on those), then it clicked that you meant for me to deactivate that code by adding the two slashes in front of it. My neighbor who's been helping me on and off did that at one point.

I added your code and the LED does blink, though I'm not sure what part of the code is doing that. The "!"? One thing that's happening is that sometimes that LED will stay on, I guess depending on where it is in the cycle.

It turns out, though, that I think I've led us down the wrong path. I've been scrutinizing my Ghostbusters Blu-ray, and upon careful examination it appears that LED blinks at a rate independent of the wing rate. You can see in the library, when the lights on the wing are cycling slowly, that that console LED is blinking noticeably faster than the wing cycle.

As far as I can tell that LED is on when the unit is powered on and starts blinking when the wings are activated. I think I can figure out how to do that.

You wrote something about "Avoid delay ()". That's not some magic piece of code that will blink something without delay, right? I assume you'd have to use the millis approach.

Once I (we?) get this lights thing worked out I need to work out a way to replace my two contact switches with touch switches. The prop uses two pairs of wire contacts (each about a quarter-inch long) on the handle, activated by a thumb touch. Each touch switch on my analog version uses a 3905 and 3906 transistor, 10µf capacitor and 100 ohm relay to trigger DPDT relays for the servos and lights. It looks like others have been trying to do the same thing to reproduce a PKE meter:

http://forum.arduino.cc/index.php/topic,43074.0.html

http://forum.arduino.cc/index.php/topic,17426.0.html

Something to play with.

Cheers.

Shawn

I tried disconnecting the servos and then removing the servo code in the sketch, but I still get a brief flash on all of the LEDs if the chase is activated after idling unlit for a while. I wonder if there's a small power surge or something happening. Would a decent-size capacitor bridging V+ and ground mitigate that? I don't know whether the Teensy 3.1 already does that when it's pulling power from the USB port.

Powering the LEDs should not cause a problem. What value series resistor do you have on each LED?

I'm wondering if the actual problem is either in the library or due to bounce on the switches. Could you post your latest code and I'll have a look.

From your video, it looked like you had two different types of switch. Is that right? If so, have you noticed the flashing problem with both of them or just one?

The "!"?

That is the "logical NOT" operator. If a variable is high, it makes it low, and vice versa. So it reads the current state of the LED and changes it to the opposite state. The function it is in gets called by the chase library on a "blink without delay" basis each time the chase pattern gets updated, so the LED gets toggled at the same time.

I assume you'd have to use the millis approach.

That's right.

Once I (we?) get this lights thing worked out I need to work out a way to replace my two contact switches with touch switches. The prop uses two pairs of wire contacts (each about a quarter-inch long) on the handle, activated by a thumb touch. Each touch switch on my analog version uses a 3905 and 3906 transistor, 10µf capacitor and 100 ohm relay to trigger DPDT relays for the servos and lights. It looks like others have been trying to do the same thing to reproduce a PKE meter:

When you start work on this, I suggest to begin with you do a completely separate test sketch. Print the readings you get to serial monitor so that you can experiment with the resistor value, different people's fingers, etc :slight_smile: Then integrate the code into your main program.

All the best

Ray

Thanks again for your offer to help, Ray. Sorry for the delayed reply. I was still having problems with my older PKE meter. I think it's good to go now.

Here's the code for the new and improved model as it exists now:

#include <Servo.h> 
#include <ChaseLEDs.h>
#define NACELLE_RATE         22    // Analog input for reading the nacelle chase rate
#define NACELLE_CHASE_LEN    8     // Length of nacelle chase, 1..6
#define NACELLE_MIN_PERIOD   25    // Minimum time to advance the nacelle chase (milliseconds)
#define NACELLE_MAX_PERIOD   250   // Maximum time to advance the nacelle chase (milliseconds)
#define NACELLE_DIM_VALUE    0      // Value for dimming previous LED in chase, 0..255
// Output pins to use for the nacelle chase
byte nacelleChasePins[8] = {14, 15, 16, 17, 18, 19, 20, 21}; // Pin 21 is not connected to leave blank spot in sequence
class NacelleChaseLEDs : public ChaseLEDs
{
public:
  NacelleChaseLEDs(const byte *pins, int num)
    : ChaseLEDs(pins, num, 0) {}
protected:
  void advance(byte prevPin, byte nextPin) {
    digitalWrite(previousPin(2), LOW);
    analogWrite(prevPin, NACELLE_DIM_VALUE);
    digitalWrite(nextPin, HIGH);
    setAdvanceTime(map(analogRead(NACELLE_RATE), 0, 1023, NACELLE_MIN_PERIOD, NACELLE_MAX_PERIOD));
    digitalWrite(13, !digitalRead(13)); // toggle the LED  <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  }
};
NacelleChaseLEDs nacelleChase(nacelleChasePins, NACELLE_CHASE_LEN);
 
Servo myservoL;  // create servo object to control a servo 
                // a maximum of eight servo objects can be created 
Servo myservoR; 

void setup()
{
  myservoL.attach(9);
  myservoR.attach(10);
  digitalWrite(13, LOW); //Status LED OFF
  pinMode(14, OUTPUT);  //Wing LED
  pinMode(15, OUTPUT);  //Wing LED
  pinMode(16, OUTPUT);  //Wing LED
  pinMode(17, OUTPUT);  //Wing LED
  pinMode(18, OUTPUT);  //Wing LED
  pinMode(19, OUTPUT);  //Wing LED
  pinMode(20, OUTPUT);  //Wing LED
  pinMode(13, OUTPUT);       // Status LED
  pinMode(12, INPUT_PULLUP); // Pushbutton
  pinMode(11, INPUT_PULLUP); // Pushbutton
}

void loop()
{
  if (digitalRead(12)) // 12 pin is high due to pullup resistor - Returns 1, so this block happens.  If it returns 0 (button pressed, pin goes low), else happens  WINGS AT HOME, NO LIGHTS
  {
    if (digitalRead(11)) // 11 pin is high due to pullup resistor - Returns 1, so this block happens.  If it returns 0 (button pressed, pin goes low), else happens  WINGS AT HOME, NO LIGHTS
  {  
    //digitalWrite(13, LOW); //Status LED OFF
    digitalWrite(14, LOW);  //Wing LED OFF
    digitalWrite(15, LOW);  //Wing LED OFF
    digitalWrite(16, LOW);  //Wing LED OFF
    digitalWrite(17, LOW);  //Wing LED OFF
    digitalWrite(18, LOW);  //Wing LED OFF
    digitalWrite(19, LOW);  //Wing LED OFF
    digitalWrite(20, LOW);  //Wing LED OFF
    myservoL.write(20);   // Servo home position
    myservoR.write(140);  // Servo home position
  } 
  
  else
  {
    // Pin is Low - returns 0 - 12 pin is low due to pushbutton pressed  WINGS HALF UP, LIGHTS
    //digitalWrite(13, HIGH);  // Status LED on
    myservoL.write(80);  // Servo half up
    myservoR.write(80);  // Servo half up
    nacelleChase.loop();
  }
  } 
  
  else
  {
    // Pin is Low - returns 0 - 12 pin is low due to pushbutton pressed  WINGS FULL UP, LIGHTS
    //digitalWrite(13, HIGH);  // Status LED on
    myservoL.write(140); // Servo Full Up
    myservoR.write(20);  // Servo Full Up
    nacelleChase.loop();
  }
}

This includes your blinking LED approach which I'll revise so the LED blinks independently of the wing LEDs.

The brief flash of the wing LEDs happens no matter which button is pressed. The intensity of the flash increases the longer it sits between button presses (powered up, of course).

Regarding the touch switches, it seems like some people have had a difficult time making those work. This gentleman, who was building a much fancier version of this prop and appears to know much more about electronics and programming than I do, had a lot of trouble. I'm not clear on his solution:

http://forum.arduino.cc/index.php/topic,18258.0.html

The touch switches I made for my old model (basically two switching transistors, a resistor and cap) have worked fairly well. I wonder whether it would be possible to use that setup to drive input pisn low to control the functions. I'm worried that just using a certain value resistor tied to an input pin on the Teesny could be hit or miss.

Cheers.

Shawn

I'll take a look at the code, Shawn.

What value series resistor do you have on each LED?

Hi Shawn

Looking into the library, the loop() function in the library has been written on the assumption that it gets called each time round the main program loop (i.e. at a frequency higher than the frequency at which the chase sequence moves from one step to the next).

In your program, you want to pause the sequence, so this is not happening.

One way to prove whether this is the cause of the problem you are seeing is as follows ...

  1. Add a global variable
boolean chaseOn = false;
  1. In your if statements at the two places where you currently have nacelleChase.loop();, remove these statements and replace with
chaseOn = true;
  1. In your if statement where you set all the LEDs low, add this
chaseOn = false;
  1. Right at the end of your main program loop, add just one
nacelleChase.loop();
  1. Near the top of your program where the advance() function is declared, change digitalWrite(nextPin, HIGH); to this
if (chaseOn)
{
    digitalWrite(nextPin, HIGH);
}

What this should do is keep the chase constantly updated but (thanks to item 5) only switch on the LEDs when one or other of the switches is closed.

Regards

Ray

Hi Ray:

Once again, my sincere thanks for all the help you're giving me.

I'll play around with the code as soon as I can. I'll be at the convention the next few days, then slammed with client work.

FYI, I'm currently using 150 ohm-ish resistors on this breadboard. Right now they're not all the same value; they're a mixture of whatever I had lying around. In my current PKE prop I'm using 7 NPN 3904 transistors to switch on each group of three LEDs (one in each wing and one on the readout screen). Each group shares a common V+ lead, and I used a single 220 ohm resistor in each common lead. Since only one LED in each group is firing at any time this seems to have worked, even though it would probably be better to have a resistor on each LED. I'm just trying to save space in the prop.

Take care.

Shawn

Where were we?

Oh yeah, I went to the 2014 Rose City Comic Con, then had a bunch of client work, then used a lot of my free time to make molds of my PKE prop shells to make resin casts, only to decide to use my master for the final prop. Then I went to the 2015 RCCC.

So I finally had a chance to integrate this new code, and lo and behold it works. Hooray for Zoidberg!!

Thanks for all of your help with this, Ray.

Now I need to play around with replacing the physical buttons with resistive touch switches.

Cheers.

Shawn