issue with Arduino using FastLed with IRremote change mode - arduino

Hi I am trying to build a arduino project to control led strip and change the light pattern when pressed different button
the code i am using is
#include <IRremote.h> //include the library
#include <FastLED.h>
// How many leds in your strip?
#define NUM_LEDS 70
#define DATA_PIN 3
#define CLOCK_PIN 13
#define Button_0 0xFF9867
#define Button_1 0xFFA25D
#define Button_2 0xFF629D
#define Button_3 0xFFE21D
#define Button_4 0xFF22DD
#define Button_5 0xFF02FD
#define Button_6 0xFFC23D
#define Button_7 0xFFE01F
#define Button_8 0xFFA857
#define Button_9 0xFF906F
int receiver = 7; //initialize pin 13 as recevier pin.
IRrecv irrecv(receiver); //create a new instance of receiver
decode_results results;
CRGB leds[NUM_LEDS];
void setup() {
Serial.begin(9600);
LEDS.addLeds<WS2812,DATA_PIN,RGB>(leds,NUM_LEDS);
LEDS.setBrightness(84);
irrecv.enableIRIn(); //start the receiver
}
void loop() {
if (irrecv.decode(&results)) { //if we have received an IR signal
Serial.println (results.value, HEX); //display HEX results
irrecv.resume(); //next value
if (results.value == Button_0) {
RunningLightSlow();
}
else if(results.value == Button_1) {
RainbowLights();
}
// switch (results.value) {
//
// case Button_0: RunningLightSlow(); break;
// case Button_1: RainbowLights(); break;
// }
}
}
// LIGHTSHOW 0 starts --------------------------------------------------------------------------------------------------
void fadeall() { for(int i = 0; i < NUM_LEDS; i++) { leds[i].nscale8(250); } }
void RunningLightSlow() {
while(1) {
static uint8_t hue = 0;
Serial.print("x");
// First slide the led in one direction
for(int i = 0; i < NUM_LEDS; i++) {
// Set the i'th led to red
leds[i] = CHSV(hue++, 255, 255);
// Show the leds
FastLED.show();
// now that we've shown the leds, reset the i'th led to black
// leds[i] = CRGB::Black;
fadeall();
// Wait a little bit before we loop around and do it again
delay(10);
}
Serial.print("x");
// Now go in the other direction.
for(int i = (NUM_LEDS)-1; i >= 0; i--) {
// Set the i'th led to red
leds[i] = CHSV(hue++, 255, 255);
// Show the leds
FastLED.show();
// now that we've shown the leds, reset the i'th led to black
// leds[i] = CRGB::Black;
fadeall();
// Wait a little bit before we loop around and do it again
delay(10);
}
}
}
// LIGHTSHOW 0 ends --------------------------------------------------------------------------------------------------------
// LIGHTSHOW 1 STARTS ------------------------------------------------------------------------------------------------------
void RainbowLights() {
randomSeed(millis());
int wait=random(10,30);
int dim=random(4,6);
int max_cycles=8;
int cycles=random(1,max_cycles+1);
while(1) {
rainbowCycle(wait, cycles, dim);
}
}
void rainbowCycle(int wait, int cycles, int dim)
{
Serial.println("Let's make a rainbow.");
//loop several times with same configurations and same delay
for(int cycle=0; cycle < cycles; cycle++)
{
byte dir=random(0,2);
int k=255;
//loop through all colors in the wheel
for (int j=0; j < 256; j++,k--)
{
if(k<0)
{
k=255;
}
//Set RGB color of each LED
for(int i=0; i<NUM_LEDS; i++)
{
CRGB ledColor = wheel(((i * 256 / NUM_LEDS) + (dir==0?j:k)) % 256,dim);
leds[i]=ledColor;
}
FastLED.show();
FastLED.delay(wait);
}
}
}
CRGB wheel(int WheelPos, int dim)
{
CRGB color;
if (85 > WheelPos)
{
color.r=0;
color.g=WheelPos * 3/dim;
color.b=(255 - WheelPos * 3)/dim;;
}
else if (170 > WheelPos)
{
color.r=WheelPos * 3/dim;
color.g=(255 - WheelPos * 3)/dim;
color.b=0;
}
else
{
color.r=(255 - WheelPos * 3)/dim;
color.g=0;
color.b=WheelPos * 3/dim;
}
return color;
}
Now the issue i am facing is when i press a button (for eg 0) it runs the function RunningLightSlow(); i have written the infinite loop code because i want infinite light show and when i press button 1 it does not change the light pattern ,
Root cause would be once the function goes into infinite loop it then never receives the ir signal and hence never change the light pattern

