הלו פיק #2: קלט ופלט דיגיטליים

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

מעגל "מנעול הקוד"
מעגל "מנעול הקוד"

תיאור המערכת

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

כל אחד מהלחצנים ייצג מספר אחר – נניח 1, 2 ו-4 (למה דילגתי על 3? כדי לקבל את הערכים הבינאריים ה"נקיים" 001, 010 ו-100 שתואמים את הביטים של פיני הקלט השונים, כפי שתראו מיד). נגדיר בתוכנה שלנו "קוד סודי", רצף כלשהו שמורכב משלושת המספרים הללו. כל עוד הרצף הזה לא הוקש במלואו, הלד האדום ידלוק; עם השלמת הרצף, הלד האדום יכבה והלד הירוק ידלוק למשך שניה אחת, ושוב מהתחלה.

למען הסדר והנוחות, נחבר את הקלט משלושת הלחצנים לפינים GP0-GP2 (פינים מס' 7, 6 ו-5 בג'וק, בהתאמה), את הלד האדום ל-GP4 (פין 3) ואת הירוק ל-GP5 (פין 2).

צילום תקריב של המעגל
צילום תקריב של המעגל

הרגיסטרים

את הרגיסטר הראשון שניעזר בו הכרנו כבר בפרויקט ה-Blink: הוא נקרא GPIO, והוא זה שמאפשר לנו לכתוב ערכים לפינים או לקרוא אותם מהם. ששת הביטים הנמוכים (0-5) של הרגיסטר הזה "מחוברים" לפינים GP0-GP5 של המיקרו-בקר, אם כי פין GP3 הוא גם פין האתחול (MCLR) ולכן לא ניגע בו בינתיים.

הרגיסטר החשוב השני הוא TRISIO, קיצור של Tri-State I/O. לכל פין יש 3 מצבים אפשריים: פלט גבוה, פלט נמוך, או קלט. סידור הביטים ב-TRISIO זהה לזה שב-GPIO; כאשר ביט מסוים הוא 0, הפין התואם פועל כפין פלט, וכאשר הביט הוא 1, הפין הוא קלט (שימו לב, זה ההיפך מהמוסכמה שקיימת במיקרו-בקרים ממשפחת AVR, כמו ה-ATtiny85). את פין GP3 יוצא הדופן, אגב, אי אפשר להגדיר כפין פלט.

הרגיסטר השלישי לא באמת חיוני למערכת שלנו, אך הוא יכול לחסוך לנו רכיבי חומרה: זהו הרגיסטר WPU (ראשי תיבות של Weak Pull-Up), שמאפשר לנו להגדיר נגד pull-up פנימי לפינים GP0, GP1, GP2, GP4 ו-GP5. כשהקלט מלחצן מסוים "צף", כלומר כשהלחצן אינו לחוץ ואינו מחבר את הפין לשום דבר, הנגד הפנימי יבטיח לנו קריאה של מתח "גבוה". כשהמשתמש ילחץ על הלחצן, יווצר חיבור של הפין לאדמה (ראו בשרטוט), ומכיוון שההתנגדות של הנתיב הזה נמוכה הרבה יותר מההתנגדות של הנגד הפנימי, הפין ירגיש מתח "נמוך" ("לוגיקה הפוכה").

שרטוט סכמטי של מעגל "מנעול הקוד"
שרטוט סכמטי של מעגל "מנעול הקוד"

עוד נקודה אחת קריטית: ברגיסטר OPTION_REG יש ביט בשם GPPU (הביט השביעי, העליון, השמאלי או MSB – איך שלא תקראו לזה 🙂 ) שמאפשר או מונע את השימוש בנגדי pull-up פנימיים. כדי שהעסק יעבוד כמו שצריך, עלינו לוודא שערך הביט הזה הוא 0.

הנה הגדרות האתחול של הרגיסטרים האלה עבור המערכת:

OPTION_REG &= 127;
TRISIO = 7;
WPU = 7;
GPIO = 16;

