PIC בהפתעה #2: עולים על הגל

בפוסט זה אראה כיצד גורמים למיקרו-בקר מדגם PIC16F616 להפיק גל ריבועי בתדר 38KHz, השימושי כזכור לתשדורות באינפרה-אדום (IR), באמצעות מודול ה-PWM המובנה בחומרה. זה נשמע טכני וזה באמת טכני – אבל אם יום אחד תצטרכו לממש PWM ב-PIC, אתם תגידו לי תודה על הפוסט הזה…

הצלחה! אות PWM על הסקופ והג'וק שיוצר אותו
הצלחה! אות PWM בתדר הנכון על הסקופ והג'וק שיוצר אותו

סיפורנו הפעם מתחיל במעגלים המודפסים שהשגתי, עם מיקרו-בקרים מדגם PIC16F616. כמה מהלוחות היו פגומים, פיזית, באופן שמנע כל יכולת להשתמש בהם, אז הלחמתי החוצה בזהירות את המיקרו-בקרים (שהגיעו בתצורת SOIC), וכדי שאוכל גם לעשות איתם משהו חוץ מאשר להסתכל עליהם, הזמנתי באיביי מתאמי SOIC-14 ל-DIP. עשרה מתאמים כאלה עלו כשלושה דולרים, וכל אחד מהם הוא דו-צדדי – אפשר להלחים אליו גם ג'וקים בתצורת TSSOP-14 הזעירה.

הג'וק (במארז SOIC-14) והמתאמים ל-DIP
הג'וק (במארז SOIC-14) והמתאמים ל-DIP

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

הג'וק מולחם למתאם, מהבהב ב-LED כאילו אין מחר
הג'וק מולחם למתאם, מהבהב ב-LED כאילו אין מחר

ניסוי מתקדם יותר

המטרה כעת היתה, כאמור, להפיק מהחומרה אות PWM בתדר 38KHz. רציתי לעשות משהו ישירות עם החומרה (בניגוד לקוד שינסה לתזמן "ידנית" את שינויי המתח בפין) כי זה חוסך משאבי עיבוד למיקרו-בקר, וחסכון כזה יכול להיות שימושי ואפילו חיוני במקרים מסוימים; ורציתי דווקא PWM כי אות כזה יכול לעזור במגוון רחב של יישומים – מנועים, צלילים, אותות דמויי-אנלוגיים, IR ועוד. תרגיל כזה יכול היה להתאים לסדרת "הלו פיק", פרט לעניין אחד קטן – למיקרו-בקר PIC12F675 שמוצג שם בכלל אין מודול PWM בחומרה…

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

שלב 1: תדר

אופן ההגדרה והפעולה של PWM ב-PIC שונה מזה שב-AVR. בג'וק הספציפי הזה, ה-PWM בחומרה קשור תמיד לטיימר Timer2 (בן 8 ביט), והפעולה הראשונה שאנחנו צריכים לעשות – לפחות מבחינה לוגית, לאו דווקא בסדר הפקודות בקוד – זה לגרום ל-Timer2 לתקתק בתדר של אות ה-PWM הרצוי לנו. בשלב זה מדובר על התדר המלא, מפסגה לפסגה; על ה-Duty Cycle נדבר בהמשך.

נניח שאני קובע שהמיקרו-בקר יעבוד עם המתנד הפנימי כמקור שעון, בתדר של 8MHz. ב-PIC האלה, כידוע, כל פעולה דורשת 4 מחזורי שעון, וזה כולל את הספירה של הטיימר, כך שבעצם מבחינה מעשית אנחנו מדברים כאן על 2MHz. תדר ה-PWM הרצוי לי הוא 38KHz. נחלק את הערך הראשון בשני ונקבל תוצאה מעוגלת של 53. מכיוון שהספירה בטיימר מתחילה מ-0 ולא מ-1, ניתן את הערך הזה מינוס 1 לרגיסטר PR2, שהוא כביכול "הסף העליון" של Timer2. בכל פעם שהמונה של הטיימר (שנקרא TMR2) יגיע לערך הזה, הוא יתאפס.

ההפעלה של הטיימר מתבצעת על ידי "הדלקה" של הביט TMR2ON שברגיסטר T2CON. בשני הביטים האחרונים (T2CKPS1/0) של אותו רגיסטר אנחנו קובעים את המחלק (Prescaler) של הטיימר. אלה אמנם שני ביטים, אבל הם מספקים רק שלוש אפשרויות. אנחנו צריכים את הראשונה (ללא חילוק) ולכן נכתוב בשני הביטים האלה 0.

