חכו רגע עם הקריאה האנלוגית

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

הערה מסתורית בקוד המקור של analogRead
הערה מסתורית בקוד המקור של analogRead

להערה המוזרה בקוד, שמופיעה בצילום המסך למעלה, אגיע בהמשך. ראשית, בואו נדבר על הפקודה analogRead. במטרה להפוך את הפונקציות של הארדואינו לידידותיות למשתמש המתחיל, המתכננים שלהן יצרו מעין הקבלה בין הפן הדיגיטלי לפן האנלוגי. זה מתחיל בסימון ומספור הפינים עצמם כ"דיגיטליים" או "אנלוגיים", וממשיך בצורת התפעול הזהה בקוד (read ו-write). צורת ההתייחסות הזו גורמת לאחת מאי-ההבנות הנפוצות אצל מתחילים, שחושבים שפינים "אנלוגיים" מתאימים לקריאות אנלוגיות בלבד. מה שגרוע עוד יותר הוא שבפועל, תהליך הקריאה של מתח אנלוגי הוא מורכב יחסית וההתייחסות הפשטנית אליו קורסת כשמנסים לעשות משהו מתקדם, למשל לקרוא מידע משניים או יותר מקורות שונים.

מבנה ה-ADC

מודול ה-ADC (ממיר אנלוגי לדיגיטלי, Analog to Digital Converter) הוא מודול עצמאי בתוך המיקרו-בקר. הוא נמצא במקום עמוק יותר, כביכול, מהקלט והפלט הדיגיטליים, ומצויד ב-Multiplexer – מנגנון שמאפשר לו להתחבר ולהאזין בכל רגע נתון רק לפין אחד מתוך תת-קבוצה מוגדרת של הפינים הדיגיטליים.

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

לא כל עכבה לטובה

ה"פחות או יותר" הזה הוא הקאץ', מכיוון שגם טעינה של קבל לוקחת זמן. אם נגיד ל-ADC להתחבר לקו מסוים ומיד לאחר מכן נבקש מדידה, יש סיכוי שהקבל לא יספיק להיטען (או להיפרק) כמו שצריך ונקבל תוצאה שגויה. הבעיה הזו תחמיר ככל שהעכבה (impedance) של מקור המתח הנמדד גדולה יותר. לצורך העניין, אפשר לחשוב על העכבה כאן כמו על התנגדות: ככל שההתנגדות גדולה יותר, כך הזרם לקבל או ממנו יהיה קטן יותר וזמן הטעינה יתארך.

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

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

הדגמה חיה

למזלם של החובבים (ושל מפתחי ארדואינו) המיקרו-בקר ATmega328 מסתדר לא רע גם בלוח זמנים צפוף. כדי לבדוק את הנושא בשטח, כתבתי תוכנית קטנה לארדואינו שקוראת משני מקורות (A ו-B) בזה אחר זה, וכותבת למוניטור הסריאלי את תוצאת המדידה ממקור B בלבד. אל הפין המתאים ל-B חיברתי מחלק מתח קבוע, של שני נגדים בערך 10K. התוצאה העקבית מאד בפלט היתה 511 – צפוי והגיוני. ברגע ששיחקתי עם המקור של A, חיברתי וניתקתי אותו מ-5V, הופיעו קפיצות קטנות במדידה של B, כפי שאפשר לראות בצילום המסך הבא (לחצו להגדלה):

סטיות במדידת מתח אנלוגי בעקבות שינויים במתח על פין אחר
סטיות במדידת מתח אנלוגי בעקבות שינויים במתח על פין אחר

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

תוספת מאוחרת: בדקתי את אותו מעגל עם נגדים גדולים, וההבדל לא היה גדול כפי שציפיתי – הוא התחיל להיות משמעותי רק כשההתנגדות נמדדה במגה-אוהמים. בעיון נוסף בקוד המקור של ספריות הליבה של ארדואינו, בקובץ wiring.c, זיהיתי כוונון של ה-ADC לתדר של 125KHz. ייתכן שזה מספיק כדי להתמודד גם עם עכבות גדולות יחסית.

להרשמה
הודע לי על
0 Comments
Inline Feedbacks
הראה את כל התגובות