How to break the loop in an Arduino? - c++

I'm trying to write a simple program in Arduino, blinking of a LED.
Program is as shown below.
#define red1 13
#define amber1 12
#define green1 11
void setup() {
// put your setup code here, to run once:
Serial.begin(9600);
pinMode(red1, OUTPUT);
pinMode(amber1, OUTPUT);
pinMode(green1, OUTPUT);
}
void Delay(int sec) {
for(int i=0;i<sec;i++){
if (Serial.available())
{
Button();
break;
}
delay(1);
}
}
void Light()
{
digitalWrite(red1,HIGH);
Delay(5000);
digitalWrite(red1,LOW);
digitalWrite(amber1,HIGH);
Delay(5000);
digitalWrite(amber1,LOW);
}
void Button()
{
digitalWrite(red1,LOW);
digitalWrite(amber1,LOW);
digitalWrite(green1,HIGH);
delay(1000);
digitalWrite(green1,LOW);
}
void loop()
{
Light();
}
When ever I enter a value in serial monitor Button() function is executed, it should end as soon as function completes due to a break, but this function keeps repeating continuously? How can I fix this such that whenever a serial monitor is interrupted, Button() is executed onetime and then continues with Light().

Try to replace
break;
with
return;
This will terminate the function instantly since you won't be executing other statements after the loop.
You can look at https://www.arduino.cc/reference/en/language/structure/control-structure/return/ for more info about return

As some others have briefly alluded to, you call Button many times due to the fact that you don't clear the serial interface.
Right now what happens is Delay is called, and let's say there's information available on the interface, then you call Button and break as expected, but since you don't clear the interface by reading the available information, you call Button again on the next call to Delay.
To fix this, you need to read the information from the serial interface either in the Button function or in the if statement before calling Button.

Related

Arduino, code hangs in weird way when a function is invoked

I have the following code behaving in a weird way, when I make a method call
#include <TimerOne.h>
#include <cppQueue.h>
#include <Arduino.h>
typedef struct Diagnostic {
String entityName;
uint16_t pin;
} Diag;
// Global setup
cppQueue q(sizeof(Diag *), 10, FIFO, false);
int ctr = 0;
void setup() {
// initialize digital pin LED_BUILTIN as an output.
pinMode(LED_BUILTIN, OUTPUT);
Serial.begin(9600);
}
// Add to queue
// the loop function runs over and over again forever
void loop() {
digitalWrite(LED_BUILTIN, HIGH); // turn the LED on (HIGH is the voltage level)
delay(2000); // wait for a second
Serial.println("After high");
digitalWrite(LED_BUILTIN, LOW); // turn the LED off by making the voltage LOW
delay(1000); // wait for a second
// Critical Section
Diag d;
Serial.println("String assignment");
d.entityName = "Front Door";
d.pin = LED_BUILTIN;
d_ptr = &d;
Serial.println("Enqueuing one");
q.push(&d);
Serial.println("Enqueued one");
Serial.println(freeMemory());
//q.pop(&d);
//Serial.println("Dequeued one" + d.entityName);
DequeueIsr();
//Serial.println("Atomic block");
//Serial.println(q.getCount());
//Serial.println("Loop end");
}
void DequeueIsr() {
Diag di;
if (!q.isEmpty())
{
Serial.println("Queue not empty");
q.pop(&di);
Serial.println("Dequeued one" + di.entityName);
Serial.println(freeMemory());
}
}
Whenever I try to pop my object in the DequeueIsr function, the code hangs after 2 or 3 iterations, there is no output on the serial monitor after that. If I just copy the code in the Dequeue method and run it in the main loop it works, it doesn't get stuck. Also this happens when I work with strings, if I remove the entityName field from Diag, it works inside the method.
Am I missing something crucial ?
What I really wanted to do was, dequeue the queue using an interrupt method using the TimerOne library. I have removed all timer related code and even a simple method call isn't working.
It looks like cppQueue copies objects using memcpy so it only works with trivially copyable objects, String is not trivially copyable so your code has undefined behaviour

SAMD21 doesn't wake up after deep sleep

I'am working on a personnal board build with an atsamd21e18a. I'am actually working on sleep mode. I make a function to put samd21 in sleep mode like that. I use RTCZero library.
So in my setup function I've something like this
RTCZero rtc;
void setup(){
// Set the XOSC32K to run in standby
SYSCTRL->XOSC32K.bit.RUNSTDBY = 1;
rtc.begin();
.... other line code ....
attachInterrupt(digitalPinToInterrupt(PIN_USER_BUTTON), wakeUpButtonUser, CHANGE);
...other line....
}
So in my setup I intialise rtc and I attach an interrupt in my user button. This button is used to power on or power off my board.
My function goTosleep() :
SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;
__DSB();
__WFI();
In my function wakeUpButtonUser I have a simple if/else statement. If the user pressed the button more than 3 seconds samd21 go to sleep with goToSleep() function, else if it's less than 3 seconds I want wake up the board and light up my led but it's doesn't work.
Here my wakeUpButtonUser function, user_button is object create from C++ for my button.
void wakeUpButtonUser(){
if (userButton.isPressed())
{
userButton.setTimeStartPressed(millis());
PRINT_DEBUG_LN("Pressed");
}
else
{
userButton.setTimeEndPressed(millis());
PRINT_DEBUG_LN("Released");
uint32_t time_pressed = userButton.getTimePressed();
if (time_pressed >= temps_on && time_pressed < temps_off)
{
PRINT_DEBUG_LN("ON");
//here I have code to light up a led
}
else
{
PRINT_DEBUG_LN("STOP");
goSleepMode();
}
}
}
This fuction works because if I comment the line goToSleep(), I can read on my serial ON or OFF depending the time I pressed my button and the led works also because I can light up led before going to sleep. But when my board go to sleep, she's never wake up I don't understand why, I missed something?

