9

I am used to Arduino sketches with a void setup() part that runs once, and a void loop() part that keeps looping. What happens when you have void functions outside of the main void loop()? Will these all keep looping in parallel or do they run one after the other? Or do certain void functions only run once certain criteria has been met (like a while loop)?

For example in the code below, when will the void receiveData(int byteCount) and the void sendData() functions run?

//I2C_test

//This code demonstrates communication via an I2C bus between a raspberry pi and an arduino.
//When the Raspberry pi (master) sends data to the Arduino (slave), the Arduino uses this
//data to control a motor. After the Arduino has recieved data from the master, it then collects
//data from the external environment via a sensor and sends this data back to the Raspberry pi.

#include <Wire.h>
int number = 0; //Declare variables
int val = 0;

void setup() {
  //Anything between the curly brackets runs once when the arduino is turned on or reset
  pinMode(0, INPUT);
  //Set pin 0 as input and 3 as output
  pinMode(3, OUTPUT);
  Serial.begin(9600);
  //Set the data rate for serial transmission at 9600bps
  Wire.begin(0x04);
  //Initiate the Wire library, join the Arduino as a slave, and specify its 7 bit slave address
  Wire.onReceive(receiveData);
  //Define callbacks for i2c communication
  Wire.onRequest(sendData);
}

void loop() {
  //The code between the curly brackets keeps repeating
  delay(100);
}

void receiveData(int byteCount) {
  while(Wire.available()) {
    number = Wire.read();
    //Set the variable "number" to the data sent by the master
    analogWrite(3, number);
    //Write this number to pin 3 (PWM). This controls the motor speed
  }
  val = analogRead(0);
  //Read the voltage on pin 0 (connected to the sensor). Map input voltages between 0 and 5 volts into integer values between 0 and 1023
}

void sendData() {
  Wire.write(val);
  //Send the data read from the sensor to the master.
}
2
  • This looks interesting. I wonder if you could post links to the source of the code (and details of connections between Arduino and Pi).
    – Milliways
    Oct 22, 2014 at 23:25
  • 1
    @Milliways I used this* tutorial to write the code on the arduino uno and Raspberry pi (B+ model), however I made a few small changes.Connect the SDA and SCL pins of the two boards, as well as the ground pins if they are connected to different power supplies. I then had pin 3 connected to a sensor configured in a potential divider configuration, connected between the +5V and Gnd pins. Pin 0 and Gnd is connected to a motor drive board.
    – Blue7
    Oct 23, 2014 at 11:20

4 Answers 4

11

The setup() and loop() functions are unusual because they are called automatically for you by the Arduino code. No other functions behave this way.

Generally speaking, a function will never run unless you explicitly call it yourself (e.g. from within setup() or loop()), or instruct another part of the program to call it. (There are other ways to execute functions, but that usually involves some very advanced tinkering which is best avoided.)

For example, pinMode() is a function just like any other. It only runs when you actually put something like pinMode(3, INPUT) in your code. At that point, it runs once, finishes, and then the calling function carries on from where it left off (they never run in parallel).

The example code you've posted is quite interesting. Look at these lines in setup():

Wire.onReceive(receiveData);
Wire.onRequest(sendData);

These lines are telling the Wire object to call receiveData() and sendData() in response to I2C events. It does this by passing function pointers which are stored and used by Wire.

I'd recommend searching for information about C/C++ function pointers online if you want to learn more about this. You may also be interested to explore Arduino's attachInterrupt() function.

5
  • Thanks for your answer. This is starting to make more sense now. However, if the receiveData() and sendData() functions are not run unless they are called, then why are they called within the void setup() function and not the main void loop() function? Surely these functions will never be called unless the rare chance that there is an i2c event while the instruction pointer is still within the void setup function? Would it not be better to call these functions from within the void loop function so whenever there is an i2c event, the function is called?
    – Blue7
    Oct 22, 2014 at 12:59
  • 4
    @Blue7 These functions are not called in void setup(), they are passed as the parameter of onReceive and onRequest, they're callbacks as the comment states. In very short summary : this tells the (code from the) Wire library to call these functions when specific things happen (arduino.cc/en/Reference/WireOnReceive, arduino.cc/en/Reference/WireOnRequest ...)
    – FredP
    Oct 22, 2014 at 13:16
  • @FredP Ah okay. Thanks for the links, I'll check them out when I'm not on my phone. I have a quick question in the meantime though, if you don't mind. Are these callbacks always ready and waiting for an i2c event? i.e, no matter where the instruction pointer is, these callbacks will instantly call the function as soon as an i2c event happens?
    – Blue7
    Oct 22, 2014 at 13:51
  • 1
    @Blue7 It will presumably be using interrupts to monitor I2C activity. When an interrupt executes, it takes control away from the main program temporarily. Oct 22, 2014 at 13:55
  • 3
    @Blue7 The callbacks are not waiting (Arduino is not multithreaded), as @PeterRBloomfield says, the Wire library enables I2C interrupt through twi_init() when you call Wire.begin. When there is I2C activity the µC stops doing its current task (unless ... nevermind for the moment :-) and goes in the code of Wire library, that then calls the (appropriate, depending on what is happening) function you registered as callback (receiveData for example). A callback is the generic name for functions like receiveData or sendData, they're called by an interrupt handler inside Wire.
    – FredP
    Oct 22, 2014 at 14:21
3

Is it not that case that setup() is called once and loop() is called repeatedly? i.e. that there is an unseen main() which might look like this:

void main(){
  setup();
  while(True){
    loop();
  }
}

Apologies as I'm just looking into the Arduino and have almost no C/C++ experience; I'm trying to get a handle on this loop() situation myself.

3
  • Basically, yes. There is also a call to init() which gets the timers going for millis, delay etc. So init() is for general initialization, setup() is for your initialization, and loop is for, well, looping. You can write your own main if you want to take full control.
    – Nick Gammon
    Sep 8, 2015 at 4:09
  • Nice post. BTW ; is not required after the penultimate } :-) Sep 16, 2015 at 22:07
  • There is also call of serial_event() is it not?
    – Divisadero
    Jan 4, 2017 at 13:34
3

I can't comment on Dee's response. The actual code that is executed in the main loop is here:

    int main(void) {
    init();
    initVariant();

    setup();

    for (;;) {
        loop();
        if (serialEventRun) serialEventRun();
    }   
    return 0;
}

And yes, setup() gets called once and loop() is being called repeatedly (together with some serial stuff).

1

It works as normal function, it must be called to make sense. loop()/setup() are called from a main() function which is compiled from Arduino directory and linked in. receiveData/sendData are to called from your program which root is in loop/setup functions.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.