Como funcionam as funções fora do loop vazio?

9

Estou acostumado a esboços do Arduino com uma void setup()peça que é executada uma vez e outra void loop()que fica em loop. O que acontece quando você tem funções nulas fora da principal void loop()? Todos eles continuarão em loop paralelo ou serão executados um após o outro? Ou certas funções nulas só são executadas quando certos critérios são atendidos (como um loop while)?

Por exemplo, no código abaixo, quando void receiveData(int byteCount)as void sendData()funções e serão executadas?

//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.
}
Blue7
fonte
Isso parece interessante. Gostaria de saber se você poderia postar links para a fonte do código (e detalhes das conexões entre Arduino e Pi).
Milliways
11
@Milliways Eu usei este tutorial * para escrever o código no arduino uno e no Raspberry pi (modelo B +), no entanto, fiz algumas pequenas alterações. estão conectados a diferentes fontes de alimentação. Eu tinha o pino 3 conectado a um sensor configurado em uma configuração de divisor em potencial, conectada entre os pinos + 5V e Gnd. Os pinos 0 e Gnd estão conectados a uma placa de acionamento do motor.
Blue7

Respostas:

11

As funções setup()e loop()são incomuns porque são chamadas automaticamente para você pelo código do Arduino. Nenhuma outra função se comporta dessa maneira.

De um modo geral, uma função nunca será executada, a menos que você a chame explicitamente (por exemplo, de dentro setup()ou loop()), ou instrua outra parte do programa a chamá-la. (Existem outras maneiras de executar funções, mas isso geralmente envolve alguns ajustes muito avançados que devem ser evitados.)

Por exemplo, pinMode()é uma função como qualquer outra. Só é executado quando você realmente coloca algo como pinMode(3, INPUT)no seu código. Nesse ponto, ele é executado uma vez, termina e, em seguida, a função de chamada continua de onde parou (eles nunca são executados em paralelo).

O código de exemplo que você postou é bastante interessante. Veja estas linhas em setup():

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

Essas linhas estão dizendo ao Wireobjeto para chamar receiveData()e sendData()em resposta aos eventos I2C. Ele faz isso passando ponteiros de função que são armazenados e usados ​​por Wire.

Eu recomendo procurar informações sobre ponteiros de função C / C ++ online, se você quiser saber mais sobre isso. Você também pode estar interessado em explorar a attachInterrupt()função do Arduino .

Peter Bloomfield
fonte
Obrigado pela sua resposta. Isso está começando a fazer mais sentido agora. No entanto, se as funções receiveData()e sendData()não são executadas, a menos que sejam chamadas, por que elas são chamadas na void setup()função e não na void loop()função principal ? Certamente, essas funções nunca serão chamadas, a menos que seja rara a chance de haver um evento i2c enquanto o ponteiro da instrução ainda estiver dentro da void setupfunção? Não seria melhor chamar essas funções de dentro da void loopfunção, portanto, sempre que houver um evento i2c, a função será chamada?
Blue7
4
@ Blue7 Estas funções não são chamados em void setup(), eles são passados como parâmetro de onReceivee onRequest, eles são chamadas de retorno como o comentário estados. Em um resumo muito curto: isso informa ao (código da) biblioteca Wire para chamar essas funções quando coisas específicas acontecem ( arduino.cc/en/Reference/WireOnReceive , arduino.cc/en/Reference/WireOnRequest ...)
FredP
@FredP Ah, tudo bem. Obrigado pelos links, vou vê-los quando não estiver no meu telefone. Entretanto, tenho uma pergunta rápida, se você não se importa. Esses retornos de chamada estão sempre prontos e aguardando um evento i2c? ou seja, não importa onde esteja o ponteiro da instrução, esses retornos de chamada chamarão a função instantaneamente assim que um evento i2c acontecer.
Blue7
11
@ Blue7 Presumivelmente, estará usando interrupções para monitorar a atividade do I2C. Quando uma interrupção é executada, ela retira o controle do programa principal temporariamente.
Peter Bloomfield
3
@ Blue7 Os retornos de chamada não estão aguardando (o Arduino não é multithread), como diz @PeterRBloomfield, a biblioteca do Wire permite a interrupção do I2C twi_init()durante a ligação Wire.begin. Quando há atividade I2C, o µC para de executar sua tarefa atual (a menos que ... não importa no momento :-) e entra no código da biblioteca Wire, que então chama a função (apropriada, dependendo do que está acontecendo) que você registrou como retorno de chamada ( receiveDatapor exemplo). Um retorno de chamada é o nome genérico para funções como receiveDataor sendData, elas são chamadas por um manipulador de interrupção dentro do Wire.
FredP 22/10
2

Não é esse o caso que setup()é chamado uma vez e loop()é chamado repetidamente? ou seja, que há um invisível main() que pode ser assim:

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

Desculpas, pois estou apenas olhando o Arduino e quase não tenho experiência em C / C ++; Estou tentando me controlar com essa loop()situação.

Dee
fonte
Basicamente sim. Há também uma chamada na init()qual os temporizadores estão funcionando millis, delayetc. O mesmo init()ocorre com a inicialização geral, setup()é para a sua inicialização e loopé para, assim, fazer um loop. Você pode escrever o seu próprio mainse quiser assumir o controle total.
Nick Gammon
Bela postagem. BTW ;não é necessário após o penúltimo }:-)
Greenonline
Há também chamada de serial_event (), não é?
Divisadero
2

Não posso comentar sobre a resposta de Dee. O código real que é executado no loop principal está aqui :

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

    setup();

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

E sim, setup()é chamado uma vez e loop()está sendo chamado repetidamente (junto com algumas coisas em série).

Petrus
fonte
0

Funciona como função normal, deve ser chamado para fazer sentido. loop () / setup () é chamado a partir de uma função main () compilada no diretório Arduino e vinculada.

TMa
fonte