לפני זמן-מה הצגתי כאן את הג'וק CD4017BE, הידוע בכינויו "מונה עשרוני" ("Decade Counter"), וציינתי שבימינו די קשה למצוא לו שימושים מעשיים. בתגובות לפוסט הנ"ל הוצעו אפשרויות ספורות, ומשני ג'וקים כאלה יצרתי גם קישוט אורות לסוכה, אך רוב הג'וקים שקניתי במבצע באיביי עדיין נותרו ללא שימוש. ובכן, מסתבר שיש עוד משהו שאפשר לעשות איתם – לפחות כתרגיל מחשבתי…
לאחרונה נתקלתי באינטרנט, במקרה, בסוג אחר לגמרי ונדיר של ג'וקים – Debouncers. כל ייעודם בחיים הוא להתמודד עם בעיית ה-Bounce המפורסמת, אותן רטיטות מכניות של לחצנים ומתגים שגורמות ללחיצה אחת (כפי שאנו תופסים אותה) להיקלט במערכות אלקטרוניות כשורה של לחיצות מהירות מאד, ורק אחריהן כמגע (או נתק) חשמלי רצוף. לדיבאונסרים האלה יש – ברמת העיקרון – כניסה למתג, כניסה לאות שעון, ויציאה. המתח ביציאה משקף את המתח בכניסה, בתנאי שהוא נשאר יציב במשך, נניח, ארבעה מחזורי שעון או יותר.
הנדירות היחסית של הדיבאונסרים מוכיחה שמתכנני מערכות מעדיפים, בדרך כלל, פתרונות אחרים, אך בתיאוריה ג'וק כזה טוב משתי בחינות: הוא חוסך קוד ומאמץ למיקרו-בקר (לא צריך דיבאונס בתוכנה), ומצד שני מאפשר יותר גמישות מאשר פתרונות חומרה אחרים (כגון קבל) במקרה של שינויים במתח ההפעלה של המערכת, החלפה של האלמנט המכני במשהו שמתנהג קצת אחרת ועוד.
כל זה הוא ברמת הידע הכללי, כי אין לי צורך או כוונה להתעסק עם ג'וקים כאלה בינתיים. אבל העניין של ספירת אות השעון העלה אצלי רעיון פרוע: אולי אפשר לאלתר דיבאונסר ממונה עשרוני?
התיאוריה
למונה העשרוני יש כניסה לאות שעון ועשר יציאות, שכל אחת מהן מוציאה מתח בתורה (מ-0 אותות שעון ועד 9). האות העשירי מחזיר את הספירה ל-0, ויש גם יציאה של Carry out ש"נדלקת" כדי לשרשר רכיבים כאלה לספרת עשרות, מאות וכו'. בנוסף, יש כניסת Reset שמאפסת את הספירה, ועוד כניסה מעניינת בשם Clock inhibit שכל עוד היא "גבוהה", הג'וק פשוט מתעלם מאות השעון ונשאר במצב בו היה קודם.
בתור התחלה, אפשר לחבר את הלחצן המכני לפין Reset כך שהג'וק יפעל רק כשהלחצן לחוץ. במקביל, נספק לג'וק אות שעון קבוע. הספירה תתאפס עם כל "קפיצה" של הלחצן, כך שאם אות השעון יהיה איטי מספיק, כל עוד יש Bounce הג'וק פשוט יתאפס שוב ושוב, ולאחר מכן יציאה מס' 5 תיתן לנו פלט זהה למה שהיינו מקבלים מדיבאונסר ייעודי (דיברנו על ארבעה מחזורי שעון של לחיצה רצופה, זוכרים?).
הבעיה היא, כמובן, שהספירה לא תעצור ביציאה 5 אלא תמשיך הלאה, ואם הלחצן יישאר לחוץ מספיק זמן, אפילו תגיע אליו שוב ושוב, כאילו לחצנו מחדש בכל עשרה מחזורי שעון. איך עוצרים את הספירה? קחו דקה לחשוב על זה…
הפתרון פשוט: מחברים את היציאה הזו לפין Clock inhibit! ברגע שיתקבל מתח חיובי מהיציאה, הג'וק יתעלם מהשעון ויישאר כמו שהוא – עד פעולת ה-Reset הבאה, שמקורה כפי שאמרנו בשחרור הלחצן.
הניסוי
האם התיאוריה הזו עובדת גם בשטח? בשלב הראשון חיברתי לד ליציאה 10 של הג'וק, וסיפקתי לו אות שעון מארדואינו באמצעות תוכנית Blink מותאמת שמהבהבת 10 פעמים בשניה. כמו שחשבתי, לחיצה שאורכה שניה אחת גרמה ללד להאיר – ולהישאר דולק עד עזיבת הכפתור. כך קיבלתי אינדיקציה ויזואלית ברורה לכך שהעסק עובד.
וכעת לדבר האמתי. בסידור החדש, לוח ארדואינו מספק את אות השעון באמצעות PWM (רוחב המחזור של PWM "רגיל" בארדואינו הוא 2 אלפיות השניה) ומקבל שני ערוצי קלט: אחד ישירות מהלחצן, ואחד מיציאה 5 של הג'וק. כל ערוץ קלט מפעיל פסיקה שמגדילה מונה נפרד, והארדואינו כותב ל-Serial את הערכים של המונים ברגע שהוא מזהה שינוי כלשהו בהם. הנה הקוד:
// Test code for the Decade Counter Debouncer // by Ido Gendel, 2014 // Share and enjoy! volatile int creg = 0, cdeb = 0; int oldSum = 999; void setup() { pinMode(5, OUTPUT); analogWrite(5, 128); Serial.begin(9600); attachInterrupt(0, countRaw, RISING); attachInterrupt(1, countDebounced, RISING); } void countRaw() { creg++; } void countDebounced() { cdeb++; } void loop() { if (oldSum != creg + cdeb) { oldSum = creg + cdeb; Serial.print("Count (raw) = "); Serial.println(creg); Serial.print("Count (debounced) = "); Serial.println(cdeb); delay(100); } }
ה-delay מונע הדפסה תכופה מדי של התוצאות כאשר ה-Bounce עצבני. והנה התוצאה, עם לחצן שהותקן בכוונה באופן רופף במיוחד על המטריצה. מבחינתי, לחצתי על הלחצן בדיוק 13 פעמים:
מסקנות ולקחים
האם זו שיטה מומלצת לבצע דיבאונס? ברוב המכריע של המקרים, לא. הפתרונות הפשוטים יותר בתוכנה או בחומרה יספיקו בדרך כלל, והג'וק אמנם זול וזמין יותר מג'וק דיבאונס ייעודי, אבל להרבה ייעודיים יש מספר ערוצים ולא רק אחד, כך שהיתרונות והחסרונות מתקזזים. כל העסק הנ"ל טוב בעיקר כתרגיל מחשבתי קטן.
עם זאת, בעולם המייקינג האלקטרוני, ואפילו בתעשייה, פתרונות מאולתרים ושימוש יצירתי ברכיבים ובתכונות חשמליות הם נפוצים ויכולים להביא המון תועלת, עד כדי חסכון משמעותי בקוד, במקום פיזי ובמחיר – מה שיכול אפילו לקבוע את גורלו של פיתוח חדש.