Arduino shows odd behaviour with LED output in loop - c++

Hi I am having a little trouble understanding the behaviour of what would seem a very simple issue.
I have 4 LED's and resistors linked up, with a push button. The idea is that I press the button and the LEDS light up sequentially, turning the previous one off.
This works fine, until it is time to restart the loop from the beginning where everything is ok in serial monitor, but the LEDS barely light up except number 4 which lights up normally.
Here is my code:
const int buttonPin = 6;
const int ledPin1 = 2;
const int ledPin2 = 3;
const int ledPin3 = 4;
const int ledPin4 = 5;
int buttonState = 0;
int pressed = 0;
void setup() {
{
Serial.begin (115200);
Serial.println ();
Serial.println ("Starting up");
}
pinMode(ledPin1, OUTPUT);
pinMode(ledPin2, OUTPUT);
pinMode(ledPin3, OUTPUT);
pinMode(ledPin4, OUTPUT);
pinMode(buttonPin, INPUT_PULLUP);
}
void loop()
{
if(digitalRead(buttonPin)==HIGH)
{
if(pressed==0)
{
pressed=1;
switch(buttonState)
{
case 0:
digitalWrite(ledPin1, LOW);
buttonState++;
break;
case 1:
digitalWrite(ledPin1, HIGH);
Serial.println ("1");
buttonState++;
break;
case 2:
digitalWrite(ledPin2, HIGH);
pinMode(ledPin1, LOW);
Serial.println ("2");
buttonState++;
break;
case 3:
digitalWrite(ledPin3, HIGH);
pinMode(ledPin2, LOW);
Serial.println ("3");
buttonState++;
break;
case 4:
digitalWrite(ledPin4, HIGH);
pinMode(ledPin3, LOW);
Serial.println ("4");
buttonState++;
break;
case 5:
digitalWrite(ledPin4, LOW);
Serial.println ("off");
buttonState=0;
return;
}
}
}
else
{
pressed=0;
}
}
Hope some of you more intelligent folks can shed some light on this unusual behaviour.
BTW I am VERY new to arduino programming so please take it easy.

You want to understand the difference between pinMode() and digitalWrite() functions.
pinMode(pin, mode) configures the specified pin to behave either as an input or an output. (doc)
digitalWrite(pin, value) writes a HIGH or a LOW value to a digital pin. (doc)
In your switch statement, you are changing pinMode from OUTPUT to INPUT.
pinMode(ledPin1, LOW)
is the same as
pinMode(ledPin1, INPUT)
because LOW and INPUT are both defined as 0x00.
When you change the pin mode to INPUT, you can no longer turn on your LED by calling digitalWrite(ledPin1, HIGH).
LED 4 works because you don't call pinMode(ledPin4, LOW) anywhere.
I think you wanted to call digitalWrite(ledPin1, LOW) instead of pinMode(ledPin1, LOW) in the switch statement.

Related

Arduino loop does not stop - only with smaller counters. Arduino Nano Every

I cannot explain to myself why this code works properly in some cases and in some not. Here is the situation:
I am trying to switch a relay with the Arduino Nano. Therefore I took the "Blink" example as a guide. It should switch on for like 5 minutes and switch off for like 25 minutes. Here is the code:
// the setup function runs once when you press reset or power the board
void setup() {
// initialize digital pin LED_BUILTIN as an output.
pinMode(LED_BUILTIN, OUTPUT);
pinMode(2, OUTPUT); // sets PIN 2 as switcher for the relay
}
// the loop function runs over and over again forever
void loop() {
int count = 0;
int run_pump = 300; // 5 Min run
int stop_pump = 1500; // 25 Min stop
digitalWrite(LED_BUILTIN, LOW); // turn the LED off (HIGH is the voltage level)
digitalWrite(2, HIGH); // turn the pump on
while(count < run_pump) {
count++;
delay(1000); // wait for a second
}
count = 0;
digitalWrite(LED_BUILTIN, HIGH); // turn the LED on by making the voltage LOW
digitalWrite(2, LOW); // turn the pump off
while(count < stop_pump) {
count++;
delay(1000); // wait for a second
}
}
if I run this code on the Arduino it will just switch on the relay forever. BUT: If I set run_pump and stop_pump for like 10 sec. it will work properly! Is there an explanation why this does not work with the bigger counters? It's so confusing....
so this code here works absolutely fine, but why does the code above not?
// the setup function runs once when you press reset or power the board
void setup() {
// initialize digital pin LED_BUILTIN as an output.
pinMode(LED_BUILTIN, OUTPUT);
pinMode(2, OUTPUT); // sets PIN 2 as switcher for the relay
}
// the loop function runs over and over again forever
void loop() {
int count = 0;
int run_pump = 5; // 5 sec run
int stop_pump = 10; // 10 sec stop
digitalWrite(LED_BUILTIN, LOW); // turn the LED off (HIGH is the voltage level)
digitalWrite(2, HIGH); // turn the pump on
while(count < run_pump) {
count++;
delay(1000); // wait for a second
}
count = 0;
digitalWrite(LED_BUILTIN, HIGH); // turn the LED on by making the voltage LOW
digitalWrite(2, LOW); // turn the pump off
while(count < stop_pump) {
count++;
delay(1000); // wait for a second
}
}
Hope someone has a clue.... Thanks!
Tom
OK guys, I solved it. The problem was a cheap relay that was trying to communicate with the Arduino... Replacing it with a better one solved the whole problem. Thanks for the idea with the LED, this brought some stones to roll... :)

