3 - מוסיפים חיישנים למעגל

מתגים הם דבר נהדר, אך בעולם האמיתי יש הרבה יותר מ On ו Off. למרות שהארדואינו הוא כלי דיגיטלי הוא יכול לקבל מידע מחיישנים אנלוגיים כדי למדוד דברים כמו טמפרטורה או אור. כדי שנוכל לעשות את זה, נשתמש בממיר המובנה של הארדואינו מאנלוגי לדיגיטלי (ADC, ראשי תיבות: Analog-to-Digital Converter). הפינים האנלוגיים הנמצאים מ A0 עד A5 מחזירים ערך בין 0-1023, שממפה את הטווח שבין 0 ל-5 וולט.

 

בפרויקט הזה נבצע שימוש בחיישן טמפרטורה על מנת למדוד כמה חם העור שלנו. לחיישן יש 3 פינים: הראשון מתחבר לאדמה, השני מתחבר למקור כוח, והשלישי מחזיר פלט בדמות משתנה של מתח. ב Sketch (ה IDE של הארדואינו), נקרא את הפלט מהחיישן ונשתמש בפלט זה כדי להדליק ולכבות נורת LED, שבעצם תצביע כמה חמה היד / אצבע שלנו.

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

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

 

חיבור הרכיבים

בדיוק כפי שעשינו עד כה, נחבר ללוח המטריצה 5V ו GND (אדמה) בעזרת חוטים מגשרים. לאחר מכן נמקם את שלושת נורות ה LED על גבי לוח המטריצה ולקתודה (הרגל הקצרה) של כל LED נחבר נגד 220Ω אל המינוס (אדמה) שבלוח המטריצה. לאנודה (הרגל הארוכה) נחבר חוט מגשר אל הפינים 2,3,4 שבלוח הארדואינו (בהתאמה), הנורות יהיו אינדיקטורים למצבים השונים.

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

Arduino Project number 3

 

הקוד

קבועים דומים למשתנים בכך שהם מאפשרים לנו לתת שמות ייחודים, אך בניגוד למשתנים הם אינם יכולים להשתנות במהלך התוכנית (ולכן השם קבוע), נותנים להם ערכים אך ורק פעם אחת (משתנה final למי שמגיע מתכנות, או ערך סופי).  כדי שיהיה לנו קל יותר, ניתן שם לפין האנלוגי (הלא הוא A0), כמובן שיש לתת שם הגיוני, על מנת שיהיה יותר קל לזכור ולקרוא את התוכנית, נקרא לו sensorPin. וניצור קבוע נוסף שישמור את הטמפרטורה ההתחלתית, נקרא לו baselineTemp (כרגע הכנסתי לתוכו את המס’ 20, ומכיוון שהוא float – המכיל מספרים שלמים, נכתוב 20.0).
*כדי ליצור קבוע בארדואינו כותבים const בתחילת המשתנה.

נכתוב את התכנית כך שעבור כל 2 מעלות נוספות (מעל הטמפרטורה ההתחלתית / הבסיסית) עוד נורת LED תדלק. כעת, נכריז על הפונקציה הראשונה: ()setup ובתוכה נכתוב פקודה חדשה הנקראת Serial.begin (שימו דגש על אותיות קטנות / גדולות), הפקודה פותחת חיבור בין הארדואינו לבין המחשב כדי שנראה את הערכים מהקלט האנלוגי (חיישן הטמפרטורה) על גבי המחשב. הפרמטר 9600 שאנו מכניסים בפקודה הזו, הוא המהירות בו הארדואינו יתקשר, 9600 ביטים לשניה.

