การขัดจังหวะทำงานบน Arduino Uno และบอร์ดที่คล้ายกันอย่างไร


11

โปรดอธิบายวิธีการขัดจังหวะการทำงานกับ Arduino Uno และบอร์ดที่เกี่ยวข้องโดยใช้โปรเซสเซอร์ ATmega328P บอร์ดเช่น:

  • Uno
  • มินิ
  • นาโน
  • Pro Mini
  • Lilypad

โดยเฉพาะอย่างยิ่งโปรดหารือ:

  • สิ่งที่จะใช้ขัดจังหวะ
  • วิธีการเขียน Interrupt Service Routine (ISR)
  • ปัญหาเรื่องเวลา
  • ส่วนที่สำคัญ
  • การเข้าถึงข้อมูลของอะตอม

หมายเหตุ: นี่เป็นคำถามอ้างอิง

คำตอบ:


25

TL; DR:

เมื่อเขียน Interrupt Service Routine (ISR):

  • ทำให้สั้น
  • ห้ามใช้ delay ()
  • อย่าทำการพิมพ์แบบอนุกรม
  • ทำให้ตัวแปรที่ใช้ร่วมกันกับรหัสหลักระเหย
  • ตัวแปรที่แชร์ด้วยรหัสหลักอาจต้องได้รับการปกป้องโดย "ส่วนที่สำคัญ" (ดูด้านล่าง)
  • อย่าพยายามปิดหรือเปิดการขัดจังหวะ

การขัดจังหวะคืออะไร

โปรเซสเซอร์ส่วนใหญ่มีการขัดจังหวะ การขัดจังหวะช่วยให้คุณตอบสนองต่อเหตุการณ์ "ภายนอก" ในขณะที่ทำอย่างอื่น ตัวอย่างเช่นหากคุณกำลังทำอาหารเย็นคุณสามารถใส่มันฝรั่งเพื่อทำอาหารเป็นเวลา 20 นาที แทนที่จะจ้องที่นาฬิกาเป็นเวลา 20 นาทีคุณอาจตั้งเวลาแล้วไปดูทีวี เมื่อตัวจับเวลาดังขึ้นคุณจะ "ขัดจังหวะ" การดูทีวีของคุณเพื่อทำบางสิ่งกับมันฝรั่ง


ตัวอย่างของการขัดจังหวะ

const byte LED = 13;
const byte SWITCH = 2;

// Interrupt Service Routine (ISR)
void switchPressed ()
{
  if (digitalRead (SWITCH) == HIGH)
    digitalWrite (LED, HIGH);
  else
    digitalWrite (LED, LOW);
}  // end of switchPressed

void setup ()
{
  pinMode (LED, OUTPUT);  // so we can update the LED
  pinMode (SWITCH, INPUT_PULLUP);
  attachInterrupt (digitalPinToInterrupt (SWITCH), switchPressed, CHANGE);  // attach interrupt handler
}  // end of setup

void loop ()
{
  // loop doing nothing
}

ตัวอย่างนี้แสดงให้เห็นว่าถึงแม้ว่าห่วงหลักจะไม่ทำอะไรเลยคุณสามารถเปิดหรือปิดไฟ LED ที่ขา 13 หากปิดสวิตช์ D2 ที่ขา

ในการทดสอบเพียงแค่เชื่อมต่อสาย (หรือสวิทช์) ระหว่าง D2 และกราวด์ pullup ภายใน (เปิดใช้งานในการตั้งค่า) บังคับให้พิน HIGH ตามปกติ เมื่อต่อสายดินมันจะต่ำ ตรวจพบการเปลี่ยนแปลงพินโดยการขัดจังหวะโดย CHANGE ซึ่งทำให้การเรียกใช้งานบริการขัดจังหวะ (ISR) ถูกขัดจังหวะ

ในตัวอย่างที่มีความซับซ้อนมากขึ้นห่วงหลักอาจทำบางสิ่งที่มีประโยชน์เช่นการอ่านค่าอุณหภูมิและอนุญาตให้ตัวจัดการขัดจังหวะตรวจจับปุ่มที่ถูกผลัก


การแปลงหมายเลขพินเป็นตัวเลขขัดจังหวะ

เพื่อให้การแปลงหมายเลขเวคเตอร์อินเตอร์รัปต์เป็นพินง่ายขึ้นคุณสามารถเรียกใช้ฟังก์ชันdigitalPinToInterrupt()โดยส่งผ่านหมายเลขพิน ส่งคืนหมายเลขอินเตอร์รัปต์ที่เหมาะสมหรือNOT_AN_INTERRUPT(-1)

ตัวอย่างเช่นบน Uno ให้กด D2 บนบอร์ดขัดจังหวะ 0 (INT0_vect จากตารางด้านล่าง)

ดังนั้นทั้งสองบรรทัดจึงมีผลเหมือนกัน:

  attachInterrupt (0, switchPressed, CHANGE);    // that is, for pin D2
  attachInterrupt (digitalPinToInterrupt (2), switchPressed, CHANGE);

อย่างไรก็ตามตัวที่สองนั้นง่ายต่อการอ่านและพกพาได้มากกว่า Arduino ชนิดอื่น


ขัดจังหวะที่มีอยู่

ด้านล่างเป็นรายการของการขัดจังหวะตามลำดับความสำคัญสำหรับ Atmega328:

 1  Reset
 2  External Interrupt Request 0  (pin D2)          (INT0_vect)
 3  External Interrupt Request 1  (pin D3)          (INT1_vect)
 4  Pin Change Interrupt Request 0 (pins D8 to D13) (PCINT0_vect)
 5  Pin Change Interrupt Request 1 (pins A0 to A5)  (PCINT1_vect)
 6  Pin Change Interrupt Request 2 (pins D0 to D7)  (PCINT2_vect)
 7  Watchdog Time-out Interrupt                     (WDT_vect)
 8  Timer/Counter2 Compare Match A                  (TIMER2_COMPA_vect)
 9  Timer/Counter2 Compare Match B                  (TIMER2_COMPB_vect)