Read a Flashing Led in Arduino

So it's a simple problem, I have several LEDs on a board where depending on their states it will trigger a command to fire a relay. Where I am stuck is figuring out how to get the Arduino to see a blinking LED, I have tried to bypass it all together but the code got larger than we wanted so it was scrapped and I am starting all over. Any ideas would be most helpful. Here is the basic code:
int Relay = 2;
int Led = 7;
int Ball = 8;
void setup()
{
Serial.begin(115200);
pinMode(Relay, OUTPUT);
pinMode(Led, INPUT);
pinMode(Ball, OUTPUT);
}
void loop()
{
digitalWrite (Relay, HIGH);
delay (500);
digitalWrite (Relay, LOW);
delay(300);
digitalRead(Led);
if(Led == HIGH)
{
digitalWrite(Ball, HIGH);
}
if(Led == LOW)
{
digitalWrite(Ball, LOW);
}
}
digitalRead(Led) throws away the value you are reading, and if (Led == LOW) is comparing a pin number with a voltage level, which is meaningless. You mean:
level = digitalRead(Led);
if (level == HIGH) { ...

Segmentation fault with wiringPi

I'm fairly new to coding, and I've been trying to write something to write a placeholder to a text document whenever a button attached to a GPIO pin on my RasPi is pressed:
//Write date function//
void record() {
ofstream myFile;
myFile.open("report.txt");
myFile << "Input at SPAM \n";
myFile.close();
}
//myRead function//
void myRead(int i){
if((digitalRead(4) == HIGH) && (i<5)) {
record();
digitalWrite(14, HIGH);
delay(500);
digitalWrite(14, LOW);
++i;
delay(500);
myRead(i);
}
else{
if((digitalRead(4) != HIGH) && (i<5)){
myRead(i);
}
}
}
int main() {
wiringPiSetup();
pinMode(12, OUTPUT);
pinMode(14, OUTPUT);
pinMode(4, INPUT);
digitalWrite(12, HIGH);
digitalWrite(14, LOW);
myRead(1);
digitalWrite(14, HIGH);
delay(5000);
digitalWrite(14, LOW);
return 0;
}
The code compiles without any complaints, but if I run it in terminal without a sudo command, I get a "segmentation fault" error.
When I run it with a sudo command, the program starts and then ends almost immediately.
For reference:
Pin 12 is providing power to a potential divider on the breadboard.
Pin 4 should take the input from this divider.
Pin 14 causes an LED to light whenever there is an input on pin 4.
Whenever I run the program and VERY QUICKLY press the button on the potential divider, the LED will light if I hold the button.
How can I get this to run properly without it stopping as soon as it starts?
I think there are several possible problems with myRead.
A minor rewrite could be:
void myRead(int i)
{
if((digitalRead(4) == HIGH) && (i<5)) {
record();
digitalWrite(14, HIGH);
delay(500);
digitalWrite(14, LOW);
++i;
delay(500);
myRead(i);
} else if((digitalRead(4) != HIGH) && (i<5)) {
myRead(i);
}
}
Notice that you have two calls to digitalRead -- this may lead to problems since the first one my return something different from HIGH and the second may return HIGH, meaning neither conditions are true.
You make a call to myRead with the same i in the alternative branch as the original call. If digitalRead returns something different from HIGH suffeciently many times, your stack will be full very fast and you'll get a segfault.
I'll propose a different version, that should be identical (baring any misunderstanding on my part):
void myRead(int i)
{
// as long as i is less than 5
while (i < 5) {
// busy wait for digitalRead(4) to be HIGH
while (digitalRead(4) != HIGH);
// do the main thing
record();
digitalWrite(14, HIGH);
delay(500);
digitalWrite(14, LOW);
++i;
delay(500);
}
}
Also please note that this is just plain C, not C++ (well, technically it's valid C++, but it's making no use of C++)

C++ (Particle Photon) Threading with changing variable

Note: The code is designed to run on a Particle Photon. Please keep this in mind while reading my question.
I want to make a led blink based on a variable called blink_type this variable will be changed dynamically in a later stage when I implement the API call to fetch the status of something else. I'm currently simulating this behaviour in the loop() function (also tried a thread but that also didn't work).
The blinking works fine until the variable changes from 0 to 1, after that it never blinks again until I do a reset.
Below you will find my code:
// This #include statement was automatically added by the Particle IDE.
#include <httpsclient-particle.h>
// Base variables.
int led = D0;
int buzzer = D1;
// Defining blink types. 0 is normal, 1 is breathe.
int blink_type = 0;
// Set the threads
Thread *normalBlinkThread;
Thread *ledBreatherThread;
void setup() {
// Setup the outputs.
pinMode(led, OUTPUT);
pinMode(buzzer, OUTPUT);
// Create the required threads.
normalBlinkThread = new Thread("rest_status_light", normalBlink);
ledBreatherThread = new Thread("rest_status_light", hearthBeatBlink);
}
os_thread_return_t normalBlink(void*) {
// Start never ending loop
for(;;) {
if(blink_type == 0) {
// Blink led
digitalWrite(led, HIGH);
delay(3000);
digitalWrite(led, LOW);
delay(3000);
}
}
}
os_thread_return_t hearthBeatBlink(void*) {
// Start never ending loop
for(;;) {
if(blink_type == 1) {
// Blink led
digitalWrite(buzzer, HIGH);
delay(500);
digitalWrite(buzzer, LOW);
delay(500);
digitalWrite(buzzer, HIGH);
delay(500);
digitalWrite(buzzer, LOW);
delay(3000);
}
}
}
void loop() {
delay(10000);
switch (blink_type) {
case 0:
blink_type = 1;
break;
case 1:
blink_type = 0;
break;
}
}
To not get confused, the "buzzer" output (D1) is currently also wired to an LED.
If there would be a better approach to blink a led in two different ways based on a dynamic variable I'm happy to adopt to this sollution!
normalBlink() and hearthBeatBlink() have delays only when (blink_type == 1). When blink_type becomes 0 there are no delays in the for loops and one of them, the first which evaluates the variable change, happily spins for eternity. Try to add a small delay in the case blink_type is 0. Hope this helps!

