how to stop a loop arduino - c

I have this loop, how would I end the loop?
void loop() {
// read the pushbutton input pin:
a ++;
Serial.println(a);
analogWrite(speakerOut, NULL);
if(a > 50 && a < 300){
analogWrite(speakerOut, 200);
}
if(a <= 49){
analogWrite(speakerOut, NULL);
}
if(a >= 300 && a <= 2499){
analogWrite(speakerOut, NULL);
}

This isn't published on Arduino.cc but you can in fact exit from the loop routine with a simple exit(0);
This will compile on pretty much any board you have in your board list. I'm using IDE 1.0.6. I've tested it with Uno, Mega, Micro Pro and even the Adafruit Trinket
void loop() {
// All of your code here
/* Note you should clean up any of your I/O here as on exit,
all 'ON'outputs remain HIGH */
// Exit the loop
exit(0); //The 0 is required to prevent compile error.
}
I use this in projects where I wire in a button to the reset pin. Basically your loop runs until exit(0); and then just persists in the last state. I've made some robots for my kids, and each time the press a button (reset) the code starts from the start of the loop() function.

Arduino specifically provides absolutely no way to exit their loop function, as exhibited by the code that actually runs it:
setup();
for (;;) {
loop();
if (serialEventRun) serialEventRun();
}
Besides, on a microcontroller there isn't anything to exit to in the first place.
The closest you can do is to just halt the processor. That will stop processing until it's reset.

Matti Virkkunen said it right, there's no "decent" way of stopping the loop. Nonetheless, by looking at your code and making several assumptions, I imagine you're trying to output a signal with a given frequency, but you want to be able to stop it.
If that's the case, there are several solutions:
If you want to generate the signal with the input of a button you could do the following
int speakerOut = A0;
int buttonPin = 13;
void setup() {
pinMode(speakerOut, OUTPUT);
pinMode(buttonPin, INPUT_PULLUP);
}
int a = 0;
void loop() {
if(digitalRead(buttonPin) == LOW) {
a ++;
Serial.println(a);
analogWrite(speakerOut, NULL);
if(a > 50 && a < 300) {
analogWrite(speakerOut, 200);
}
if(a <= 49) {
analogWrite(speakerOut, NULL);
}
if(a >= 300 && a <= 2499) {
analogWrite(speakerOut, NULL);
}
}
}
In this case we're using a button pin as an INPUT_PULLUP. You can read the Arduino reference for more information about this topic, but in a nutshell this configuration sets an internal pullup resistor, this way you can just have your button connected to ground, with no need of external resistors.
Note: This will invert the levels of the button, LOW will be pressed and HIGH will be released.
The other option would be using one of the built-ins hardware timers to get a function called periodically with interruptions. I won't go in depth be here's a great description of what it is and how to use it.

The three options that come to mind:
1st) End void loop() with while(1)... or equally as good... while(true)
void loop(){
//the code you want to run once here,
//e.g., If (blah == blah)...etc.
while(1) //last line of main loop
}
This option runs your code once and then kicks the Ard into
an endless "invisible" loop. Perhaps not the nicest way to
go, but as far as outside appearances, it gets the job done.
The Ard will continue to draw current while it spins itself in
an endless circle... perhaps one could set up a sort of timer
function that puts the Ard to sleep after so many seconds,
minutes, etc., of looping... just a thought... there are certainly
various sleep libraries out there... see
e.g., Monk, Programming Arduino: Next Steps, pgs., 85-100
for further discussion of such.
2nd) Create a "stop main loop" function with a conditional control
structure that makes its initial test fail on a second pass.
This often requires declaring a global variable and having the
"stop main loop" function toggle the value of the variable
upon termination. E.g.,
boolean stop_it = false; //global variable
void setup(){
Serial.begin(9600);
//blah...
}
boolean stop_main_loop(){ //fancy stop main loop function
if(stop_it == false){ //which it will be the first time through
Serial.println("This should print once.");
//then do some more blah....you can locate all the
// code you want to run once here....eventually end by
//toggling the "stop_it" variable ...
}
stop_it = true; //...like this
return stop_it; //then send this newly updated "stop_it" value
// outside the function
}
void loop{
stop_it = stop_main_loop(); //and finally catch that updated
//value and store it in the global stop_it
//variable, effectively
//halting the loop ...
}
Granted, this might not be especially pretty, but it also works.
It kicks the Ard into another endless "invisible" loop, but this
time it's a case of repeatedly checking the if(stop_it == false) condition in stop_main_loop()
which of course fails to pass every time after the first time through.
3rd) One could once again use a global variable but use a simple if (test == blah){} structure instead of a fancy "stop main loop" function.
boolean start = true; //global variable
void setup(){
Serial.begin(9600);
}
void loop(){
if(start == true){ //which it will be the first time through
Serial.println("This should print once.");
//the code you want to run once here,
//e.g., more If (blah == blah)...etc.
}
start = false; //toggle value of global "start" variable
//Next time around, the if test is sure to fail.
}
There are certainly other ways to "stop" that pesky endless main loop
but these three as well as those already mentioned should get you started.