Remove all infinite loops from your program and create a simple structure in loop() where you check for IR signal and update a "state" variable with the last button pressed.
void loop() {
// create a function or add here whatever is needed to read the IR code
irCode = readIrCode();
// check if the new code is identical to a previous code
if (lastIrCode != irCode) {
// memorize the current code
lastIrCode = irCode;
/ act according to user selection
switch (irCode) {
case Button_0:
doThis(); // this could be your RunningLightSlow()
break;
case Button_1:
doThat(); // maybe RainbowLights()
break;
default:
// for cases you have not handled above
doWhatever();
}
}
}
Do not forget to remove the infinite loops from the functions that run the lights and obviously you would need to declare the variables and set the correct calls.

Related

How do i send data from my esp8266 light sensor to blynk?

I am trying to know whether the lights have tripped using a light sensor to detect light intensity. However, i do not know how to upload my data onto blynk, as i am new to blynk and new to arduino as well. Below is my code. I tried using a telegram bot to get the data but somehow it stopped working and i am finding alternatives to get the data remotely. If there are any other methods other than Blynk please suggest too.
#include <ESP8266WiFi.h> // WIFI LIBRARY
#include <WiFiClient.h> //CLIENT LIBRARY
#include <ESP8266WebServer.h> //WEBSERVICER LIBRARY
#include <ESP8266HTTPClient.h> //HTTP CLIENT LIBRARY
char auth[] = BLYNK_AUTH_TOKEN;
char ssid[] = "ArchiEngStudio";
char pass[] = "a12345678";
int CNT = 0, sent, i, j;
float count = 0;
int limit = 800; // SET LIMIT HERE
void setup() {
// initialize serial communication at 9600 bits per second:
Serial.begin(9600);
}
void loop() {
float reading = analogRead(A0);
Serial.println(reading);
delay(3000);
/* NO LIGHT CONDITION */
if (reading < limit)
{
if (CNT < 1) // CHECK LOOP ONLY RUNS ONCE
{
count = 0;
for (i=0; i<10; i++) //TAKING 10 READINGS TO CHECK IF LIGHTS ARE REALLY OFF
{
delay(1000);
int read2 = analogRead(A0);
Serial.println(read2);
if (read2 < limit)
{
Serial.println("(1) No Light ...");
}
else
{
Serial.println("(1) Light on...");
i= i+20;
}
}
if (i < 11) // IF ALL 10 READINGS SHOW THAT LIGHTS ARE OFF, SEND MESSAGE
{
if (sent == 0)
{
Serial.println("Tripped!");
sent = 1;
}
}
}
CNT++;
}
else
{
CNT = 0;
}
/* LIGHTS ON CONDITION */
if (sent == 1) //ONLY ALLOWED IF LIGHTS WERE OFF
{
if (reading >= limit)
{
for (j=0; j<10; j++) //TAKING 10 READINGS TO CHECK IF LIGHTS ARE REALLY ON
{
delay(1000);
int read3 = analogRead(A0);
Serial.println(read3);
if (read3 >= limit)
{
Serial.println("(2) Light on...");
}
else
{
Serial.println("(2) No light...");
j= i+10;
}
}
if (j < 11) //IF ALL 10 READINGS SHOW THAT LIGHTS ARE ON, SEND MESSAGE
{
Serial.println("Light on!");
sent = 0;
}
}
}
}
Blynk provides a decent way to display your data and is very easy to use once you are familiar with the concept.
You can store your reading variable in a virtual pin 'Vx' on the Blynk server by adding this line to your code:
Blynk.virtualWrite(Vx, reading);
If you want to display it on the app just use "value display" widget and configure it to display your virtual pin 'Vx'.

Pausing a loop to run another in Arduino

