Як працюють функції поза циклом недійсності?


9

Я звик до ескізів Ардуїно з void setup()частиною, яка працює один раз, і void loop()частиною, яка продовжує циклічно. Що відбувається, коли у вас є порожнечі функції поза головною void loop()? Чи всі вони продовжуватимуть циклічно паралельно чи вони запускаються одна за одною? Або певні функції недійсності виконуються лише після того, як будуть виконані певні критерії (наприклад, цикл "час")?

Наприклад, у наведеному нижче коді, коли будуть void receiveData(int byteCount)виконуватися void sendData()функції та функції?

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

Це виглядає цікаво. Цікаво, чи можете ви розмістити посилання на джерело коду (та деталі зв’язків між Arduino та Pi).
Міллівей

1
@Milliways Я використовував цей * підручник для написання коду на arduino uno та Raspberry pi (модель B +), проте я вніс декілька невеликих змін. Підключіть шпильки SDA та SCL двох дощок, а також заземлюючі штифти, якщо вони підключені до різних джерел живлення. Потім у мене був контакт 3, підключений до датчика, налаштованого в конфігурації подільника, підключеного між контактами + 5 В та Gnd. Контакт 0 і Gnd підключено до плати приводу двигуна.
Blue7

Відповіді:


11

Функції setup()та loop()функції незвичні, оскільки вони автоматично викликаються для вас кодом Arduino. Жодні інші функції не ведуть себе таким чином.

Взагалі кажучи, функція ніколи не буде запускатися, якщо ви явно не зателефонуєте їй самостійно (наприклад, зсередини setup()або loop()) або не доручите іншій програмі її зателефонувати. (Є й інші способи виконання функцій, але це, як правило, включає дуже вдосконалене майстерність, якого найкраще уникати.)

Наприклад, pinMode()це функція, як і будь-яка інша. Він запускається лише тоді, коли ви фактично помістили щось подібне pinMode(3, INPUT)до свого коду. У цей момент він запускається один раз, закінчується, а потім функція виклику переходить з того місця, де він припинився (вони ніколи не працюють паралельно).

Приклад коду, який ви опублікували, досить цікавий. Подивіться на ці рядки setup():

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

Ці рядки сповіщають Wireоб'єкт на дзвінок receiveData()та sendData()у відповідь на події I2C. Це робиться шляхом передачі функціональних покажчиків, які зберігаються та використовуються Wire.

Я рекомендую шукати в Інтернеті інформацію про покажчики функцій C / C ++, якщо ви хочете дізнатися більше про це. Вам також може бути цікаво вивчити attachInterrupt()функцію Ардуїно .


Дякую за вашу відповідь. Це зараз починає мати більше сенсу. Однак, якщо функції receiveData()і sendData()функції не виконуються, якщо вони не викликаються, то чому вони називаються у межах void setup()функції, а не головної void loop()функції? Безумовно, ці функції ніколи не будуть викликатися, якщо рідкісний шанс появи події i2c, поки покажчик інструкцій все ще знаходиться в межах void setupфункції? Чи не було б краще викликати ці функції зсередини void loopфункції, тому всякий раз, коли є подія i2c, ця функція викликається?
Blue7

4
@ Blue7 Ці функції не називаються в void setup(), вони передаються в якості параметра onReceiveі onRequest, вони зворотні виклики в якості коментаря станів. Якщо дуже короткий підсумок: це повідомляє (код від) Бібліотека проводів викликати ці функції, коли трапляються конкретні речі ( arduino.cc/en/Reference/WireOnReceive , arduino.cc/en/Reference/WireOnRequest ...)
FredP

@FredP Ну добре. Дякую за посилання, я перевірю їх, коли я не перебуваю на телефоні. Тим часом у мене швидке запитання, якщо ви не заперечуєте. Чи завжди ці зворотні виклики готові і чекають події i2c? тобто, незалежно від того, де знаходиться покажчик інструкцій, ці зворотні виклики миттєво викликають функцію, як тільки відбудеться подія i2c?
Blue7

1
@ Blue7 Імовірно, буде використовувати переривання для моніторингу активності I2C. Коли виконується переривання, він тимчасово відбирає контроль від основної програми.
Пітер Блумфілд

3
@ Blue7 Зворотні дзвінки не чекають (Arduino не є багатопотоковим), як говорить @PeterRBloomfield, бібліотека дротів дозволяє I2C переривати twi_init()час, коли ви телефонуєте Wire.begin. Коли є активність I2C, µC перестає виконувати своє поточне завдання (якщо тільки ... ніколи не пам’ятаю на даний момент :-) і переходить до коду бібліотеки проводів, який потім викликає (відповідно, залежно від того, що відбувається) функцію, яку ви зареєстрували як зворотний виклик ( receiveDataнаприклад). Як передзвонити це загальна назва для функцій , таких як receiveDataабо sendData, як вони називаються з допомогою обробника переривань всередині дроти.
ФредП

2

Чи не той випадок setup()називається один раз і loop()називається повторно? тобто є невидимий, main() який може виглядати так:

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

Вибачте, що я просто заглядаю в Ардуїно і майже не маю досвіду C / C ++; Я сам намагаюся впоратися з цією loop()ситуацією.


В основному, так. Існує також виклик , init()який отримує таймери збирається для millis, і delayт.д. Таким чином , init()для загальної ініціалізації setup()для вашої ініціалізації, і loopдля, ну, зациклення. Ви можете написати своє, mainякщо хочете взяти повний контроль.
Нік Гаммон

Гарний пост. BTW ;не потрібно після передостаннього }:-)
Greenonline

Також є дзвінок serial_event (), чи не так?
Дивізадеро

2

Я не можу коментувати відповідь Ді. Фактичний код, який виконується в основному циклі, знаходиться тут :

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

    setup();

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

І так, setup()дзвонять один раз і loop()дзвоняться повторно (разом із деякими серійними матеріалами).


0

Він працює як нормальна функція, його потрібно викликати, щоб мати сенс. loop () / setup () викликаються з функції main (), яка компілюється з каталогу Arduino і пов'язана в. getData / sendData викликаються з вашої програми, корінь якого знаходиться у функціях циклу / настройки.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.