This will turn off interrupts and put the CPU into (permanent until reset/power toggled) sleep:
cli();
sleep_enable();
sleep_cpu();
See also http://arduino.land/FAQ/content/7/47/en/how-to-stop-an-arduino-sketch.html, for more details.

just use this line to exit function:
return;

Related

FreeRTOS: xEventGroupWaitBits() crashes inside a loop with scheduler running

We have several tasks running on an STM32 MCU. In the main.c file we call all the init functions for the various threads. Currently there is one renewing xTimer to trigger a periodic callback (which, at present, does nothing except print a message that it was called). Declarations as follows, outside any function:
TimerHandle_t xMotorTimer;
StaticTimer_t xMotorTimerBuffer;
EventGroupHandle_t MotorEventGroupHandle;
In the init function for the thread:
xMotorTimer = xTimerCreateStatic("MotorTimer",
xTimerPeriod,
uxAutoReload,
( void * ) 0,
MotorTimerCallback,
&xMotorTimerBuffer);
xTimerStart(xMotorTimer, 100);
One thread starts an infinite loop that pauses on an xEventGroupWaitBits() to determine whether to enter an inner loop, which is then governed by its own state:
DeclareTask(MotorThread)
{
bool done = false;
EventBits_t event;
for (;;)
{
Packet * pkt = NULL;
event = xEventGroupWaitBits( MotorEventGroupHandle,
EVT_MOTOR_START | EVT_MOTOR_STOP, // EventBits_t uxBitsToWaitFor
pdTRUE, // BaseType_t xClearOnExit
pdFALSE, // BaseType_t xWaitForAllBits,
portMAX_DELAY //TickType_t xTicksToWait
);
if (event & EVT_MOTOR_STOP)
{
MotorStop(true);
}
if (event & EVT_MOTOR_START)
{
EnableMotor(MOTOR_ALL);
done = false;
while (!done && !abortTest)
{
xQueueReceive(motorQueue, &pkt, portMAX_DELAY);
if (pkt == NULL)
{
done = true;
} else {
done = MotorExecCmd(pkt);
done = ( uxQueueMessagesWaiting(motorQueue) == ( UBaseType_t ) 0);
FreePacket(pkt);
}
}
}
}
}
xEventGroupWaitBits() fires successfully once, the inner loop enters, then exits when the program state meets the expected conditions. The outer loop repeats as it should, but when it arrives again at the xEventGroupWaitBits() call, it crashes almost instantly. In fact, it crashes a few lines down into the wait function, at a call to uxTaskResetEventItemValue(). I can't even step the debugger into the function, as if calling a bad address. But if I check the disassembly, the memory address for the BL instruction hasn't changed since the previous loop, and that address is valid. The expected function is actually there.
I can prevent this chain of events happening altogether by not calling that xTimerStart() and leaving everything else as-is. Everything runs just fine, so it's definitely not xEventGroupWaitBits() (or at least not just that). We tried switching to xEventGroupGetBits() and adding a short osDelay to the loop just as an experiment. That also froze the whole system.
So, main question. Are we doing something FreeRTOS is not meant to do here, using xEventGroupWaitBits() with xTimers running? Or is there supposed to be something between xEventGroupWaitBits() calls, possibly some kind of state reset that we've overlooked? Reviewing the docs, I can't see it, but I could have missed a detail. The