I'm working on a circuit that has two separate 4-bit binary counters with LEDs. I press a button and one counter begins counting to 15 in binary. I press a second button and the first counter pauses where it is and the second group of LEDs begin counting to 15 in binary. I got both counters working, but I can't get the first group to pause and the second to begin. I've tried using if statements with a boolean flag, but it messes up the first group of LEDs. How can I get ledPins1[] to pause when button2 is pressed, then resume when ledPins2[] finish?
int ledPin1[] = {2,3,4,5};
int ledPin2[] = {7,8,9,10};
int button1 = 11;
int button2 = 12;
boolean button1Last = LOW;
boolean button1Current = LOW;
boolean button2Last = LOW;
boolean button2Current = LOW;
void setup()
{
pinMode(button1, INPUT);
pinMode(button2, INPUT);
for(int i=0; i<4; i++)
{
pinMode(ledPin1[i], OUTPUT);
}
for(int i=0; i<4; i++)
{
pinMode(ledPin2[i], OUTPUT);
}
}
boolean waitForButtonPush1 (boolean lastStartSwitchState1)
{
boolean currentStartSwitchState1 = digitalRead(button1);
if(lastStartSwitchState1 != currentStartSwitchState1) delay(20);
currentStartSwitchState1 = digitalRead(button1);
return currentStartSwitchState1;
}
boolean waitForButtonPush2 (boolean lastStartSwitchState2)
{
boolean currentStartSwitchState2 = digitalRead(button2);
if(lastStartSwitchState2 != currentStartSwitchState2) delay(20);
currentStartSwitchState2 = digitalRead(button2);
return currentStartSwitchState2;
}
void loop()
{
button1Current = waitForButtonPush1(button1Last);
if(button1Last == LOW && button1Current == HIGH)
{
for (byte counter =0;counter<=15; counter++)
{
displayBinary(counter);
delay(500);
}
}
button2Current = waitForButtonPush2(button2Last);
if(button2Last == LOW && button2Current == HIGH)
{
for (byte counter =0;counter<=15; counter++)
{
displayBinary2(counter);
delay(500);
}
}
}
void displayBinary(byte numToShow)
{
for (int i =0;i<4;i++)
{
if (bitRead(numToShow, i)==1)
{
digitalWrite(ledPin1[i], HIGH);
}
else
{
digitalWrite(ledPin1[i], LOW);
}
}
}
void displayBinary2(byte numToShow)
{
for (int i =0;i<4;i++)
{
if (bitRead(numToShow, i)==1)
{
digitalWrite(ledPin2[i], HIGH);
}
else
{
digitalWrite(ledPin2[i], LOW);
}
}
}
Welcome to the world of embedded devices!
Getting a small microprocessor to do several things at the same time is a bit tricky.
The key is to never block. No calls to delay(), no sending large buffers on the serial port at 9600 bauds in one go, etc...
There are some simple techniques to do it, one of the most commonly used is finite state machines.
Let's analyse your app a bit.
2 similar dssplay counters, with delay
2 buttons, buttons usually need to be debounced, that also involves a delay.
Some code, for you to tinker with:
// ****************************
// pinout
static const byte ledPin1[] = { 2, 3, 4, 5 };
static const byte ledPin2[] = { 7, 8, 9, 10 };
constexpr byte button1 = 11; // using constexpr for these saves 2 bytes of RAM.
constexpr byte button2 = 12;
// ****************************
// Counter data
static constexpr unsigned int led_delay = 500; // 500 ms, for all counters.
// constexpr ?? arduino supports c++17. Not all features in the main .ino
// module and all features in .cpp modules.
// Hint: you could have a member variable in the structure below for delay,
// this would allow for counters running at different speeds, or add buttons
// to increase/decrease speed.
// we have only 2 states, but you could add more, like running
// backwards, or run a different chase pattern maybe?
enum class led_counter_state : byte
{
stopped,
running,
};
struct led_counter_data_t
{
led_counter_state state; // STATE
byte counter; // counter current value
unsigned int timestamp; // used for timing.
const byte* leds; // LED pins.
};
static led_counter_data_t led_counter[2];
void led_display_init()
{
for (byte i = 0; i < 2; ++i)
{
led_counter[i].state = led_counter_state::stopped;
led_counter[i].counter = 0;
led_counter[i].timestamp = 0;
}
led_counter[0].leds = ledPin1;
led_counter[1].leds = ledPin2;
}
// ****************************
// LED cotrrol
static void leds_display_value(const led_counter_data_t& cntr)
{
for (byte i = 0, val = cntr.counter; i < 4; ++i, val >>= 1)
digitalWrite(cntr.leds[i], val & 0x01);
}
static void leds_control(led_counter_data_t& cntr)
{
const auto now = (unsigned int)millis(); // keep track of time.
switch(cntr.state)
{
default: // something is wrong.. stop.
cntr.state = led_counter_state::stopped;
// fall through ...
case led_counter_state::stopped:
return; // if not running, do nothing
case led_counter_state::running:
if (now - cntr.timestamp >= led_delay) // check delay
{
if (++cntr.counter > 15) // advance counter.
cntr.counter = 0;
leds_display_value(cntr); // show value.
cntr.timestamp = now; // keep track of time.
}
break;
}
}
static void leds_start(led_counter_data_t& cntr)
{
if (cntr.state != led_counter_state::stopped)
return;
cntr.state = led_counter_state::running;
if (++cntr.counter > 15) // advance counter.
cntr.counter = 0;
led_display_value(cntr); // show value.
cntr.timestamp = (unsigned int)millis();
}
static void leds_stop(led_counter_data_t& cntr)
{
cntr.state = led_counter_state::stopped;
}
// ****************************
// switch inputs data
static constexpr byte switch_debounce_delay = 30; // 30ms is a good value for
// debouncing
struct switch_data_t
{
byte sw1_state : 1; // no need to waste more than 1 bit per switch
byte sw2_state : 1;
byte timestamp; // we'll only count to 30 ms, so 1 byte timestamp will do
};
static switch_data_t switch_data;
// ****************************
// switch inputs code
static void control_inputs()
{
const auto now = (byte)millis();
if (now - switch_data.timestamp < switch_debounce_delay)
return;
switch_data.timestamp = now;
// All switch control logic is regrouped here, and isolated
// form other control code, this makes the logic easier to
// write, read, and debug.
bool b = digitalRead(button1);
if (b & !switch_data.sw1_state) // button was pushed right now.
{
if (led_counter[0].state == led_counter_state::stopped)
{
leds_start(led_counter[0]); // start counter 1
leds_stop(led_counter[1]); // stop counter 2
}
else
{
leds_stop(led_counter[0]); // stop counter 1
}
}
switch_data.sw1_state = b;
b = digitalRead(button2);
if (b & !switch_data.sw2_state) // button was pushed right now.
{
if (led_counter[1].state == led_counter_state::stopped)
{
leds_start(led_counter[1]); // start counter 2
leds_stop(led_counter[0]); // stop counter 1
}
else
{
leds_stop(led_counter[1]); // stop counter 2
}
}
switch_data.sw2_state = b;
}
// ****************************
void setup()
{
pinMode(button1, INPUT);
pinMode(button2, INPUT);
for (byte i = 0; i < 4; ++i)
{
digitalWrite(ledPin1[i], LOW);
pinMode(ledPin1[i], OUTPUT);
digitalWrite(ledPin2[i], LOW);
pinMode(ledPin2[i], OUTPUT);
}
led_display_init();
}
// ****************************
// The goal, always, is to exit loop() as fast as possible, so
// everything will run smoothly, and appear to run simultaneously.
void loop()
{
control_inputs();
leds_control(led_counter[0]);
leds_control(led_counter[1]);
}
I do not have an arduino with me, so I did not comppile nor ran this, but it should be pretty close. Let me know if you're having issues or have any questions.

