שְׁאֵלָה:
תזמון דיוק גבוה בארדואינו לתקשורת סדרתית
user3284376
2014-03-11 14:13:09 UTC
view on stackexchange narkive permalink

אני משתמש ב- Arduino Uno כדי לשלוח מידע על זמן ומתח על היציאה הטורית לפייתון כדי להתוות. עם זאת נראה שתזמוני המרווחים בין חותמות זמן עוקבות הולכים וגוברים עם הזמן, ומשפיעים על העלילה שלי. זה נכון במיוחד כאשר קצב השידור מוגדר ל 9600, שם הפרשי הזמן הראשוניים שלי אולי 1320 ועולים ל 16400 לאחר פרק זמן קצר יחסית. כאשר קצב זה מוגדר למקסימום של 115200 bps השינוי הוא איטי יותר ופחות מורגש, מסביבות 1340 ל- 1500 גם לאחר זמן שליחה יחסית ארוך. כל הזמנים ניתנים במיקרו-שניות.

ברצוני לדעת אם אוכל להפחית או לבטל את האפקט הזה, ואם לא להבין מדוע הוא קיים. קראתי דברים על הפרעות ועיכובים הגורמים לכך, אך אני לא מעריך את המורכבות של האלקטרוניקה בהישג יד ורוצה לדעת:

  1. האם אוכל לקבל דיוק רב יותר בתזמון?
  2. מה גורם לשינוי בתזמון הזה?

הנה מה שיש לי כרגע:

  # כלול <eHealth.h>extern נדיף זמן לא ארוך חתום 0_זרימת_ספירה; fanalog0 צף; int אנלוגי 0; זמן לא חתום בייט serialByte; הגדרת חלל () {Serial.begin (9600);} loop loop () {while (Serial.available () >0) {serialByte = Serial.read (); if (serialByte == 'S') {while (1) {fanalog0 = eHealth.getECG (); // השתמש בטיימר 0 = > 1 סמן כל 4 us time = (timer0_overflow_count << 8) + TCNT0; // המרת מיקרו-שניות. זמן = (זמן * 4); // הדפס בקובץ להדמיה //Serial.print(time); //Serial.print (""); Serial.print (fanalog0,5); Serial.print ("\ n"); אם (Serial.available () >0) {serialByte = Serial.read (); אם (serialByte == 'F') הפסקה; }}}}}  