Stuck before delay in sub program

I have the task to program two timers, where I display something on my LCD-Display. I have a matrix keyboard where I can type in some basic things like numbers and some letters with this code:
void keyboard_read()
{
digitalWrite(s1, LOW);
digitalWrite(s2, HIGH);
digitalWrite(s3, HIGH);
digitalWrite(s4, HIGH);
if(digitalRead(r1) == LOW){lcd.print("1"); delay(200);k++;feld[k]=1;}
if(digitalRead(r2) == LOW){lcd.print("4"); delay(200);k++;feld[k]=4;}
if(digitalRead(r3) == LOW){lcd.print("7"); delay(200);k++;feld[k]=7;}
if(digitalRead(r4) == LOW){lcd.print("A"); delay(200);k++;feld[k]='A';}
digitalWrite(s1, HIGH);
digitalWrite(s2, LOW);
digitalWrite(s3, HIGH);
digitalWrite(s4, HIGH);
if(digitalRead(r1) == LOW){lcd.print("2"); delay(200);k++;feld[k]=2;}
if(digitalRead(r2) == LOW){lcd.print("5"); delay(200);k++;feld[k]=5;}
if(digitalRead(r3) == LOW){lcd.print("8"); delay(200);k++;feld[k]=8;}
if(digitalRead(r4) == LOW){lcd.print("0"); delay(200);k++;feld[k]=0;}
digitalWrite(s1, HIGH);
digitalWrite(s2, HIGH);
digitalWrite(s3, LOW);
digitalWrite(s4, HIGH);
if(digitalRead(r1) == LOW){lcd.print("3"); delay(200);k++;feld[k]=3;}
if(digitalRead(r2) == LOW){lcd.print("6"); delay(200);k++;feld[k]=6;}
if(digitalRead(r3) == LOW){lcd.print("9"); delay(200);k++;feld[k]=9;}
if(digitalRead(r4) == LOW){lcd.print("B"); delay(200);k++;feld[k]='B';}
digitalWrite(s1, HIGH);
digitalWrite(s2, HIGH);
digitalWrite(s3, HIGH);
digitalWrite(s4, LOW);
if(digitalRead(r1) == LOW){lcd.print("F"); delay(200);k++;feld[k]='F';}
if(digitalRead(r2) == LOW){lcd.print("E"); delay(200);k++;feld[k]='E';}
if(digitalRead(r3) == LOW){lcd.print("D"); delay(200);k++;feld[k]='D';}
if(digitalRead(r4) == LOW){lcd.print("C"); delay(200);k++;feld[k]='C';}
}
When I type in the first Timer (Timer0) keyboard_read() works just fine, but when I go into the second Timer (Timer2) keyboard_read() stops at the delay command. When I tried to put keyboard_read() in the loop() it still stops at the delay command (There isn't this command in the loop at the moment).
Code for Timer0:
ISR(TIMER0_COMPA_vect) //Durchlaufendes MenĂ¼
{
cnt0++;
//Tastatureingabe_______________________________________________________________
keyboard_read();
if(feld[k]=='A') //Abfrage nach AutoStart
{
lcd.clear(); lcd.setCursor(0,0); lcd.print("AutoStart");
TCCR0B = 0x00; //Timer0 ausschalten
TCCR2B = 0x07; //Timer2 einschalten
}
else if(feld[k]=='E') //Abfrage nach Einstellungen
{
lcd.clear(); lcd.setCursor(0,0); lcd.print("Einstellungen");
TCCR0B = 0x00; //Timer0 ausschalten
//TCCR1B = 0x00; //Timer1 einschalten (not declared yet)
k=0;
}
else if((feld[k]!=NULL)) //Falsche Eingabe Abfrage
{
lcd.clear(); lcd.setCursor(0,0); lcd.print("Falsche Eingabe");
} //other things are not necessary
Code for Timer2:
ISR(TIMER2_COMPA_vect) //Ausgabe der Parameter
{
cnt2++;
loop();
//Tastatureingabe_________________________________________________________
keyboard_read();
if(feld[k]=='B') //Abfrage nach AutoStart
{
lcd.clear(); lcd.setCursor(0,0); lcd.print("Zuruek");
TCCR0B = 0x0D; //Timer0 einschalten
TCCR2B = 0x00; //Timer2 ausschalten
}
else if((feld[k]!=NULL))
{
lcd.clear(); lcd.setCursor(0,0); lcd.print("Falsche Eingabe");
}
Do I have to change something in the keyboard_read() sub program or the Timers to make it work?
Thanks in advance for any help.
You can read long article about interrupts: How do interrupts work on the Arduino Uno and similar boards? on Arduino SE by Nick Gammon
And in short:
Interrupt must be as short as possible. If you need delay, you are doing it wrong and you can handle it in loop later. Just set some flag (or you can use COMPA overflow flag directly without its interrupt, you just have to check this flag and clear it by writing logic 1 into it)
You can't use Arduinos delay as it needs Timer/Counter 0 overflow interrupt running. And all interrupts are blocked in the ISR handler automatically. So you are waiting for changing millis that never happen.
Also you can't use anything else that could relly on another interrupt. For example Serial.write/print works until the send buffer gets filled and then deadlock will appear.
Why are you calling loop()? It'll return back to the interrupted code right after the handler finishes the job.