ESP32 handle webserver and neopixels (with delay) in two cores

I'm searching the answer for a while but haven't found how to fix this problem. I have a lot of neopixel animations (currently 50 of them), these are written with delays which keeps the animations simple and readable. disadvantage is the delays as you all know. 50 animations to rewrite is a hell of a job so I want to avoid this. What I did is bought an ESP32 with two cores, so I thought I could run the animations on one core and the webserver on one core. previously I wanted to do I with an interrupt on a ESP8266 but I red and tested that I was not possible to do communication things or run a webserver in an interrupt for example. Is it possible to do that with two cores on an ESP32 or am I running in to the same problem as earlier? current output of the program: My webserver starts and the neopixel animation is showed when pushing the button, however my webserver continuously restarts over and over again. Any help appreciated, thanks in advance!
ps: In the worst case scenario I have to rewrite my animations, anyone an idea how to replace 3 for loops in to non blocking code?
code running on ESP32:
TaskHandle_t Task1;
TaskHandle_t Task2;
#include <Adafruit_NeoPixel.h>
#define PIN 6
#define NUM_LEDS 24
// Parameter 1 = number of pixels in strip
// Parameter 2 = pin number (most are valid)
// Parameter 3 = pixel type flags, add together as needed:
// NEO_KHZ800 800 KHz bitstream (most NeoPixel products w/WS2812 LEDs)
// NEO_KHZ400 400 KHz (classic 'v1' (not v2) FLORA pixels, WS2811 drivers)
// NEO_GRB Pixels are wired for GRB bitstream (most NeoPixel products)
// NEO_RGB Pixels are wired for RGB bitstream (v1 FLORA pixels, not v2)
Adafruit_NeoPixel strip = Adafruit_NeoPixel(NUM_LEDS, PIN, NEO_GRB + NEO_KHZ800);
void colorWipe(byte red, byte green, byte blue, int SpeedDelay) {
for(uint16_t i=0; i<NUM_LEDS; i++) {
setPixel(i, red, green, blue);
showStrip();
delay(SpeedDelay);
}
}
// *** REPLACE TO HERE ***
void showStrip() {
#ifdef ADAFRUIT_NEOPIXEL_H
// NeoPixel
strip.show();
#endif
#ifndef ADAFRUIT_NEOPIXEL_H
// FastLED
FastLED.show();
#endif
}
void setPixel(int Pixel, byte red, byte green, byte blue) {
#ifdef ADAFRUIT_NEOPIXEL_H
// NeoPixel
strip.setPixelColor(Pixel, strip.Color(red, green, blue));
#endif
#ifndef ADAFRUIT_NEOPIXEL_H
// FastLED
leds[Pixel].r = red;
leds[Pixel].g = green;
leds[Pixel].b = blue;
#endif
}
void setAll(byte red, byte green, byte blue) {
for(int i = 0; i < NUM_LEDS; i++ ) {
setPixel(i, red, green, blue);
}
showStrip();
}
#include <WiFi.h>
const char* WIFI_NAME= "xxxxxxxxxx";
const char* WIFI_PASSWORD = "xxxxxxxxxx";
WiFiServer server(80);
String header;
// Auxiliary variables to store the current output state
String output5State = "off";
String output4State = "off";
// Assign output variables to GPIO pins
const int output5 = 2;
const int output4 = 4;
// Current time
unsigned long currentTime = millis();
// Previous time
unsigned long previousTime = 0;
// Define timeout time in milliseconds (example: 2000ms = 2s)
const long timeoutTime = 2000;
String ledState = "off";
void setup() {
//create a task that will be executed in the Task1code() function, with priority 1 and executed on core 0
xTaskCreatePinnedToCore(
Task1code, /* Task function. */
"Task1", /* name of task. */
10000, /* Stack size of task */
NULL, /* parameter of the task */
1, /* priority of the task */
&Task1, /* Task handle to keep track of created task */
0); /* pin task to core 0 */
delay(500);
//create a task that will be executed in the Task2code() function, with priority 1 and executed on core 1
xTaskCreatePinnedToCore(
Task2code, /* Task function. */
"Task2", /* name of task. */
10000, /* Stack size of task */
NULL, /* parameter of the task */
1, /* priority of the task */
&Task2, /* Task handle to keep track of created task */
1); /* pin task to core 1 */
delay(500);
Serial.begin(115200);
// Initialize the output variables as outputs
pinMode(output5, OUTPUT);
pinMode(output4, OUTPUT);
// Set outputs to LOW
digitalWrite(output5, LOW);
digitalWrite(output4, LOW);
}
//Task1code: blinks an LED every 1000 ms
void Task1code( void * pvParameters ){
Serial.print("Task1 running on core ");
Serial.println(xPortGetCoreID());
strip.begin();
strip.show(); // Initialize all pixels to 'off'
for(;;){
/*
digitalWrite(output5, HIGH);
delay(1000);
digitalWrite(output5, LOW);
delay(1000);*/
//Serial.print("state:" + ledState);
if(ledState == "on") {
//digitalWrite(output4, HIGH);
colorWipe(0x00,0xff,0x00, 50);
colorWipe(0x00,0x00,0x00, 50);
} else {
strip.clear();
strip.show();
}
}
}
//Task2code: blinks an LED every 700 ms
void Task2code( void * pvParameters ){
Serial.print("Connecting to ");
Serial.println(WIFI_NAME);
WiFi.begin(WIFI_NAME, WIFI_PASSWORD);
while (WiFi.status() != WL_CONNECTED) {
delay(1000);
Serial.print("Trying to connect to Wifi Network");
}
Serial.println("");
Serial.println("Successfully connected to WiFi network");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());
server.begin();
for(;;){
WiFiClient client = server.available();
if (client) {
Serial.println("New Client."); // print a message out in the serial port
String currentLine = ""; // make a String to hold incoming data from the client
currentTime = millis();
previousTime = currentTime;
while (client.connected() && currentTime - previousTime <= timeoutTime) { // loop while the client's connected
currentTime = millis();
if (client.available()) { // if there's bytes to read from the client,
char c = client.read(); // read a byte, then
Serial.write(c); // print it out the serial monitor
header += c;
if (c == '\n') { // if the byte is a newline character
// if the current line is blank, you got two newline characters in a row.
// that's the end of the client HTTP request, so send a response:
if (currentLine.length() == 0) {
// HTTP headers always start with a response code (e.g. HTTP/1.1 200 OK)
// and a content-type so the client knows what's coming, then a blank line:
client.println("HTTP/1.1 200 OK");
client.println("Content-type:text/html");
client.println("Connection: close");
client.println();
// turns the GPIOs on and off
if (header.indexOf("GET /5/on") >= 0) {
Serial.println("GPIO 5 on");
output5State = "on";
//digitalWrite(output5, HIGH);
} else if (header.indexOf("GET /5/off") >= 0) {
Serial.println("GPIO 5 off");
output5State = "off";
//digitalWrite(output5, LOW);
} else if (header.indexOf("GET /4/on") >= 0) {
Serial.println("GPIO 4 on");
output4State = "on";
ledState = "on";
//digitalWrite(output4, HIGH);
} else if (header.indexOf("GET /4/off") >= 0) {
Serial.println("GPIO 4 off");
output4State = "off";
ledState = "off";
//digitalWrite(output4, LOW);
}
// Display the HTML web page
client.println("<!DOCTYPE html><html>");
client.println("<head><meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">");
client.println("<link rel=\"icon\" href=\"data:,\">");
// CSS to style the on/off buttons
// Feel free to change the background-color and font-size attributes to fit your preferences
client.println("<style>html { font-family: Helvetica; display: inline-block; margin: 0px auto; text-align: center;}");
client.println(".button { background-color: #195B6A; border: none; color: white; padding: 16px 40px;");
client.println("text-decoration: none; font-size: 30px; margin: 2px; cursor: pointer;}");
client.println(".button2 {background-color: #77878A;}</style></head>");
// Web Page Heading
client.println("<body><h1>ESP8266 Web Server</h1>");
// Display current state, and ON/OFF buttons for GPIO 5
client.println("<p>GPIO 5 - State " + output5State + "</p>");
// If the output5State is off, it displays the ON button
if (output5State=="off") {
client.println("<p><button class=\"button\">ON</button></p>");
} else {
client.println("<p><button class=\"button button2\">OFF</button></p>");
}
// Display current state, and ON/OFF buttons for GPIO 4
client.println("<p>GPIO 4 - State " + output4State + "</p>");
// If the output4State is off, it displays the ON button
if (output4State=="off") {
client.println("<p><button class=\"button\">ON</button></p>");
} else {
client.println("<p><button class=\"button button2\">OFF</button></p>");
}
client.println("</body></html>");
// The HTTP response ends with another blank line
client.println();
// Break out of the while loop
break;
} else { // if you got a newline, then clear currentLine
currentLine = "";
}
} else if (c != '\r') { // if you got anything else but a carriage return character,
currentLine += c; // add it to the end of the currentLine
}
}
}
// Clear the header variable
header = "";
// Close the connection
client.stop();
Serial.println("Client disconnected.");
Serial.println("");
}
}
}
void loop(){
}
animation with three for loops:
void theaterChaseRainbow(int SpeedDelay) { /* for wheel watch higher in the code */
byte *c;
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 < NUM_LEDS; i=i+3) {
c = Wheels( (i+j) % 255);
setPixel(i+q, *c, *(c+1), *(c+2)); //turn every third pixel on
}
showStrip();
delay(SpeedDelay);
for (int i=0; i < NUM_LEDS; i=i+3) {
setPixel(i+q, 0,0,0); //turn every third pixel off
}
}
}
}
You're 95% of the way there. ESP32 runs FreeRTOS with preemptive multi-threading. Your code is quite reasonably divided into two threads (Task1 and Task2) which run on different cores. In fact, the number of cores doesn't really matter much as long as you're not running out of CPU cycles or violating the real-time deadlines of your animations. You could probably run both tasks concurrently on a single core without the ESP32 breaking a sweat.
As for the HTTP server restarting - that's the intended behaviour of your code, is it not? The (rather horribly indented) function Task2code runs a never-ending loop which starts the HTTP server, serves a page and the stops. Is this loop really necessary?