למה אתה מתכוון ב"מדויק "? הזמנים שנתן הדלפק יהיו מדויקים למדי, מדויקים ועם רזולוציה טובה. האם אתה רוצה שהזמנים יהיו דטרמיניסטיים (כלומר תמיד זהים)?
מתנצל, כן אני מניח שלכך התכוונתי, שההבדל ביניהם יהיה עקבי ואם לא, הסיבה שהם לא
הוסף את חותמת הזמן בסוף המחשב ולא בסוף Arduino, או השתמש במודול RTC (שעון זמן אמת). מודולים של RTC זולים למדי בחנויות אינטרנט שונות, רק וודאו שהחנות מקשרת לגליון הנתונים. שיטה אחרת היא לתכנת טיימר ולהשתמש בשגרת שירות להפסיק כדי לקבל תזמון מדויק באופן סביר.
מה עושה `eHealth.getECG ()`? האם השיחה הזו נמשכת תמיד באותו פרק זמן?
האם תוכל לציין כמה זמן נמשך "פרק זמן קצר יחסית"? האם זה תמיד אותו דבר לאחר הפעלה מחדש של הארדואינו?
getECG () קורא לפונקציה שלוקחת את ערך ה- ECG מאלקטרודות המחוברות לנושא. זהו ערך מתח ופרק זמן קצר כולל בדרך כלל 10 - 15 שניות
פרסום שיטת 'getECG ()' יכול לעזור להסביר את ההתנהגות שאתה צופה. האם זו שיטה שכתבת בעצמך או שקיבלת אותה מספרייה?
למרות שאין לי דברים של א.ק.ג, ניסיתי לשחזר את ההתנהגות שאתה מתאר (והחלפתי את 'getECG ()' בעיכוב פשוט (10) '). ב 9600 bps, לא יכולתי לראות שינוי בתזמון כפי שאתה מתאר.
חותמת זמן בקצה המחשב תהיה טובה להימנע מ"צבירת * שגיאות, אך תוסיף קצת * ריצוד * עקב * האריזות האסינכרוניות * דרך ה- USB הסידורי. אז למרווחים מדויקים בטווח הקצר, עדיף לתקן את חותמת הזמן במקור.
"getECG ()" פשוט ממיר את הערך האנלוגי מאנלוגי 0 לערך מתח בין 0 ל -5, זה חישוב פשוט.
שְׁלוֹשָׁה תשובות:
#1
+4
jippie
2014-03-11 22:16:43 UTC
view on stackexchange narkive permalink

השתמש בטיימר וב- ISR (הפסקת שגרת השירות) כדי להפוך את התזמון למדוייק יותר.

התבונן ב הוכחת הרעיון המתוזמן של 1 ms. הרעיון הוא שיהיה במערכת 'פעימות לב' מדויקות למדי בהן ניתן להשתמש כדי להפעיל אירועים אחרים. ב- PoC משתמשים בו כדי להבהב נורית LED ב- ½ הרץ, אך בעל גישה למשתנים החדשים millisecondCounter ו- secondCounter מאפשר לך להפעיל אירועים בלולאה הראשית באופן שרירותי (אך רגעים מתוזמנים במדויק.

ה- PoC שלך מעניין מאוד אך יש בו פגם (קל לתיקון) בעובדה שהוא קורא ערך של 2 בתים בזמן שהפרעות מופעלות (ב- `loop ()`), ערך זה משתנה על ידי ISR. זה יכול לקרות ש'לולאה () 'קוראת ערך רע (באמצע שינוי על ידי ה- ISR). פרסמתי תגובה בבלוג שלך על כך.
נקודה מעניינת @jfpoilpret שאתה שם, מעולם לא חשבתי על הפרעה המתרחשת במחצית הדרך ואוחזרת את הערך מ- RAM. אני הולך לבדוק את הפירוק הערב ולעדכן את המאמר. אולי סיבה טובה לכתוב גם מאמר אחר: o)
יצרתי דוגמה מ- PoC שלך ויכולתי לראות שהבעיה מתרחשת לפחות אחת ל -10 שניות ב- UNO שלי. אבל כמובן שבמציאות זה תלוי מאוד במה שאתה עושה ב'לולאה () 'שלך: המדגם שלי בדיוק קיבל את ערך המילישניות, התאם אותו לערך הקריאה הקודם ואם ההבדל> 0 (מלבד איפוס הדלפק ל -0), הצג הודעה.
@jfpoilpret מעולם לא שם לב לזה. אני פשוט משתמש בו כדופק כדי לפקח על דלי המזון עבור החתולים שלי ולהפוך הבזק לד כאשר החתולים שלי יתאכזבו ...; o) זה בהחלט ישנה את האופן שבו אני משתמש ב- ISR בעתיד.
קוד @jfpoilpret עודכן. צריך לשבת לכתוב על זה בלוג נחמד. Thnx
למרות ש- Uno משיג רזולוציה של 1ms בקלות, בסיס הזמן שלו בדרך כלל פחות מ 1000 עמודים לדקה. במילים אחרות הוא בדרך כלל נסחף ליותר מ -1 ms לשנייה. זה לא נדיר שאו"ם נסחפים יותר משני בכל עשר דקות.
@UdoKlein לשמירה על זמן מדויק כדאי להשתמש ב- RTC בכל מקרה, אבל 1000 עמודים לדקה זה הרבה בשביל מתנד קריסטל. הייתי מצפה לסדר גודל של 100 עמודים לדקה
ל- UNO אין מתנד קריסטל לבקר. יש בו רק מתנד קריסטל לחיבור הסדרתי. הבקר הראשי מופעל מהדהד. לפיכך הסטייה האופיינית של UNO היא >> 1000 עמודים לדקה. ארדואינו ישנים יותר (עם קריסטל) היו בעבר ~ 30 עמודים לדקה ומעלה.
@UdoKlein http: // arduino.cc / he / uploads / Main / Arduino_Uno_Rev3-schematic.pdf עדיין מראה גביש 16 מגה-הרץ.
זה מראה גביש המחובר לבלוק ATMEGA16U2 ומהוד המחובר ל- ATMEGA328P-PU. ה- 16U2 מיועד לממשק הטורי ה- 328P הוא "הארדואינו". באופן מעניין ש 16U2 יוכל לדחוף את שעונו לשבב אחר, למשל. את 328P.
@UdoKlein חיפשתי את מספר החלק ואני עומד מתוקן. החלטה עיצובית מביכה.
#2
+3
zmo
2014-03-11 20:28:40 UTC
view on stackexchange narkive permalink