Looking for good algorithm to run specific code on given time. (Arduino C program)

I'm writing a timer/scheduler simple program for Arduino.
It's a c program, with 'main' loop that is running again and again.
Arduino has DS3231 RTC module connected to it and provides the current day-of-week, hour, minute, second, etc.
What I need to achieve is sending a specific string over the serial port, but in contrast to many examples about 'lighting a LED at a specific time' - I can't allow the code to run more than once.
So, if a normal 'light a LED on a specific time' just loops again and again the 'if' check and according to it sets the digital output 'HIGH' or 'LOW' (again and again) - I can't use this approach.
The approach I'm using now, and it works, is like this:
I made an array with the wanted times, and 'action code' for each time - all of them are Integers, like this:
const int A = 6; // Action Array Size
int ActionTimes[A][4] = {
{6,18,37,1},
{6,18,38,2},
{5,15,20,11},
{5,16,35,51},
{5,16,40,52},
{5,23,55,15}
};
Then, from the main loop I call a "Check" function that runs a 'for' loop to check if there is an action that should be run in this current time:
int i;
for ( i = 0; i < A; i++ ) {
if ((dt.DayOfWeek()==ActionTimes[i][0]) && (dt.Hour()==ActionTimes[i][1]) && (dt.Minute()==ActionTimes[i][2]) && (dt.Second() < 2)) {
RunMyAction(ActionTimes[i][3]);
}
And then - I have the 'action' function that runs the actual needed code, like this:
void RunMyAction(const int& MyActionCode)
{
switch(MyActionCode) {
case 1:
digitalWrite(2, LOW); // Turn the LED on by making the voltage LOW
Serial.println("S041ONE");
break;
case 2:
digitalWrite(2, HIGH); // Turn the LED off by making the voltage HIGH
Serial.println("S017ONE");
break;
case 11: //Before Knissat Shabat - Full status update.
Serial.println("S01D00000D00ES02D01001100ES03D00101101ES04D1100D0DDES05D10011DDDE");
delay(1000);
break;
case 15: //Last GoodNight Shabat - Full status update.
Serial.println("S01D00000000ES02D00000000ES03D00000100ES04D1000D00DES05D00011DDDE");
delay(1500);
break;
case 51:
Serial.println("S036OFE");
delay(1500);
break;
case 52:
Serial.println("S047OFES036ONE");
delay(1500);
break;
}
}
That works for me and 'do the job' but I feel (algorithmically speaking) maybe it's not the best way to write it.
For example - all the actions and the needed times are hard-coded into the program itself. For any added action - I have to manually change the const of the array size, manually change the array definition, and add additional code to the switch function.
(Thought about excel-made #include files to merge into the array part and the switch function, but this also has to re-compile the program for every time/action change).
Would appreciate any insight about how to look at it for more professional, effective, way.
Many thanks!
To avoid executing the same action twice in a row, I'd add a global variable to hold the index into ActionTImes[] of the most recently executed action, then test that variable in the if statement.
int latestActionIndex = -1; // -1 so on startup we don't think we've executed ActionTimes[0].
then in the For loop:
if ((dt.DayOfWeek()==ActionTimes[i][0])
&& (dt.Hour()==ActionTimes[i][1])
&& (dt.Minute()==ActionTimes[i][2]
&& latestActionIndex != i)) {
latestActionIndex = i; // note that we've run this action
RunMyAction(ActionTimes[i][3]);
}
I removed the (dt.Second() < 2) from the if statement, because the action will likely execute within a second or so of dt.second() == 0, and the new variable keeps RunMyAction() from being executed more than once.

Switching between modes with an interrupt

I have two modes that I want to switch between with an interrupt that is generated by a sliding switch. Initially I read the current position and choose a mode/function. I want to switch between the two right when the position of the switch is changed. I have an interrupt which occurs on both edges (whenever the position is changed). However since both functions run continuously in a while loop, I can't just call them in the interrupt. Basically I have something like this:
interrupt()
{
//not sure how to switch between modes here
}
main()
{
//choose mode on startup
if (switch_HIGH)
modeA();
else
modeB();
}
modeA()
{
while(1)
{
//do something
}
}
modeB()
{
while(1)
{
//do something
}
}
I don't know if it's a good idea to just leave a function where it is and just move to something else but I can't think of any other way to do it. I'd really appreciate it if someone could tell me how I can go about this.
The language I'm using is C and the platform is a NIOS system on a Altera DE1 development board.
Using an interrupt for this seems very pointless; it's much simpler to just poll the input on each loop, and call the proper function just as you're doing.
UPDATE: I just relized your code doesn't have a loop, so the above is a bit hard to understand, of course.
I meant that you can structure your program like this:
int main(void)
{
initialize_hardware();
while(1)
{
if(switch_HIGH)
modeA();
else
modeB();
}
}
This makes the CPU go around in an infinite loop, and on each iteration it checks the switch and calls either modeA() or modeB() depending on the current mode.
Adding an interrupt gains you nothing except adding more complexity.
That said, what I would do is use a function pointer to indicate the current mode, and change the function pointer's value inside the interrupt, depending on the state of the switch. Then in the main loop just call the pointed-at function.
Remember to initialize the function properly, since you probably won't get an interrupt when teh device comes out of reset. This is another argument against this solution; the complexity is much bigger than just checking the switch on each iteration.
How about calling the two functions as threads. The interrupt function can kill the active thread and start the other thread. Pseudo code:
thread threada,threadb;
flag a=0;
interrupt()
{
if(a==0)
{
thread_kill(threada);
threadb=thread_create(modeB);
a=1;
}
else
{
thread_kill(threadb);
threada=thread_create(modeA);
a=0;
}
}
main()
{
thread_create(threada);
a=1;
}
modeA()
{
while(1)
{
//do something
}
}
modeB()
{
while(1)
{
//do something
}
}
Rather than killing the thread, you can have graceful shutdown mechanism using some kind of synchronization.

Serial.print only once Arduino

I have a light sensor that prints the value of its input to the Serial monitor. It's pretty much a trip wire but when an object is in its way, it prints the value every 1 millisecond. If I add a delay it won;t trigger the second sensor until the delay is done. How would I get it to only print once, without any disturbance or interference with the other sensors?
void loop() {
if (analogRead(sensor1) == 0) {
timer.start ();
tStop = false;
//Serial.println (timer.elapsed());
Serial.println ("Start Time = 0");
}
This is quite an interesting problem, in the normal world of computers we would solve this via threading. However as you are running without an OS we have to do one of two things, implement coroutines (fake threading without an OS) or use asynchronous code and interrupts.
My understanding is that you print something when an object first comes into the way of your sensor, as the arduino uno as opposed to the due is not easy to implement coroutines on we shall try the interrupt route.
First you will likely be interested in this library http://playground.arduino.cc/Code/Timer1
It allows you to add an interrupt service routine to run on a timer. Use the attachInterrupt(function, period) function in the library for this.
In your interrupt service routine you will want to check the sensor, set a variable to say how long ago since it was last triggered and print the message if appropriate. This means your main loop is completely free to run other code and will not block your other sensors.
For example:
void TimFun()
{
static int LastRead;
if(LastRead && (0 == analogRead(sensor1))
{
Serial.println("SensorTrip");
}
LastRead = analogRead(sensor1);
}
void loop()
{
// Do other stuff here
}
void setup()
{
Timer1.initialize(100000);
Timer1.attachInterrupt(TimFun);
// Rest of setup Here
}
I managed to make an int before the void setup and then used a while loop. with in the if statement.
int i = 1;
if (analogRead(sensor1) == 0) {
timer.start ();
tStop = false;
while (i == 1) {
Serial.println ("Start Time = 0");
i++;
}
}
You probably should use an if instead of a while loop that will never execute more than once.
bool tripped = false;
void setup(){
//setup stuff here
}
void loop() {
if ( analogRead(sensor1) == 0 )
{
timer.start ();
tStop = false;
if ( tripped == false )
{
Serial.println ("Start Time = 0");
tripped = true;
}
}
}

How to set an int to 1 if dependent on a button and in a while loop?

I'm programming a robot, and unfortunately in its autonomous mode I'm having some issues.
I need to set an integer to 1 when a button is pressed, but in order for the program to recognize the button, it must be in a while loop. As you can imagine, the program ends up in an infinite loop and the integer values end up somewhere near 4,000.
task autonomous()
{
while(true)
{
if(SensorValue[positionSelectButton] == 1)
{
positionSelect = positionSelect + 1;
wait1Msec(0350);
}
}
}
I've managed to get the value by using a wait, but I do NOT want to do this. Is there any other way I can approach this?
assuming that the SensorValue comes from a physical component that is asynchronous to the while loop, and is a push button (i.e. not a toggle button)
task autonomous()
{
while(true)
{
// check whether
if(current_time >= next_detect_time && SensorValue[positionSelectButton] == 1)
{
positionSelect = positionSelect + 1;
// no waiting here
next_detect_time = current_time + 0350;
}
// carry on to other tasks
if(enemy_is_near)
{
fight();
}
// current_time
current_time = built_in_now()
}
}
Get the current time either by some built-in function or incrementing an integer and wrap around once reach max value.
Or if you are in another situation:
task autonomous()
{
while(true)
{
// check whether the flag allows incrementing
if(should_detect && SensorValue[positionSelectButton] == 1)
{
positionSelect = positionSelect + 1;
// no waiting here
should_detect = false;
}
// carry on to other tasks
if(enemy_is_near)
{
if(fight() == LOSING)
should_detect = true;
}
}
}
Try remembering the current position of the button, and only take action when its state changes from off to on.
Depending on the hardware, you might also get a signal as though it flipped back and forth several times in a millisecond. If that's an issue, you might want to also store the timestamp of the last time the button was activated, and then ignore repeat events during a short window after that.
You could connect the button to an interrupt and then make the necessary change in the interrupt handler.
This might not be the best approach, but it will be the simplest.
From The Vex Robotics catalogue :
(12) Fast digital I/O ports which can be used as interrupts
So, most probably which ever micro-controller of Vex you are using will support Interrupts.
Your question is a bit vague
I m not sure why u need this variable to increment and how things exactly work...but i ll make a try.Explain a bit more how things work for the robot to move...and we will be able to help more.
task autonomous()
{
int buttonPressed=0;
while(true)
{
if(SensorValue[positionSelectButton] == 1)
{
positionSelect = positionSelect +1;
buttonPressed=1;
}
else{
buttonPressed = 0;
}
//use your variables here
if( buttonPressed == 1){
//Move robot front a little
}
}
}
The general idea is :
First you detect all buttons pressed and then you do things according to them
All these go in your while loop...that will(and should) run forever(at least as long as your robot is alive :) )
Hope this helps!

Resources