Why doesn't my arduino button work on ports other than 0 and 1?

I have a button that turns on a LED but it only works when I assign the button the port 0 and 1. If I try port 2 it doesn't work. Therefore I am only able to use two buttons. On the board 0 and 1 seems to be special compared to the other ones. How do I get around that to be able to use the other ports?
Here is a simple program that models what I think you were describing.
In your code, if you want to turn on an LED when you press a button:
You need to make sure that the LED pin is set to output.
The button pin needs to be set to input.
sample program:
#define LED 13
#define BUTTON 5
void setup()
{
pinMode(LED, OUTPUT);
pinMode(BUTTON, INPUT);
}
void loop()
{
if ( digitalRead(BUTTON) )
{
digitalWrite(LED, HIGH);
}
else
{
digitalWrite(LED, LOW);
}
}
Regarding the circuit,
you need to have a current limiting resistor in series with the LED.
make sure the LED is facing the right way.
The button needs to be connected from +5V to the button pin.
You need to have a pulldown resistor between the button pin and ground.

Empty while loop without which the code doesn't work

I ran into some code for a sumo robot. I don't understand why while(BTN) is used in the code. What is the use of the while loop?
Without the first while(BTN) the code doesn't work, without the second one the robot doesn't stop. All relevant code is listed below.
#include <Wire.h>
void setup() {
//Button
pinMode(A2, INPUT);
digitalWrite(A2, HIGH);
#define BTN !digitalRead(A2)
void loop() {
Forward(0, 0); //Stop motors
delay(100);
if (BTN) { //Turn on program with button
while (BTN) {}
while (!BTN) { //stop robot if button is pushed again
//code to move the robot was included here
}
while(BTN){}
}
}
Consider the code after BTN has been expanded:
if (!digitalRead(A2)) {
while (!digitalRead(A2)) {}
while (digitalRead(A2)) {
// move code
}
while (!digitalRead(A2)) {}
}
So it’s saying:
if the button is down;
wait until it is no longer down;
then do movement code until the button is down again
and wait until it’s no longer down.
(Note This code doesn’t consider switch bounce at all, it’s likely to behave somewhat erratically.)

How to clear the bytes of Serial interface in an Arduino?

I'm trying to interrupt the serial monitor to execute a certain function and continue with the previous function after completion of the interrupted function, my code is as bellow
#define red1 13
#define amber1 12
#define green1 11
void setup() {
// put your setup code here, to run once:
Serial.begin(9600);
pinMode(red1, OUTPUT);
pinMode(amber1, OUTPUT);
pinMode(green1, OUTPUT);
}
void Delay(int sec) {
for(int i=0;i<sec;i++){
if (Serial.available())
{
Button();
break;
}
delay(1);
}
}
void Light()
{
digitalWrite(red1,HIGH);
Delay(5000);
digitalWrite(red1,LOW);
digitalWrite(amber1,HIGH);
Delay(5000);
digitalWrite(amber1,LOW);
}
void Button()
{
digitalWrite(red1,LOW);
digitalWrite(amber1,LOW);
digitalWrite(green1,HIGH);
delay(1000);
digitalWrite(green1,LOW);
}
void loop()
{
Light();
}
Whenever I enter a value in serial monitor Button() function is executed, it should end as soon as function completes due to a break, but this function keeps repeating continuously? How can I fix this such that whenever a serial monitor is interrupted, Button() is executed onetime and then continues with Light().
I tried using a break but the serial interface buffer is not cleared so its keep continuing this function also it exits if loop, so I tried using return
void Delay(int sec) {
for(int i=0;i<sec;i++){
if (Serial.available())
{
Button();
return;
}
delay(1);
}
}
the same thing happens
the function doesn't exit it keeps repeating the same since the serial interface is not cleared from an earlier encounter, I could've used serial.available in void loop() but whenever Arduino is at delay function its sleeping so it doesn't read a serial interrupter, so I created separate Delay()
so how can I change the code to end this function and go back to Light()
but the serial interface buffer is not cleared
Then you have to clear it:
while (Serial.available())
Serial.read(); // remove 1 character