הגדרת ה-Prescaler של Timer2 (מתוך ה-datashhet)
הגדרת ה-Prescaler של Timer2 (מתוך ה-datashhet)

שלב 2: Duty Cycle

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

קודם כל, נחשב את הסף העליון של הטיימר, PR2, בסקאלה החדשה:

= PR2 / 255 * 1023

במקרה שלנו, התוצאה המעוגלת היא 209. כלומר, המחזור השלם אורכו 209, ואנחנו צריכים להחליט כמה מתוך זה יהיה HIGH. אם מחזור הפעילות (Duty Cycle) הרצוי הוא 50%, הערך המתאים הוא חצי של 209, כלומר 104 או 105 מעוגל. אגב, שימו לב שככל שהתדר מהיר יותר (PR2 קטן יותר), כך הרזולוציה שאפשר להשיג בהגדרת ה-Duty Cycle יורדת.

נניח שבחרנו ב-105. איפה כותבים את הערך הזה? ובכן, מכיוון שהוא בסקאלה של 0-1023, כלומר 10 ביט, הוא מתחלק בין שני רגיסטרים: 8 הביטים הגבוהים נכתבים ל-CCPR1L, והשניים הנמוכים נכתבים לביטים מס' 5 ו-4 ברגיסטר CCP1CON. ביטים אלה נקראים גם DC1B1 ו-DC1B0. נכון פשוט?

שלב 3: פינים

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

ב-PIC16F616, יש רק פין אחד שיכול לתת לנו אות PWM חומרה עצמאי בלי להפריע לשום דבר אחר: פין RC5. לא ניכנס כאן לפרטים, מספיק לומר שאנחנו רוצים כאן מצב Single Output, ומגיעים אליו על ידי הגדרת זוג הביטים P1M1/0 (מס' 7 ו-6 ב-CCP1CON) כ-0. כמו כן, צריך לקבוע שפין זה יהיה Output, וזאת על ידי איפוס הביט המתאים ברגיסטר TRISC.

בנוסף, מודול החומרה שאחראי ל-PWM נקרא ECCP, על שם כל הפונקציות שהוא יכול למלא: Enhanced Capture/Compare/PWM, ואנחנו צריכים להגיד לו להתרכז עכשיו ספציפית ב-PWM. את זה עושים עם ארבעת הביטים האחרונים של CCP1CON, שנקראים CCP1M3-0. הם מאפשרים מספר הגדרות PWM שמתייחסות להיפוך של האות בפינים השונים שיכולים להיות קשורים לעניין. מכיוון שאנחנו עובדים ב-Single Output ולא צריכים שום היפוך, ניתן לביטים האלה את הערך הבינארי 1100.

ברגע שבחרנו מצב PWM, ניהול המתח בפין הפלט מתבצע אוטומטית: בכל פעם שהטיימר מתאפס הפין עובר למצב HIGH, ובכל פעם שהוא מגיע לסף שהגדרנו עבור ה-Duty Cycle הוא יורד ל-LOW.

קדימה לקוד

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

void main() {

   TRISC = 0; // all C pins output
   PR2 = 52; // Closest to 52.631579 - 1...
   // Ratio = PR2 / 255 * 1023 = 209
   // We want half for 50% duty cycle, so 105
   // In binary that's 11010-01

   // PWM single output     : 00
   // +LSBs of duty cycle   : 01
   // +PWM mode,            : 11
   // +PWM pins active-High : 00, and together:
   CCP1CON = 0x2C;
   
   CCPR1L = 0x1A; // MSBs of duty cycle

   T2CON = 4; // prescaler = 1, timer on
   
   while (1) {} 

}

קוד זה מפיק את הסיגנל היציב והיפה שמופיע בתמונה העליונה.

סיכום

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

ועוד דבר אחד קטן: אם תדר השעון הפנימי של ה-PIC מזייף מעט, אפשר להיעזר ברגיסטר OSCTUNE כדי לכוונן אותו לתדר הרצוי. גם כאן, זה עובד אחרת מאשר הרגיסטר OSCCAL של AVR שהזכרתי בפוסט הזה. חפשו אותו ב-datasheet אם זה מעניין אתכם.

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