לאחר מכן, נגדיר את הפינים של נורות ה LED כפיני פלט (OUTPUT) וניתן להם את הערך LOW (לא מקבלים מתח). אך במקום לכתוב אחד אחד, לכל פין 2 שורות קוד (סה”כ 6 שורות קוד), נבצע את זה בלולאה. לולאת for (סוג הלולאה שאנחנו נשתמש בה כעת) הינה טכניקה לביצוע פקודה או סט פקודות כלשהם מספר רב פעמים (ידוע מראש, כמה שאנו נגדיר). נכתוב for ונפתח סוגריים על מנת לכתוב את מבנה הלולאה, נגדיר משתנה int בשם pinNumber שיהיה שווה ל-2 (על מנת להתחיל מהפין השני, זהו הפין הראשון אליו מחוברת נורת LED), לאחר מכן נסיים את הפקודה בנקודה פסיק (;) ונכתוב את התנאי, “כל עוד המשתנה pinNumber קטן מ-5” {זאת אומרת שנרוץ מ-2 (כולל) עד 5 (לא כולל)} תבצע את הלולאה ושוב נסיים את הפקודה בנקודה פסיק. ולבסוף נכתוב מה קורה כל פעם שהבקר מסיים לעבור על גוף הלולאה פעם אחת, ובמקרה שלנו מגדיל את pinNumber באחד (++pinNumber זוהי כתיבה מקוצרת של הוספת 1, בדיוק כמו לכתוב pinNumber = pinNumber + 1) וסיימנו את מבנה הלולאה אז נסגור את הסוגריים.

כעת נפתח סוגריים מסולסלים על מנת לכתוב את גוף הלולאה, נכתוב את הפקודה pinMode שבעזרתה אנו מגדירים את המצב של הפינים, הפקודה מקבלת 2 פרמרטים, הראשון מספר הפין שהוא יהיה כל פעם אחר, תלוי במצב הלולאה, לכן נכתוב pinNumber, ונגדיר את כל הפינים להיות פלט, לכן נכתוב פסיק ואז OUTPUT. הפקודה השניה תיהיה לכתוב לכל הפינים להיות כבויים, נבצע זאת בעזרת הפקודה digitalWrite המקבלת 2 פרמטרים, הראשון הוא מס’ הפין (שוב, יהיה pinNumber) והשני הוא המצב דולק/מכובה (יהיה LOW).

 

סיימנו את ה setup ולכן נסגור את הסוגריים המסולסלים, כדי שיהיה קל לקרוא נעשה שורה רווח ונכריז על הפונקציה השנייה בה אנו משתמשים: ()loop ונפתח סוגריים מסולסלים. הפקודה הראשונה אותה נכתוב בפונ’ זו היא הגדרת משתנה בשם sensorVal שיהיה מסוג int (מספרים שלמים), במשתנה זה נכניס את הקלט מהחיישן, לכן נכתוב שווה (=) ואת הפקודה ()analogRead המקבלת פרמטר אחד (מס’ הפין האנלוגי ממנו מתקבל הקלט). בתחילת התוכנית הגדרנו עיצור בשם sensorPin המכיל את מס’ הפין האנלוגי אליו מחובר החיישן (A0), לכן נכתוב בסוגריים של הפקודה sensorPin, ונסיים אותה בנקודה פסיק.

