הלו טייני #4: המרת ADC בסיסית

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

בקלט/פלט הדיגיטלי הכל מסתכם בשלושה בייטים עם תפקידים מוגדרים וברורים (DDRB, PORTB ו-PINB). הקלט האנלוגי, לעומת זאת, הוא פרוצדורה מורכבת. אבל זה לא סתם מרוע לב – למעשה, יש לזה סיבה טובה מאד: המנגנון שפועל מאחורי הקלעים כדי לאפשר את הקלט האנלוגי הוא בעצמו מסובך, והלבישו עליו כל כך הרבה אפשרויות ויכולות, עד שגם השליטה בהן חייבת להיות מורכבת.

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

הצצה לחומרה

לשבב הטייני יש ארבעה פינים שמהם אפשר לקרוא קלט אנלוגי. לפי מספור הפינים החיצוני, אלו הם 1, 7, 3 ו-2. הכינויים שלהם הם ADC0 עד ADC3, בהתאמה, והם חופפים לכינויים PB5 (פין האתחול), PB2 ו-PB4/3. כלומר, כל עוד אנחנו שומרים את PB5 למטרות Reset, יש לנו למעשה רק 3 פינים זמינים לקלט אנלוגי. בנוסף, אפשר לקבל קלט לקריאה אנלוגית מחיישן הטמפרטורה הפנימי (שנקרא גם ADC4) וממתח פנימי קבוע של כ-1.1V, שנקרא VBG.

בניגוד לקלט הדיגיטלי, שמתבצע בפינים השונים בו-זמנית, הקלט האנלוגי מבוסס על מודול חומרה פנימי שמסוגל לטפל במשימה אחת בכל פעם. המודול הזה יכול לגשת, כאמור, לכל אחד ממספר מקורות קלט – ויש לו גם מספר אופציות לבחירת המתח החשמלי שאליו הקלט יושווה: המתח שהמיקרו-בקר עצמו מקבל, מתח חיצוני כלשהו שמגיע לפין AREF (פין מס' 5, או PB0), מתח פנימי של 1.1 וולט או מתח פנימי של 2.56 וולט. כל זה דומה מאד למה שמתרחש בפונקציית הארדואינו analogReference.

בחירת מקור קלט ומתח להשוואה

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

פירוט הביטים ברגיסטר ADMUX

פירוט הביטים ברגיסטר ADMUX (לחצו להגדלה)

לדוגמה, אם נרצה למדוד את מתח הקלט בפין ADC2 ביחס למתח שבפין AREF, הביטים ברגיסטר ADMUX צריכים להיראות כך: 010X0010 (כאשר X מסמל "לא משנה"). שימו לב שקבעתי את הערך של הביט החמישי, ADLAR, ל-0 שהוא ערך ברירת המחדל. ביט זה קובע את סדר הבייטים של תוצאת המדידה (שנשמרת על פני שני בייטים, כפי שנראה בהמשך), וברוב המקרים ברירת המחדל היא מה שאנחנו צריכים.

כיוונון מהירות וביצוע מדידה

מנגנון ההמרה מאנלוגי לדיגיטלי (ובקיצור ADC) פועל לפי שעון, וכדי להשיג דיוק מיטבי נדרש קצב שעון של 50KHz עד 200KHz. זהו קצב שונה ואיטי, בדרך כלל, מזה של שעון המערכת הכללי, ולכן עלינו להגדיר פקטור לחלוקה. הגדרה זו מתבצעת בשלושת הביטים הנמוכים של הרגיסטר ADCSRA. הם נקראים ADPS0-2 (קיצור של Analog to Digital PreScaler), ואפשר לציין בעזרתם, בבסיס בינארי, את הערכים אפס עד שבע. המחלק יהיה שתיים-בחזקת-הערך-המיוצג, פרט לערך 000, שמסיבה לא ברורה נותן גם הוא מחלק של 2.

לדוגמה, אם מהירות השעון הכללי של המיקרו-בקר היא 8MHz, אז מחלק של 64 ישים אותנו במקום מצוין מבחינת ה-ADC, של 125KHz. המספר 64 הוא שתיים בחזקת שש, כך ששלושת הביטים התחתונים של ADCSRA צריכים להיות 110.

פירוט ביטים ברגיסטר ADCSRA

פירוט ביטים ברגיסטר ADCSRA

הביט הגבוה (השביעי) של ADCSRA נקרא ADEN, קיצור של Analog to Digital ENable – כלומר, כאשר הוא 0 מנגנון ה-ADC כבוי, וכדי לבצע קריאות אנלוגיות אנחנו צריכים קודם כל לכתוב אליו 1.

הביט האחרון שמעניין אותנו כרגע ב-ADCSRA הוא הביט השישי, שנקרא ADSC (מ-Start Conversion). כאשר כותבים אליו 1 המדידה מתחילה, וכאשר היא מסתיימת – מה שיכול לקחת 13 מחזורי שעון ADC בדרך כלל, או 25 מחזורים במדידה הראשונה – המיקרו-בקר עצמו משנה את הערך של הביט הזה בחזרה לאפס. זה הסימן עבורנו שהמדידה הסתיימה, ושאפשר לקרוא את התוצאה מרגיסטר התוצאה ADC. שימו לב, מכיוון שהתוצאה היא ברזולוציה של 10 ביטים, ADC הוא למעשה בגודל שני בייטים, שהם 16 ביטים, ולא 8 ביטים כמו רגיסטרים רגילים.

דוגמה מהשטח

התוכנה שרצה בגאדג'ט שבסרטון למעלה מבצעת קריאות אנלוגיות מפין ADC3, בהשוואה למתח האספקה של המיקרו-בקר (Vcc). לכן, בתחילת התוכנית מתבצעות ההגדרות הבאות:

// ADC3, Vcc ref
ADMUX = 3;
// ADC enabled, prescaler is 64
ADCSRA = 1 << ADEN | 6;

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

uint16_t getADCReading() {

 ADCSRA |= 1 << ADSC; // Start
 while (ADCSRA & (1 << ADSC)); // wait for finish
 return ADC; 	

}

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

עד כאן לגבי קריאות אנלוגיות. להתראות בפעם הבאה!

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