การรักษาเวลาโดยใช้มิลลิวินาที Arduino ไม่ถูกต้องหรือไม่ถูกต้อง?


9

ฉันใช้ Arduino เพื่อบันทึกข้อมูลบางอย่าง ในร่าง Arduino ของฉันฉันยังใช้millis()ฟังก์ชั่นเพื่อให้ฉันสามารถติดตามเวลาที่แต่ละค่าที่ฉันวัดถูกนำมาใช้ อย่างไรก็ตามฉันสังเกตเห็นว่าเวลาไม่ถูกต้อง ตัวอย่างเช่น 30 วินาทีในชีวิตจริงเท่านั้นออกมาเป็น 10 วินาที (ทำขึ้นตัวอย่าง)

ฉันถูกต้องหรือไม่ในการบอกว่าฟังก์ชั่นการหน่วงเวลา Arduino มีผลต่อการใช้เวลาอย่างต่อเนื่องmillis()หรือไม่? กล่าวอีกนัยหนึ่งสมมติว่าฉันมีความล่าช้า 50 มิลลิวินาทีนั่นหมายความว่าmillis()ฟังก์ชั่นจะหยุดในช่วงเวลานั้นเช่นกันจากนั้นจึงดำเนินการต่อไปเรื่อย ๆ ตลอดระยะเวลาของการเชื่อมต่อหรือไม่ ฉันสังเกตเห็นสิ่งนี้เมื่อฉันพยายามพล็อตข้อมูลบางส่วนและพบว่าความถี่ของยอดเขาในข้อมูลของฉันบ่อยเกินไปตามเวลาที่ผ่านไป ดังนั้นฉันต้องการทราบว่านั่นเป็นเหตุผลสำหรับการไม่ตรงตามกำหนดเวลานี้หรือไม่และถ้าเป็นเช่นนั้นฉันจะแก้ไขได้อย่างไรเพื่อให้สามารถเก็บเวลาแต่ละตัวอย่างได้

เพื่อให้บริบทนี่คือร่างของฉัน:

#include <eHealth.h>    

unsigned long time;
// The setup routine runs once when you press reset:
void setup() {
  Serial.begin(9600);  
}

// The loop routine runs over and over again forever:
void loop() {

  float ECG = eHealth.getECG();
  time = millis();
  Serial.print(time);
  Serial.print(" ");
  Serial.print(ECG, 5); 
  Serial.println("");    

  delay(50);
}

คุณใช้หนึ่งในบอร์ด Uno อย่างเป็นทางการหรือไม่?
Peter Bloomfield

1
เวลาจริงแทนที่จะเป็นค่าที่ทำขึ้น (จอภาพแบบอนุกรมที่มีการประทับเวลาเส้นเหมาะ) อาจช่วยให้ทราบว่าเกิดอะไรขึ้น
Ignacio Vazquez-Abrams

3
การคำนวณของmillis()ถูกขัดจังหวะดังนั้นdelay()ไม่ควรส่งผลกระทบต่อมัน
microtherion

ฉันมีปัญหาเดียวกัน แต่เมื่อฉันรวมมัน (millis ()) เป็นรหัสที่ซับซ้อน ฉันเดาว่าความซับซ้อนของรหัสส่งผลกระทบต่อความถูกต้องของวิธีการที่จะเกิดความล่าช้ามากขึ้นกับความซับซ้อนของรหัส มีวิธีหลีกเลี่ยงปัญหานี้หรือไม่? อาจจะใช้โมดูล RTC แยกต่างหาก?
Josip7171

คำตอบ:


10

millis()ถูกขัดจังหวะการขับเคลื่อนดังนั้นdelay()จะไม่ส่งผลกระทบกับมันอย่างน้อยก็ไม่ได้อยู่บนบอร์ด ATmega

ไม่ได้บอกว่าmillis()ถูกต้องทั้งหมดเช่นกัน เห็บของตัวจับเวลาแต่ละตัวไม่ได้มีค่าเพียง 1 มิลลิวินาที แต่เป็น 1.024 มิลลิวินาที ข้อผิดพลาดนี้จะค่อยๆสะสมจนกว่าจะทำการแก้ไข สิ่งนี้สามารถเห็นได้ในการใช้งานตัวจัดการขัดจังหวะ TIMER0_OVF (ตัวจับเวลา 0 ล้น)

แหล่งที่มาของความไม่ถูกต้องอีกประการหนึ่งคือ oscillator / crystal นั้นซึ่งไม่ได้เป็น 16MHz อย่างแน่นอน มันค่อนข้างใกล้และตราบใดที่อุณหภูมิไม่เปลี่ยนแปลงมากเกินไปก็ค่อนข้างเสถียร

วิธีการดังกล่าวข้างต้นที่คุณอาจจะเกี่ยวกับ 1ms millis()ออกเมื่อใช้ สิ่งนี้ไม่ดูเหมือนปัญหาของคุณ

ปัญหาที่อาจเกิดขึ้นอีกอย่างหนึ่งgetECG()คือสิ่งที่กำลังทำ - อาจช้ามาก

float eHealthClass::getECG(void)
    {
        float analog0;
        // Read from analogic in. 
        analog0=analogRead(0);
        // binary to voltage conversion
        return analog0 = (float)analog0 * 5 / 1023.0;   
    }

analogRead() ช้า แต่ไม่ช้าเท่ากับกระทบลูปแบบนี้

