Hey All! I am currently working on a project using the arduino to run a high powered LED light that I built. The system uses a button and a potentiometer to read in information and change modes/speeds etc. So far, all of the different "modes" have been successfully written and work. (RGB Fades, Blinky modes, strobe modes, etc) However I've run into some trouble when it comes to switching modes. Attached is the main loop of my code where I use a debounced button and edge detection to advance the mode and then a simple switch mode machine to switch between modes. It all works okay, but you seem to have to hit the button at the perfect time to get it to change modes or, it will read the button press but not change modes for a second or two. Does anyone have any advice?
void loop() {
val = digitalRead(btn);
delay(10); //Wait to make sure button press is good
val2 = digitalRead(btn);
if (val == val2){ //debounce check
if (val != butState && val == HIGH){ //If we see a change in the button state,
mode++; //we increment the mode value by 1
}
}
butState = val; //update the most recent button state
if (modeState != mode){
switch (mode) {
case 2: //Start with Case 2 because Case 1 is considered the default
ColorBreath("r"); //"start-up" mode.
break;
case 3:
ColorBreath("g");
break;
case 4:
ColorBreath("b");
break;
case 5:
RGBAllFade();
break;
default:
mode = 1;
ColorSelect();
break;
}
}
}
I should also note that each function, when run independently of the switching program, results in smooth dimming of the LEDs. However, when run through the state machine, the dimming becomes choppy and erratic.
Yeah, so that modeState variable was a line that I left out. here is the updated code. However, now the function under the mode is running once and then not doing anything, but the button works perfectly to switch modes! Any clues?
void loop() {
val = digitalRead(btn);
delay(10); //Wait to make sure button press is good
val2 = digitalRead(btn);
if (val == val2){ //debounce check
if (val != butState && val == HIGH){ //If we see a change in the button state,
mode++; //we increment the mode value by 1
}
}
butState = val; //update the most recent button state
if (modeState != mode){
switch (mode) {
case 2: //Start with Case 2 because Case 1 is considered the default
ColorBreath("r"); //"start-up" mode.
break;
case 3:
ColorBreath("g");
break;
case 4:
ColorBreath("b");
break;
case 5:
RGBAllFade();
break;
default:
mode = 1;
ColorSelect();
break;
}
}
modeState = mode;
}
msmith419:
It all works okay, but you seem to have to hit the button at the perfect time to get it to change modes or, it will read the button press but not change modes for a second or two. Does anyone have any advice?
It sounds like your function are using delays, but that is just a guess as you seem to not want to post all of your code. If that is the case, you'll have to take a look at the Blink Without Delay example and restructure your functions to run non-blocking code with the concepts demonstrated in the aforementioned example.
I don't mind posting my entire code, it's just really long an not exactly well commented. I would like to solve the switch problem first before I solve the dimming problem. Here it is though. (Sorry, I posted the wrong code initially, here is the right code)
/******************
* High Power LED *
* 13 April 2013 *
* Mitchell Smith *
*******************/
//===============================================================================
// GLOBAL VARIABLES
//===============================================================================
//LED Pins
int LedR = 11, LedG = 10, LedB = 9;
//Analog Button and Potentiometer Pins
int btn = 4;
int pot = A0;
//Set LED attributes
int RBright = 0, GBright = 0, BBright = 0; //initial brightness
int Rmax = 240, Gmax = 255, Bmax = 255; //maximum brightness (necessary on R LED)
//Set fade attributes
int fadeAmount = 1;
int fadeUpSp = 1, fadeDnSp = 1;
int chaseSpeed = 100;
//button state variables
int butState = 0; //Last Button State
int val = 0, val2 = 0; // Button Pin HIGH/LOW Status (twice for debounce)
//Switch Mode Variables
int mode = 0; //Selector State (Initial state = everything off)
int modeState = 0; //Last Mode State
//===============================================================================
// Set-Up
//===============================================================================
void setup() {
pinMode(btn, INPUT);
pinMode(pot, INPUT);
pinMode(LedR, OUTPUT);
pinMode(LedG, OUTPUT);
pinMode(LedB, OUTPUT);
//butState = digitalRead(btn);
Serial.begin(9600);
}
//===============================================================================
// PROGRAM LOOP
//===============================================================================
void loop() {
val = digitalRead(btn);
delay(10); //Wait to make sure button press is good
val2 = digitalRead(btn);
if (val == val2){ //debounce check
if (val != butState && val == HIGH){ //If we see a change in the button state,
mode++; //we increment the mode value by 1
}
}
butState = val; //update the most recent button state
if (modeState != mode){
switch (mode) {
case 2: //Start with Case 2 because Case 1 is considered the default
ColorBreath("r"); //"start-up" mode.
break;
case 3:
ColorBreath("g");
break;
case 4:
ColorBreath("b");
break;
case 5:
RGBAllFade();
break;
default:
mode = 1;
ColorSelect();
break;
}
}
else {
switch (modeState) {
case 2: //Start with Case 2 because Case 1 is considered the default
ColorBreath("r"); //"start-up" mode.
break;
case 3:
ColorBreath("g");
break;
case 4:
ColorBreath("b");
break;
case 5:
RGBAllFade();
break;
default:
mode = 1;
ColorSelect();
break;
}
}
modeState = mode;
}
//===============================================================================
// Color Funcitons
//===============================================================================
void ColorSelect(){
analogWrite(LedR, rWheel(getColor()));
analogWrite(LedG, gWheel(getColor()));
analogWrite(LedB, bWheel(getColor()));
}
void ColorBreath(String color){
if (color == "r"){
RFadeUp();
delay(getChase());
RFadeDown();
delay(getChase());
}
else if (color == "g"){
GFadeUp();
delay(getChase());
GFadeDown();
delay(getChase());
}
else if (color == "b"){
BFadeUp();
delay(getChase());
BFadeDown();
delay(getChase());
}
}
void RGBAllFade() {
RFadeUp();
BFadeDown();
delay(getChase());
GFadeUp();
RFadeDown();
delay(getChase());
BFadeUp();
GFadeDown();
delay(getChase());
}
//===============================================================================
// Utility Functions
//===============================================================================
double getFade() {
double fdVal = analogRead(pot);
double fadeSp = map(fdVal, 0, 1023, 1, 50);
return fadeSp;
}
double getChase(){
double chVal = analogRead(pot);
double chaseSp = map(chVal, 0, 1023, 0, 1000);
return chaseSp;
}
int getColor(){
int colVal = analogRead(pot);
int col = map(colVal, 0, 1023, 0, 383);
return col;
}
//Color Wheel Functions
double rWheel(int WheelPos){
int r;
switch(WheelPos/128){
case 0:
r = 127 - WheelPos % 128;
break;
case 1:
r = 0;
break;
case 2:
r = WheelPos % 128;
break;
}
return r;
}
double gWheel(int WheelPos){
int g;
switch(WheelPos/128){
case 0:
g = WheelPos % 128;
break;
case 1:
g = 127 - WheelPos % 128;
break;
case 2:
g = 0;
break;
}
return g;
}
double bWheel(int WheelPos){
int b;
switch(WheelPos/128){
case 0:
b = 0;
break;
case 1:
b = WheelPos % 128;
break;
case 2:
b = 127 - WheelPos % 128;
break;
}
return b;
}
//Fade Up Commands
void RFadeUp() {
while(RBright < Rmax) {
analogWrite(LedR, RBright);
RBright = RBright + fadeAmount;
delay(getFade());
}
}
void GFadeUp() {
while(GBright < Gmax) {
analogWrite(LedG, GBright);
GBright = GBright + fadeAmount;
delay(getFade());
}
}
void BFadeUp() {
while(BBright < Bmax) {
analogWrite(LedB, BBright);
BBright = BBright + fadeAmount;
delay(getFade());
}
}
//Fade Down Commands
void RFadeDown() {
while(RBright > 0) {
analogWrite(LedR, RBright);
RBright = RBright - fadeAmount;
delay(getFade());
}
}
void GFadeDown() {
while(GBright > 0) {
analogWrite(LedG, GBright);
GBright = GBright - fadeAmount;
delay(getFade());
}
}
void BFadeDown() {
while(BBright > 0) {
analogWrite(LedB, BBright);
BBright = BBright - fadeAmount;
delay(getFade());
}
}
why would they be my problem. All they do is read an analogue value from the POT pin and map it. Sorry that seems mean. Is there a better way to do that? I want the dimming curves to be fully adjustable during the cycle, not just at the beginning and end. Also, when the functions are run independently as the main loop, the dimming is smooth and the delay doesn't cause problems.
You shouldn't be using "delay()" at all, but even if you wanted to, it doesn't take a "float" as a parameter.
Worse, "float"s are slow, and here unnecessary.
Okay.... but it's reading the value before the delay starts in order to get a length for the delay. Also, when I run the functions independently, they work! What I mean is shown in the code below.
it's reading the value before the delay starts in order to get a length for the delay.
I know that, but I'm telling you you shouldn't be using "delay()" at all.
It's painful, initially, but necessary.
Have you looked a "blink without delay", as suggested?
I took a look at "blink without delay." I think I understand what's happening here. would replacing all of my "delays" with something like this work?
where f is the mapped input from the potentiometer. Any place I would normally use a delay would be replaced with an if statement to see if the delay had been met. (at this rate, I am using the word delay as a word for what I want to program to do, not as the actual function. I understand that delay is not what I should be using.)
boolean cusDelay;
boolean myDelay(double f) {
long currentMillis = millis();
long previousMillis = 0;
if (currentMillis - previousMillis > f){
previousMillis = currentMillis;
if (cusDelay == false){
cusDelay = true;
}
else{
cusDelay = false;
}
}
return cusDelay;
}
No, I don't think your proposed solution will work.
What you really need is a finite state machine or a small number of separate finite state machines.
I'm sorry, but there is no easy fix - a rewrite is necessary.
Do you have any code suggestions other than just saying it's wrong? How would I go about implementing something like you are suggesting? I've gone through every tutorial that I thought was even remotely relevant but I'm still having issues. Has anyone else ever used a finite state machine with LED dimming on the PWM outputs?
Do you have any code suggestions other than just saying it's wrong?
Yes, I do.
Take the technique set out in the "blink without delay" example, substitute "micros" for "millis", and write a sketch that implements a slow fade up and down of the on-board LED on pin 13.
(this pin isn't PWM-capable, remember)
This is a learning exercise, and hopefully will give you an insight into doing what you want to achieve.
Edit: Mission creep: Make the fade period variable by using a pot.
So you're saying that in order to properly fade I will have to not only create a function to step the brightness of the LED up and down (fading) but I also need to rewrite the PWM function that is already built in to the arduino?
No, I never said it was necessary to rewrite analogWrite, just that you can easily write code to perform two simple tasks operating at different rates without resorting to "delay()"
For the task described, if you get to sixty lines of code, you've gone too far.