Getting an Arduino function to loop within a switch case - arduino

I'm trying to get the function flash() to repeat, but it stops when clickevent() occurs again and case 0 becomes active.
I think my error is that case 0 is not becoming active because it's stuck on case 1 maybe? I can get it to start using while() statements or do while() statements but then I can't exit the loop, any help would be very appreciated.
// ======== change the lighting mode setting between flash and solid with a single click of the button ===========
int ModeSetting = 0;
void clickEvent()
{
Serial.println("Click Occured");
ModeSetting++;
if (ModeSetting > 1)
ModeSetting = 0;
ChangeMode(ModeSetting);
}
void ChangeMode(int i)
{
switch (i)
{
case 0:
strip.setBrightness(255);
Serial.println("MODE = SOLID COLOUR"); // SOLID LIGHT;
break;
case 1:
flash(); // THE FUNCTION THAT NEEDS TO LOOP pls help
break;
}
}
int flashstate = LOW;
unsigned long PrevFlashMillis = 0;
const long flashinterval = 1000;
void flash()
{
unsigned long currentFlashMillis = millis();
if (currentFlashMillis - PrevFlashMillis >= flashinterval)
{
// save the last time you blinked the LED
PrevFlashMillis = currentFlashMillis;
// if the LED is off turn it on and vice-versa:
if (flashstate == LOW)
{
strip.setBrightness(255);
Serial.println("FLASH ON");
flashstate == HIGH;
}
else
{
strip.setBrightness(0);
Serial.println("FLASH OFF");
flashstate == LOW;
}
}
}

Related

How can I exit a 'for' loop in the main Arduino loop with a serial command?

