what is outside loop() ?

Status
Not open for further replies.

mm7

Active member
I am new in arduino programming.
I tried to find but failed what is a role of loop() function.
Obviously I know that it is called "in loop" while the machine (hardware and "OS") is working.
But I want to have some deeper understanding:

1 - is it important always to exit from loop() allowing the machine to cycle?

2 - how long is it safe to stay in loop() ?
Can I create my infinite loop in loop()
Code:
void loop() {
   while (true){
      doSomething();
      delay(100);  
   }
}
Will the machine work well?

3 - Can I create my infinite loop in setup() so the machine never enters loop() ?
Code:
void setup() {
   while (true){
      doSomething();
      delay(100);  
   }
}
void loop() {}


3 - what the machine does after program leaves setup() but not yet entered into loop()?

4 - what the machine does after program leaves loop() before next entering into loop()?

Thanks!
 
There are a few things which are handled outside the loop(), mostly the handling of incoming data at the different serial ports which is done through the "hidden" yield() function.

If you don't need processing incoming serial data, you might do an infinite loop either inside loop(), or inside setup(). Or you might override the core yield() function by your own.

The surrounding C/C++ code structure is basically like this :

void main() {
setup();
while(true) {
loop();
yield();
}
}
 
setup() is just called as shown in post #2 once before ever entering loop() - to allow one time setup to be done without later having to work around it.

The yield() function helps processing incoming data by calling the 'optional' serialEvent() functions, this is a' nicety' added to Arduino. If you never exit loop() the system still runs, but no calls will be made to the serialEvent{} functions from yield().

As Theremingenieur notes the yield() function can be replaced with a local function that can be empty or do whatever in the infinite loop in post #2 that just calls loop() then yield()

You can see the Teensy3 code on your system at I:\arduino-1.8.1\hardware\teensy\avr\cores\teensy3\yield.cpp
Code:
void yield(){ // any or no code here  }

Initially the serialEvent() calls seemed nice - but don't really add much. If unused doing the empty yield() code can take away unneeded overhead for loop() calls.
 
Lots of thanks!

Yes I need to read from Serial1, and may be to write some basic log to Serial. I am working on GPS logger.

Can I call the real yeld() from my infinite loop, or from different places in my program to keep Serials in good state?

Is serialEvent() a callback function? I need something that waits until data appears in Serial1 (from GPS)
then it should read the data and process it. The hardware should sleep when there is no data. I need this to reduce battery consumption.

I believe that there already should be some generic pattern for "a sleepy serial logger". If you know about some, just give me a hint.

Thanks again!
 
Depending on which Teensy you are using, the original yield() would check up to 6 serial ports for the Teensy 3.6. You might call yield() from wherever you want, but if you want already to go around the default yield stuff, you'd perhaps better override it with your own optimized yield(). Or if you check Serial1.available() in your own infinite loop, you might override yield() completely.

yield() is not needed for writing serial stuff out, it's just a mapper to check all serialX.available() and to launch the corresponding callback functions. As defragster pointed you towards the original code above, you should normally understand all that by yourself...
 
Last edited:
I took a look into code. There is function void serialEvent1() {} in file hardware/teensy/avr/cores/teensy3/HardwareSerial1.cpp

It does nothing. To me it means that calling yeld() does nothing for HardwareSerial1.
Is my understanding correct?
 
mm7, I wonder where you learned C/C++... the empty serialEvent1(){} is pretty much like the declaration of a variable. It just has to be there as a default in case you don't define and thus override it elsewhere.

As soon as you write your own void serialEvent1() {} in your .ino file, but outside setup() and loop(), it's this one which will be called instead as soon as data arrives on the corresponding serial port UART0.
 
One of the very nice things or using Arduino, is for the most part you can see all of the sources of the code, that you are using.

No where in your stuff have I noticed if you have said you are using a teensy, but from another thread I believe you are using a T3.5?

If so the sources are installed: where you installed Arduino, in the hardware/teensy/avr/cores/teensy3 directory. If you look there you will see, main.cpp (I have removed the part under ifdef for USING_MAKEFILE
Code:
#include "WProgram.h"

extern "C" int main(void)
{
	// Arduino's main() function just calls setup() and loop()....
	setup();
	while (1) {
		loop();
		yield();
	}
}
So as you can see nothing mysterious. If your setup never returns, no big deal. If your loop does not return again no big deal.

And as mentioned if you look at yield, you will see:
Code:
void yield(void) __attribute__ ((weak));
void yield(void)
{
	static uint8_t running=0;

	if (running) return; // TODO: does this need to be atomic?
	running = 1;
	if (Serial.available()) serialEvent();
	if (Serial1.available()) serialEvent1();
	if (Serial2.available()) serialEvent2();
	if (Serial3.available()) serialEvent3();
#ifdef HAS_KINETISK_UART3
	if (Serial4.available()) serialEvent4();
#endif
#ifdef HAS_KINETISK_UART4
	if (Serial5.available()) serialEvent5();
#endif
#if defined(HAS_KINETISK_UART5) || defined (HAS_KINETISK_LPUART0)
	if (Serial6.available()) serialEvent6();
#endif
	running = 0;
};
The interesting thing here is the attribute of weak. This implies that this version will be used if no other is found.

Also you will see here that for a majority of programs, it is doing stuff that may take up more time than is helpful. That is it is checking all 6 of your possible Serial ports on the T3.5 to see if they have any input available, and if so again call off to some function.
serialEvent() or serialEvent1()... serialEvent6()... depending on which queue. Again each of these names has a default implementation (attribute weak) that does nothing.

So if I have a program that I wish to run as quick as possible I will often provide my own version of yield (which in many cases does nothing).

But unlike most other Arduinos, the yield function is useful as it is called in other places than the main loop. Like when your program is doing a wait operation...

Again I personally don't use the serialEvent objects very often. I typically have specific code that checks to see if there is data available and process it. What I am trying to say is for example if in your code you are wanting to process stuff from Serial1, you don't necessarily have to do this in the SerialEvent1() function.

Your main code can just as easily call Serial1.available() to see if there is data available or it can do it as part of a call to Serial.read()
Example, you could have lines like: while ((int val = Serial.read()) !- -1) { process the input character }
 
That's the default. You can add your own implementation of "serialEvent1()" that does something.

Thank you tni.
I just wanted to make sure I understand it correctly. It is just placeholder for callback.

mm7, I wonder where you learned C/C++... the empty serialEvent1(){} is pretty much like the declaration of a variable. It just has to be there as a default in case you don't define and thus override it elsewhere.
As soon as you write your own void serialEvent1() {} in your .ino file, but outside setup() and loop(), it's this one which will be called instead as soon as data arrives on the corresponding serial port UART0.

Dear Theremingenieur,
A declaration of an external function, or a forward declaration of a function that will be implemented down the road, does not have an execution block { }.
The serialEvent1(){} is neither external, nor forward, nor virtual nor abstract. It is regular function definition that might be overridden. It might, but it is not required to override it.
Kind of virtual in C.
However just before this serialEvent1(){} definition, there is the forward declaration that tells linker that this function should be overridden if another strong one is found.
void serialEvent1() __attribute__((weak));

I have not overridden serialEvent1(), so the default one is being called. And it does nothing.

PS/ empty serialEvent1(){} is no way like the declaration of a variable.

-----------

KurtE thank you! I am getting more understanding.
Yes, I am using Teensy 3.5 now.
 
Last edited:
Status
Not open for further replies.
Back
Top