המספר 127 בבינארי הוא 01111111; פעולת AND איתו על הרגיסטר OPTION תהפוך ל-0 את הביט הגבוה (GPPU) ותאפשר לנו לעבוד עם נגדי ה-pull-up הפנימיים.

המספר 7 בבינארי הוא 111, כלומר שלושת הביטים הנמוכים ב-TRISIO וב-WPU יהפכו ל-1 (ויגרמו לפינים GP0-GP2 להפוך לפיני קלט עם נגד pull-up מופעל). הערך 16, שהוא 10000 בבינארי, יגרום לביט הרביעי – מתחילים מאפס, זוכרים? – ב-GPIO להיות 1, וכך הלד האדום יידלק. זהו, עכשיו אפשר לגשת ל-

הלוגיקה של המנעול

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

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

  1. נמתין שהמשתמש ילחץ על משהו (לא לשכוח debounce!)
  2. אם הלחיצה שלו תואמת את הספרה הנוכחית בקוד, נגדיל את האינדקס באחד.
  3. אם האינדקס שווה לאורך הקוד הסודי, סימן שהקוד כולו הוקש כהלכה – נדליק לרגע את הלד הירוק ולאחר מכן נתחיל הכל מהתחלה.
  4. לעומת זאת, אם הלחיצה לא תואמת את הספרה הנוכחית בקוד, נחזיר את האינדקס לאחור.
  5. נחכה שהמשתמש יעזוב את הלחצנים (גם כאן, debounce!).

והנה מלכודת קטנה: בשלב 4, כשכתבתי "נחזיר את האינדקס לאחור", אני לא מתכוון בהכרח שנאפס אותו, כי הדבר ייצור בעיה בתפקוד המנעול! מי רוצה לעצור עכשיו ולחשוב למה?

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

הקוד המלא

הנה הקוד המלא של תוכנת המנעול, ואחריו וידאו של העסק בפעולה.

// For MPLAB X with the XC8 Compiler
// by Ido Gendel (info AT idogendel.com)

// Connections : Red LED to GP4, Green LED to GP5
// Three momentary buttons from GND to GP0-GP2

#define _XTAL_FREQ 4000000
#include 

#pragma config FOSC = INTRCIO   
#pragma config WDTE = OFF       
#pragma config PWRTE = OFF      
#pragma config MCLRE = OFF      
#pragma config BOREN = OFF      
#pragma config CP = OFF         
#pragma config CPD = OFF        

#define redLedIO 4
#define greenLedIO 5

char buttonInput() {
  // Reversed logic reversed...
  return 7 - (GPIO & 7);
}

int main() {

  const char secretCode[] = {1, 2, 4 ,2 ,1};
  char codeIndex;

  ANSEL = 0;            
  CMCON = 7;            
  ADCON0 = 0;           
  TRISIO = 7;           
  OPTION_REG &= 127;    
  WPU = 7;              

  while (1) {
    
    GPIO = 1 << redLedIO; // Red LED pin High
    codeIndex = 0;

    while (codeIndex < sizeof(secretCode)) {

      // Wait for any input, then debounce
      while (!buttonInput()) ;
      __delay_ms(10);

      // Check input
      if (buttonInput() == 
          secretCode[codeIndex]) 
        codeIndex++;
      else codeIndex = 
        (buttonInput() == secretCode[0]) ? 1 : 0;

      // Wait for button release, then debounce
      while (buttonInput()) ;
      __delay_ms(10);

    } // while

    // Correct combination sequence
    GPIO = 1 << greenLedIO; // Green LED pin High
    __delay_ms(1000);

  } // while

  return 0;

} // main

להרשמה
הודע לי על
9 תגובות
מהכי חדשה
מהכי ישנה לפי הצבעות
Inline Feedbacks
הראה את כל התגובות

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

תודה רבה
שכחתי להוסיף שקיים משהו דומה של דב מורן -מקלדת עם מסך חיווי -והבנתי שהפרויקט לא ממש הצליח ומעניין אותי אם קיים חיקוי כלשהו

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

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

אה הבנתי , תודה רבה רבה אחלה מדריך !!!