I have an arduino set up to flash a few lights and control a Parallax Colorpal. The time between the flashes and color changes is determined by me pressing a button 5 times and averaging the time differences between each sequential press. This is intended to be used as a cool lighting effect for school dances. (Now all I need is a glowing Arch Linux logo to flex on the hot girls that I use Arch btw.) However, after what seems like about an hour (I didn't actually time it), the program seems to crash. If it's probably a few minutes away from crashing anyways, pressing the button to adjust the flash rate will also prompt a crash. When it crashes, serial output stops completely, one of the LEDs connected directly to the pins flashes every few minutes, and the arduino is unresponsive to input from the button. If I reset it, it continues to work as usual, but that gets annoying, especially if I have to find a way to integrate it into my dance moves. I cannot find anything wrong with my code. AFAIK, millis() overflows every 50 days, so that really shouldn't be what's going on.
const int leftLED = 5;
const int rightLED = 3;
const int button = 2;
const int statusLED = 13;
const String colors[6] = {
"=rFF0000!",
"=rFFFF00!",
"=r00FF00!",
"=r00FFFF!",
"=r0000FF!",
"=rFF00FF!"
};
void setup() {
pinMode(leftLED, OUTPUT);
pinMode(rightLED, OUTPUT);
pinMode(statusLED, OUTPUT);
pinMode(button, INPUT);
pinMode(1, INPUT);
do{
delay(100);
}while(digitalRead(1) == LOW);
pinMode(1,OUTPUT);
digitalWrite(1, LOW);
delay(100);
Serial.begin(4800);
digitalWrite(leftLED, HIGH);
digitalWrite(rightLED, HIGH);
digitalWrite(statusLED, HIGH);
Serial.print("=r00FF00!");
while(digitalRead(button) == HIGH){}
while(digitalRead(button) == LOW){}
digitalWrite(statusLED, LOW);
}
int currentColor = -1;
void updateColors(){
currentColor++;
Serial.print(colors[currentColor % 6]);
}
unsigned long switchInterval = 200;
unsigned long nextSwitchTime = millis() + switchInterval;
int btnPressIndex = 0;
unsigned long btnPressTimes[5];
unsigned long switchCounter = 0;
void loop() {
if(millis() >= nextSwitchTime){
updateColors();
nextSwitchTime = millis() + switchInterval;
if (switchCounter % 5 == 0){
analogWrite(leftLED, 255);
analogWrite(rightLED, 127); //The LEDs, due to being random under-the-bed LEDs are not identical. If both pins are high, this one is about twice as bright as the other one.
delay(50);
digitalWrite(leftLED, LOW);
digitalWrite(rightLED, LOW);
}
switchCounter++;
}
if(digitalRead(button) == LOW){
digitalWrite(statusLED, HIGH);
btnPressTimes[btnPressIndex] = millis();
btnPressIndex++;
if(btnPressIndex == 5){
btnPressIndex = 0;
switchInterval = (
(btnPressTimes[1] - btnPressTimes[0]) +
(btnPressTimes[2] - btnPressTimes[1]) +
(btnPressTimes[3] - btnPressTimes[2]) +
(btnPressTimes[4] - btnPressTimes[3])
) / 20;
delay(50);
digitalWrite(statusLED, LOW);
}
while(digitalRead(button) == LOW){};
delay(10);
}
}
It is not a good idea to use the String (capital S) class on an Arduino as it can cause memory corruption in the small memory on an Arduino. This can happen after the program has been running perfectly for some time. Just use cstrings - char arrays terminated with '\0' (NULL).
Robin2:
It is not a good idea to use the String (capital S) class on an Arduino as it can cause memory corruption in the small memory on an Arduino. This can happen after the program has been running perfectly for some time. Just use cstrings - char arrays terminated with '\0' (NULL).
...R
Seriously? I'm just referencing the same hard coded strings over and over again. Why is it making more and more instances of the string if that's the case?
gcjr:
why do you print w/o linefeeds?
Serial.print(colors[currentColor % 6]);
Because the device I'm connected to doesn't specify a need for line feeds, so I'd rather save two keystrokes and IO time and just not print the line feeds. Is there a problem with that?
Robin2:
The only way I can think to answer that is to re-write the program without using the String class and see if the problem goes away.
Maybe it will. Maybe it won't.
I know what I would do, but it's your call.
...R
All that is needed to get rid of the single occurence of String is to change "const String" to "const char * "
How is the button connected? A floating input might cause some odd behavior. Have you tried printing out the value of switchInterval to make sure it isn't getting set to something very large?
david_2018:
All that is needed to get rid of the single occurence of String is to change "const String" to "const char * "
How is the button connected? A floating input might cause some odd behavior. Have you tried printing out the value of switchInterval to make sure it isn't getting set to something very large?
Changing it to const char * does not break anything, but I haven't had enough testing time to confirm that it isn't broken. I think my program takes up less storage space too. The button is normally open and goes from the pin to ground, and a 10k ohm resistor between 5V and the pin. As far as I know, this works perfectly. If I remove the resistor, I get lots of false low readings, so I'm going to keep it. I really don't think switchInterval is the problem because the code involving it looks bug free, and actions that are not dependent on it (such as polling the button and setting pin 13 when pressed) also stop.
Danois90:
Your timing is malformed:
unsigned long nextSwitchTime = millis() + switchInterval; //NO!
if (millis() - previousActionMillis >= actionInterval) {...}
I made that change and yours works too, but I don't understand why mine isn't rollover safe. (Not that it's a problem because this will only be operated for at most 3 hours at a time, but I guess I'll fix it anyways.) Suppose that millis() is 4294967196 and switchInterval is 200. nextSwitchTime should be set to 4294967396, but it wraps around to 100 because we only have 32 bits. millis() will also wrap around when exceeding 32 bits and therefore will still approach and exceed 100.
After making the changes, the code takes closer to about 15 minutes to crash, and when it does crash, serial data is corrupted and the LEDs flash irregularly a couple times a minute.
Actually, it's not simply every 15 minutes. On the first attempt, it crashed after 15 minutes, but on another test with no change to the code it's been running for well over an hour with no problems.
Well, it just started misbehaving again, so there goes that. The LEDs are directly driven from the pins through wires, and then connected to ground. The ColorPAL is connected directly to 5V, ground, and an IO pin. The button was already described, but is NO to ground with a 10k pullup resistor. In real world use, it is powered by my USB power bank. During testing, it is powered by my laptop's USB port. It happens on both power sources.
wc767KaJf2v7bT9M6fnmVCoQ:
Well, it just started misbehaving again, so there goes that. The LEDs are directly driven from the pins through wires, and then connected to ground. The ColorPAL is connected directly to 5V, ground, and an IO pin. The button was already described, but is NO to ground with a 10k pullup resistor. In real world use, it is powered by my USB power bank. During testing, it is powered by my laptop's USB port. It happens on both power sources.
No current limiting resistors on the LEDs?
Most arduino's have internal pullup resistors on the inputs, if you set pinMode to INPUT_PULLUP, so the 10K resistor on the button really isn't necessary. The most common mistake is to not have any pullup/pulldown resistor.
The only other thing I can think to do is change the delay(10) at the very end to delay(50) in case there is a lot of switch bounce.
Just in case, I'm going to try to run it overnight on AC power and let you know how it goes. Because flooding my room with light when I want to sleep is very healthy.
david_2018:
No current limiting resistors on the LEDs?
Most arduino's have internal pullup resistors on the inputs, if you set pinMode to INPUT_PULLUP, so the 10K resistor on the button really isn't necessary. The most common mistake is to not have any pullup/pulldown resistor.
The only other thing I can think to do is change the delay(10) at the very end to delay(50) in case there is a lot of switch bounce.
Your post went onto the second page, so I completely missed it. There are no current limiting resistors on the LEDs. They aren't burning out, so I don't think it's a problem. I don't think the delay(10) is involved because switch-independent actions are affected too. It crashed on a USB wall wart, so I'll try my 9V wall wart and the ardunio's built in regulator.
wc767KaJf2v7bT9M6fnmVCoQ:
... There are no current limiting resistors on the LEDs. They aren't burning out, so I don't think it's a problem..
Leds arent burning out because of pin limitations. But this makes pin output suffer a lot.
4-5 leds with no limiting resistors go beyond that and make the whole chip power rail suffer.