10  Timer/Counter2 Overflow                         (TIMER2_OVF_vect)
11  Timer/Counter1 Capture Event                    (TIMER1_CAPT_vect)
12  Timer/Counter1 Compare Match A                  (TIMER1_COMPA_vect)
13  Timer/Counter1 Compare Match B                  (TIMER1_COMPB_vect)
14  Timer/Counter1 Overflow                         (TIMER1_OVF_vect)
15  Timer/Counter0 Compare Match A                  (TIMER0_COMPA_vect)
16  Timer/Counter0 Compare Match B                  (TIMER0_COMPB_vect)
17  Timer/Counter0 Overflow                         (TIMER0_OVF_vect)
18  SPI Serial Transfer Complete                    (SPI_STC_vect)
19  USART Rx Complete                               (USART_RX_vect)
20  USART, Data Register Empty                      (USART_UDRE_vect)
21  USART, Tx Complete                              (USART_TX_vect)
22  ADC Conversion Complete                         (ADC_vect)
23  EEPROM Ready                                    (EE_READY_vect)
24  Analog Comparator                               (ANALOG_COMP_vect)
25  2-wire Serial Interface  (I2C)                  (TWI_vect)
26  Store Program Memory Ready                      (SPM_READY_vect)

ชื่อภายใน (ซึ่งคุณสามารถใช้เพื่อตั้งค่าการเรียกกลับ ISR) อยู่ในวงเล็บ

คำเตือน: หากคุณสะกดชื่อเวกเตอร์ขัดจังหวะแม้เพียงแค่ทำให้ตัวพิมพ์ใหญ่ผิด (เป็นเรื่องง่ายที่จะทำ) รูทีนการขัดจังหวะจะไม่ถูกเรียกใช้และคุณจะไม่ได้รับข้อผิดพลาดของคอมไพเลอร์


เหตุผลในการใช้อินเตอร์รัปต์

สาเหตุหลักที่คุณอาจใช้อินเตอร์รัปต์คือ:

  • ในการตรวจจับการเปลี่ยนแปลงพิน (เช่นตัวเข้ารหัสแบบหมุนให้กดปุ่ม)
  • ตัวจับเวลา Watchdog (เช่นถ้าไม่มีอะไรเกิดขึ้นหลังจาก 8 วินาทีขัดจังหวะฉัน)
  • ขัดจังหวะตัวจับเวลา - ใช้สำหรับการเปรียบเทียบ / จับเวลาล้น
  • การถ่ายโอนข้อมูล SPI
  • การถ่ายโอนข้อมูล I2C
  • การถ่ายโอนข้อมูล USART
  • แปลง ADC (อนาล็อกเป็นดิจิตอล)
  • EEPROM พร้อมใช้งาน
  • หน่วยความจำแฟลชพร้อม

"การถ่ายโอนข้อมูล" สามารถใช้เพื่อให้โปรแกรมทำอย่างอื่นในขณะที่ข้อมูลกำลังถูกส่งหรือรับในพอร์ตอนุกรม, พอร์ต SPI หรือพอร์ต I2C

ปลุกโปรเซสเซอร์

การขัดจังหวะภายนอกการขัดจังหวะการเปลี่ยนพินและการจับเวลาขัดจังหวะการจ้องจับผิดก็สามารถใช้เพื่อปลุกโปรเซสเซอร์ให้ตื่นขึ้น สิ่งนี้มีประโยชน์มากเช่นในโหมดสลีปโปรเซสเซอร์สามารถกำหนดค่าให้ใช้พลังงานน้อยลงมาก (เช่นประมาณ 10 ไมโครแคม) การขัดจังหวะที่เพิ่มขึ้นลดลงหรือระดับต่ำสามารถใช้เพื่อปลุกแกดเจ็ต (เช่นหากคุณกดปุ่มบน) หรือการขัดจังหวะ "ตัวจับเวลาจ้องจับผิด" อาจปลุกเป็นระยะ ๆ (เช่นเพื่อตรวจสอบเวลาหรือ อุณหภูมิ).

การขัดจังหวะการเปลี่ยนขาสามารถใช้ปลุกหน่วยประมวลผลได้หากกดปุ่มบนแป้นพิมพ์หรือคล้ายกัน

โปรเซสเซอร์สามารถถูกปลุกได้ด้วยการจับเวลาขัดจังหวะ (เช่นจับเวลาถึงค่าที่แน่นอนหรือล้น) และเหตุการณ์อื่น ๆ เช่นข้อความ I2C ที่เข้ามา


เปิดใช้งาน / ปิดใช้งานการขัดจังหวะ

การขัดจังหวะ "รีเซ็ต" ไม่สามารถปิดใช้งานได้ อย่างไรก็ตามการขัดจังหวะอื่น ๆ สามารถปิดใช้งานได้ชั่วคราวด้วยการล้างการตั้งค่าสถานะอินเตอร์รัปต์โกลบอล

เปิดใช้งานการขัดจังหวะ

คุณสามารถเปิดใช้งานการขัดจังหวะด้วยการเรียกใช้ฟังก์ชัน "ขัดจังหวะ" หรือ "sei" ดังนี้:

interrupts ();  // or ...
sei ();         // set interrupts flag

ปิดใช้งานการขัดจังหวะ

หากคุณต้องการปิดการใช้งานอินเตอร์รัปต์คุณสามารถ "ล้าง" ค่าสถานะอินเตอร์รัปต์โกลบอลแบบนี้:

noInterrupts ();  // or ...
cli ();           // clear interrupts flag

วิธีการใดวิธีการหนึ่งมีผลเหมือนกันการใช้interrupts/ noInterruptsเป็นเรื่องง่ายกว่าที่จะจำได้ว่าใช้วิธีไหน

ค่าเริ่มต้นใน Arduino สำหรับการขัดจังหวะที่จะเปิดใช้งาน อย่าปิดการใช้งานเป็นเวลานานหรือสิ่งต่าง ๆ เช่นตัวจับเวลาจะทำงานไม่ถูกต้อง

เหตุใดจึงปิดใช้งานการขัดจังหวะ

อาจมีบางส่วนของรหัสที่สำคัญซึ่งคุณไม่ต้องการให้ถูกขัดจังหวะตัวอย่างเช่นตัวจับเวลาจะถูกขัดจังหวะ

นอกจากนี้หากมีการอัปเดตฟิลด์หลายไบต์โดย ISR คุณอาจต้องปิดการใช้งานอินเตอร์รัปต์เพื่อให้ได้ข้อมูล "อะตอม" มิฉะนั้นหนึ่งไบต์อาจได้รับการปรับปรุงโดย ISR ในขณะที่คุณอ่านอีกอัน

ตัวอย่างเช่น:

noInterrupts ();
long myCounter = isrCounter;  // get value set by ISR
interrupts ();

การปิดอินเทอร์รัปต์เป็นการชั่วคราวทำให้มั่นใจได้ว่า isrCounter (ตัวนับที่ตั้งไว้ภายใน ISR) จะไม่เปลี่ยนแปลงขณะที่เราได้รับค่าของมัน