switching between functions using an IR remote

I have bought a WS2812B Led Strip. I'm trying to controll it with a IR remote. it is all controlled by a arduino uno.
I know the leds work and i know the remote works. I'm trying to pre-program a few animations on the remote.
The code below is as far as i got. I can show one animation, but i have to wait until it end to change it to onother one.
Is it possible to interupt this (becouse some animations are infinite) when i push a button to choose another animation?
#include <IRremote.h>
#include "FastLED.h"
#define NUM_LEDS 232
CRGB leds[NUM_LEDS];
#define PIN 7
const int RECV_PIN = 6;
IRrecv irrecv(RECV_PIN);
decode_results results;
unsigned long key_value = 0;
void setup(){
FastLED.addLeds<WS2812B, PIN, RGB>(leds, NUM_LEDS).setCorrection( TypicalLEDStrip );
Serial.begin(9600);
irrecv.enableIRIn();
irrecv.blink13(true);
}
//switch case for remote
void loop(){
if (irrecv.decode(&results)){
if (results.value == 0XFFFFFFFF)
results.value = key_value;
switch(results.value){
case 0xFF30CF:
Serial.println("1");
RGBLoop();
break ;
case 0xFF18E7:
Serial.println("2");
red();
break ;
case 0xFF7A85:
Serial.println("3");
break ;
}
key_value = results.value;
irrecv.resume();
}
}
void RGBLoop(){
while(key_value==key_value){
for(int j = 0; j < 6; j++ ) {
// Fade IN
for(int k = 0; k < 256; k++) {
switch(j) {
case 0: setAll(k,0,0); break;
case 2: setAll(k,k,0); break;
case 3: setAll(0,k,0); break;
case 4: setAll(0,k,k); break;
case 5: setAll(0,0,k); break;
}
showStrip();
delay(3);
}
// Fade OUT
for(int k = 255; k >= 0; k--) {
switch(j) {
case 0: setAll(k,0,0); break;
case 2: setAll(k,k,0); break;
case 3: setAll(0,k,0); break;
case 4: setAll(0,k,k); break;
case 5: setAll(0,0,k); break;
}
showStrip();
delay(3);
}
}
}
}
void red(){
irrecv.resume();
setAll(0,255,255);
showStrip();
}
void setPixel(int Pixel, byte red, byte green, byte blue) {
#ifdef ADAFRUIT_NEOPIXEL_H
// NeoPixel
strip.setPixelColor(Pixel, strip.Color(red, green, blue));
#endif
#ifndef ADAFRUIT_NEOPIXEL_H
// FastLED
leds[Pixel].r = red;
leds[Pixel].g = green;
leds[Pixel].b = blue;
#endif
}
void setAll(byte red, byte green, byte blue) {
for(int i = 0; i < NUM_LEDS; i++ ) {
setPixel(i, red, green, blue);
}
showStrip();
}
void showStrip() {
#ifdef ADAFRUIT_NEOPIXEL_H
// NeoPixel
strip.show();
#endif
#ifndef ADAFRUIT_NEOPIXEL_H
// FastLED
FastLED.show();
#endif
}
void fadeall() { for(int i = 0; i < NUM_LEDS; i++) { leds[i].nscale8(250); } }
being honnest most of this I got online. it is my first time programming an arduino. but so far Im liking it
Instead of using infinite loops, you can just check for if any other command is received.
E.g:
instead of
while ( key_value == key_value ) //This is a weird infinite loop condition but whatever
{
// do stuff
}
you can have
while ( decode() == condition_for_this_loop )
{
// do stuff
}
or
for(;;) //This also is just an infinite loop, but looks nicer.
{
// do stuff
if ( decode() != condition_for_this_loop ) { break; }
}
Note that this is a pseudo code. You need to properly implement it. And you may need to alter the logic of your program a bit.
Since you have defined irrecv object globally, it will be visible for other functions below, this won't be a problem. Your code may even work just by replacing the loop condition. But if you get errors, you need to deal with them, I am just pointing to the logic. In the end, you can have something like this:
irrecv.decode( &results );
switch ( results )
{
case CONDITION_1:
inf_loop1();
break;
case CONDITION_2:
int_loop2();
break;
}
...
void inf_loop1()
{
for(;;)
{
// do stuff
irrecv.decode( &results );
if ( results != CONDITION_1 ) { break; }
}
}
void inf_loop2()
{
for(;;)
{
// do stuff
irrecv.decode( &results );
if ( results != CONDITION_2 ) { break; }
}
}
By the way, it's not a good idea to start with relatively big projects. By your question, I am assuming this is not only your first program for Arduino, but your first ever program. You don't run before you walk. Start slowly, blink some LEDs, implement some fun algorithms with LEDs, i don't know, have multiple of them and light them in different sequences, have some buttons and combine them with LEDs. Just play with LEDs. As you get more experience, you won't be asking questions like this. And if you start with some big project, chances are, you won't be able to do it, and got disappointed, or you will be just followed some online tutorials and copy-paste code, hence it won't feel like you did it.