I need to exit a 'for' loop running in the main loop on an Arduino board through a serial command, but it looks like that up to the end of the main loop the Serial Event is not taken in consideration. How can I solve this?
I supply some simplified code to have a better understanding of the problem:
boolean start = false;
boolean abortLoop = false;
String inputString = "";
void setup() {
Serial.begin(9600);
}
void loop() {
if(start) {
Serial.println("start");
for(int i=0; i <10; i++) {
if(abortLoop)
break;
Serial.println(i);
delay(1000);
}
start = false;
abortLoop = false;
}
}
void serialEvent()
{
while (Serial.available())
{
// Get the new byte:
char inChar = (char)Serial.read();
// Add it to the inputString:
inputString += inChar;
//Serial.println(inputString);
// If the incoming character is a newline, set a flag
// so the main loop can do something about it:
if (inChar == '\n')
{
inputString = inputString.substring(0, inputString.length() - 1);
//Serial.println(inputString);
//Serial.println(inputString.length());
if (inputString[0] == 's')
{
Serial.println("start");
start = true;
}
if (inputString[0] == 'a')
{
abortLoop = true;
Serial.println("abort");
}
inputString = "";
}
}
}
If sending the command 'a' in the middle of the loop, the loop keeps going up to the end.
The result is:
start
start
0
1
2
3
4
5
6
7
8
9
abort
abort
In this case, the 'a' command was sent two times.
The solution is pretty simple. The only thing you have to do is to call your function in the for loop, else the function can't be executed.
// ...
for(int i=0; i <10; i++) {
serialEvent();
if(abortLoop)
break;
Serial.println(i);
delay(1000);
}
// ...
Moreover, I think it's better if you call your function at this place too:
// ...
void loop() {
serialEvent();
if(start) {
// ...
It's strangely not necessary, but in my opinion it's better. And 'start' is printed out two times, because you call it two times. One time here:
void loop() {
if(start) {
Serial.println("start");
for(int i=0; i <10; i++) {
and another time here:
if (inputString[0] == 'a')
{
abortLoop = true;
Serial.println("abort");
}
so you can remove one of them.

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.

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.

I want to count the number of presses of the button(switch) before it executes

my code only executes the case 1. i need if i press 3 times. it will execute my case 3. thank you so much
int pushButton = 13;
void setup() {
Serial.begin(9600);
pinMode(pushButton, INPUT);
for(int pin=10;pin<=12;pin++){
pinMode(pin,OUTPUT);
}
}
void loop() {
int ctr=0;
int buttonState = digitalRead(pushButton);
if(buttonState ==1)
{
ctr+=1;
Serial.println(ctr);
}
switch (ctr) {
case 1:
Serial.println("00000000000000000000");
blinking();
break;
case 2:
Serial.println("AAAAAAAAAAAAAAAA");
running();
break;
case 3:
incremental();
default:
Serial.println("push the button");
}
}
void blinking(){
for(int z=0;z<=3;z++){
for(int i=10;i<=12;i++){
digitalWrite(i,HIGH);
}delay(500);
for(int i=10;i<=12;i++){
digitalWrite(i,LOW);
}delay(500);
}
}
void running(){
for(int z=0;z<=2;z++){
for(int i=10;i<=12;i++){
digitalWrite(i,HIGH);
delay(500);
digitalWrite(i,LOW);
}
}
}
void incremental(){
for(int z=0;z<=2;z++){
int d=1500;
for(int i=10;i<=12;i++){
digitalWrite(i,HIGH);
delay(d); d-=500;
}
for(int i=10;i<=12;i++){
digitalWrite(i,LOW);
}delay(500);
}
}
my code only executes the case 1. i need if i press 3 times. it will execute my case 3. thank you so much
Change int ctr=0 to static int ctr=0
It is the same thing as declare ctr with global scope.
It will not reset to 0 each time loop function is called.
Button debounce should be checked.
Apart from the fact that ctr is assigned zero every time loop() runs, you also have the problem that if the button is held down, ctr will increment continuously, which may not be what you want. It also increments ctr past three, when the default case will run indefinitely. It is not clear that you intended case 3 to fall-through to the default case; it is generally considered bad practice or a mistake, so worth a comment if it is deliberate.
The following code makes ctr static so it is nor always assigned zero, and increments ctr only when the button is pressed down, and will not increment it if it is merely held-down or stuck. It also returns ctr to zero in the default case so you can cycle the states (which may not be your intent). I have removed the debug output for clarity.
void loop()
{
static int ctr = 0 ;
static bool button_down = false ;
int button_state = digitalRead(pushButton) == 1 ;
if( !button_down && button_state = 1 )
{
ctr++ ;
button_down = true ;
}
else if( button_state = 0 )
{
button_down = false ;
}
switch( ctr )
{
case 1:
blinking();
break;
case 2:
running();
break;
case 3:
incremental();
break ;
default:
ctr = 0 ;
break ;
}
}

Arduino not entering for loop

I'm having a problem with an if ladder and the for loops in each of them in this gameProcess function. Essentially the for loop in the (mode == 1) loop is not entered at all and I'm not sure why.
I think it's something to do with the positioning because if (mode == 1) is switched with (mode == 0), the (mode == 1) for loop will be entered but the (mode == 0) won't. Been stuck on this for a while and can't seem to spot what's up with the function. Any help would be greatly appreciated. Thanks.
// 5 means 10 switches as one iteration is a change between one mode to another, not on and off.
int gameProcess(int mode) {
Serial.println("> Starting game process.");
// 4 second delay between
int interval = 1000;
int initialDelay = 5000;
enter code here:
//delay(initialDelay);
if (mode == 1) {
// for a standard 25 round with a 2 sec interval
Serial.println("starting mode 1");
for (int i; i < 51; i++) {
Serial.println("In loop");
Serial.println(interval);
flickPin(13);
workingDelay(interval);
}
Serial.println("finished mode 1");
} else if (mode == 2) {
while(true) {
flickPin(13);
int minRandVal = 1000;
int maxRandVal = 15000;
int randomDelay = random(minRandVal, maxRandVal);
Serial.println(randomDelay);
workingDelay(randomDelay);
}
} else if (mode == 0) {
// for 10 rounds. Find out why it needs 35 and not 20.
Serial.println(" - Mode 0 .");
for (int i; i < 35; i++) {
Serial.println(interval);
flickPin(13);
workingDelay(interval);
}
Serial.println(" - finished Mode 0 .");
} else {
char error[80];
sprintf(error, "Unknown mode = %d", mode);
Serial.println(error);
}
}
Here is the main loop and the initializeGame function where the gameProcess function is called from.
int initializeGame(bool started, int mode) {
if (started == true) {
Serial.println(" -> in startMonitor, start button pressed");
Serial.println(mode);
gameProcess(mode);
// if the mode is 0 (none of the lights are on), that means it's in random mode and any interval between 5 and 60 secs come up until you stop it!
// set it back to false and turn the game light off because the game is over.
started = false;
digitalWrite(9, LOW);
} else {
started = false;
}
return started;
}
void loop()
{
// check if the pushbutton is pressed.
mode = stateMonitor(activeButton);
// now set the game mode led.
lightUpModeLed(ledPins[mode]);
// now check to see if the game has been initialized.
started = startMonitor(startButton, ledPins[4], started);
// read the state of the pushbutton value:
// initialize game if it hasn't already started.
// TODO this is where the loop will likely spend the majority of it's time so how can this be
started = initializeGame(started, mode);
saveData();
}
if you are using windows then install Atmel Studio and the Visual Micro Plugin then you can debug and watch what the code is doing and the values of variables.
This will take away the mystery, which it did for me.

Resources