ฟังก์ชั่นภายนอกของ void loop นั้นทำงานอย่างไร


9

ฉันคุ้นเคยกับภาพร่าง Arduino ซึ่งมีชิ้น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)
Milliways

1
@Milliways ฉันใช้นี้ *กวดวิชาเพื่อเขียนรหัสบน arduino uno และ Raspberry pi (รุ่น B +) แต่ฉันทำการเปลี่ยนแปลงเล็กน้อยไม่กี่เชื่อมต่อ SDA และ SCL พินของทั้งสองแผงเช่นเดียวกับหมุดภาคพื้นดินถ้าพวกเขา เชื่อมต่อกับแหล่งจ่ายไฟที่แตกต่างกัน จากนั้นฉันก็มีการเชื่อมต่อขา 3 กับเซ็นเซอร์ที่กำหนดค่าในการกำหนดค่าตัวแบ่งที่อาจเกิดขึ้นเชื่อมต่อระหว่าง + 5V และหมุด Gnd Pin 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()ฟังก์ชั่นของ Arduino


ขอบคุณสำหรับคำตอบ. สิ่งนี้เริ่มมีเหตุผลมากขึ้นแล้ว อย่างไรก็ตามหากฟังก์ชัน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 เมื่อมีการดำเนินการขัดจังหวะมันจะควบคุมจากโปรแกรมหลักชั่วคราว
Peter Bloomfield

3
@ Blue7 เรียกกลับจะไม่รอ (Arduino ไม่ได้ multithreaded) เช่น @PeterRBloomfield กล่าวว่าห้องสมุดลวดช่วยขัดจังหวะ I2C ผ่านเมื่อคุณเรียกtwi_init() Wire.beginเมื่อมีกิจกรรม I2C µC หยุดทำงานปัจจุบัน (ยกเว้น ... ไม่เป็นไรในขณะนี้ :-) และไปที่รหัสของห้องสมุดลวดซึ่งจะเรียกฟังก์ชั่น (เหมาะสมขึ้นอยู่กับสิ่งที่เกิดขึ้น) ที่คุณลงทะเบียนเป็น โทรกลับ ( receiveDataตัวอย่าง) การเรียกกลับเป็นชื่อสามัญสำหรับฟังก์ชันเช่นreceiveDataหรือsendDataพวกมันถูกเรียกโดยตัวจัดการขัดจังหวะภายใน Wire
FredP

2

ไม่ใช่กรณีที่setup()ถูกเรียกครั้งเดียวและloop()ถูกเรียกซ้ำ ๆ กัน? นั่นคือมีสิ่ง main()ที่มองไม่เห็นซึ่งอาจมีลักษณะเช่นนี้:

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

ขอโทษด้วยที่ฉันแค่มองหา Arduino และแทบไม่มีประสบการณ์ C / C ++ ฉันพยายามรับloop()สถานการณ์นี้ด้วยตัวเอง


โดยทั่วไปแล้วใช่ นอกจากนี้ยังมีการเรียกร้องให้init()ที่ได้รับจับเวลาไปสำหรับmillis, delayฯลฯ ดังนั้นinit()จะสำหรับการเริ่มต้นทั่วไปsetup()สำหรับคุณเริ่มต้นและloopเป็นดีบ่วง คุณสามารถเขียนของคุณเองmainหากคุณต้องการควบคุมเต็มรูปแบบ
Nick Gammon

โพสต์ที่ดี ;ไม่จำเป็นต้องใช้BTW หลังจากสิ้นสุด}:-)
Greenonline

นอกจากนี้ยังมีการเรียก serial_event () ใช่ไหม?
Divisadero

2

ฉันไม่สามารถแสดงความคิดเห็นในการตอบสนองของดี รหัสจริงที่ดำเนินการในลูปหลักอยู่ที่นี่ :

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

    setup();

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

และใช่setup()ได้รับการเรียกครั้งเดียวและloop()ถูกเรียกซ้ำหลายครั้ง (พร้อมกับบางสิ่งอนุกรม)


0

มันทำงานเป็นฟังก์ชั่นปกติมันจะต้องเรียกให้เข้าท่า loop () / setup () ถูกเรียกจากฟังก์ชั่น main () ซึ่งรวบรวมจากไดเรกทอรี Arduino และเชื่อมโยงมา acceptData / sendData จะถูกเรียกจากโปรแกรมของคุณซึ่งรูทอยู่ในฟังก์ชันลูป / การตั้งค่า

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.