אני יכול לחשוב על כמה דברים שיכולים להשפיע על ה"עקביות "של תזמוני הכתיבה הטורית:

  • גודל הנתונים שיש להדפיס

זה יכול להיות הדבר הברור ביותר שיש לחשוב עליו, אך אכן ככל שתדפיס יותר, כך ייקח יותר להתמודד עם זה.

פתרון: פרמט הדפס את המחרוזת למחרוזת באורך ידוע.

  • באמצעות סדרתי שנאגר

ב- unix אתה יכול לגשת ליציאה הסדרתית בצורה מאוצרת או לא מתוקנת. שימוש בדרך המאגר לאורך זמן עשוי להאט אותו מעט ככל שהמאגר מתמלא, בדרך כלל זה קורה כאשר הנתונים נכנסים מהר יותר ממה שאתה קורא אותו ...

פתרון: השתמש בשורה הסדרתית הלא מאופקת ( למשל : ב- Darwin / OSX זה /dev/cu.usbmodemXXX במקום /dev/tty.usbmodemXXX)

  • עדיפות של הטיימרים

נראה שאתה משתמש בהפרעה ל- TC, ול- AVR יש סדרי עדיפויות באופן הטיפול בהפרעות, אני לא יודע את סדר העדיפות של ה- Atmega328, וזה לא אחד מהמאפיינים המתועדים ביותר בסביבה, כך שאני לא יודע כמה בטוח TC0 לעומת הפרעת ה- UART.

פתרון: חפש עוד למעלה בתיעוד / גיליון הנתונים לגבי סדרי עדיפויות להפסיק ושינוי הטיימר במידת צורך ; ו / או לערוך בדיקה מבלי שהטיימר השני יפעל.

  • לנתונים שאתה קורא לוקח זמן רב יותר לקרוא לאורך זמן

מנהלי התקנים צריכים לבצע ממוצע או לבצע פעולות על פני הערכים הקודמים, כך שככל שתמדוד יותר ערכים, כך המאגר יהיה ארוך יותר, וחישוב הערך ייקח יותר זמן עד שתגיע לגודל המרבי של המאגר.

פתרון: התבונן בקוד המקור של הספרייה בה אתה משתמש, או בצע אופטימיזציה, הסר את החשבון אם יש כזה או קח בחשבון את זמן העיבוד ההולך וגדל.

  • הימנעות ממסגרת הארדואינו תקורה

אבל אם אתה באמת רוצה לייעל את התפוקה הסדרתית מהארדואינו, עליך להימנע משימוש בתקורה הארדואינו ... אבל זה פחות אלגנטי ונוח לשימוש.

אני ' אני די בטוח שיש עוד נקודות שחסרות לי, אבל זה הדברים הראשונים שאבדוק לפני שאעמוד הלאה.

HTH

#3
+2
Udo Klein
2014-04-28 13:52:37 UTC
view on stackexchange narkive permalink

הקוד שלך כולל את משך הפלט במדידות הבאות. כך תלוי באורך הפלט תמדוד זמנים שונים. ניתן לתקן זאת על ידי עיצוב לפלט באורך קבוע.

הנושא הבא הוא של- UNO יש בסיס זמן גרוע מאוד. חפש כאן ל השוואה בין סוגי ארדואינו שונים לעומת הפניה לזמן DCF77.

מסקנה: אם אתה זקוק לתזמון מדויק, קבל ארדואינו עם קריסטל או עבור ל- RTC . אני יכול להמליץ ​​בחום על DS3231 / DS3232 RTC מכיוון שאלו בדרך כלל משיגים דיוק של 2 עמודים לדקה מהקופסה.



שאלה ותשובה זו תורגמה אוטומטית מהשפה האנגלית.התוכן המקורי זמין ב- stackexchange, ואנו מודים לו על רישיון cc by-sa 3.0 עליו הוא מופץ.
Loading...