I think that simply reading the key as is done up till now will not work. You will have to make use of keypad events to determine when a key was pressed, held or released. Below example makes use of keypad events; it's meant to show how it works under the hood. It's a stripped down version of the original example that you can study as well. The below also demonstrates a simple "do two things at the same time" where the blinking of the led does not interfere with the keypad.
#include <Keypad.h>
//********************************************
//set up for Switches or Keypad
const byte ROWS = 2; //final panel many need to be expanded upto 4 Rows
const byte COLS = 2; //final panel many need to be expanded upto 3 Cols
char keys[ROWS][COLS] = {
{ '1', '2' },
{ '3', '4' }
};
byte rowPins[ROWS] = { 2, 3 };
byte colPins[COLS] = { 4, 5 };
Keypad keypad = Keypad(makeKeymap(keys), rowPins, colPins, ROWS, COLS);
//********************************************
// led pin for non-blocking blink
const uint8_t ledPin = 13;
//********************************************
// section to update based on switch; 0 indicates that no section needs to be updated.
int8_t section = 0;
void setup()
{
Serial.begin(115200);
while (!Serial)
;
pinMode(ledPin, OUTPUT); // Sets the digital pin as output.
digitalWrite(ledPin, HIGH); // Turn the LED on.
keypad.addEventListener(keypadEvent); // Add an event listener for this keypad
}
void loop()
{
// read keypad; we can ignore the key that was pressed, it's handled in the event handler
keypad.getKey();
// do a non-blocking blink
blinkIt();
}
// Taking care of some special events.
void keypadEvent(KeypadEvent key)
{
switch (keypad.getState())
{
case PRESSED:
Serial.write(key);
Serial.println(F(" pressed"));
break;
case RELEASED:
Serial.write(key);
Serial.println(F(" released"));
break;
case HOLD:
Serial.write(key);
Serial.println(F(" held"));
break;
case IDLE:
Serial.println(F("Idle"));
break;
}
}
/*
non-blocking blink
*/
void blinkIt()
{
// the start time for the delay
static uint32_t delayStarttime;
// if one second has lapsed
if (millis() - delayStarttime > 1000)
{
// update the start time of the next delay
delayStarttime = millis();
// toggle the led
digitalWrite(ledPin, !digitalRead(ledPin));
}
}
Now you can use the event handler to set or clear the section that you want to modify; the above code already contains a global variable section for that. We're only interested in the fact that a key is pressed and in the fact that a key is released.
// Taking care of some special events.
void keypadEvent(KeypadEvent key)
{
switch (keypad.getState())
{
case PRESSED:
Serial.write(key);
Serial.println(F(" pressed"));
// set the section based on the key that was pressed
section = key - '0';
break;
case RELEASED:
Serial.write(key);
Serial.println(F(" released"));
// clear the section
section = 0;
break;
case HOLD:
Serial.write(key);
Serial.println(F(" held"));
break;
case IDLE:
Serial.println(F("Idle"));
break;
}
}
The line section = key - '0';
converts the key character to an integer.
And in loop() you can call two functions that make use of the section variable..
void loop()
{
// read keypad; we can ignore the key that was pressed, it's handled in the event handler
keypad.getKey();
// twinkle the strip
bool rv = twinkle(section);
// update section
rv |= updateSection(section);
// if one or more les changed colour, show
if (rv == true)
{
FastLED.show();
}
}
This makes use of two functions to update (but not show)
- the complete strip with the possible exception of a section
- a section of the strip if selected
/*
twinkle; set colours for full strip, exclude section if needed
In:
section number (1..4) of section to exclude; 0 indicates nothing to exclude
Returns:
true if the colour setting of a led changed, else false
*/
bool twinkle(int8_t section)
{
return false;
}
/*
set colours for a specific section of the strip
In:
section number (1..4) of section to update; 0 indicates no section to update
Returns:
true if the colour setting of a led changed, else false
*/
bool updateSection(int8_t section)
{
return false;
}
Both functions are non-blocking and return true if the colour of one or more leds were changed by the function, else they return false. The idea is to only call show
once if te colour of a led was changed in either of the functions; which makes it slightly faster. They also take the section as an argument; 0 indicates that no section was selected on the keypad, 1..4 indicate that a section was selected on the keypad; there is no hardening so if you manage to select a section higher than 4 there is a good chance that the code will crash.
You will have to add a few constants at the beginning of the above code.
//*********** strip update intervals *******************
// rate at which strip is updated
const uint16_t twinkleInterval = 100;
// rate at which section is updated
const uint16_t sectionInterval = 50;
You will also need to add the CRGB and ESTwinkle arrays back and add the FastLED stuff in setup().
Now you can fill in the details. twinkle()
will twinkle the strip and is based on your twinkle. It will exclude a section if one was selected.
/*
twinkle; set colours for full strip, exclude section if needed
In:
section number (1..4) of section to exclude; 0 indicates nothing to exclude
Returns:
true if the colour setting of a led changed, else false
*/
bool twinkle(int8_t section)
{
// start time of delay
static uint32_t delayStarttime;
// if it's time to twinkle again
if (millis() - delayStarttime >= twinkleInterval)
{
// update start time of next delay
delayStarttime = millis();
// set the twinkle colours
for (int8_t cnt = 0; cnt < NUM_LEDS; cnt++)
{
// random number for led to set
int8_t ledIndex = random(NUM_LEDS);
// if twinkle applies to full strip or if ledIndex outside selected section
if (section == 0 || ledIndex < (section - 1) * SECTION_LENGTH || ledIndex >= section * SECTION_LENGTH)
{
// set the led with a random colour selection from the ESTwinkle array
leds[ledIndex] = ESTwinkle[random(sizeof(ESTwinkle) / sizeof(ESTwinkle[0]))];
}
}
// indicate that we need to show() the change
return true;
}
// no show() needed
return false;
}
updateSection()
will have a single blue led running up and down in the selected section.
/*
set colours for a specific section of the strip
In:
section number (1..4) of section to update; 0 indicates no section to update
Returns:
true if the colour setting of a led changed, else false
*/
bool updateSection(int8_t section)
{
// start time of delay
static uint32_t delayStarttime;
// index of led to be updated
static int8_t ledIndex;
// direction (up = 1, down = -1)
static int8_t direction = 1;
// detection of change of section
static int8_t prevSection = 0;
// if section equals 0, there is no section to update
if (section == 0)
{
// nothing to do
return false;
}
// if it's not time to update the section yet
if (millis() - delayStarttime < sectionInterval)
{
// nothing to do
return false;
}
// set the start time of the next delay
delayStarttime = millis();
// if there was a change in section
if (prevSection != section)
{
// reset ledIndex to 0
ledIndex = 0;
// reset direction to go up
direction = 1;
// clear the previous section
if (prevSection != 0)
{
int8_t ledOffset = (prevSection - 1) * SECTION_LENGTH;
for (int8_t cnt = ledOffset; cnt < ledOffset + SECTION_LENGTH; cnt++)
{
leds[cnt] = CRGB::Black;
}
}
}
// update the previous section to reflect the passed section
prevSection = section;
// first led to change depends on the section
int8_t ledOffset = (section - 1) * SECTION_LENGTH;
// clear all leds in section
for (int8_t cnt = ledOffset; cnt < ledOffset + SECTION_LENGTH; cnt++)
{
leds[cnt] = CRGB::Black;
}
// set a led
leds[ledOffset + ledIndex] = CRGB::Blue;
// next led or previous led
ledIndex += direction;
// if begin or end of section
if (ledIndex == 0 || ledIndex >= SECTION_LENGTH - 1)
{
// change the direction
direction *= -1;
}
// indicate that we have to call show()
return true;
}
I unfortunately don't have one setup to give complete code. The KeypadEvent was tested on a Leonardo and the FastLED part was tested on a Mega. I hope there are no missing variables but I think that you can figure it out.