ปัญหาอื่นที่ฉันเคยเห็นผู้คนมีก็คือเมื่อพวกเขาเปลี่ยนความเร็วนาฬิกา แต่ไม่เปลี่ยน boards.txt อย่างถูกต้อง ซึ่งหมายความว่าค่าคงที่ที่ใช้ในการmillis()ปรับใช้ผิดและเวลาผิด

หากคุณต้องการอ่านค่าทุก ๆ 50ms วิธีที่ดีกว่าในการนำไปใช้คือการทำสิ่งต่อไปนี้

static long lastUpdate;

if (millis() - lastUpdate > 50)
{
    lastUpdate = millis();
    //Do stuff
}

เราต้องการเห็นการประทับเวลาที่คุณได้รับจริงๆ หากคุณเห็นว่า 30s แสดงเป็น 10 วินาทีจริง ๆ แล้วก็มีอะไรอีกที่ทำงาน


2
โปรดทราบว่าสำหรับ Uno นาฬิกานั้นไม่ได้ขับเคลื่อนด้วยคริสตัล แต่เพียงใช้ resonator แบบเซรามิกซึ่งมีความแม่นยำน้อยกว่าคริสตัล
jfpoilpret

@jfpoilpret Ah รู้ดี มองไปที่วงจรนี้จะเป็น CSTCE16M0V53-R0 อุปกรณ์ Murata CERALOCK
Chris O

Resonators มีความทนทานเริ่มต้นที่ไม่ดี (มักจะ 0.5-2%) และความเสถียรของอุณหภูมิที่ไม่ดี แต่ถ้าคุณปรับเทียบเวลาลูปเมื่อใช้พวกมันพวกเขาสามารถปรับได้ตราบใดที่อุณหภูมิไม่ขยับ
Cybergibbons

2
Millis () ยังคงทำงานในตัวจับเวลาที่ทำเครื่องหมายทุก 1.024ms แต่พวกเขาเพิ่มการชดเชยข้อผิดพลาดในรูปแบบของการเพิ่มขึ้นเมื่อใดก็ตามที่ตัวแปรเมตรข้อผิดพลาดได้รับสูงเกินไป ฉันคิดว่ามันเป็นอัลกอริทึมของ Roman Black จริง ๆ แล้ว ดังนั้นเวลาควรใกล้เคียงกับ 1ms มาก ๆ github.com/arduino/Arduino/blob/master/hardware/arduino/cores/…
EternityForest

สำหรับผู้ที่ยังคงสนใจดูความคิดเห็นที่ฉันโพสต์ในคำตอบของ JRobert ฉันไม่ต้องการตอบด้วยคำตอบของตัวเองตั้งแต่ฉันไม่มีสักคำฉันเพิ่งจะแก้ปัญหาใหม่
user3284376

2

หากมีการปิดอินเทอร์รัปต์สำหรับeHealth.getECG()ช่วงเวลาการโทรในส่วนที่สำคัญการmillis()นับจำนวนอาจล้มเหลว มิฉะนั้นmillis()ควรส่งคืนเวลาที่แม่นยำมากกว่าข้อผิดพลาด 3x ที่คุณอธิบาย

คุณกล่าวว่าสัญญาณตัวอย่างของคุณมีความถี่สูงกว่าที่คาดไว้ซึ่งอาจเกิดขึ้นได้หากอัตราตัวอย่างต่ำกว่าที่คุณต้องการ คุณเป็นตัวอย่างอัตรา 20Hz หรือไม่? การวนซ้ำของคุณอาจใช้เวลานานกว่า 50ms เล็กน้อยซึ่งคุณจะเห็นในเวลาที่พิมพ์ แต่สิ่งเหล่านั้นยังควรติดตามเวลาของนาฬิกา หากคุณไม่ได้คำนึงถึงสิ่งนั้น แต่สันนิษฐานว่า 50ms / ตัวอย่างคุณจะเห็นข้อมูลที่ชัดเจนขึ้น

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


1
ฉันได้เล่นกับมันต่อไปและได้ตระหนักว่าปัญหาไม่ได้อยู่กับ Arduino, ฟังก์ชั่น millis () สำหรับส่วนใหญ่ทำงานได้ดีมากค่าบางอย่างไม่แตกต่างกัน 8ms (ล่าช้า) แต่จากสิ่งที่ คุณบอกว่าจะต้องคาดหวัง ข้อผิดพลาด 3x ที่ฉันอธิบายนั้นเป็นจริงของด้าน Python ของสิ่งที่ฉันใช้เพื่อรับข้อมูล ความคิดใด ๆ ที่อาจเป็นผลมาจากฉันใช้ Python Pyserial และมันช้าเหมือนนรก
user3284376

ฉันไม่รู้เกี่ยวกับการใช้งานของคุณมากพอที่จะให้คุณมากกว่า 1/2 @ 'เดา แต่ด้าน Python ช้าพอที่จะวางตัวอย่าง?
JRobert

0

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


1
"เหมือนกันที่นี่" หมายถึงอะไร? รู้รอบควรอยู่ด้วยตัวเองเนื่องจาก StackExchange สามารถเรียงลำดับสิ่งต่าง ๆ ได้ (ต่างจากฟอรัม) ดังนั้น "เหมือนกันที่นี่" อาจหมายถึงอะไรก็ได้ขึ้นอยู่กับการตอบ / คำถามที่คำตอบของคุณปรากฏใต้
Nick Gammon

โพสต์นี้จะเหมาะสมกว่าเป็นความคิดเห็นแม้ว่า (เป็นที่ยอมรับ) คุณไม่มีชื่อเสียงเพียงพอ
Greenonline

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