คำเตือน:หากคุณไม่แน่ใจว่าอินเทอร์รัปต์เปิดอยู่หรือไม่คุณจำเป็นต้องบันทึกสถานะปัจจุบันและกู้คืนในภายหลัง ตัวอย่างเช่นโค้ดจากฟังก์ชัน millis () ทำสิ่งนี้:

unsigned long millis()
{
  unsigned long m;
  uint8_t oldSREG = SREG;    // <--------- save status register

  // disable interrupts while we read timer0_millis or we might get an
  // inconsistent value (e.g. in the middle of a write to timer0_millis)
  cli();
  m = timer0_millis;
  SREG = oldSREG;            // <---------- restore status register including interrupt flag

  return m;
}

หมายเหตุบรรทัดที่ระบุให้บันทึก SREG ปัจจุบัน (การลงทะเบียนสถานะ) ซึ่งรวมถึงการตั้งค่าอินเตอร์รัปต์ หลังจากที่เราได้รับค่าตัวจับเวลา (ซึ่งมีความยาว 4 ไบต์) เราจะนำการลงทะเบียนสถานะกลับมาเหมือนเดิม


เคล็ดลับ

ชื่อฟังก์ชั่น

ฟังก์ชั่นcli/ seiและ register SREG นั้นเฉพาะกับโปรเซสเซอร์ AVR หากคุณใช้โปรเซสเซอร์อื่น ๆ เช่น ARM ฟังก์ชั่นอาจแตกต่างกันเล็กน้อย

ปิดการใช้งานทั่วโลกและปิดการใช้งานหนึ่งขัดจังหวะ

หากคุณใช้cli()คุณปิดการใช้งานการขัดจังหวะทั้งหมด (รวมถึงการขัดจังหวะตัวจับเวลาขัดจังหวะอนุกรม ฯลฯ )

อย่างไรก็ตามหากคุณต้องการปิดการใช้งานอินเตอร์รัปต์เฉพาะคุณควรล้างการตั้งค่าสถานะอินเตอร์รัปต์สำหรับแหล่งขัดจังหวะนั้นโดยเฉพาะ detachInterrupt()ตัวอย่างเช่นสำหรับการขัดจังหวะภายนอกโทร


ลำดับความสำคัญของการขัดจังหวะคืออะไร

เนื่องจากมีอินเทอร์รัปต์ 25 รายการ (นอกเหนือจากการรีเซ็ต) จึงมีความเป็นไปได้ที่อาจเกิดเหตุการณ์อินเตอร์รัปต์มากกว่าหนึ่งเหตุการณ์ในครั้งเดียวหรืออย่างน้อยก็เกิดขึ้นก่อนที่จะประมวลผลก่อนหน้านี้ นอกจากนี้อาจเกิดเหตุการณ์ขัดจังหวะขณะที่อินเตอร์รัปต์ถูกปิดใช้งาน

ลำดับความสำคัญคือลำดับที่โปรเซสเซอร์ตรวจสอบเหตุการณ์ขัดจังหวะ รายการยิ่งสูงลำดับความสำคัญยิ่งสูง ตัวอย่างเช่นคำขอการขัดจังหวะภายนอก 0 (pin D2) จะได้รับการบริการก่อนคำขอการขัดจังหวะภายนอก 1 (ขา D3)


การขัดจังหวะสามารถเกิดขึ้นได้ในขณะที่การขัดจังหวะถูกปิดใช้งานหรือไม่?

เหตุการณ์ขัดจังหวะ(นั่นคือการสังเกตเห็นเหตุการณ์) สามารถเกิดขึ้นได้ตลอดเวลาและส่วนใหญ่จะถูกจดจำโดยการตั้งค่าสถานะ "ขัดจังหวะเหตุการณ์" ภายในโปรเซสเซอร์ หากการอินเตอร์รัปต์ถูกปิดใช้งานอินเทอร์รัปต์นั้นจะถูกจัดการเมื่อเปิดใช้งานอีกครั้งตามลำดับความสำคัญ


คุณใช้อินเตอร์รัปต์อย่างไร

  • คุณเขียน ISR (รูทีนการบริการขัดจังหวะ) สิ่งนี้ถูกเรียกเมื่อเกิดการขัดจังหวะ
  • คุณบอกโปรเซสเซอร์เมื่อคุณต้องการที่จะให้ขัดจังหวะ

เขียน ISR

รูทีนการบริการขัดจังหวะเป็นฟังก์ชันที่ไม่มีอาร์กิวเมนต์ ไลบรารี Arduino บางตัวได้รับการออกแบบมาเพื่อเรียกใช้ฟังก์ชันของคุณเองดังนั้นคุณเพียงแค่จัดหาฟังก์ชั่นทั่วไป (เช่นในตัวอย่างด้านบน) เช่น

// Interrupt Service Routine (ISR)
void switchPressed ()
{
 flag = true;
}  // end of switchPressed

อย่างไรก็ตามหากห้องสมุดยังไม่ได้ให้ "hook" กับ ISR คุณสามารถสร้างของคุณเองได้เช่นนี้

volatile char buf [100];
volatile byte pos;

// SPI interrupt routine
ISR (SPI_STC_vect)
{
byte c = SPDR;  // grab byte from SPI Data Register

  // add to buffer if room
  if (pos < sizeof buf)
    {
    buf [pos++] = c;
    }  // end of room available
}  // end of interrupt routine SPI_STC_vect

ในกรณีนี้คุณใช้แมโคร "ISR" และระบุชื่อของเวกเตอร์ขัดจังหวะที่เกี่ยวข้อง (จากตารางก่อนหน้านี้) ในกรณีนี้ ISR กำลังจัดการการถ่ายโอน SPI ให้เสร็จสมบูรณ์ (หมายเหตุรหัสเก่าบางตัวใช้ SIGNAL แทน ISR แต่ SIGNAL นั้นไม่รองรับ)

การเชื่อมต่อ ISR เข้ากับอินเตอร์รัปต์

สำหรับการขัดจังหวะที่จัดการโดยไลบรารีคุณเพียงแค่ใช้อินเตอร์เฟสที่มีเอกสาร ตัวอย่างเช่น:

void receiveEvent (int howMany)
 {
  while (Wire.available () > 0)
    {
    char c = Wire.receive ();
    // do something with the incoming byte
    }
}  // end of receiveEvent

void setup ()
  {
  Wire.onReceive(receiveEvent);
  }

