ใช้ millis () และ micros () ภายในรูทีน interrupt


13

เอกสารสำหรับattachInterrupt()พูดว่า:

... millis()อาศัยการขัดจังหวะในการนับดังนั้นมันจะไม่เพิ่มขึ้นภายใน ISR เนื่องจากdelay()ต้องการการขัดจังหวะในการทำงานมันจะไม่ทำงานหากเรียกภายใน ISR micros()ทำงานในขั้นต้น แต่จะเริ่มทำงานผิดปกติหลังจาก 1-2 ms ...

วิธีการที่ไม่micros()แตกต่างจากmillis()(ยกเว้นของหลักสูตรเพื่อความแม่นยำของพวกเขา)? คำเตือนข้างต้นหมายความว่าการใช้micros()ภายในรูทีนการขัดจังหวะเป็นความคิดที่ไม่ดีอยู่เสมอ

บริบท - ฉันต้องการวัดอัตราการเต้นของชีพจรต่ำดังนั้นฉันจึงต้องทริกเกอร์รูทีนเมื่อสัญญาณอินพุทของฉันเปลี่ยนแปลงและบันทึกเวลาปัจจุบัน

คำตอบ:


16

คำตอบอื่น ๆ นั้นดีมาก แต่ฉันต้องการอธิบายอย่างละเอียดเกี่ยวกับวิธีการmicros()ทำงาน มันมักจะอ่านตัวจับเวลาฮาร์ดแวร์ปัจจุบัน (อาจTCNT0) ซึ่งมีการปรับปรุงอย่างต่อเนื่องโดยฮาร์ดแวร์ (ในความเป็นจริงทุก 4 µs เพราะพรีสเกลเลอร์ของ 64) จากนั้นจะเพิ่มการนับจำนวนล้นของตัวจับเวลา 0 ซึ่งอัปเดตโดยตัวจับเวลาล้นการขัดจังหวะ (คูณด้วย 256)

ดังนั้นแม้ใน ISR คุณสามารถพึ่งพาการmicros()อัปเดตได้ อย่างไรก็ตามหากคุณรอนานเกินไปคุณจะพลาดการอัปเดตข้อมูลมากเกินไปและผลลัพธ์ที่ส่งคืนจะลดลง (เช่นคุณจะได้รับ 253, 254, 255, 0, 1, 2, 3 ฯลฯ )

นี่คือmicros()- ลดความซับซ้อนเล็กน้อยเพื่อกำหนดคำจำกัดความของโปรเซสเซอร์อื่น:

unsigned long micros() {
    unsigned long m;
    uint8_t oldSREG = SREG, t;
    cli();
    m = timer0_overflow_count;
    t = TCNT0;
    if ((TIFR0 & _BV(TOV0)) && (t < 255))
        m++;
    SREG = oldSREG;
    return ((m << 8) + t) * (64 / clockCyclesPerMicrosecond());
}

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


TLDR;

  • อย่าทำให้ล่าช้าภายใน ISR
  • ถ้าคุณต้องทำพวกเขาคุณสามารถเวลาแล้วด้วยแต่ไม่micros() millis()ยังdelayMicroseconds()เป็นไปได้
  • อย่าล่าช้าเกิน 500 ors หรือมากกว่านั้นหรือคุณจะพลาดการจับเวลาล้น
  • แม้ความล่าช้าในระยะสั้นอาจทำให้คุณพลาดข้อมูลอนุกรมที่เข้ามา (ที่ 115200 baud คุณจะได้รับตัวละครใหม่ทุก ๆ 87 µs)

ไม่สามารถเข้าใจคำสั่งที่ระบุด้านล่างที่ใช้ในไมโคร () คุณช่วยอธิบายรายละเอียดได้ไหม? เนื่องจากเขียน ISR แล้วจะมีการล้างค่าสถานะ TOV0 ทันทีที่ป้อน ISR ดังนั้นเงื่อนไขด้านล่างอาจไม่เป็นจริง! ถ้า ((TIFR0 & _BV (TOV0)) && (t <255)) m ++;
Rajesh

micros()ไม่ใช่ ISR มันเป็นฟังก์ชั่นปกติ การตั้งค่าสถานะ TOV0 ช่วยให้คุณทดสอบฮาร์ดแวร์เพื่อดูว่าตัวจับเวลาล้นเกิดขึ้น (แต่ยังไม่ได้ประมวลผล)
Nick Gammon

เนื่องจากการทดสอบถูกขัดจังหวะด้วยการปิดคุณจะรู้ว่าการตั้งค่าสถานะจะไม่เปลี่ยนแปลงในระหว่างการทดสอบ
Nick Gammon

ดังนั้นคุณหมายถึงว่าหลังจากฟังก์ชั่น cli () ใน micros () หากมีการล้นใด ๆ เกิดขึ้นจำเป็นต้องตรวจสอบหรือไม่ นั่นทำให้รู้สึก มิฉะนั้นแม้ว่า micros จะไม่ใช่ฟังก์ชัน TIMER0_OVF_vect ISR จะล้าง TOV0 ใน TIFR0 เป็นสิ่งที่ฉันสงสัย
Rajesh

ทำไมจึงเปรียบเทียบ TCNT0 กับ 255 เพื่อดูว่าน้อยกว่า 255 หรือไม่ หลังจาก cli () ถ้า TCNT0 ถึง 255 จะเกิดอะไรขึ้น
Rajesh

8

ไม่ผิดที่จะใช้millis()หรือmicros()ภายในรูทีนการขัดจังหวะ

