Come funzionano le funzioni al di fuori del ciclo vuoto?


9

Sono abituato agli schizzi di Arduino con una void setup()parte che viene eseguita una volta e una void loop()parte che continua in loop. Cosa succede quando si hanno funzioni nulle al di fuori della principale void loop()? Continueranno tutti questi cicli in parallelo o correranno uno dopo l'altro? Oppure determinate funzioni vuote vengono eseguite solo dopo aver soddisfatto determinati criteri (come un ciclo while)?

Ad esempio nel codice seguente, quando verranno eseguite void receiveData(int byteCount)le void sendData()funzioni e?

//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.
}

Questo sembra interessante. Mi chiedo se potresti pubblicare link alla fonte del codice (e dettagli sulle connessioni tra Arduino e Pi).
Milliways,

1
@Milliways Ho usato questo * tutorial per scrivere il codice su Arduino Uno e Raspberry Pi (modello B +), tuttavia ho apportato alcune piccole modifiche.Collegare i pin SDA e SCL delle due schede, nonché i pin di massa se sono collegati a diversi alimentatori. Ho quindi avuto il pin 3 collegato a un sensore configurato in una potenziale configurazione del divisore, collegato tra i pin + 5V e Gnd. Pin 0 e Gnd sono collegati a una scheda di azionamento del motore.
Blue7,

Risposte:


11

Le funzioni setup()e loop()sono insolite perché vengono chiamate automaticamente per te dal codice Arduino. Nessun'altra funzione si comporta in questo modo.

In generale, una funzione non verrà mai eseguita a meno che tu non la chiami esplicitamente da te (ad es. Dall'interno setup()o loop()), o indichi a un'altra parte del programma di chiamarla. (Esistono altri modi per eseguire le funzioni, ma ciò di solito comporta alcuni ritocchi molto avanzati che è meglio evitare.)

Ad esempio, pinMode()è una funzione come qualsiasi altra. Funziona solo quando si inserisce qualcosa di simile pinMode(3, INPUT)nel proprio codice. A quel punto, viene eseguito una volta, termina e quindi la funzione di chiamata prosegue da dove era stata interrotta (non funzionano mai in parallelo).

Il codice di esempio che hai pubblicato è piuttosto interessante. Guarda queste righe in setup():

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

Queste linee indicano Wireall'oggetto di chiamare receiveData()e sendData()in risposta agli eventi I2C. Lo fa passando puntatori di funzioni che sono memorizzati e utilizzati da Wire.

Ti consiglio di cercare informazioni sui puntatori a funzioni C / C ++ online se vuoi saperne di più. Potresti anche essere interessato a esplorare la attachInterrupt()funzione di Arduino .


Grazie per la tua risposta. Questo sta iniziando a dare più senso ora. Tuttavia, se le funzioni receiveData()e sendData()non vengono eseguite a meno che non vengano chiamate, perché vengono chiamate all'interno della void setup()funzione e non nella void loop()funzione principale ? Sicuramente queste funzioni non verranno mai chiamate a meno che la rara possibilità che ci sia un evento i2c mentre il puntatore alle istruzioni è ancora all'interno della void setupfunzione? Non sarebbe meglio chiamare queste funzioni all'interno della void loopfunzione, quindi ogni volta che si verifica un evento i2c, la funzione viene chiamata?
Blue7,

4
@ Blue7 Queste funzioni non sono chiamati in void setup(), vengono passati come parametro di onReceivee onRequest, sono i callback come commento Stati. In breve riassunto: questo dice al (codice dalla) libreria Wire di chiamare queste funzioni quando accadono cose specifiche ( arduino.cc/en/Reference/WireOnReceive , arduino.cc/en/Reference/WireOnRequest ...)
FredP

@FredP Ah ok. Grazie per i collegamenti, li controllerò quando non sono sul mio telefono. Nel frattempo ho una domanda veloce, se non ti dispiace. Questi callback sono sempre pronti e in attesa di un evento i2c? cioè, indipendentemente da dove si trovi il puntatore dell'istruzione, questi callback chiameranno immediatamente la funzione non appena si verifica un evento i2c?
Blue7,

1
@ Blue7 Presumibilmente utilizzerà gli interrupt per monitorare l'attività I2C. Quando viene eseguito un interrupt, allontana temporaneamente il controllo dal programma principale.
Peter Bloomfield,

3
@ Blue7 I callback non attendono (Arduino non è multithread), come dice @PeterRBloomfield, la libreria Wire abilita l'interruzione I2C twi_init()quando chiami Wire.begin. Quando c'è attività I2C, µC smette di svolgere il suo compito attuale (a meno che ... non ci pensi per il momento :-) e va nel codice della libreria Wire, che quindi chiama la funzione (appropriata, a seconda di ciò che sta accadendo) che hai registrato come callback ( receiveDataad esempio). Un callback è il nome generico per funzioni come receiveDatao sendData, sono chiamate da un gestore di interrupt all'interno di Wire.
FredP,

2

Non è quel caso che setup()viene chiamato una volta e loop()viene chiamato più volte? cioè che c'è un invisibile main() che potrebbe assomigliare a questo:

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

Mi scuso perché sto solo esaminando Arduino e non ho quasi nessuna esperienza C / C ++; Sto cercando di capire da solo questa loop()situazione.


Fondamentalmente sì. C'è anche una chiamata a init()cui vanno i timer millis, delayecc. Così init()è per l'inizializzazione generale, setup()è per la tua inizializzazione, e loopper, beh, il looping. Puoi scrivere il tuo mainse vuoi avere il pieno controllo.
Nick Gammon

Bel post. BTW ;non è richiesto dopo il penultimo }:-)
Greenonline

C'è anche il richiamo di serial_event () non è vero?
Divisadero,

2

Non posso commentare la risposta di Dee. Il codice effettivo che viene eseguito nel ciclo principale è qui :

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

    setup();

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

E sì, setup()viene chiamato una volta e loop()viene chiamato ripetutamente (insieme ad alcune cose seriali).


0

Funziona come una normale funzione, deve essere chiamato per avere un senso. loop () / setup () sono chiamati da una funzione main () che è compilata dalla directory di Arduino e collegata in.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.