ในกรณีนี้ไลบรารี I2C ได้รับการออกแบบเพื่อจัดการกับ I2C ไบต์ที่เข้ามาภายในแล้วเรียกใช้ฟังก์ชันที่คุณให้ไว้ที่ส่วนท้ายของสตรีมข้อมูลขาเข้า ในกรณีนี้ receiveEvent ไม่ใช่ ISR อย่างเคร่งครัด (มีอาร์กิวเมนต์) แต่ถูกเรียกโดย ISR แบบ inbuilt

อีกตัวอย่างหนึ่งคืออินเตอร์รัปต์ "พินภายนอก"

// Interrupt Service Routine (ISR)
void switchPressed ()
{
  // handle pin change here
}  // end of switchPressed

void setup ()
{
  attachInterrupt (digitalPinToInterrupt (2), switchPressed, CHANGE);  // attach interrupt handler for D2
}  // end of setup

ในกรณีนี้ฟังก์ชั่น attachInterrupt จะเพิ่มฟังก์ชั่นสวิตช์กดลงในตารางภายในและนอกจากนี้ยังกำหนดค่าสถานะอินเตอร์รัปต์ที่เหมาะสมในโปรเซสเซอร์

การกำหนดค่าตัวประมวลผลเพื่อจัดการการขัดจังหวะ

ขั้นตอนต่อไปเมื่อคุณมี ISR คือการบอกโปรเซสเซอร์ว่าคุณต้องการให้เงื่อนไขเฉพาะนี้เพิ่มการขัดจังหวะ

ตัวอย่างเช่นสำหรับการขัดจังหวะภายนอก 0 (การขัดจังหวะ D2) คุณสามารถทำสิ่งนี้:

EICRA &= ~3;  // clear existing flags
EICRA |= 2;   // set wanted flags (falling level interrupt)
EIMSK |= 1;   // enable it

อ่านได้มากขึ้นจะใช้ชื่อที่กำหนดเช่นนี้

EICRA &= ~(bit(ISC00) | bit (ISC01));  // clear existing flags
EICRA |= bit (ISC01);    // set wanted flags (falling level interrupt)
EIMSK |= bit (INT0);     // enable it

EICRA (External Interrupt Control Register A) จะถูกตั้งค่าตามตารางนี้จากแผ่นข้อมูล Atmega328 ที่กำหนดประเภทของการขัดจังหวะที่คุณต้องการ:

  • 0: INT0 ระดับต่ำสร้างคำขออินเตอร์รัปต์ (LOW Interrupt)
  • 1: การเปลี่ยนแปลงเชิงตรรกะใด ๆ บน INT0 จะสร้างคำขออินเตอร์รัปต์ (CHANGE Interrupt)
  • 2: ขอบที่ยาวเหยียดของ INT0 สร้างคำขออินเตอร์รัปต์ (FALLING อินเตอร์รัปต์)
  • 3: ขอบที่เพิ่มขึ้นของ INT0 สร้างคำขออินเตอร์รัปต์ (RISING อินเตอร์รัปต์)

EIMSK (External Interrupt Mask Register) เปิดใช้งานการขัดจังหวะ

โชคดีที่คุณไม่จำเป็นต้องจำตัวเลขเหล่านั้นเพราะ AttachInterrupt ทำเพื่อคุณ อย่างไรก็ตามนั่นคือสิ่งที่เกิดขึ้นจริงและสำหรับการขัดจังหวะอื่น ๆ คุณอาจต้องตั้งค่าสถานะ "ขัดจังหวะ" ด้วยตนเอง


ISR ระดับต่ำกับไลบรารี ISR

เพื่อให้ชีวิตของคุณง่ายขึ้นตัวจัดการขัดจังหวะทั่วไปบางตัวจะอยู่ในรหัสห้องสมุด (ตัวอย่างเช่น INT0_vect และ INT1_vect) จากนั้นจะมีการให้ส่วนต่อประสานกับผู้ใช้ที่เป็นมิตรมากขึ้น (เช่น attachInterrupt) สิ่งที่แนบมากับอินเทอรัลขัดจริงคือบันทึกที่อยู่ของตัวจัดการอินเตอร์รัปต์ที่คุณต้องการลงในตัวแปรแล้วเรียกสิ่งนั้นจาก INT0_vect / INT1_vect เมื่อต้องการ นอกจากนี้ยังตั้งค่าสถานะการลงทะเบียนที่เหมาะสมเพื่อเรียกตัวจัดการเมื่อจำเป็น


ISR สามารถถูกขัดจังหวะได้หรือไม่?

ในระยะสั้นไม่ไม่เว้นแต่คุณต้องการให้พวกเขาเป็น

เมื่อ ISR ป้อนขัดจังหวะจะถูกปิดการใช้งาน โดยปกติแล้วจะต้องเปิดใช้งานตั้งแต่แรกมิฉะนั้นจะไม่มีการป้อน ISR อย่างไรก็ตามเพื่อหลีกเลี่ยง ISR ตัวเองถูกขัดจังหวะโปรเซสเซอร์จะปิดการขัดจังหวะ

เมื่อมีการออก ISR แล้วขัดจังหวะจะเปิดใช้งานอีกครั้ง คอมไพเลอร์ยังสร้างรหัสภายใน ISR เพื่อบันทึกการลงทะเบียนและการตั้งค่าสถานะดังนั้นสิ่งที่คุณทำเมื่อการขัดจังหวะที่เกิดขึ้นจะไม่ได้รับผลกระทบ

อย่างไรก็ตามคุณสามารถเปิดการขัดจังหวะภายใน ISR ได้หากคุณต้องการเช่น

// Interrupt Service Routine (ISR)
void switchPressed ()
{
  // handle pin change here
  interrupts ();  // allow more interrupts

}  // end of switchPressed

โดยปกติคุณจะต้องมีเหตุผลที่ดีในการทำเช่นนี้เนื่องจากการขัดจังหวะอีกครั้งอาจส่งผลให้เกิดการเรียกซ้ำไปยัง pinChange ซึ่งอาจเป็นผลลัพธ์ที่ไม่พึงประสงค์


ใช้เวลาดำเนินการ ISR นานเท่าไหร่