มันเป็นความผิดที่จะใช้พวกเขาอย่างไม่ถูกต้อง

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

ดังนั้นคุณสามารถโทรmillis()หรือmicros()ค้นหาเวลาปัจจุบันภายใน ISR ของคุณได้อย่างแน่นอน แต่อย่าคาดหวังว่าเวลาจะเปลี่ยน

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

ดังนั้นโดยพื้นฐานmillis()แล้วmicros()จะบอกเวลาที่ISR ของคุณถูกเรียกว่าไม่ว่าใน ISR ของคุณคุณจะใช้มัน


3
ไม่micros()อัปเดต มันจะอ่านการลงทะเบียนตัวจับเวลาฮาร์ดแวร์เสมอ
Nick Gammon

4

วลีที่ยกมาไม่ใช่คำเตือนมันเป็นเพียงคำแถลงเกี่ยวกับการทำงานของสิ่งต่าง ๆ

ไม่มีอะไรผิดปกติกับการใช้งานmillis()หรือmicros()ภายในรูทีนขัดจังหวะที่เขียนอย่างถูกต้อง

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

รูทีนการอินเตอร์รัปต์ที่ใช้เวลามากกว่าสองสามไมโครวินาทีในการทำงานคือในทุกโอกาสที่เขียนไม่ถูกต้อง

ในระยะสั้น: การเขียนอย่างถูกต้องประจำการขัดจังหวะจะไม่ทำให้เกิดปัญหาหรือเผชิญหน้ากับหรือmillis()micros()

แก้ไข: เกี่ยวกับ“ ทำไม micros ()“ เริ่มทำงานผิดปกติ”” ตามที่อธิบายไว้ในหน้าเว็บ“ การตรวจสอบฟังก์ชั่น Arduino microsmicros()โค้ดใน Uno สามัญนั้นเทียบเท่ากับการใช้งาน

unsigned long micros() {
  return((timer0_overflow_count << 8) + TCNT0)*(64/16);
}

สิ่งนี้จะส่งคืนความยาวที่ไม่ได้ลงชื่อสี่ไบต์ประกอบด้วยสามไบต์ต่ำสุดจากtimer0_overflow_countและหนึ่งไบต์จากการลงทะเบียน count-0

timer0_overflow_countจะเพิ่มขึ้นประมาณหนึ่งครั้งต่อมิลลิวินาทีโดยTIMER0_OVF_vectจัดการขัดจังหวะตามที่อธิบายไว้ในการตรวจสอบการทำงานของ Arduino มิลลิวินาทีหน้าเว็บ

ก่อนที่ตัวจัดการขัดจังหวะจะเริ่มต้นขึ้นฮาร์ดแวร์ AVR จะปิดใช้งานการขัดจังหวะ หาก (ตัวอย่าง) ตัวจัดการขัดจังหวะต้องทำงานเป็นเวลาห้ามิลลิวินาทีโดยที่อินเตอร์รัปต์ยังปิดใช้งานอยู่จะมีการพลาดอย่างน้อยสี่ตัวจับเวลา 0 โอเวอร์โฟลว์ [การขัดจังหวะที่เขียนด้วยรหัส C ในระบบ Arduino ไม่ใช่ reentrant (ความสามารถในการจัดการการประมวลผลที่ทับซ้อนกันหลายอย่างภายในตัวจัดการเดียวกัน) แต่สามารถเขียนตัวจัดการภาษาแอสเซมบลี reentrant ที่เปิดใช้งานการขัดจังหวะก่อนเริ่มกระบวนการใช้เวลานาน]

กล่าวอีกนัยหนึ่งตัวจับเวลาล้นไม่ได้“ ซ้อนกัน”; เมื่อใดก็ตามที่มีการล้นเกิดขึ้นก่อนที่การขัดจังหวะจากการโอเวอร์โฟลด์ก่อนหน้าจะได้รับการจัดการตัวmillis()นับจะสูญเสียมิลลิวินาทีและความคลาดเคลื่อนtimer0_overflow_countก็จะทำให้micros()เกิดความผิดพลาดโดยมิลลิวินาทีเช่นกัน

เกี่ยวกับ“ สั้นกว่า 500 μs” เป็นขีด จำกัด เวลาสูงสุดสำหรับการประมวลผลขัดจังหวะ“ เพื่อป้องกันการบล็อกการขัดจังหวะตัวจับเวลาเป็นเวลานานเกินไป” คุณสามารถไปที่ระดับต่ำกว่า 1024 μs (เช่น 1,020 μs) และmillis()ยังคงใช้งานได้ เวลา. อย่างไรก็ตามฉันถือว่าตัวจัดการขัดจังหวะที่ใช้เวลามากกว่า 5 μsเป็นคนเกียจคร้านมากกว่า 10 μsเฉื่อยชามากกว่า 20 μsเหมือนหอยทาก


คุณช่วยอธิบายรายละเอียดเกี่ยวกับ "วิธีการทำงานของสิ่งต่าง ๆ " โดยเฉพาะอย่างยิ่งทำไมmicros()"เริ่มทำงานผิดปกติ" และคุณหมายถึงอะไรโดย "รูทีนการขัดจังหวะอย่างถูกต้อง"? ฉันคิดว่ามันหมายถึง "สั้นกว่า 500us" (เพื่อป้องกันการบล็อกตัวจับเวลาขัดจังหวะนานเกินไป), "ใช้ตัวแปรระเหยสำหรับการสื่อสาร" และ "ไม่เรียกรหัสห้องสมุด" เท่าที่จะทำได้มีอะไรอีกไหม?
Petr Pudlák

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