I am using the FastLED library and the Keypad library to run code on my WS2812 lights. When I used just a basic keypad layout to print out what key was being pressed, this code worked. But now that I added methods to run code from the keypad if statements, it seems as if it is not working. Nothing happens to the lights when I press a number on the keypad. Currently the LED code is in methods. I had previously just had it in the if statements for the keypad itself. I'm going to keep the code included here as concise as possible as to not flood the screen with what I think isn't relevant. If you have any questions I can provide relevant snippets of the rest of the code.
void setup() {
FastLED.addLeds<WS2812, LED_PIN, GRB>(leds, NUM_LEDS);
FastLED.setBrightness(32);
Serial.begin(9600);
}
void christmas() {
for(int i = 0; i < 6; i++){
for(int i = 0; i > 299; i++) {
leds[i] = CRGB (0, 128, 0); //green
FastLED.show();
leds[i+1] = CRGB (255, 0, 0); //red
FastLED.show();
delay(20);
}
//the second loop turns the first light red and the second light green starting at the end
for (int i = 299; i <= 0; i--) {
leds[i] = CRGB (255, 0, 0); //green
FastLED.show();
leds[i + 1] = CRGB (0, 128, 0); //red
FastLED.show();
delay(20);
}
}
}
void loop() {
char key = keypad.getKey(); //determines what key is pressed
if (key == '1'){
christmas();
}
if (key == '2'){
dot();
}
if (key == '3'){
mavericks();
}
if (key == '4'){
rainbow();
}
if (key == '5'){
blueBar();
}
if (key == '6'){
purple();
}
To be clear there is no error when running the code. It runs fine. But, it does nothing when the keys are pressed on the keypad, where as it should, I believe, run the methods called and effect the lights accordingly.
Edit:
After implementing Bobby Tables suggestions, it works to an extent. Except now When I press 1, which is:
void christmas() {
delay(10);
for(int j = 0; j < 6; j++){
delay(10);
for(int i = 0; i > 299; i++) {
delay(10);
leds[i] = CRGB::Red; //green
FastLED.show();
leds[i+1] = CRGB::Green; //red
FastLED.show();
delay(20);
}
//the second loop turns the first light red and the second light green starting at the end
for (int i = 299; i >= 0; i--) {
leds[i] = CRGB::Green; //green
FastLED.show();
leds[i + 1] = CRGB::Red;
FastLED.show();
delay(20);
}
}
}
it runs instantly but if I press any other key it does not fully function. Such as when I press 5 which is:
void blueBar() {
delay(10);
fill_solid(leds, NUM_LEDS, CRGB::White);
delay(10);
for(int j = 0; j < 6; j++) {
delay(10);
for(int i = 0; i < 299; i++) {
leds[i] = CRGB::Blue;
leds[i + 1] = CRGB::Blue;
leds[i + 2] = CRGB::Blue;
leds[i + 3] = CRGB::Blue;
leds[i + 4] = CRGB::Blue;
leds[i + 5] = CRGB::Blue;
FastLED.show();
delay(200);
leds[i] = CRGB::White;
FastLED.show();
}
}
}
It does nothing. Except when I press 5 and then press 1 afterwards. It will fill the initial solid white but then start running christmas().
I now believe that your if statements are working fine, but as a result of incorrect formation of your loop conditionals, christmas() does nothing. I suspect you have similar problems in your other lighting patterns.
This is using i for both loops. Also the second loop will never run since i > 299 is immediately false:
for(int i = 0; i < 6; i++){
for(int i = 0; i > 299; i++) {
This also will never run since i is immediately greater than 0:
for (int i = 299; i <= 0; i--) {
Related
I am trying to adapt this version of the Adafruit NeoPixel theater chase example to be non-blocking by not using the delay() function and instead of using the millis() function to create a counter, however, I am having no luck as the NeoPixels just light up constantly. Am I missing something? I decided to place the if statement at the point where the nested for loop turns off every 3rd pixel in the strand thinking this would be the spot to put it since in the old code the delay() was called previous to this step.
Here is this version I made which doesn't work:
//Theatre-style crawling lights.
void theaterChase(uint32_t c, const long wait) {
unsigned long currentMillis = millis();
for (int j = 0; j < 10; j++) { //do 10 cycles of chasing
for (int q = 0; q < 3; q++) {
for (uint16_t i = 0; i < strip.numPixels(); i = i + 3) {
strip.setPixelColor(i + q, c); //turn every third pixel on
}
strip.show();
if (currentMillis - previousMillis >= wait) {
previousMillis = currentMillis;
for (uint16_t i = 0; i < strip.numPixels(); i = i + 3) {
strip.setPixelColor(i + q, 0); //turn every third pixel off
}
}
}
}
}
and here is the old version:
//Theatre-style crawling lights.
void theaterChase(uint32_t c, uint8_t wait) {
for (int j=0; j<10; j++) { //do 10 cycles of chasing
for (int q=0; q < 3; q++) {
for (uint16_t i=0; i < strip.numPixels(); i=i+3) {
strip.setPixelColor(i+q, c); //turn every third pixel on
}
strip.show();
delay(wait);
for (uint16_t i=0; i < strip.numPixels(); i=i+3) {
strip.setPixelColor(i+q, 0); //turn every third pixel off
}
}
}
}
The for loops wrapped around the delay are what does the blocking.
You have to disassemble the nested for loops that are wrapped around delay() into their constituent parts.
You can turn the for(j...){} loop into the if( currentMillis -last > wait){} conditional and rely on the outer loop() to call this function frequently.
You make q save state with a static and do the iteration arithmetic yourself
Untested code:
//Theatre-style crawling lights.
void theaterChase(uint32_t c, const long wait) {
static unsigned long last;
static int q;
unsigned long currentMillis = millis();
if( currentMillis -last > wait){
last = currentMillis;
if(q >= 3) q = 0;
if(q < 3){
for (uint16_t i = 0; i < strip.numPixels(); i = i + 3) {
strip.setPixelColor(i + q, c); //turn every third pixel on
}
strip.show();
// setup to turn them back off during the next iteration
for (uint16_t i = 0; i < strip.numPixels(); i = i + 3) {
strip.setPixelColor(i + q, 0); //turn every third pixel off
}
q++;
}// if(q ...
} // if( currentMillis...
}
I'm using Arduino to control a project which contains addressable LEDs and buttons.
The libraries I'm using are in the title.
For an unknown reason, when I use each code separately everything works fine, but when I combine them the FastLED library blocks the button reading and causes weird things - like giving double press, or stop doing other things.
How can I fix the issue? (I tried to eliminate the delay(), but it wasn't helpful)
Thanks in advance!
/*
Author: Yuval Kedar - KD Technology
Instagram: https://www.instagram.com/kd_technology/
Date: Oct 19
Dev board: Arduino Uno
There are two button types: Red and Blue.
Red btn = -1
Blue btn = +1
On the machine's background there is an LED matrix which shows the user's progress.
There are 4 levels (square frames) until one reaches the core and wins.
The trick? The floor, which includes the buttons, is spinning.
*/
#include <FastLED.h>
#include <ezButton.h>
#include "Arduino.h"
#define WINNING_SENSOR_PIN (12)
#define LED_DATA_PIN (6)
#define BLUE_BTN_PIN (A0)
#define RED_BTN_PIN (A3)
#define SERIAL_BAUDRATE (115200)
#define NUM_LEDS (64)
#define LED_BRIGHTNESS (200)
#define WINNING_FX_TIME (1000)
ezButton blue_btn(BLUE_BTN_PIN);
ezButton red_btn(RED_BTN_PIN);
CRGB leds[NUM_LEDS];
uint8_t score = 0;
uint8_t last_score = 0;
uint8_t level[] = {0, 28, 48, 60, 63}; //levels 0 to 4
void level_up(uint8_t led_num) {
uint8_t start_point = 0;
if (led_num == level[1]) start_point = 0; //up from level 0 to 1
if (led_num == level[2]) start_point = 28; //up from level 1 to 2
if (led_num == level[3]) start_point = 48; //up from level 2 to 3
if (led_num == level[4]) start_point = 60; //...
for (uint8_t current_pixel = start_point; current_pixel < led_num; current_pixel++) {
leds[current_pixel] = CRGB::Blue;
FastLED.show();
delay(50);
}
delay(2500); //debounce
}
void level_down(uint8_t led_num) { //clear prev level's frame and do the opposite direction effect with red color
uint8_t start_point = 0;
if (led_num == level[0]) start_point = 28; //down from level 1 to 0
if (led_num == level[1]) start_point = 48; //down from level 2 to 1
if (led_num == level[2]) start_point = 60; //down from level 3 to 2
if (led_num == level[3]) start_point = 63; //...
for (int8_t i = start_point - 1; i > led_num; i--) {
leds[i] = CRGB::Red;
FastLED.show();
delay(50);
}
for (int8_t i = start_point - 1; i > led_num; i--) {
leds[i] = CRGB::Black;
FastLED.show();
}
delay(2500); //debounce
}
void fadeall() {
for(uint8_t i = 0; i < NUM_LEDS; i++) {
leds[i].nscale8(250);
}
}
void winning() {
static uint8_t hue = 0;
for(uint8_t x = 0; x < 5; x++) {
for(int8_t i = 0; i < NUM_LEDS; i++) {
leds[i] = CHSV(hue++, 255, 255);
FastLED.show();
fadeall();
// delay(10);
}
for(int8_t i = (NUM_LEDS)-1; i >= 0; i--) {
leds[i] = CHSV(hue++, 255, 255);
FastLED.show();
fadeall();
// delay(10);
}
}
}
void reset_game() {
score = 0;
last_score = 4;
digitalWrite(WINNING_SENSOR_PIN, LOW);
FastLED.clear();
FastLED.show();}
void winning_check() {
(score == 4) ? analogWrite(WINNING_SENSOR_PIN, 175) : digitalWrite(WINNING_SENSOR_PIN, LOW);
}
void update_score() {
if (blue_btn.isPressed()) {
Serial.println("+PLUS+");
if (score++ >= 4) score = 4;
}
if (red_btn.isPressed()) {
Serial.println("-MINUS-");
if (score-- <= 0) score = 0;
}
if (score == 0){
if (last_score == 1) level_down(level[0]);
last_score = 0;
digitalWrite(WINNING_SENSOR_PIN, LOW);
}
else if (score == 1) {
if (last_score == 0) level_up(level[1]); // if last_score was 0 make the blue effect because level is up
if (last_score == 2) level_down(level[1]); // if last_score was 2 make the red effect because level is down
last_score = 1;
digitalWrite(WINNING_SENSOR_PIN, LOW);
}
else if (score == 2) {
if (last_score == 1) level_up(level[2]);
if (last_score == 3) level_down(level[2]);
last_score = 2;
digitalWrite(WINNING_SENSOR_PIN, LOW);
}
else if (score == 3) {
if (last_score == 2) level_up(level[3]);
if (last_score == 4) level_down(level[3]);
last_score = 3;
digitalWrite(WINNING_SENSOR_PIN, LOW);
}
else if (score == 4) {
winning_check();
// winning(); //this func makes issue when using ezButton.h. It calls "show" too many times.
reset_game();
}
}
void setup() {
Serial.begin(SERIAL_BAUDRATE);
pinMode(WINNING_SENSOR_PIN, OUTPUT);
digitalWrite(WINNING_SENSOR_PIN, LOW);
blue_btn.setDebounceTime(150);
red_btn.setDebounceTime(150);
FastLED.addLeds<NEOPIXEL, LED_DATA_PIN>(leds, NUM_LEDS); // GRB ordering is assumed
FastLED.setBrightness(LED_BRIGHTNESS);
FastLED.clear();
FastLED.show();
Serial.println(F(
"_______________________________\n"
"\n"
" G e a r M a c h i n e \n"
"_______________________________\n"
"\n"
" ~ Made by KD Technology ~ \n"
"\n"));
}
void loop() {
blue_btn.loop();
red_btn.loop();
Serial.println(score);
update_score();
FastLED.show();
}
The reason is that, you used the delay() function. If you use the delay, some pressed events will be missed, not only for ezButton, but also for any kind of button press implementation. The ezButton already has the internal debounce function.
Im having issues where my code running up the w2812b strip is working fine but when I run down the strip I get an error.
This is the error
/home/runner/work/esp32-arduino-lib-builder/esp32-arduino-lib-builder/esp-idf/components/freertos/queue.c:1443 (xQueueGenericReceive)- assert failed! abort() was called at PC 0x40087f1d on core 1
I have tried looking it up and changing how I iterate through but nothing has worked so far. I have figured out that it breaks on the first run through in for loop within the ledDown function when I call the showStrip function.
The code is being uploaded to a esp32 but I'm pretty sure that doesn't have anything to do with it.
Any help would be amazing.
Here is my code. I currently just have the LedDown function commented out.
#include "FastLED.h"
#define NUM_LEDS 100
#define LEDPIN 26
CRGB leds[NUM_LEDS];
void setup()
{
// Debug console
Serial.begin(9600);
FastLED.addLeds<WS2812B, LEDPIN, GRB>(leds, NUM_LEDS).setCorrection( TypicalLEDStrip );
}
void showStrip() {
FastLED.show();
}
void setPixel(int Pixel, byte red, byte green, byte blue) {
// FastLED
leds[Pixel].r = red;
leds[Pixel].g = green;
leds[Pixel].b = blue;
}
void setAll(byte red, byte green, byte blue) {
for(int i = 0; i < NUM_LEDS; i++ ) {
setPixel(i, red, green, blue);
}
showStrip();
}
void loop() {
LedUp();
//LedDown();
}
void LedDown() {
for(int i = NUM_LEDS; i > 1; i--){
Serial.println(i);
setAll(0,0,0);
delay(100);
if(i < 33){
setPixel(i,0,0xff,0);
}else if(i < 63){
setPixel(i,0xff,0,0);
}else{
setPixel(i,0,0,0xff);
}
showStrip();
}
}
void LedUp() {
for(int i = 0; i < NUM_LEDS; i++){
setAll(0,0,0);
delay(20);
if(i < 30){
setPixel(i,0,0xff,0);
}else if(i < 60){
setPixel(i,0xff,0,0);
}else{
setPixel(i,0,0,0xff);
}
showStrip();
}
}
for(int i = NUM_LEDS; i > 1; i--)
You need to start from NUM_LEDS - 1 and go to zero:
for(int i = NUM_LEDS - 1; i >= 0; i--)
Because NUM_LEDS itself is out of range.
I am trying to create a simple project using Blynk on D1 Mini where I can select any animation any time and that should play unless I stop that using my Blynk App. While everything else working perfectly, I am not able to figure out what is wrong on my theaterchaserainbow function, that while selected, my D1 gets disconnected and connected again. Here is the code.
I understood from various forum that I must use blynk.timer instead and set count more than 1000L in setup. But that won't help me either for this particular theaterchaserainbow function. All other functions works perfectly. Any help would be greatly appreciated.
#include <ESP8266WiFi.h>
#include <BlynkSimpleEsp8266.h>
#include <Adafruit_NeoPixel.h>
#include <wifi_credentials.h>
#define BLYNK_PRINT Serial
#define myPixelPin D2
#define myPixels 16
char auth[] = "xxxxxxxmy_authxxxxxx";
int select;
BlynkTimer timer;
// Instatiate the NeoPixel from the ibrary
Adafruit_NeoPixel strip = Adafruit_NeoPixel(myPixels, myPixelPin, NEO_GRB + NEO_KHZ800);
// Timer to repeat animations
void myTimerEvent() {
if (select == 1) {
allOff();
} else if (select == 12) {
theaterChaseRainbow(50);
}
}
// NeoPixel all off Switch
BLYNK_WRITE(V0) {
int pinValue = param.asInt();
select = 1;
}
// Menu based Animation Selection
BLYNK_WRITE(V1) {
int pinValue = param.asInt();
switch (pinValue) {
case 1: // Item 1
select = 11;
break;
case 2: // Item 2
select = 12;
break;
}
}
void setup()
{
Serial.begin(9600);
Blynk.begin(auth, ssid, pass);
strip.begin();
strip.show();
timer.setInterval(1000L, myTimerEvent);
}
void loop() {
Blynk.run();
timer.run(); // Initiates BlynkTimer;
}
// Theatre Chase Rainbow
//*****************************************************************************
void theaterChaseRainbow(uint8_t wait) {
for (int j=0; j < 256; j++) { // cycle all 256 colors in the wheel
for (int q=0; q < 3; q++) {
for (int i=0; i < strip.numPixels(); i=i+3) {
strip.setPixelColor(i+q, Wheel( (i+j) % 255)); //turn every third pixel on
}
strip.show();
delay(wait);
for (int i=0; i < strip.numPixels(); i=i+3) {
strip.setPixelColor(i+q, 0); //turn every third pixel off
}
}
}
}
// Clear Program
//*****************************************************************************
void allOff() {
for ( int i = 0; i < strip.numPixels(); i++ ) {
strip.setPixelColor(i, 0, 0, 0 );
}
strip.show();
}
// Default Wheel defination
//*****************************************************************************
uint32_t Wheel(byte WheelPos) {
if (WheelPos < 85) {
return strip.Color(WheelPos * 3, 255 - WheelPos * 3, 0);
} else if (WheelPos < 170) {
WheelPos -= 85;
return strip.Color(255 - WheelPos * 3, 0, WheelPos * 3);
} else {
WheelPos -= 170;
return strip.Color(0, WheelPos * 3, 255 - WheelPos * 3);
}
}
I have an if statement inside a for loop. When the the condition in if statement is true, I want to break out of the for loop.
here is what exactly I have
if (data < voltage && data2 < voltage) {
digitalWrite(pump, HIGH);
digitalWrite(valve, HIGH);
digitalWrite(valve2, HIGH);
for (int i = 0; i < 10; i++) {
lcd.setCursor(0, 2);
lcd.print("S_1:");
if (data > 260 && data < 295)
lcd.print("MID");
else if (data < 260)
lcd.print("LOW");
else
lcd.print("HIGH");
lcd.setCursor(7, 0);
lcd.print("Pump:ON");
lcd.setCursor(0, 1);
lcd.print("V1:ON");
lcd.setCursor(9, 2);
lcd.print("S_2:");
if (data2 > 260 && data2 < 295)
lcd.print("MID");
else if (data2 < 260)
lcd.print("LOW");
else
lcd.print("HIGH");
lcd.setCursor(7, 1);
lcd.print("V2:ON");
lcd.setCursor(14, 1);
lcd.print("V3:OFF");
sum += data;
sum2 += data2;
delay(1000);
}
average = sum / 10;
average2 = sum2 / 10;
if (average > voltage || average2 > voltage) {
digitalWrite(pump, LOW);
digitalWrite(valve, LOW);
digitalWrite(valve2, LOW);
}
sum = 0;
sum2 = 0;
lcd.clear();
}
It seams not going throw the whole conditions.
You could use the break keyword.
for (int i = 0; i < 100; i++){
if (i == 2){
break;
}
}
Also, this is considered by OOD people a gotoish code, prefer inserting the break condition in the for condition :
boolean shouldBreak = false;
for (int i = 0; i < 100 && !shouldBreak; i++){
if (i == 2){
shouldBreak = true;
}
}
Use the break; keyword to do that.