ตามแผ่นข้อมูลระยะเวลาที่น้อยที่สุดในการให้บริการการขัดจังหวะคือ 4 รอบนาฬิกา (เพื่อผลักตัวนับโปรแกรมปัจจุบันไปยังสแต็ค) ตามด้วยรหัสตอนนี้รันที่ตำแหน่งเวกเตอร์ขัดจังหวะ โดยปกติจะประกอบด้วยการข้ามไปยังที่รูทีนการขัดจังหวะจริง ๆ ซึ่งเป็นอีก 3 รอบ การตรวจสอบรหัสที่ผลิตโดยคอมไพเลอร์แสดงให้เห็นว่า ISR ที่ทำกับการประกาศ "ISR" สามารถใช้เวลาประมาณ 2.625 tos ในการดำเนินการรวมถึงสิ่งที่ตัวเองทำ จำนวนเงินที่แน่นอนนั้นขึ้นอยู่กับจำนวนการลงทะเบียนและการเรียกคืนที่ต้องการ จำนวนเงินขั้นต่ำจะเป็น 1.1875 µs

อินเทอร์รัปต์ภายนอก (ที่คุณใช้ attachInterrupt) ทำได้อีกเล็กน้อยและใช้เวลาทั้งหมด 5.125 (s (ทำงานด้วยนาฬิกา 16 MHz)


นานแค่ไหนก่อนที่โปรเซสเซอร์จะเริ่มเข้าสู่ ISR

สิ่งนี้แตกต่างกันบ้าง ตัวเลขที่ยกมาข้างต้นเป็นตัวเลขในอุดมคติที่มีการประมวลผลอินเทอร์รัปต์ทันที ปัจจัยบางอย่างอาจล่าช้าที่:

  • หากตัวประมวลผลหลับมีการกำหนด "เวลาปลุก" ซึ่งอาจใช้เวลาไม่กี่มิลลิวินาทีในขณะที่นาฬิกาถูกสปูลกลับเป็นความเร็ว เวลานี้จะขึ้นอยู่กับการตั้งค่าฟิวส์และความลึกของการนอนหลับ

  • หากรูทีนการบริการขัดจังหวะการทำงานอยู่แล้วการขัดจังหวะเพิ่มเติมจะไม่สามารถป้อนได้จนกว่าจะเสร็จสิ้นหรือเปิดใช้งานการขัดจังหวะตัวเอง นี่คือเหตุผลที่คุณควรทำให้แต่ละบริการขัดจังหวะสั้น ๆ เพราะทุกวินาทีที่คุณใช้ในหนึ่งคุณอาจล่าช้าในการดำเนินการอีก

  • บางรหัสปิดการขัดจังหวะ ตัวอย่างเช่นการเรียกมิลลิวินาที () สั้น ๆ จะปิดการขัดจังหวะ ดังนั้นเวลาสำหรับการขัดจังหวะที่จะรับบริการจะขยายออกไปตามระยะเวลาที่ถูกขัดจังหวะ

  • การขัดจังหวะสามารถให้บริการได้เมื่อสิ้นสุดคำสั่งเท่านั้นดังนั้นหากคำสั่งนั้นใช้เวลาสามรอบนาฬิกาและเพิ่งเริ่มต้นการขัดจังหวะจะล่าช้าอย่างน้อยสองรอบนาฬิกา

  • เหตุการณ์ที่เปิดการขัดจังหวะกลับมา (เช่นการกลับมาจากรูทีนบริการขัดจังหวะ) รับประกันว่าจะดำเนินการคำสั่งอย่างน้อยหนึ่งครั้ง ดังนั้นแม้ว่า ISR จะสิ้นสุดลงและการขัดจังหวะของคุณยังคงค้างอยู่ก็ยังคงต้องรอคำสั่งเพิ่มเติมอีกครั้งก่อนที่จะให้บริการ

  • เนื่องจากการขัดจังหวะมีความสำคัญการขัดจังหวะที่มีลำดับความสำคัญสูงกว่าอาจได้รับการบริการก่อนการขัดจังหวะที่คุณสนใจ


ข้อควรพิจารณาด้านประสิทธิภาพ

การขัดจังหวะสามารถเพิ่มประสิทธิภาพได้ในหลาย ๆ สถานการณ์เพราะคุณสามารถทำงานกับ "งานหลัก" ของโปรแกรมได้โดยไม่ต้องทำการทดสอบอย่างต่อเนื่องเพื่อดูว่ามีการกดสวิตช์หรือไม่ ต้องบอกว่าค่าใช้จ่ายในการให้บริการขัดจังหวะดังที่ได้กล่าวไว้ข้างต้นจะเป็นมากกว่าการทำ "การวนรอบ" ที่แน่นหนาในการสำรวจพอร์ตอินพุตเดี่ยว คุณแทบจะไม่สามารถตอบกลับเหตุการณ์ภายในไมโครวินาทีได้ ในกรณีนี้คุณอาจปิดการใช้งานอินเตอร์รัปต์ (เช่นตัวจับเวลา) และเพียงแค่วนลูปเพื่อหาพินที่จะเปลี่ยน


อินเตอร์รัปต์ถูกจัดคิวอย่างไร

มีการขัดจังหวะสองประเภท:

  • บางคนตั้งค่าสถานะและพวกเขาได้รับการจัดการในลำดับความสำคัญแม้ว่าเหตุการณ์ที่ทำให้พวกเขาหยุด ตัวอย่างเช่นการเพิ่มขึ้นลดลงหรือการเปลี่ยนระดับการขัดจังหวะบนพิน D2

  • คนอื่นจะได้รับการทดสอบก็ต่อเมื่อพวกเขากำลัง "เกิดขึ้น" ตัวอย่างเช่นการขัดจังหวะระดับต่ำบนพิน D2

คนที่ตั้งค่าสถานะอาจถือได้ว่าถูกจัดคิวเนื่องจากสถานะการขัดจังหวะยังคงตั้งค่าจนกว่าจะถึงเวลาที่มีการป้อนประจำการขัดจังหวะซึ่งเวลาที่หน่วยประมวลผลล้างธง แน่นอนเนื่องจากมีเพียงหนึ่งแฟล็กหากเงื่อนไขการอินเตอร์รัปต์เดียวกันเกิดขึ้นอีกครั้งก่อนที่โพรเซสแรกจะถูกประมวลผลมันจะไม่ได้รับการบริการสองครั้ง

สิ่งที่ต้องระวังคือสามารถตั้งค่าสถานะเหล่านี้ก่อนที่คุณจะแนบตัวจัดการขัดจังหวะ ตัวอย่างเช่นเป็นไปได้ที่การขัดจังหวะระดับสูงขึ้นหรือลดลงบนพิน D2 จะเป็น "ตั้งค่าสถานะ" แล้วทันทีที่คุณทำการแนบอินเทอร์รัปต์อินเทอรัปต์จะขัดจังหวะการยิงทันทีแม้ว่าเหตุการณ์จะเกิดขึ้นหนึ่งชั่วโมงก่อนก็ตาม เพื่อหลีกเลี่ยงปัญหานี้คุณสามารถล้างค่าสถานะด้วยตนเอง ตัวอย่างเช่น:

EIFR = bit (INTF0);  // clear flag for interrupt 0
EIFR = bit (INTF1);  // clear flag for interrupt 1

อย่างไรก็ตามอินเตอร์รัปต์ "ระดับต่ำ" จะถูกตรวจสอบอย่างต่อเนื่องดังนั้นหากคุณไม่ระวังพวกเขาก็จะทำการยิงต่อไปแม้ว่าจะมีการเรียกใช้อินเตอร์รัปต์ก็ตาม นั่นคือ ISR จะออกแล้วขัดจังหวะจะยิงอีกครั้งทันที เพื่อหลีกเลี่ยงปัญหานี้คุณควรทำการ detachInterrupt ทันทีหลังจากที่คุณทราบว่ามีการขัดจังหวะ


คำแนะนำสำหรับการเขียน ISR

โดยย่อให้พวกเขาสั้น ๆ ! ในขณะที่ ISR กำลังดำเนินการอินเตอร์รัปต์อื่นไม่สามารถประมวลผลได้ ดังนั้นคุณอาจพลาดการกดปุ่มหรือการสื่อสารแบบอนุกรมขาเข้าได้ง่ายหากคุณพยายามทำมากเกินไป โดยเฉพาะอย่างยิ่งคุณไม่ควรลองทำการดีบั๊ก "พิมพ์" ภายใน ISR เวลาในการทำสิ่งเหล่านั้นมีแนวโน้มที่จะทำให้เกิดปัญหามากกว่าที่พวกเขาแก้

สิ่งที่สมเหตุสมผลที่ต้องทำคือตั้งค่าสถานะไบต์เดียวแล้วทดสอบค่าสถานะนั้นในฟังก์ชันวนรอบหลัก หรือเก็บไบต์ขาเข้าจากพอร์ตอนุกรมลงในบัฟเฟอร์ การจับเวลาแบบ inbuilt ขัดจังหวะการติดตามเวลาที่ผ่านไปโดยการยิงทุกครั้งที่ตัวจับเวลาภายในล้นและทำให้คุณสามารถคำนวณเวลาที่ผ่านไปโดยรู้ว่าตัวจับเวลาล้นมากี่ครั้ง

โปรดจำไว้ว่าภายในการขัดจังหวะ ISR จะถูกปิดใช้งาน ดังนั้นหวังว่าเวลาที่ส่งคืนโดยการเรียกฟังก์ชันมิลลิวินาที () จะเปลี่ยนไปซึ่งจะนำไปสู่ความผิดหวัง ถูกต้องเพื่อให้ได้เวลาตามนั้นเพียงแค่ระวังว่าตัวจับเวลาไม่เพิ่มขึ้น และหากคุณใช้เวลานานเกินไปใน ISR ตัวจับเวลาอาจพลาดเหตุการณ์ล้นทำให้เวลาที่มิลลิวินาที () กลับมาไม่ถูกต้อง

การทดสอบแสดงให้เห็นว่าในโปรเซสเซอร์ 16 MHz Atmega328 การโทรไปยังไมโคร () ใช้เวลา 3.5625 µs การเรียกมิลลิวินาที () ใช้เวลา 1.9375 µs การบันทึก (การบันทึก) ค่าตัวจับเวลาปัจจุบันเป็นสิ่งที่สมเหตุสมผลที่ต้องทำใน ISR การค้นหามิลลิวินาทีที่ผ่านไปนั้นเร็วกว่าไมโครวินาทีที่ผ่านไป (จำนวนมิลลิวินาทีจะถูกดึงจากตัวแปร) อย่างไรก็ตามได้รับการนับไมโครวินาทีโดยการเพิ่มมูลค่าปัจจุบันของตัวจับเวลา Timer 0 (ซึ่งจะเพิ่มขึ้นเรื่อย ๆ ) ให้กับ "Timer 0 overflow count" ที่บันทึกไว้

คำเตือน:เนื่องจากอินเตอร์รัปต์ถูกปิดใช้งานภายใน ISR และเนื่องจาก Arduino IDE รุ่นล่าสุดใช้อินเทอร์รัปต์สำหรับการอ่านและการเขียนแบบอนุกรมและสำหรับการเพิ่มตัวนับที่ใช้โดย "มิลลิวินาที" และ "ล่าช้า" คุณไม่ควรใช้ฟังก์ชั่นเหล่านั้น ภายใน ISR วิธีนำอีกวิธีหนึ่ง:

  • อย่าพยายามชะลอเช่น delay (100);
  • คุณสามารถรับเวลาจากการโทรถึงมิลลิวินาที แต่จะไม่เพิ่มขึ้นดังนั้นอย่าพยายามล่าช้าโดยรอให้เพิ่มขึ้น
  • อย่าพิมพ์ภาพต่อเนื่อง (เช่นSerial.println ("ISR entered");)
  • อย่าพยายามอ่านต่อเนื่อง

ปักหมุดการขัดจังหวะ

มีสองวิธีที่คุณสามารถตรวจจับเหตุการณ์ภายนอกด้วยพินได้ ที่แรกก็คือพิน "การขัดจังหวะภายนอก" พิเศษ D2 และ D3 เหตุการณ์อินเตอร์รัปต์ทั่วไปเหล่านี้ไม่ต่อเนื่องหนึ่งรายการต่อขา คุณสามารถไปที่สิ่งเหล่านั้นได้โดยใช้ AttachInterrupt สำหรับแต่ละพิน คุณสามารถระบุเงื่อนไขที่เพิ่มขึ้นลดลงเปลี่ยนหรือระดับต่ำสำหรับการขัดจังหวะ

อย่างไรก็ตามยังมี "การเปลี่ยนพิน" ขัดจังหวะสำหรับพินทั้งหมด (ใน Atmega328 ซึ่งไม่จำเป็นต้องใช้พินทั้งหมดในโปรเซสเซอร์อื่น) การกระทำเหล่านี้ในกลุ่มของพิน (D0 ถึง D7, D8 ถึง D13 และ A0 ถึง A5) พวกเขายังมีความสำคัญต่ำกว่าการขัดจังหวะเหตุการณ์ภายนอก อย่างไรก็ตามพวกเขาจะใช้เที่ยวยุ่งยิ่งกว่าอินเตอร์รัปต์เล็กน้อยเพราะจัดกลุ่มเป็นแบตช์ ดังนั้นหากสัญญาณขัดจังหวะการยิงคุณต้องทำงานในรหัสของคุณเองว่าขาไหนทำให้เกิดการขัดจังหวะ

รหัสตัวอย่าง:

ISR (PCINT0_vect)
 {
 // handle pin change interrupt for D8 to D13 here
 }  // end of PCINT0_vect

ISR (PCINT1_vect)
 {
 // handle pin change interrupt for A0 to A5 here
 }  // end of PCINT1_vect

ISR (PCINT2_vect)
 {
 // handle pin change interrupt for D0 to D7 here
 }  // end of PCINT2_vect


void setup ()
  {
  // pin change interrupt (example for D9)
  PCMSK0 |= bit (PCINT1);  // want pin 9
  PCIFR  |= bit (PCIF0);   // clear any outstanding interrupts
  PCICR  |= bit (PCIE0);   // enable pin change interrupts for D8 to D13
  }

หากต้องการจัดการการขัดจังหวะการเปลี่ยนพินคุณต้อง:

  • ระบุหมุดที่อยู่ในกลุ่ม นี่คือตัวแปร PCMSKn (โดยที่ n คือ 0, 1 หรือ 2 จากตารางด้านล่าง) คุณสามารถขัดจังหวะมากกว่าหนึ่งพิน
  • เปิดใช้งานกลุ่มอินเทอร์รัปต์ที่เหมาะสม (0, 1 หรือ 2)
  • จัดหาตัวจัดการขัดจังหวะตามที่แสดงด้านบน

สารบัญ -> พินเปลี่ยนชื่อ / มาสก์

D0    PCINT16 (PCMSK2 / PCIF2 / PCIE2)
D1    PCINT17 (PCMSK2 / PCIF2 / PCIE2)
D2    PCINT18 (PCMSK2 / PCIF2 / PCIE2)
D3    PCINT19 (PCMSK2 / PCIF2 / PCIE2)
D4    PCINT20 (PCMSK2 / PCIF2 / PCIE2)
D5    PCINT21 (PCMSK2 / PCIF2 / PCIE2)
D6    PCINT22 (PCMSK2 / PCIF2 / PCIE2)
D7    PCINT23 (PCMSK2 / PCIF2 / PCIE2)
D8    PCINT0  (PCMSK0 / PCIF0 / PCIE0)
D9    PCINT1  (PCMSK0 / PCIF0 / PCIE0)
D10   PCINT2  (PCMSK0 / PCIF0 / PCIE0)
D11   PCINT3  (PCMSK0 / PCIF0 / PCIE0)
D12   PCINT4  (PCMSK0 / PCIF0 / PCIE0)
D13   PCINT5  (PCMSK0 / PCIF0 / PCIE0)
A0    PCINT8  (PCMSK1 / PCIF1 / PCIE1)
A1    PCINT9  (PCMSK1 / PCIF1 / PCIE1)
A2    PCINT10 (PCMSK1 / PCIF1 / PCIE1)
A3    PCINT11 (PCMSK1 / PCIF1 / PCIE1)
A4    PCINT12 (PCMSK1 / PCIF1 / PCIE1)
A5    PCINT13 (PCMSK1 / PCIF1 / PCIE1)

การประมวลผลตัวจัดการขัดจังหวะ

ตัวจัดการอินเทอร์รัปต์จะต้องตรวจสอบว่าพินใดทำให้เกิดการขัดจังหวะหากมาสก์ระบุมากกว่าหนึ่ง (เช่นหากคุณต้องการอินเตอร์รัปต์บน D8 / D9 / D10) ในการทำเช่นนี้คุณจะต้องเก็บสถานะก่อนหน้าของพินนั้นและทำงาน (โดยทำ digitalRead หรือคล้ายกัน) หากพินนี้มีการเปลี่ยนแปลง


คุณอาจใช้อินเทอร์รัปต์อยู่ดี ...

สภาพแวดล้อม "ปกติ" ของ Arduino นั้นใช้อินเทอร์รัปต์อยู่แล้วแม้ว่าคุณจะไม่ได้พยายามก็ตาม การเรียกใช้ฟังก์ชัน millis () และ micros () ใช้ประโยชน์จากคุณสมบัติ "ตัวจับเวลาล้น" หนึ่งในตัวจับเวลาภายใน (ตัวจับเวลา 0) ถูกตั้งค่าให้ขัดจังหวะประมาณ 1,000 ครั้งต่อวินาทีและเพิ่มตัวนับภายในซึ่งจะกลายเป็นตัวนับมิลลิวินาทีได้อย่างมีประสิทธิภาพ มันมีอะไรที่มากกว่านั้นอีกเล็กน้อยเนื่องจากมีการปรับตามความเร็วสัญญาณนาฬิกาที่แน่นอน

นอกจากนี้ไลบรารีอนุกรมฮาร์ดแวร์ยังใช้การขัดจังหวะเพื่อจัดการข้อมูลอนุกรมขาเข้าและขาออก สิ่งนี้มีประโยชน์มากเพราะโปรแกรมของคุณสามารถทำสิ่งอื่น ๆ ในขณะที่สัญญาณขัดจังหวะการทำงานและการเติมบัฟเฟอร์ภายใน จากนั้นเมื่อคุณตรวจสอบ Serial.available () คุณสามารถค้นหาสิ่งที่มีอยู่ในบัฟเฟอร์นั้น


ดำเนินการคำสั่งถัดไปหลังจากเปิดใช้งานการขัดจังหวะ

หลังจากการพูดคุยและการวิจัยในฟอรัม Arduino เราได้ชี้แจงว่าเกิดอะไรขึ้นหลังจากที่คุณเปิดใช้งานอินเตอร์รัปต์ มีสามวิธีหลักที่ฉันสามารถนึกได้ว่าคุณสามารถเปิดใช้งานการขัดจังหวะซึ่งก่อนหน้านี้ไม่ได้เปิดใช้งาน:

  sei ();  // set interrupt enable flag
  SREG |= 0x80;  // set the high-order bit in the status register
  reti  ;   // assembler instruction "return from interrupt"

ในทุกกรณีตัวประมวลผลรับประกันว่าคำสั่งถัดไปหลังจากเปิดใช้งานอินเทอร์รัปต์ (หากปิดใช้งานก่อนหน้านี้) จะถูกดำเนินการเสมอแม้ว่าเหตุการณ์อินเตอร์รัปต์จะค้างอยู่ (โดย "ถัดไป" ฉันหมายถึงลำดับถัดไปในลำดับของโปรแกรมไม่จำเป็นต้องเป็นหนึ่งในการติดตามตัวอย่างเช่นคำสั่ง RETI กระโดดกลับไปยังตำแหน่งที่อินเตอร์รัปต์เกิดขึ้น

นี่ให้คุณเขียนโค้ดแบบนี้:

sei ();
sleep_cpu ();

หากไม่ใช่สำหรับการรับประกันนี้การขัดจังหวะอาจเกิดขึ้นก่อนที่โปรเซสเซอร์จะหลับแล้วจะไม่ถูกปลุก


อินเตอร์รัปต์ว่างเปล่า

หากคุณต้องการให้อินเทอร์รัปต์ปลุกตัวประมวลผล แต่ไม่ทำอะไรเป็นพิเศษคุณสามารถใช้คำสั่ง EMPTY_INTERRUPT เช่น

EMPTY_INTERRUPT (PCINT1_vect);

สิ่งนี้จะสร้างคำสั่ง "reti" (กลับมาจากการขัดจังหวะ) เนื่องจากไม่ได้พยายามบันทึกหรือกู้คืนการลงทะเบียนจึงเป็นวิธีที่เร็วที่สุดในการหยุดชะงักเพื่อปลุก


ส่วนที่สำคัญ (การเข้าถึงตัวแปรอะตอมมิก)

มีปัญหาเล็กน้อยเกี่ยวกับตัวแปรที่ใช้ร่วมกันระหว่างรูทีนการบริการขัดจังหวะ (ISR) และรหัสหลัก (นั่นคือรหัสไม่ได้อยู่ใน ISR)

เนื่องจาก ISR สามารถเริ่มทำงานได้ตลอดเวลาเมื่อมีการเปิดใช้งานอินเทอร์รัปต์คุณจึงต้องระมัดระวังเกี่ยวกับการเข้าถึงตัวแปรที่แชร์ดังกล่าวเนื่องจากอาจมีการอัปเดตในขณะที่คุณเข้าถึงพวกเขา

ก่อน ... คุณใช้ตัวแปร "ระเหย" เมื่อใด

ตัวแปรควรถูกทำเครื่องหมายความผันผวนหากมีการใช้ทั้งภายใน ISR และภายนอก

  • ตัวแปรเพียงใช้นอก ISR ควรไม่ได้มีความผันผวน
  • ตัวแปรเพียงใช้ภายใน ISR ควรไม่ได้มีความผันผวน
  • ตัวแปรที่ใช้ทั้งภายในและภายนอก ISR ควรมีความผันผวน

เช่น.

volatile int counter;

การทำเครื่องหมายตัวแปรเป็นความผันผวนจะบอกคอมไพเลอร์ว่าไม่ "แคช" เนื้อหาของตัวแปรในการลงทะเบียนโปรเซสเซอร์ แต่ควรอ่านจากหน่วยความจำเสมอเมื่อจำเป็น นี่อาจทำให้การประมวลผลช้าลงซึ่งเป็นเหตุผลว่าทำไมคุณไม่ทำให้ตัวแปรแปรผันทุกอย่างเมื่อไม่ต้องการ

ปิดการขัดจังหวะขณะเข้าถึงตัวแปรระเหย

ตัวอย่างเช่นในการเปรียบเทียบcountกับบางหมายเลขให้ปิดการขัดจังหวะในระหว่างการเปรียบเทียบในกรณีcountที่ ISR หนึ่งไบต์ได้รับการอัปเดตโดย ISR ไม่ใช่ไบต์อื่น

volatile unsigned int count;

ISR (TIMER1_OVF_vect)
  {
  count++;
  } // end of TIMER1_OVF_vect

void setup ()
  {
  pinMode (13, OUTPUT);
  }  // end of setup

void loop ()
  {
  noInterrupts ();    // <------ critical section
  if (count > 20)
     digitalWrite (13, HIGH);
  interrupts ();      // <------ end critical section
  } // end of loop

อ่านแผ่นข้อมูล!

ข้อมูลเพิ่มเติมเกี่ยวกับการขัดจังหวะตัวจับเวลาและอื่น ๆ สามารถรับได้จากแผ่นข้อมูลสำหรับโปรเซสเซอร์

http://www.atmel.com/images/Atmel-8271-8-bit-AVR-Microcontroller-ATmega48A-48PA-88A-88PA-168A-168PA-328-328P_datasheet_Complete.pdf


ตัวอย่างเพิ่มเติม

ข้อควรพิจารณาเกี่ยวกับพื้นที่ (จำกัด ขนาดโพสต์) ป้องกันการแสดงตัวอย่างโค้ดของฉัน สำหรับโค้ดตัวอย่างเพิ่มเติมโปรดดูที่หน้าของฉันเกี่ยวกับการขัดจังหวะ


การอ้างอิงที่มีประโยชน์มากนั่นคือคำตอบที่รวดเร็วน่าประทับใจ
Dat Han Bag

มันเป็นคำถามอ้างอิง ฉันมีคำตอบที่เตรียมไว้และมันจะเร็วขึ้นถ้าคำตอบไม่ได้ยาวเกินไปดังนั้นฉันต้องตัดมันกลับ ดูเว็บไซต์ที่เชื่อมโยงสำหรับรายละเอียดเพิ่มเติม
Nick Gammon

เกี่ยวกับ "โหมดสลีป" นั้นมีประสิทธิภาพในการทำให้ Arduino นอนหลับได้หรือไม่ถ้าอย่างนั้น 500ms?
Dat Ha

@Nick Gammon ฉันเดาว่าการเปิดหรือปิดเครื่อง (ด้วยระบบอัตโนมัติหรือไม่) สำหรับซีพียูนั้นสามารถกำหนดได้ว่าเป็นการขัดจังหวะแบบไม่เป็นทางการ - หากคุณต้องการทำเช่นนั้น "ฉันมีคำตอบที่เตรียมไว้" - คุณเพิ่งใช้เวทย์มนตร์ทั้งหมดในช่วงเวลานั้นที่ฉันคิดว่ามันมี
Dat Han Bag

1
ฉันกลัวว่าไม่เป็นความจริง ฉันมีตัวอย่างที่ใช้การขัดจังหวะการเปลี่ยนพินเพื่อปลุกจากโหมดปิดเครื่อง นอกจากนี้ตามที่ฉันพูดถึงในหน้าของฉันเกี่ยวกับการขัดจังหวะ Atmel ได้ยืนยันว่าการขัดจังหวะภายนอกใด ๆ จะปลุกโปรเซสเซอร์ (เช่นการเพิ่มขึ้น / ลดลง / เปลี่ยนและต่ำ)
Nick Gammon
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.