arduino interrupts with servo motor

currently am working on project to open a door with access code using arduino UNO and a servo motor. Normal operation requires entering access code using keypad which is working fine. Another option requires pressing a button that causes an interrupt to rotate the servo motor. My problem is my interrupt only works once and never works again. Plus how do i put the for-loop to rotate the servo motor inside the interrupt function with a delay. I know that is not possible but am calling another function that has the delayMicroseconds but all this is not working. Below is my implementation please help
#include <Keypad.h>
#include <LiquidCrystal.h>
#include <Servo.h>
Servo servo;
const int openButtonPin = 2;
void setup() {
// put your setup code here, to run once:
servo.attach(5);
pinMode(openButtonPin, INPUT); //Pin 2 is input
attachInterrupt(0, enforceOpenAccess, HIGH); // PIN 2
}
void(* resetFunc)(void) = 0;
void loop()
{
//My other keypad implementations go here
}
void myDelay(int x) // function to cause delay in the interrupt
{
for(int i = 0; i<x; i++)
{
delayMicroseconds(1000);
}
}
void enforceOpenAccess() // ISR
{
for(int k =0; k<=180; k+=2)
{
servo.write(k); //rotate the servo
myDelay(30); //delay the rotation of the servo
}
}
The code above is run on arduino UNO being simulated in proteus and the interrupt button is a push button. Please if there is other ways of implementing that but with the same behaviour as I have described above help out. Thanks a lot
There are a couple of problems in the slice of code you posted. Just for completeness, you should post the loop function, since we can't guess what you wrote inside.
Just one comment: did you put a pullup? Otherwise use INPUT_PULLUP instead of INPUT for the button pinmode.
The main one is that you attached the interrupt for the HIGH mode, which will trigger the interrupt any time the pin is up, not on the rising edge. And please use the macro digitalPinToInterrupt to map to the correct pin:
attachInterrupt(digitalPinToInterrupt(openButtonPin), enforceOpenAccess, RISING);
Then.. Let's improve the code. You really should use the interrupts only when strictly necessary when you have to respond IMMEDIATELY (= less than a couple of milliseconds) to an input. Here you don't have to, so it's MUCH better to check for the button in the loop (more on turning the motor following)
uint8_t lastState;
void setup()
{
...
lastState = LOW;
}
void loop()
{
uint8_t currentState = digitalRead(openButtonPin);
if ((currentState != lastState) && (currentState == HIGH))
{
// Start turning the motor
}
lastState = currentState;
...
}
This will enable you to properly debounce the button too:
#include <Bounce2.h>
Bounce debouncer = Bounce();
void setup()
{
...
pinMode(openButtonPin, INPUT); //Pin 2 is input
debouncer.attach(openButtonPin);
debouncer.interval(5); // interval in ms
}
void loop()
{
debouncer.update();
if (debouncer.rose())
{
// Start turning the motor
}
...
}
If, on the other way, you REALLY want to use the interrupts (because waiting for a couple of milliseconds is too much for you), you should do something like this:
#include <Bounce2.h>
Bounce debouncer = Bounce();
void setup()
{
...
pinMode(openButtonPin, INPUT);
attachInterrupt(digitalPinToInterrupt(openButtonPin), enforceOpenAccess, RISING);
}
void loop()
{
...
}
void enforceOpenAccess() // ISR
{
// Start turning the motor
}
It looks like your code? No, because now we'll speak about turning the motor
You should NOT use delays to make steps, because otherwise you will wait for 30ms * 180 steps = 5.4s before being able to do anything else.
You can, however, make a sort of reduced state machine. You want your servo to move from 0 to 180 in steps of 1. So let's code the "don't move" state with any value greater than 180, and consequently we can do something like this in the loop:
unsigned long lastServoTime;
uint8_t servoPosition = 255;
const int timeBetweenSteps_in_ms = 30;
void loop()
{
...
if (servoPosition <= 180)
{ // servo should move
if ((millis() - lastServoTime) >= timeBetweenSteps_in_ms)
{
lastServoTime += timeBetweenSteps_in_ms;
servoPosition++;
if (servoPosition <= 180)
servo.write(servoPosition);
}
}
}
Then, using any of the previous examples, instead of // Start turning the motor write
lastServoTime = millis();
servoPosition = 0;
servo.write(servoPosition);
This way you won't block the main loop even when the button is pressed
This is what is in my loop()
char key = keypad.getKey();
if(key)
{
if(j < 10)
{
studentNumber[j] = key;
//holdMaskedNumber[j] = '*';
lcd.setCursor(0,2);
lcd.print(String(studentNumber));
if(j == 9)
{
studentNumber[9] = '\0';
//holdMaskedNumber[9] = 0;
lcd.clear();
//String number = String(studentNumber);
//lcd.print(number);
//delay(1000);
//lcd.clear();
lcd.print("Access Code");
}
j++;
}
else
{
if(i < 5)
{
accessCode[i] = key;
holdMaskedCode[i] = '*';
lcd.setCursor(1,2);
lcd.print(String(holdMaskedCode));
if(i == 4)
{
holdMaskedCode[5] = '\0';
accessCode[5] = '\0';
//lcd.clear();
//lcd.setCursor(0,0);
//accessCodeString = String(accessCode);
//lcd.print(accessCodeString);
//delay(1000);
lcd.clear();
for(int i =0; i<6; i++)
{
lcd.print("Please wait.");
delay(500);
lcd.clear();
lcd.print("Please wait..");
delay(500);
lcd.clear();
lcd.print("Please wait...");
delay(500);
lcd.clear();
}
digitalWrite(4, HIGH);
lcd.print("Access Granted");
for(int k =0; k<=180; k+=2)
{
servo.write(k);
delay(30);
}
resetFunc();
}
i++;
}
}
}

Resources