Bagaimana cara kerja di luar void loop?

9

Saya terbiasa sketsa Arduino dengan void setup()bagian yang berjalan sekali, dan void loop()bagian yang terus berulang. Apa yang terjadi ketika Anda memiliki fungsi batal di luar utama void loop()? Apakah ini semua akan tetap berulang secara paralel atau apakah mereka menjalankan satu demi satu? Atau apakah fungsi void tertentu hanya berjalan setelah kriteria tertentu telah dipenuhi (seperti loop sementara)?

Misalnya dalam kode di bawah ini, kapan akan void receiveData(int byteCount)dan void sendData()fungsinya berjalan?

//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.
}
Biru7
sumber
Ini terlihat menarik. Saya ingin tahu apakah Anda dapat memposting tautan ke sumber kode (dan detail koneksi antara Arduino dan Pi).
Milliways
1
@Milliways Saya menggunakan tutorial * ini untuk menulis kode pada arduino uno dan Raspberry pi (model B +), namun saya membuat beberapa perubahan kecil. Sambungkan pin SDA dan SCL dari dua papan, serta pin ground jika mereka terhubung ke catu daya yang berbeda. Saya kemudian menyambungkan pin 3 ke sensor yang dikonfigurasi dalam konfigurasi pembagi potensial, terhubung antara pin + 5V dan Gnd. Pin 0 dan Gnd terhubung ke papan drive motor.
Biru7

Jawaban:

11

Fungsi setup()dan loop()tidak biasa karena mereka dipanggil secara otomatis untuk Anda oleh kode Arduino. Tidak ada fungsi lain yang berperilaku seperti ini.

Secara umum, suatu fungsi tidak akan pernah berjalan kecuali jika Anda secara eksplisit menyebutnya sendiri (misalnya dari dalam setup()atau loop()), atau memerintahkan bagian lain dari program untuk memanggilnya. (Ada cara lain untuk menjalankan fungsi, tetapi itu biasanya melibatkan beberapa mengutak-atik yang sangat canggih yang sebaiknya dihindari.)

Misalnya, pinMode()adalah fungsi sama seperti yang lain. Ini hanya berjalan ketika Anda benar-benar memasukkan sesuatu seperti pinMode(3, INPUT)dalam kode Anda. Pada titik itu, ia berjalan sekali, selesai, dan kemudian fungsi panggilan melanjutkan dari tempat itu ditinggalkan (mereka tidak pernah berjalan secara paralel).

Contoh kode yang Anda posting cukup menarik. Lihatlah garis-garis ini di setup():

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

Baris-baris ini memberi tahu Wireobjek untuk memanggil receiveData()dan sendData()menanggapi peristiwa I2C. Ini dilakukan dengan melewati pointer fungsi yang disimpan dan digunakan oleh Wire.

Saya akan merekomendasikan mencari informasi tentang pointer fungsi C / C ++ online jika Anda ingin mempelajari lebih lanjut tentang ini. Anda mungkin juga tertarik untuk menjelajahi attachInterrupt()fungsi Arduino .

Peter Bloomfield
sumber
Terima kasih atas jawaban anda. Ini mulai lebih masuk akal sekarang. Namun, jika fungsi receiveData()dan sendData()tidak dijalankan kecuali jika dipanggil, lalu mengapa mereka dipanggil dalam void setup()fungsi dan bukan void loop()fungsi utama ? Tentunya fungsi-fungsi ini tidak akan pernah dipanggil kecuali kemungkinan langka bahwa ada acara i2c sementara pointer instruksi masih dalam void setupfungsi? Bukankah lebih baik memanggil fungsi-fungsi ini dari dalam void loopfungsi sehingga setiap kali ada acara i2c, fungsi tersebut dipanggil?
Biru7
4
@ Blue7 Fungsi-fungsi ini tidak disebut dalam void setup(), mereka lulus sebagai parameter onReceivedan onRequest, mereka callback sebagai negara komentar. Dalam ringkasan yang sangat singkat: ini memberitahu (kode dari) Wire library untuk memanggil fungsi-fungsi ini ketika hal-hal tertentu terjadi ( arduino.cc/en/Reference/WireOnReceive , arduino.cc/en/Reference/WireOnRequest ...)
FredP
@ FredP Ah baik-baik saja. Terima kasih atas tautannya, saya akan memeriksanya saat saya tidak menggunakan telepon saya. Sementara itu, saya punya pertanyaan singkat, jika Anda tidak keberatan. Apakah panggilan balik ini selalu siap dan menunggu acara i2c? yaitu, tidak peduli di mana penunjuk instruksi berada, callback ini akan langsung memanggil fungsi begitu peristiwa i2c terjadi?
Biru7
1
@ Blue7 Agaknya akan menggunakan interupsi untuk memantau aktivitas I2C. Ketika interupsi dijalankan, ia mengambil kendali dari program utama untuk sementara waktu.
Peter Bloomfield
3
@ Blue7 Callback tidak menunggu (Arduino tidak multithreaded), seperti yang dikatakan @PeterRBloomfield, pustaka kawat memungkinkan I2C mengganggu twi_init()saat Anda menelepon Wire.begin. Ketika ada aktivitas I2C μC berhenti melakukan tugasnya saat ini (kecuali ... tidak ingat untuk saat ini :-) dan masuk dalam kode perpustakaan Wire, yang kemudian memanggil fungsi (sesuai, tergantung pada apa yang terjadi) fungsi Anda terdaftar sebagai panggilan balik ( receiveDatamisalnya). Sebuah callback adalah nama generik untuk fungsi-fungsi seperti receiveDataatau sendData, mereka disebut oleh interrupt handler dalam Wire.
FredP
2

Bukankah itu kasus yang setup()disebut sekali dan loop()disebut berulang kali? yaitu bahwa ada yang tak terlihat main() yang mungkin terlihat seperti ini:

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

Maaf karena saya hanya melihat ke dalam Arduino dan hampir tidak memiliki pengalaman C / C ++; Saya mencoba menangani loop()situasi ini sendiri.

Dee
sumber
Pada dasarnya ya. Ada juga panggilan init()yang membuat timer berjalan millis, delaydll. Begitu init()juga untuk inisialisasi umum, setup()untuk inisialisasi Anda , dan loopuntuk, yah, pengulangan. Anda dapat menulis sendiri mainjika Anda ingin mengambil kendali penuh.
Nick Gammon
Pos yang bagus. BTW ;tidak diperlukan setelah kedua dari belakang }:-)
Greenonline
Ada juga panggilan serial_event () bukan?
Divisadero
2

Saya tidak bisa mengomentari tanggapan Dee. Kode aktual yang dieksekusi di loop utama ada di sini :

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

    setup();

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

Dan ya, setup()dipanggil sekali dan loop()dipanggil berulang kali (bersama dengan beberapa hal serial).

Petrus
sumber
0

Ini berfungsi sebagai fungsi normal, itu harus disebut masuk akal. loop () / setup () dipanggil dari fungsi main () yang dikompilasi dari direktori Arduino dan ditautkan. acceptData / sendData dipanggil dari program Anda yang rootnya ada di fungsi loop / setup.

TMa
sumber