הפונקציה ()Serial.print שולחת מידע מהארדואינו אל המחשב המחובר אליו. נוכל לראות את המידע הזה במסך ה Serial monitor (לחצן עם זכוכית מגדלת בצד הימיני-עליון של הIDE). אם נשים בתוך הסוגריים של הפונקציה גרשיים של ציטוט, הפונקציה פשוט תדפיס את מה שבגרשיים, אך אם נשים משתנה כלשהו (ללא הגרשיים) הפונקציה תדפיס את הערך שהמשתנה מכיל. לכן נכתוב פעמיים את הפונקציה ()Serial.print, כדי שיהיה מובן על מה אנו מסתכלים, בראשונה נכתוב טקסט: “ :Sensor Value (כתבו את הטקסט עם הגרשיים על מנת שהפונקציה תדפיס את הטקסט ולא תחפש משתנה בשם זה. ובשנייה נכתוב את הערך של החיישן, לכן בתוך הסוגריים נכתוב sensorVal(שהינו הקלט מהחיישן).

כפי שאמרנו הערך שמתקבל מהחיישן ,מתקבל בערכים של 0-1023 (ז”א 1024 אפשרויות), וכדי להפוך את הערך הנ”ל לערך של מתח (בין 0 ל-5 וולט) נחלק אותו ב-1024 ונכפיל ב-5. יש לזכור שהערך יכול לצאת מספר לא שלם (עם נקודה עשרונית) לכן יש לשמור אותו במשתנה שיכול להכיל נקודה עשרונית, כמו float. למשתנה החדש נקרא בשם הגיוני, כמו voltage, ושימו לב לשים סוגריים על מנת לשמור על סדר פעולות חשבון. בנוסף, כדי שנוכל לראות מה הולך, בואו נדפיס גם את הערך הזה. שוב ע”י 2 פקודות ()Serial.print, הראשונה תכיל טקסט, והשניה את המשתנה.

יש לזכור שמה שאנו רוצים למדוד הוא המעלות בצלזיוס, לכן אנו צריכים שוב להפוך מערך של מתח למעלות צלזיוס. שוב ניצור משתנה חדש בשם temperature (מסוג float). את הערך שקיבלו ב voltage נחסיר ב-0.5 ולאחר מכן נכפיל אותו ב-100. ושוב נדפיס את הערך בעזרת הפונקציה ()Serial.print. (שימו לב שבפקודת הדפסה האחרונה הוספתי println במקום print, זו היא פונקציה קצת שונה, שיוצרת שורה חדשה לאחר ההדפסה, ז”א שהשורה הבאה שתודפס תהיה בשורה חדשה, נפרדת).

 

לבסוף, נכתוב מספר if-ים על מנת לקבוע אילו נורות LED ידלקו ומתי. נשתמש בטמפרטורה ההתחלתית השמורה במשתנה baselineTemp כנקודת פתיחה, נדליק עוד נורת LED בכל עליה של 2 מעלות מעבר לטמפרטורה ההתחלתית. לכן נתחיל בכך שאם הטמפרטורה הנוכחית קטנה מהטמפרטורה ההתחלתית (שהגדרנו אותה להיות 20, כל הנורות יהיו על LOW (כבויות).
אחרת, אם (במילים אחרות: else if), הטמפרטורה הנוכחית שווה או גדולה מהטמפרטורה ההתחלתית+2, וגם קטנה מהטמפרטורה ההתחלתית+4, תדליק את נורה אחת (זהוי המחוברת לפין הדיגיטלי 2).
אחרת, אם הטמפרטורה שווה או גדולה מהטמפרטורה ההתחלתית+4 וגם קטנה מהטמפרטורה ההתחלתית+6, תדליק 2 נורות (פין 2 ופין 3).
אחרת, אם הטמפרטורה שווה או גדולה מהטמפרטורה ההתחלתית+6 תדליק את כל הנורות.

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

לאחר שסיימנו את הבדיקות, נזכור שאנו בתוך פונקציית ה loop, לכן הפונקציה תפעל כל עוד הארדואינו פועל. ז”א תיקח דגימה של הטמפרטורה, תהפוך אותה למתח, ולאחר מכן למעלות צלזיוס, ולבסוף תבדוק את קבוצת ה if-ים ותקבע איזה נורות LED להדליק / לכבות. לכן בסוף התוכנית נכתוב את הפונקציה ()delay עם המס’ אחד בתוכה (מכיוון שאם נקרא מהחיישן בתדירות גבוה מידי המספרים שנקרא לא יהיו יציבים (הוא לא יספיק להתקרר לפני שנזיז את האצבע, בכל זאת זה לא החיישן האיכותי בעולם..)

כך יראה הקוד הסופי:

const int sensorPin = A0;
const float baselineTemp = 24.0;

void setup(){
   Serial.begin(9600); // open a serial port

    for(int pinNumber=2; pinNumber < 5; pinNumber++){
        pinMode(pinNumber, OUTPUT);
        digitalWrite(pinNumber, LOW);
    }
}

void loop(){
    int sensorVal = analogRead(sensorPin);
    Serial.print("Sensor Value: ");
    Serial.print(sensorVal);

    // convert the ADC reading to voltage
    float voltage = (sensorVal/1024.0) * 5.0;
    Serial.print(", Volts: ");
    Serial.print(voltage);

    // convert the voltage to temperature in degrees
    float temperature = (voltage - 0.5) * 100;
    Serial.print(", degrees C: ");
    Serial.println(temperature);

    if (temperature < baselineTemp){
        digitalWrite(2, LOW);
        digitalWrite(3, LOW);
        digitalWrite(4, LOW);
    }else if (temperature >= beaselineTemp+2 && temperature  < beselineTemp+4){
        digitalWrite(2, HIGH);
        digitalWrite(3, HIGH);
        digitalWrite(4, LOW);
    }else if (temperature >= beaselineTemp+6){
        digitalWrite(2, HIGH);
        digitalWrite(3, HIGH);
        digitalWrite(4, HIGH);
    }
    dealy(1);
}

 

לסיכום

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

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