מדריך ארדואינו למתחילים חלק ב'

מדריך ארדואינו למתחילים חלק ב'

ארדואינו למתחילים חלק ב'
מאסימו באנזי – אחד ממפתחי ארדואינו

פרקים:

  1. מנועים
  2. תקשורת I2C ו- SPI
  3. מסך LCD
  4. לוח מקשים
  5. תקשורת אינפרה אדום
  6. תקשורת בלוטוס
  7. תקשורת אינטרנט
  8. כרטיס זכרון
  9. מגיני הרחבה
  10. תזמונים השהיות ופסיקות

בספר ארדואינו למתחילים חלק ב' נמשיך להפעיל רכיבים שונים עם הארדואינו ונלמד על צורות תקשורת חדשות.

מנועים

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

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

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

לכל פין של הארדואינו יש מגבלת זרם של 40 מיליאמפר לערך, וכל הבקר בעצמו (ATmega328) אינו יכול לספק יותר מ- 200 מיליאמפר. כניסת המתח של ה- USB יכולה לספק פחות או יותר 750 מיליאמפר שזהו הסטנדרט של USB 3.0 , וחיבור דרך בטריה יכול לספק כמה זרם שהבטריה מסוגלת וזה משתנה מבטריה לבטריה וכך גם לגבי ספקי כח – לדוגמה ספק כח של 5V 1A יכול לספק עד 1 אמפר.

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

מנועי DC

book-dc-motor

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

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

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

טרנזיסטור

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

לטרנזיסטור יש 3 פינים: כשאנחנו מעבירים זרם בפין מסוים שנקרא BASE נסגר מעגל בין 2 הפינים הנותרים EMITTER ו- COLLECTOR וזרם יכול לעבור בהם ממקור הכח החיצוני. ישנו רף מינימלי של זרם להפעלת הטרנזיסטור, וכן רף מקסימלי בו מותר להשתמש ועליהם ניתן לקרוא במפרט הטכני שלו.

אם כך הארדואינו בסה"כ נותן פקודה להעברת זרם ממקור כח חיצוני על ידי העברת זרם נמוך בפין מסוים.

 

book-2n3904

טרנזיסטור פופולרי הוא 2n3904 שהומצא בשנות ה- 60 ועדיין עושה את העבודה גם היום. אל הפין האמצעי(BASE) הולך הפין של ארדואינו, אל הפין הימני(COLLECTOR) הולך מקור הכח החיצוני והפין השמאלי הולך ל- GND משותף עם הארדואינו והבטריה.

טרנזיסטור זה בנוי לזרמים נמוכים והמקסימום זרם שהוא יכול להעביר זה 200mA. אתם יכולים לשים לב שהוא מתחמם בקלות ואם נמשיך להפעיל אותו לזמן ממושך הוא עלול להישרף.

book-fritzing-dc

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

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

דיודה

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

קבל

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

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

הפעלת מנוע בכיוון אחד

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

book-dc-2n3904

 

קוד:

void setup(){ 
  pinMode(A0, INPUT); // potentiometer
  pinMode(9, OUTPUT); // pin that goes to BASE pin in the transistor
}

void loop(){
  analogWrite(9, map(analogRead(0), 0, 1023, 0, 255));
}

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

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

book-tip120-explanation

 

שימו לב שהחיבורים שלו שונים מהטרנזיסטור הקודם שהשתמשנו בו.

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

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

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

שליטה בכיוון המנוע

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

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

הוא נועד להקל עלינו את העבודה ויש לו בדרך כלל שתי שורות שהאריזה שלהם נקראת DIP עם פינים שיוצאים ויכולים להתחבר למטריצה או לוח הלחמה. L293D הוא שבב H-BRIDGE פופולרי עם 16 יציאות דיפ שיכול להפעיל שתי מנועים בשתי כיוונים שונים.

store-l293d-ic

l293d-pin-diagram

חיבורים:

  • ENABLE1 – פין שמדליק ומכבה את מנוע 1 ושולט גם במהירות המנוע(PWM). בדוגמה הוא הולך לפין 11 בארדואינו
  • INPUT1 – פין ששולט בכיוון מנוע 1. בדוגמה הוא הולך לפין 10 בארדואינו
  • OUTPUT1 – יציאה למנוע 1
  • GND – הולך לאפס משותף עם הארדואינו
  • OUTPUT2 – הולך לצד השני של מנוע 1
  • INPUT2 – פין שליטה בכיוון מנוע  1 – בדוגמה הולך לפין 9 בארדואינו
  • VS – מקור כח חיצוני מבטריה או ספק
  • VSS – לוגיקת מתח של 5V. הולך ל- 5V בארדואינו

כל שאר החיבורים בצד שני יכולים לשלוט במנוע נוסף.

fritzing-l293d

book-l293d

בתמונה זהו ארדואינו נאנו. כל החיבורים בתמונה יכולים להתבצע גם כמובן עם ארדואינו אונו.

מנועי צעד

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

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

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

store-uln2003

store-28BYJ-48-DC-5V-Stepper-motor

אלו החיבורים:

  • מחברים את 5 החוטים של המנוע אל השקע הלבן במודול.
  • מחברים את פינים 8,9,10,11 בארדואינו אל ארבעת החיבורים במודול in1, in2, in3, in4.
  • מספקים כח חיצוני על ידי ספק או בטריה ומחברים ל + ו – במודול. מנוע זה עובד על 5V.
  • מעלים את הקוד לארדואינו.
const int s1 = 8;
const int s2 = 9;
const int s3 = 10;
const int s4 = 11;
int motorSpeed = 1500; // motor speed between 1000-4000. small number is bigger speed 
void setup() { 
 pinMode(s1, OUTPUT); 
 pinMode(s2, OUTPUT); 
 pinMode(s3, OUTPUT); 
 pinMode(s4, OUTPUT); 
}

void loop() {
  for (int i=0; i<=509; i++){ // go forward one circle, 509 steps
    forward();
  }
  for (int i=0; i<=509; i++){ // go back one circle. 
    back();
 }
}

void motorOff(){ // turn off motor
 digitalWrite(s1, LOW); 
 digitalWrite(s2, LOW); 
 digitalWrite(s3, LOW); 
 digitalWrite(s4, LOW); 
}

void back(){ // function to move 1 step back
  digitalWrite(s1, HIGH); 
  digitalWrite(s2, LOW); 
  digitalWrite(s3, LOW); 
  digitalWrite(s4, LOW); 
  delayMicroseconds(motorSpeed);
  digitalWrite(s1, HIGH); 
  digitalWrite(s2, HIGH); 
  digitalWrite(s3, LOW); 
  digitalWrite(s4, LOW); 
  delayMicroseconds(motorSpeed);
  digitalWrite(s1, LOW); 
  digitalWrite(s2, HIGH); 
  digitalWrite(s3, LOW); 
  digitalWrite(s4, LOW); 
  delayMicroseconds(motorSpeed);
  digitalWrite(s1, LOW); 
  digitalWrite(s2, HIGH); 
  digitalWrite(s3, HIGH); 
  digitalWrite(s4, LOW); 
  delayMicroseconds(motorSpeed);
  digitalWrite(s1, LOW); 
  digitalWrite(s2, LOW); 
  digitalWrite(s3, HIGH); 
  digitalWrite(s4, LOW); 
  delayMicroseconds(motorSpeed);
  digitalWrite(s1, LOW); 
  digitalWrite(s2, LOW); 
  digitalWrite(s3, HIGH); 
  digitalWrite(s4, HIGH); 
  delayMicroseconds(motorSpeed);
  digitalWrite(s1, LOW); 
  digitalWrite(s2, LOW); 
  digitalWrite(s3, LOW); 
  digitalWrite(s4, HIGH); 
  delayMicroseconds(motorSpeed);
  digitalWrite(s1, HIGH); 
  digitalWrite(s2, LOW); 
  digitalWrite(s3, LOW); 
  digitalWrite(s4, HIGH); 
  delayMicroseconds(motorSpeed);
}

void forward(){ // function to move 1 step forward
  digitalWrite(s1, HIGH); 
  digitalWrite(s2, LOW); 
  digitalWrite(s3, LOW); 
  digitalWrite(s4, HIGH); 
  delayMicroseconds(motorSpeed);
  digitalWrite(s1, LOW); 
  digitalWrite(s2, LOW); 
  digitalWrite(s3, LOW); 
  digitalWrite(s4, HIGH); 
  delayMicroseconds(motorSpeed);
  digitalWrite(s1, LOW); 
  digitalWrite(s2, LOW); 
  digitalWrite(s3, HIGH); 
  digitalWrite(s4, HIGH); 
  delayMicroseconds(motorSpeed);
  digitalWrite(s1, LOW); 
  digitalWrite(s2, LOW); 
  digitalWrite(s3, HIGH); 
  digitalWrite(s4, LOW); 
  delayMicroseconds(motorSpeed);
  digitalWrite(s1, LOW); 
  digitalWrite(s2, HIGH); 
  digitalWrite(s3, HIGH); 
  digitalWrite(s4, LOW); 
  delayMicroseconds(motorSpeed);
  digitalWrite(s1, LOW); 
  digitalWrite(s2, HIGH); 
  digitalWrite(s3, LOW); 
  digitalWrite(s4, LOW); 
  delayMicroseconds(motorSpeed);
  digitalWrite(s1, HIGH); 
  digitalWrite(s2, HIGH); 
  digitalWrite(s3, LOW); 
  digitalWrite(s4, LOW); 
  delayMicroseconds(motorSpeed);
  digitalWrite(s1, HIGH); 
  digitalWrite(s2, LOW); 
  digitalWrite(s3, LOW); 
  digitalWrite(s4, LOW); 
  delayMicroseconds(motorSpeed);
}

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

book-stepper-motor

 

מנועי סרוו

store-towerpro-micro-servo

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

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

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

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

book-servo-motor

 

קוד:

#include <Servo.h>
Servo myservo; // create servo object to control a servo
// twelve servo objects can be created on most boards
int pos = 0; // variable to store the servo position

void setup() {
   myservo.attach(9); // attaches the servo on pin 9 to the servo object
}

void loop() {
   for (pos = 0; pos <= 180; pos += 1) { // goes from 0 degrees to 180 degrees
   // in steps of 1 degree
     myservo.write(pos); // tell servo to go to position in variable 'pos'
     delay(15); // waits 15ms for the servo to reach the position
   }
   for (pos = 180; pos >= 0; pos -= 1) { // goes from 180 degrees to 0 degrees
     myservo.write(pos); // tell servo to go to position in variable 'pos'
     delay(15); // waits 15ms for the servo to reach the position
   }
}

סיכום מנועים

מנועי DC

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

מנועי צעד:

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

מנועי סרוו:

  • מהירות בינונית
  • מחיר בינוני
  • קלים לתפעול
  • מדויקים יחסית

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

דוחפי ובקרי מנוע

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

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


 

תקשורת I2C ו SPI

בספר ארדואינו למתחילים חלק א' התעסקנו עם תקשורת טורית והפעלנו אותה על ידי הפונקציה SERIAL. סוגי התקשורת שנציג פה הם גם סוג של תקשורת טורית אבל הם עובדים בפרוטוקול קצת מתוחכם יותר מה שמוסיף להם אינטיליגנציה.

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

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

  • SPI הוא בדרך כלל מהיר יותר
  • SPI נחשב פחות מתוחכם אבל עם זאת יותר פשוט להפעלה
  • SPI דורש יותר חוטים מ I2C
  • I2C דורש רק 2 חוטים לתקשורת
  • I2C יכול להיות יותר מסובך להפעלה מבחינת תכנות
  • I2C דורש 2 נגדי PULL UP על חוטי העברת המידע

הנה שתי איורים עם הארכיטקטורה של כל אחד מהפרוטוקולים:

i2c-bus
I2C bus

 

spi-three-slaves
spi-three-slaves

שימו לב לשני הנגדים המחוברים בתקשורת I2C וגם לכמות החוטים הגבוהה יותר ב-SPI.

הארכיטקטורה של I2C היא של master ו- slave כשהארדואינו הוא ה master שמתחיל תקשורת עם רכיבים שנקראים slave והתקשורת נעשית באמצעות שתי חוטים :

SDA – אחראי להעברת נתונים בין הארדואינו לרכיבים האחרים. בארדואינו אונו זהו פין אנלוגי A4

SCL – קו שעון שאחראי לתזמון של העברת הנתונים. בארדואינו אונו זהו פין אנלוגי A5

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

  • הארדואינו שולח ביט להתחלת תקשורת
  • הארדואינו שולח כתובת של 7 ביט שמופנית לאחד הרכיבים
  • הארדואינו שולח קריאה(0) או כתיבה(1) כדי להגדיר את הפעולה שברצונו לעשות
  • הרכיב שולח חזרה ביט שקיבל את הודעה
  • הארדואינו כותב או קורא מהרכיב על ידי שליחת בייט אחד אחרי השני, הרכיב מודיע שקיבל את הבייט אחרי כל שליחה
  • הארדואינו שולח ביט לסגירת תקשורת

ישנה ספריה בסביבת העבודה של ארדואינו שנקראת wire שמקלה על התקשורת ונהוג להשתמש בה כשמשתמשים ב- I2C:

https://www.arduino.cc/en/Reference/wire

 

בתקשורת SPI ישנם ארבעה חיבורים של העברת מידע:

  • SCLK – קו שעון תזמון משותף לכל הרכיבים
  • MOSI – מידע שיוצא מ- MASTER(ארדואינו במקרה שלנו) ומגיע ל- SLAVE(הרכיב)
  • MISO – מידע שיוצא מהרכיב ומגיע לארדואינו
  • SS – בחירת רכיב. כשישנם כמה רכיבים מחוברים במקביל ישנו חיבור ייחודי לכל אחד שנקרא SLAVE SELECT

החיבורים לארדואינו אונו הם בפינים 11,12,13 וזה אפשרי גם לחבר דרך חיבורי ה- ICSP(ששת החיבורים הבודדים) , דבר שמקל על חיבור מגינים. ישנה ספרייה ייעודית בארדואינו שנקראת SPI. עוד מידע על SPI :

https://www.arduino.cc/en/Reference/SPI


 

מסך LCD

store-lcd-1602

מסך LCD מסוג 1602A הוא מסך פופולרי לתצוגה בסיסית של 16×2 אותיות ולמרות שיש המון סוגים שלו רובם עובדים באותה צורה ומבוססים על בקר HITACHI HD44780. אפשר לזהות אותם בדרך כלל על ידי מספר הפינים שהוא 16.

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

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

book-lcd-headers2

עכשיו הכניסו אל תוך המטריצה כדי להפוך את ההלחמה לנוחה יותר:

book-lcd-headres1

הלחמה היא משהו שדורש קצת נסיון אבל בהחלט לא דבר מסובך . אלה השלבים:

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

book-lcd-headers3

הסבר על הפינים של 1602A:

  1. VSS – פין שהולך לאפס
  2. VDD – מתח לוגיקה ,הולך ל- 5V
  3. V0 – שליטה בבהירות המסך, הולך לפוטנציומטר
  4. RS – אפשרות לבחור בין קלט מידע או הוראות(פקודה או אות), הולך לפין 12 בארדואינו ונשלט על ידי התוכנה
  5. R/W – לקרוא או לכתוב לשבב, הולך לאפס(לכתוב)
  6. להתחיל הפעלת אות, הולך לפין 11 בארדואינו
  7. D4,D5, D6, D7 הולכים לפינים 5,4,3,2 בארדואינו, בעזרת התוכנה אפשר להשתמש ב 4 פינים בלבד במקום ב 8 להעברת מידע.
  8. ארבעת הפינים הנותרים D0, D1, D2, D3 נשארים ריקים.
  9. A – הולך ל- 5V
  10. K – הולך לאפס. שתי הפינים האלה הם אור אחורי של המסך ורצוי לחבר אותם עם נגד.

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

לארדואינו יש ספריה מצוינת לשליטה במסך שנקראית LiquidCrystal ומגיעה עם סביבת העבודה של ארדואינו.

 

הנה הדרך לחבר את המסך לארדואינו:

book-fritzing-lcd

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

#include <LiquidCrystal.h>
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);

אחרי זה נתחיל את המסך עם הגודל המתאים:

lcd.begin(16, 2);

לאחר מכן אפשר פשוט לכתוב למסך על ידי :

lcd.print("");

ולזוז בין הריבועים השונים על ידי ע"י:

lcd.setCursor();

כשהפרמטר הראשון הוא מספר עמודה והשני מספר שורה.

שימוש במסך LCD הוא שימושי ביותר ואפשר לחשוב על עשרות שימושים שאפשר לעשות בו:

  • להציג מידע מחיישנים שונים
  • להציג חיווי על נתונים כמו זרם או מתח
  • להציג שעה ותאריך

ועוד הרבה שימושים… הנה דוגמה למשחק טקסט בו המשתמש צריך לענות על שאלה חשבונית על ידי לחיצה על אחד הכפתורים. ישנו גם זמזם שנועד לחיווי ו-10  שניות של ספירה לאחור. בהתאם לתשובה של המשתמש המסך מציג אם היא נכונה או לא וגם משמיע צפצוף תואם:

book-text-lcd

 

קוד:

#include <LiquidCrystal.h>
char message1[13] = "Arduino Game"; //opening messages for the game
char message2[16] = "Answer question";
// initialize the library with the numbers of the interface pins
LiquidCrystal lcd(12, 11, 5, 4, 3, 2); // create object with the same pins we connected and name it lcd
void setup() {
  pinMode(8, INPUT); // button 1
  pinMode(9, INPUT); // button 2
  pinMode(7, OUTPUT); // buzzer
  digitalWrite(10, HIGH); //set reset pin to high 
  pinMode(10, OUTPUT); // initialize reset pin
  lcd.begin(16, 2); // start lcd with character size 16x2
  for(int i=0; i < 12; i++){ // show message character by character
    lcd.print(message1[i]);
   delay(300);
   }
  delay(200);
  lcd.setCursor(0, 1); // move to second row
  for(int i=0; i < 15; i++){
    lcd.print(message2[i]);
   delay(300);
   }
 delay(1000);
}
void loop() {
lcd.clear();
lcd.print("14 x 8 = ");
lcd.setCursor(0, 1);
lcd.print(" 112 122");
lcd.setCursor(15, 0);
for(int i = 10; i > 0; i--){ // run 10 seconds until a button is pressed
  tone(7, 700, 80);
  lcd.print(i);
delay(1000);
if ( digitalRead(9) == HIGH){
   lcd.clear();
   lcd.print("Correct Answer!");
   tone(7, 900, 800); // correct tone
   delay(4000);;
   digitalWrite(10, LOW); // reset program to beginning
 }
 else if ( digitalRead(8) == HIGH){
   lcd.clear();
   lcd.print("Wrong Answer");
   tone(7, 200, 150); // wrong tone
   delay(4000);
   digitalWrite(10, LOW); // reset program to beginning
   }
  lcd.setCursor(15, 0);
 }
 lcd.clear();
 lcd.print("Too Slow!!!");
 tone(7, 200, 150);
 delay(1000);
}

מסך LCD I2C

כאמור מסך זה משתמש רק בארבעה חיבורים שנמצאים בגב המסך –
VCC, GND SCL, SDA
יש גם פוטנציומטר לחדות המסך שאפשר לכוון.
כבר למדנו על תקשורת בפרוטוקול I2C ובמקרה הזה היא עושה לנו את החיים קלים. פשוט נחבר את SDA לפין אנלוגי A4 ואת SCL לפין אנלוגי A5.
הקוד להפעלת המסך צריך להתחיל תקשורת I2C עם המסך בצורה הבאה והמסך שאנחנו עובדים איתו ניתנה לו הכתובת 0x27. יש גם צורך להתקין את ספריית LiquidCrystal_I2C ואותה אפשר להוריד מתוך סביבת הפיתוח – סקיצה > הוסף ספרייה > ניהול ספריות ושם להקליד את השם שלה ולהוריד.

#include "Wire.h" // i2c library
 #include <LiquidCrystal_I2C.h> // lcd_i2c library
 LiquidCrystal_I2C lcd(0x27,16,2); // i2c address, rows,columns

void setup(){
 lcd.init(); // initialize screen
 lcd.backlight(); // turn backlight on
 lcd.print("hello world");
 lcd.setCursor(0,1); // move to second row
 lcd.print("Arduino LCD I2C");
 }
 void loop(){}
lcd-i2c-display
lcd-i2c-display

לוח מקשים

store-arduino-key-pad-4x3

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

בוא נניח שאנחנו רוצים ליצור מערכת של בקרת כניסה על ידי מנעול אלקטרוני. ללוח מקשים זה ישנם 7 כניסות – ארבעת הכניסות הראשונות הם השורות ונחבר אותם לפינים 2-5 ואת העמודות נחבר ל 6-8. הספריה Keypad משייכת את המקשים לתגובת הפלט שאנחנו רוצים לראות .

book-arduino-keypad

 

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

הפין של הארדואינו אינו יכול לספק זרם מספיק למנעול כי המנעול דורש 330mA בעוד הפין יכול לספק רק 40mA. לכן נשתמש בטרנזיסטור tip120 למרות שאפשר גם להשתמש בממסר. מקור הכח שנספק למנעול הוא 12V DC ממנו אפשר גם לספק כח לארדואינו.

אם רוצים ליצור אפקט זמזום למנעול כמו בדלתות אינטרקום למשל אפשר לספק לו זרם מתחלף AC.

חיבורים:

  • צריך לספק למעגל מקור כח של 12V עם לפחות 500mA
  • פין 13 בארדואינו יפעיל טרנזיסטור דרך נגד 220 שיקשר בין מקור הכח למנעול החשמלי.
  • פין 12 בארדואינו יחובר לזמזם שישמיע צפצוף בכל פעם שלוחצים על כפתור, ובנוסף ישמיע זמזום שמח או עצוב בהתאם לססמה

book-keypad-electric-lock

 

קוד:

#include <Keypad.h>
 #define Password_Length 5 // Give enough room for 4 chars + NULL char
 char Data[Password_Length]; // 4 is the number of chars it can hold + the null char = 5
 char Master[Password_Length] = "1234"; // the password
 byte data_count = 0, master_count = 0;
 bool Pass_is_good;
 char customKey;
 const byte ROWS = 4; //four rows
 const byte COLS = 3; //three columns
 char keys[ROWS][COLS] = {
 {'1','2','3'},
 {'4','5','6'},
 {'7','8','9'},
 {'*','0','#'}
 };

byte rowPins[ROWS] = {2,3,4,5}; //connect to the row pinouts of the keypad
byte colPins[COLS] = {6,7,8}; //connect to the column pinouts of the keypad
Keypad keypad = Keypad( makeKeymap(keys), rowPins, colPins, ROWS, COLS );
void setup(){
   Serial.begin(9600);
   pinMode(13, OUTPUT); // goes to BASE in transistor
   pinMode(12, OUTPUT); // goes to buzzer
 }

void loop(){
   customKey = keypad.getKey(); // save pressed key in variable
   if (customKey){ // makes sure a key is actually pressed, equal to (customKey != NO_KEY)
      tone(12, 600, 40); // pressing tone
      Data[data_count] = customKey; // store char into data array
      Serial.println(Data[data_count]); // print char at said cursor
      data_count++; // increment data array by 1 to store new char, also keep track of the number of chars entered
     }
   if(data_count == Password_Length-1){ // if the array index is equal to the number of expected chars, compare data  to master
     Serial.println("Password is ");
   if(!strcmp(Data, Master)){ // equal to (strcmp(Data, Master) == 0)
     Serial.println("Good");
     clearData();
     tone(12, 800, 40); // make happy tone
     delay(100);
     tone(12, 900, 40);
     digitalWrite(13, HIGH); // open the electric lock for 3 seconds 
     delay(3000);
     digitalWrite(13, LOW);
   } 
   else{
     tone(12, 90, 500); // make sad tone if password is not correct
     Serial.println("Bad");
     clearData();
   }
  }
 }

void clearData(){
   while(data_count !=0){ // This can be used for any array size, 
   Data[data_count--] = 0; //clear array for new data
   }
 return;
 }

תקשורת אינפרה אדום

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

book-electromagnetic-spectrum

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

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

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

אינפרה אדום היא צורת תקשורת חסכונית ולכן בטריה קטנה כמו CR2025 של 3V יכולה לעבוד במשך שנים.

בדוגמה הבאה נשתמש בערכה של שלט ורסיבר וגם בספריה של ארדואינו שנקראית IRremote.

store-IR-remote

באמצעות השלט נפעיל שתי מנועי DC ונשלוט בכיוון הסיבוב ובמהירות שלהם. נשתמש במודול דוחף מנוע שמבוסס על שבב L298:

store-DC-Stepper-Motor-Drive-Controller

חיבורים:

  • מנוע אחד מתחבר ל- OUT1 ו- OUT2
  • מנוע שני מתחבר ל- OUT3 ו- OUT4
  • IN1, IN2, IN3, IN4 הולכים לפינים 4, 5, 7, 8 בארדואינו
  • EN1 הולך לפין 6 ו- EN2 הולך לפין 9 בארדואינו. אלה הם פינים ששולטים במהירות וצריך להוציא ג'מפרים כדי לחבר אותם.
  • המודול רסיבר אינפרה אדום מתחבר ל- GND , 5V ו- S מתחבר לפין 11 בארדואינו
  • מקור כח חיצוני 12V מתחבר ל- 12V ול- GND בדוחף המנוע.

 

l298-driver-module

 

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

הפונקציות פה הם די פשוטות – אם רוצים לדוגמה לסובב את מנוע 1 מפעילים את פין IN1 ומכבים את פין IN2. שליטה במהירות נעשית על ידי EN1 שמופעל על ידי פין PWM 6 בארדואינו. אם רוצים לשנות את הכיוון של מנוע 1 מכבים את פין IN1 ומדליקים את IN2.

#include "IRremote.h"
int receiver = 11; // receiver pin
int speed = 0;
IRrecv irrecv(receiver); 
decode_results results;
void setup() { 
  pinMode(4, OUTPUT); // IN1
  pinMode(5, OUTPUT); // IN2
  pinMode(6, OUTPUT); // EN1
  pinMode(7, OUTPUT); // IN3
  pinMode(8, OUTPUT); // IN4
  pinMode(9, OUTPUT); // EN2
  Serial.begin(9600);
  //Serial.println("IR Receiver Button Decode"); 
  irrecv.enableIRIn(); // Start the receiver
}

void loop() {
 if (irrecv.decode(&results)) {// have we received an IR signal?
 translateIR(); 
 irrecv.resume(); // receive the next value
 }
 analogWrite(6, speed); // CONTROL MOTOR1 SPEED
 analogWrite(9, speed); // CONTROL MOTOR2 SPEED
}
/*-----( Functions)-----*/
void translateIR() {// takes action based on IR code received
// describing Remote IR codes
  switch(results.value) {
    case 0xFF629D: forward(); break; // FORWARD button
    case 0xFF22DD: if (speed > 0)speed--; break; // "LEFT" button
    case 0xFF02FD: Serial.println("-OK-"); break; // 
    case 0xFFC23D: speed++; break; // RIGHT button
    case 0xFFA857: back(); break; // BACK button
    default: 
      Serial.println(" other button ");
  }
 delay(500);
}

void forward(){ // SPIN BOTH MOTORS FORWARD
  digitalWrite(4, HIGH);
  digitalWrite(5, LOW);
  digitalWrite(7, HIGH);
  digitalWrite(8, LOW);
 }
void back(){ // SPIN BOTH MOTORS BACK
  digitalWrite(4, LOW);
  digitalWrite(5, HIGH);
  digitalWrite(7, LOW);
  digitalWrite(8, HIGH);
 }

book-motors-ir


תקשורת בלוטוס

עוד צורה נפוצה מאוד של תקשורת בשנים האחרונות היא בלוטוס (BLUETOOTH). זהו פרוטוקול תקשורת אלחוטי לטווח קצר בתדר 2.4GHz ומשמש להמון אפליקציות כמו דיבורית לרכב או רמקולים ניידים. הטווח של בלוטוס הוא בערך 10 עד 15 מטר ובניגוד לאינפרא אדום הוא חוצה קירות.

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

כמו בצורות תקשורת אחרות רבות משתמשים כמו I2C , SPI גם פה יש הגדרה של MASTER ו-SLAVE . מיהו האדון שמנהל את כל המשרתים שעובדים בשבילו 🙂 . האדון יכול לדבר עם כל המשרתים שלו אבל המשרתים לא יכולים לדבר אחד עם השני כמו בצורה של הפרד ומשול. יש גם פרופילים שונים של בלוטוס כמו של העברת אודיו, שליטה בקונסולות משחק או הפרופיל שנשתמש בו שהוא פרופיל תקשורת טורית (SPP). יש כאן הסבר מצוין על הבסיס של תקשורת בלוטוס אם זה מעניין אתכם.

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

מודול בלוטוס הדלקת נורה

מודול בלוטוס על מטריצה

 

  • 5V בארדואינו > VCC בבלוטוס
  • GND בארדואינו > GND בבלוטוס
  • RX בארדואינו > TX בבלוטוס
  • TX בארדואינו > RX בבלוטוס

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

רק עוד שני חלקים חסרים לנו בפאזל – למצוא אפליקציה באנדרואיד שתשלח את המידע אל מודול HC-05, ולכתוב קוד בארדואינו שיעבד את המידע הזה וידליק ויכבה נורת לד בהתאם למידע.

האפליקציה הכי פשוטה שהצלחתי למצוא היא Arduino Bluetooth של circuit magic. מתקינים אותה ואז לוחצים על CONNECT. בוחרים מהרשימה את HC-05 ואז בדרך כלל נדרשת ססמה שבפרוטוקול בלוטוס היא כמעט תמיד 1234, ואז נכנסים אל Led controller.

bluetooth-app-1

bluetooth-app-2

bluetooth-app-3

 

לחיצה על אייקון ON תשלח את הספרה 1 אל המודול שיעביר את זה לארדואינו, ולחיצה על אייקון OFF תשלח את הספרה אפס. עכשיו נכתוב את הקוד בארדואינו שיקבל את המידע:

void setup(){
    Serial.begin(9600);                                  
    pinMode(13, OUTPUT); 
}

void loop() {
   if(Serial.available() > 0) {
      char data = Serial.read();  
      if(data == '1'){            
         digitalWrite(13, HIGH);
      }  
      else if(data == '0') {        
         digitalWrite(13, LOW);
      }
   }
}

 

הקוד הזה הוא בדיוק אותו קוד שהשתמשנו לתקשורת טורית דרך USB עם המחשב בספר הראשון.

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

bluetooth-app-4

אנחנו שולחים מחרוזת '55' דרך הטרמינל ובצד השני הארדואינו ממיר את המחרוזת למספר INT שאפשר להשתמש בו על ידי הפונקציה analogWrite שהשתמשנו בה כבר בעבר. הוא מדליק את הנורה בעוצמה נמוכה של 55 מתוך 255.

void setup(){
    Serial.begin(9600);                                  
    pinMode(11, OUTPUT); 
}

void loop() {
   if(Serial.available() > 0) {
      int data = Serial.parseInt();
      analogWrite(11, data);   
   }
}

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

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

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

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

bluetooth-app-6

 

bluetooth-nokia5110

 

ואת זה אפשר לבצע בקלות על ידי השורה הבאה:

if(Serial.available() > 0) {
      String data = Serial.readString();
      // now we can write data into the lcd
}

שינוי הגדרות במודול

המודול HC-05 הוא לא כזה אהבל כמו שזה נראה ממבט ראשון ויש אפשרות לשנות את ההגדרות שלו באמצעות פקודות AT ברגע שנכנסים למצב הגדרות(SET). כדי לעשות את זה מושכים את רגל EN אל 5 וולט בארדואינו או שלוחצים על הכפתור שנמצא על המודול. ישנם 35 פקודות AT שונות איתם אפשר לשנות ססמה, שם שנחשף בפני משתמשים, תפקיד(master/slave), קצב העברת נתונים ועוד הרבה דברים אחרים.

לא הייתי ממליץ למתחילים להתעסק עם זה בכלל אבל אם כבר החלטתם לעשות את זה תשתדלו בתור התחלה לא לשנות קצב נתונים (baud rate) כי זה יכול להפסיק את התקשורת עם הארדואינו. עם האפשרות להשתמש בשני מודולים HC-05 כדי לדבר אחד עם השני (master mode) לא נתעסק פה אבל אולי בפעם אחרת, יש על זה הרבה מידע ברשת אם אתם מחפשים.

 


תקשורת אינטרנט

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

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

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

איך האינטרנט עובד?

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

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

HTTP הוא הפרוטוקול הנפוץ ביותר והוא פרוטוקול שנועד להעברה של דפי אינטרנט. הפונקציה העיקרית שלו היא GET וזוהי פקודה שאומרת לשרת להעביר אלינו את דף הבית שנמצא בו. בדוגמה הבאה אנחנו משתמשים בפונקציית POST שבדרך כלל משמשת לשליחת נתונים.

צריך להבחין גם בין רשת מקומית(LAN) לרשת גלובלית(WAN) – הארדואינו שנחבר לאינטרנט הוא חלק מרשת מקומית של הבית שלנו והמוח של הרשת הזו הוא הנתב הביתי שלנו. כתובת ה- IP שיקבל הארדואינו תהיה בטווח שנקבע על ידי הנתב בדרך כלל: 192.168.1.100 –  192.168.1.200  כלומר סיומת של בין 100 ל- 200.

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

שליחת נתונים אל האינטרנט

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

 

blog-alarm-ethernet

 

שימו לב שפינים 10,11,12,13 שמורים למגן האינטרנט ואינם ניתנים לשימוש אחר…מגן אינטרנט זה פועל בפרוטוקול SPI.

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

thingspeak-new-channel

 

עכשיו מה שצריך לעשות זה לחבר לארדואינו חיישן טמפרטורה, בדוגמה זו אנחנו משתמשים ב- DHT11 ובנוסף לחיישן LDR שקורא את כמות האור בחדר. בדוגמה אני מחבר את חיישן הטמפרטורה הדיגיטלי לפין 2 ואת חיישן האור לפין אנלוגי A0. אני לא אעבור על החיבורים כי אני מניח שבשלב זה אתם כבר יודעים איך לחבר חיישנים אלה לארדואינו.

 

ethernet-connection

 

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

#include <SPI.h> // INCLUDE SPI LIBRAY
#include <Ethernet.h> // INCLUDE ETHERNET LIBRARY
#include <DHT.h> // INCLUDE DHT LIBRARY
String apiKey = "THINGSPEAK WRITE API KEY";// replace with your channel’s thingspeak API key
const char* server = "api.thingspeak.com"; // NAME OF SERVER
#define DHTPIN 2 // input digital pin on Arduino shield
#define DHTTYPE DHT11 // WE ARE USING DHT11
DHT dht(DHTPIN, DHTTYPE); // CREATE DHT INSTANCE NAMED dht
EthernetClient client; // CREATE INSTANCE OF ETHERNETCLIENT NAMED client
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };// CREATE MAC ADDRESS(ANY MAC ADDRESS WILL WORK)

void setup() {
  Serial.begin(9600);
  Ethernet.begin(mac); // CONNECT TO ROUTER
  delay(1000); // WAIT FOR CONNECTION
  dht.begin(); // BEGIN DHT OPERATION
}

void loop() {
  float t = dht.readTemperature(); // READ TEMPERATURE TO VARIABLE t
  int light = analogRead(A0); // READ LIGHT VALUE FROM ANALOG A0 AND SAVE TO VARIABLE light
  if (isnan(t)) { // CHECK IF TEMPERATURE SENSOR HAS BEEN WORKING
    Serial.println("Failed to read from DHT sensor!");
    return;
  }
  if (client.connect(server,80)) { // CONNECT TO THINGSPEAK SERVER 
    Serial.println("connected");
    String postStr = apiKey; // PUT ALL THE VARIABLES IN THE STRING
    postStr +="&field1=";
    postStr += t;
    postStr +="&field2=";
    postStr += light;

    client.print("POST /update HTTP/1.1\n"); // START HTTP POST REQUEST
    client.print("Host: api.thingspeak.com\n");
    client.print("Connection: close\n");
    client.print("X-THINGSPEAKAPIKEY: "+apiKey+"\n");
    client.print("Content-Type: application/x-www-form-urlencoded\n");
    client.print("Content-Length: ");
    client.print(postStr.length());client.print("\n\n");
    client.print(postStr); // SEND THE STRING WITH THE TWO FIELDS
    }
  client.stop(); // STOP HTTP REQUEST
  delay(60000); // thingspeak needs 15 sec delay between updates
}

 

העלו את הקוד לארדואינו ותוך כמה שניות הוא אמור להתחיל לשלוח נתונים.

 

thingspeak-temp-light

 

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

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

הערה: ישנו שרת בגרסת בטא של חברת Adafruit שנותן לנו ליצור ממשק משתמש ודרכו לשלוט בארדואינו וגם לקבל נתונים. השרת עובד בפרוטוקול MQTT שהוא קצת שונה מ- HTTP ואפשר לקרוא עליו וגם ללמוד איך להשתמש בו כאן.

הארדואינו כשרת אינטרנט

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

נעשה שימוש בשפת תגיות שנקראת HTML כדי לשלוח חזרה תגובה ללקוח עם ממשק משתמש. ישנם הרבה דוגמאות ברשת של ממשקי משתמש אבל הבעיה שברובם הקוד מסובך מדי.

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

לכן הדוגמה הבאה היא כמה שיותר פשוטה(עד כמה שאפשר) וכוללת ריבוע סימון אחד שמדליק ומכבה נורת לד בפין מספר 2. אתם יכולים ליצור עוד כפתורים וריבועים שמפעילים פינים שונים רק זכרו שלא ניתן להשתמש בפינים 10-13 כל עוד מגן האינטרנט מחובר.

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

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

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

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

#include <SPI.h>
#include <Ethernet.h>
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
EthernetServer server(80); // create a server at port 80
String HTTP_req; // stores the HTTP request
boolean LED_status = false; // state of LED, off by default
void setup(){
  Ethernet.begin(mac); // initialize Ethernet device
  server.begin(); // start to listen for clients
  Serial.begin(9600); 
  pinMode(2, OUTPUT); // LED on pin 2
  Serial.println(Ethernet.localIP()); // print ip address
}

void loop(){
  EthernetClient client = server.available(); // try to get client
  if (client) { // got client?
    boolean currentLineIsBlank = true;
    while (client.connected()) {
    if (client.available()) { // client data available to read
      char c = client.read(); // read 1 byte (character) from client
      HTTP_req += c; // save the HTTP request 1 char at a time
      // last line of client request is blank and ends with \n
      // respond to client only after last line received
      if (c == '\n' && currentLineIsBlank) {
      // send a standard http response header
        client.println("HTTP/1.1 200 OK");
        client.println("Content-Type: text/html");
        client.println("Connection: close");
        client.println();
       // send web page
        client.println("<!DOCTYPE html>");
        client.println("<html>");
        client.println("<head>");
        client.println("<style>");
        client.println("body{background-image: url('http://www.planwallpaper.com/static/images/518097-background-hd.jpg');text-align:center;color:white;}");
        client.println("</style>");
        client.println("<meta charset='UTF-8'>"); 
        client.println("<title>הפעלה וכיבוי של נורת לד</title>");
        client.println("</head>");
        client.println("<body>");
        client.println("<h1>הפעלה וכיבוי של נורת לד</h1>");
        client.println("<p>סמנו את הריבוע להדליק ולכבות את הנורה</p>");
        client.println("<form method=\"get\">");
        ProcessCheckbox(client);
        client.println("</form>");
        client.println("</body>");
        client.println("</html>");
        Serial.print(HTTP_req);
        HTTP_req = ""; // finished with request, empty string
        break;
       }
   // every line of text received from the client ends with \r\n
   if (c == '\n') {
   // last character on line of received text
   // starting new line with next character read
   currentLineIsBlank = true;
   } 
   else if (c != '\r') {
     // a text character was received from client
     currentLineIsBlank = false;
     }
   }
 }
 delay(1); // give the web browser time to receive the data
 client.stop(); // close the connection
 }
}

// switch LED and send back HTML for LED checkbox
void ProcessCheckbox(EthernetClient cl){
  if (HTTP_req.indexOf("LED") > -1) { // see if checkbox was clicked
    // the checkbox was clicked, toggle the LED
    LED_status = !LED_status;
 }
  if (LED_status) { // switch LED on
    digitalWrite(2, HIGH);
    // checkbox is checked
    cl.println("<input type=\"checkbox\" name=\"LED\" value=\"1\" \
    onclick=\"submit();\" checked>LED");
   }
   else { // switch LED off
     digitalWrite(2, LOW);
     // checkbox is unchecked
     cl.println("<input type=\"checkbox\" name=\"LED\" value=\"1\" \
     onclick=\"submit();\">LED");
   }
}

כך אמור להיראות ממשק המשתמש בדפדפן פיירפוקס:

 

server

 

שליטה מכל מקום בעולם

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

  • הכניסו את הכתובת של הנתב הביתי לדפדפן – בדרך כלל הכתובת היא 192.168.1.1  או 192.168.0.1
  • הכניסו שם משתמש וססמה – בדרך כלל admin/admin. הנה רשימה מפורטת לפי סוג ודגם הנתב
  • לאחר מכן תצטרכו לקדם את פתחה (port) 80 אל עבר הכתובת של הארדואינו. ב- TPLINK ככה זה עובד: לחצו על forwarding  ואז על virtual servers. לחצו על add new. קדמו את פורט 80 אל עבר הכתובת של הארדואינו אותה אתם אמורים הייתם למצוא כבר בדוגמה הקודמת בחלון התקשורת הטורית. שמרו על ידי לחיצה על save

port-forwarding


 

כרטיס זכרון

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

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

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

סוגים של מודולים לכרטיס זכרון

store-arduino-ethernet

store-microsd-module

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

ישנה ספרייה מצויינת(אם כי גדולה למדי) לכתיבה וקריאה של כרטיסי זכרון והיא תומכת בכרטיסים מסוג SD ו- SDHC במערכות קבצים של FAT16/FAT32. אם קניתם כרטיס זכרון חדש אפשר פשוט להתחיל לעבוד איתו, אבל אם הוא משומש יכול להיות שיהיה צורך לפרמט אותו לאחת ממערכות הקבצים של FAT. אם הוא גדול מ- 2GB הפרמוט צריך להיות FAT32 ואם הוא 2GB ומטה אז FAT16.

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

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

הצורה הפשוטה ביותר לכתוב לקובץ בכרטיס הזכרון היא זו:

#include <SPI.h>
#include <SD.h>
File myFile; // create instance named myfile

void setup() {
 SD.begin(4); // begin sd card at pin 4
 myFile = SD.open("test.txt", FILE_WRITE); // create file test.txt in write mode
 myFile.println("this is a test");
 myFile.close();
}

void loop() {
 // do nothing
}

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

בדוגמה הבאה נעשה משהו קצת יותר מעניין – נכתוב נתוני טמפרטורה ולחות כל 10 דקות לכרטיס ונשתמש גם בשעון זמן אמת (RTC) real time clock כדי לכתוב את השעה. את כל המידע הזה נכתוב לקובץ CSV אשר מוכר יותר כקובץ אקסל כדי שנוכל לאחר מכן ליצור ממנו גרף.

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

שעה, טמפרטורה, לחות

12:34, 27.0, 34.0

12:44, 28.0 ,34.0

12:54, 28.0, 33.0

וכן הלאה……

אז אלו החיבורים שלנו בדוגמה הבאה  –

  • יש לנו את כרטיס הזיכרון שמתחבר למגן האינטרנט באמצעות פרוטוקול SPI , למרות שכל מודול אחר של כרטיס זיכרון יכול לעבוד
  • יש לנו את חיישן הטמפרטורה והלחות DHT11 שאנחנו כבר מכירים מהעבר
  • אנחנו מצרפים מודול שעון זמן אמת מסוג DS1307 שמתחבר לארדואינו בפרוטוקול I2C והחיבורים בו הם כדלקמן – GND ו- VCC הולכים ל GND ו- 5V בארדואינו, SCL הולך ל- A5 ו- SDA  הולך ל- A4. אפשר לחבר לחיבורים בצידו השמאלי או הימני, זה לא משנה.
  • השעון עובד עם בטריה CR2032 או CR2025 למרות שכל עוד הוא מחובר למחשב אין צורך בבטריה. הוא משתמש בספריית RTClib שאפשר להוריד ממנהל הספריות של ארדואינו

tiny-rtc

הקוד:

#include "DHT.h" // DHT11 LIBRARY
#include <SPI.h> // SPI LIBRARY
#include <SD.h> // SD LIBRARY
#include <Wire.h> // I2C LIBRARY
#include "RTClib.h" // RTC LIBRARY
#define DHTPIN 2 // DHT GO TO PIN 2
#define DHTTYPE DHT11 // DHT IS OF TYPE 11
RTC_DS1307 rtc; // CREATE INSTANCE OF RTC
File myFile; // create instance named myfile
DHT dht(DHTPIN, DHTTYPE); // INITIALIZE DHT

void setup() {
 SD.begin(4); // begin sd card at pin 4
 myFile = SD.open("log.csv", FILE_WRITE); // create file test.txt in write mode
 myFile.println("שעה, טמפרטורה, לחות"); // CREATE FIRST LINE ONCE
 rtc.begin(); // BEGIN COMMUNICATION WITH RTC
 rtc.adjust(DateTime(F(__DATE__), F(__TIME__))); // GRAB THE TIME FROM THE COMPUTER
 myFile.close(); // CLOSE FILE
 dht.begin();
}

void loop() {
 myFile = SD.open("log.csv", FILE_WRITE); // OPEN FILE FOR WRITING AGAIN
 float t = dht.readTemperature(); // GET TEMPERATURE
 float h = dht.readHumidity(); // GET HUMIDITY
 DateTime now = rtc.now(); // PUT TIME INTO VARIABLE
 myFile.print(now.hour(), DEC); // WRITE HOUR TO FILE
 myFile.print(":");
 myFile.print(now.minute(), DEC); // WRITE MINUTES TO FILE
 myFile.print(",");
 myFile.print(t); // WRITE TEMPERATURE TO FILE
 myFile.print(",");
 myFile.print(h); // WRITE HUMIDITY TO FILE
 myFile.println(); // MOVE TO NEXT LINE
 myFile.close(); // CLOSE FILE
 delay(600000); // WAIT 10 MINUTES BETWEEN READING
}

book-sd-rtc-dht11

 

אחרי 24 שעות של קריאת טמפרטורה ולחות כל 10 דקות אמורים להיות לנו 144 שורות של נתונים. ננתק את הארדואינו מהחשמל נוציא את כרטיס הזכרון ונכניס אותו למחשב. כעת נפתח אותו עם אקסל או תוכנה דומה והיא תנסה להבין מהנתונים מהו ציר ה-X ומהו ציר ה-Y. לאחר שהקובץ נפתח נסמן את כל הנתונים וניצור מהם תרשים. בתמונה למטה הגרף העליון הוא תלת מימדי והתחתון גרף רגיל ושניהם מייצגים את אותם הנתונים:

 

temp-humidity-graphs

 

המסקנה: ישנו יחס הפוך בין טמפרטורה ללחות – ככל שהטמפרטורה יורדת הלחות עולה ולהיפך.


מגיני הרחבה

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

רשימת מגיני הרחבה לארדואינו
רשימת מגיני הרחבה לארדואינו

בשביל זה הומצאו מגיני הרחבה שמתלבשים על הארדואינו כמו סנדביץ' ויש בהם כבר הכל רק צריך לחבר אותם. זהו רק חלק ממגיני ההרחבה הקיימים:

  • מגן פרוטו ליצירת אבטיפוס
  • מגן דוחף מנועים
  • מגן מסך LCD
  • מגן אינטרנט
  • מגן לוח מקשים
  • מגן בלוטוס
  • מגן WIFI
  • מגן ג'ויסטיק וכפתורים

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

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

אם החיבורים במגן למעלה הם נקבה אז אפשר להלביש על המגן עוד מגן נוסף וכך לשרשר מספר מגיני הרחבה אחד על השני.

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

אם יש פינים נותרים אז אפשר להשתמש בהם.

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

מגיני הרחבה אינטרנט ומסך מגע
מגיני הרחבה אינטרנט ומסך מגע

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

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

תזמונים השהיות ופסיקות

כשהקוד הופך להיות קצת יותר מסובך פונקציית DELAY שמשהה את התוכנה לא יכולה יותר לעשות את העבודה. לדוגמה בואו ניקח מקרה שבו אנחנו מנסים להבהב נורה אחת כל שניה ובנוסף להבהב נורה אחרת כל 3 שניות. קודם כל תנסו לבצע את זה דרך פונקצית DELAY שאנחנו כבר מכירים.

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

הנה נסיון לכתוב קוד כזה:

void setup(){
  pinMode(2, OUTPUT);
  pinMode(3, OUTPUT);
    
  }

void loop(){
    digitalWrite(2, HIGH);
    digitalWrite(3, HIGH);
    delay(1000);
    digitalWrite(2, LOW);
    delay(1000);
    digitalWrite(2, HIGH);
    delay(1000);
    digitalWrite(2, LOW);
    digitalWrite(3, LOW);
    delay(1000);
    
 }
ארדואינו שתי השהיות
ארדואינו שתי השהיות

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

אז מה הפתרון? הפתרון הוא פונקציית millis שבודקת כמה זמן(במילישניות) עבר מאז שהתחלנו את התוכנה. פונקציה זו משתמשת בשעון הפנימי של הארדואינו ונותנת לנו לתזמן דברים בלי צורך לתקוע את הקוד.

בעזרת טכניקה פשוטה של תשאול אנחנו יוצרים משתנה שדוגם את מספר המילישניות שעברו מאז שהתחלנו את התוכנה(הכוונה היא לרגע שקמפלנו את הקוד או הפעלנו את הארדואינו). בואו נניח שבדגימה קיבלנו 40000 כלומר ארבעים שניות, אנחנו רוצים להמשיך ולדגום את millis עד שהמספר יעלה ל-41000 ואז נדע שעברה שניה.

בקוד אנחנו כותבים משהו כזה: אם הדגימה השניה פחות הדגימה הראשונה גדולה מ-1000 נהפוך את המשתנה של הדגימה הראשונה למשתנה שלל הדגימה השניה וכך גם נדע כמובן שעברה שניה אחת. אם נרצה השהיה של שלוש שניות במקום של שניה אחת נשנה את המספר מ-1000 ל- 3000.

בואו נראה דוגמה איך להבהב נורה בפין 2 על ידי הפונקציה הזו וגם נדפיס למסך כדי לראות מה קורה:

  int ledState = LOW;  // ledState used to set the LED
long previousMillis = 0; // will store last time LED was updated
 
void setup() {
  Serial.begin(9600);
  // set the digital pin as output:
  pinMode(2, OUTPUT);      
}
 
void loop(){
 
  unsigned long currentMillis = millis();
  Serial.println(currentMillis - previousMillis);
  if(currentMillis - previousMillis > 1000) {
    // save the last time you blinked the LED 
    previousMillis = currentMillis;   
 
    // if the LED is off turn it on and vice-versa:
    if (ledState == LOW)
      ledState = HIGH;
    else
      ledState = LOW;
 
    // set the LED with the ledState of the variable:
    digitalWrite(2, ledState);
  }
}

כשפותחים את מסך התקשורת בתוכנת ארדואינו אפשר לראות איך המספרים של millis עולים מ-0 ל-1000 ואז מתאפסים חזרה לאפס. בצורה הזו אנחנו מהבהבים את הנורה בלי פונקציית DELAY.

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

int ledState = LOW; // ledState used to set the LED
int ledState2 = LOW;
long previousMillis = 0; // will store last time LED was updated
long previousMillis2 = 0;
void setup() {
  // set the digital pin as output:
  pinMode(2, OUTPUT);
  pinMode(3, OUTPUT);      
}
 
void loop(){
 
  unsigned long currentMillis = millis();
  unsigned long currentMillis2 = millis();
  
  if(currentMillis - previousMillis > 1000) {
    // save the last time you blinked the LED 
    previousMillis = currentMillis;   
 
    // if the LED is off turn it on and vice-versa:
    if (ledState == LOW)
      ledState = HIGH;
    else
      ledState = LOW;
 
    // set the LED with the ledState of the variable:
    digitalWrite(2, ledState);
  }

  if(currentMillis2 - previousMillis2 > 3000) {
    // save the last time you blinked the LED 
    previousMillis2 = currentMillis2;   
 
    // if the LED is off turn it on and vice-versa:
    if (ledState2 == LOW)
      ledState2 = HIGH;
    else
      ledState2 = LOW;
 
    // set the LED with the ledState of the variable:
    digitalWrite(3, ledState);
  }
  
}

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

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

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

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

int ledState = LOW; // ledState used to set the LED
long previousMillis = 0;        // will store last time LED was updated
void setup() {
  // set the digital pin as output:
  pinMode(2, OUTPUT); // led
  pinMode(3, INPUT); // button   
}
 
void loop(){
 
  unsigned long currentMillis = millis();
  
  if(currentMillis - previousMillis > 1000) {
    // save the last time you blinked the LED 
    previousMillis = currentMillis;   
 
    // if the LED is off turn it on and vice-versa:
    if (ledState == LOW)
      ledState = HIGH;
    else
      ledState = LOW;
 
    // set the LED with the ledState of the variable:
    digitalWrite(2, ledState);
  }

  if(digitalRead(3) == HIGH) {
    // do something
  }
  
}

כדי לעבוד עם כפתורים בצורה מדויקת ומקצועית יותר נצטרך להשתמש בפסיקות.

פסיקות

הדרך שעבדנו איתה עד עתה להבין אם מצב של פין השתנה היא על ידי תשאול(polling). הקוד שמחפש את השינוי רץ כל כמה מילישניות בצורה הבאה:

if(digitalRead(pin) == HIGH)

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

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

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

void setup() {
  pinMode(9, OUTPUT);
  pinMode(2, INPUT);
}

void loop() {
  if (digitalRead(2) == HIGH){
     // do something
}

for (int i = 0; i < 256; i++){
  analogWrite(9, i);
  delay(10);
}

for (int i = 255; i > 0; i--){
  analogWrite(9, i);
  delay(10);
 }
}

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

הקוד שפותר את הבעיה הזו משתמש בפסיקה:

void setup() {

  pinMode(9, OUTPUT); // led

  pinMode(13, OUTPUT); // buzzer

  pinMode(2, INPUT_PULLUP); // pullup pin2 to high

  attachInterrupt(0, buzzer, FALLING); // when pin 2 is low, execute buzzer function

}

void buzzer(){

  tone(13, 200, 1000);

}

void loop() {

  for (int i = 0; i < 256; i++){

  analogWrite(9, i); delay(10);

}

for (int i = 255; i > 0; i--){

  analogWrite(9, i); delay(10);

  }

}

עכשיו אפשר ללחוץ על הכפתור תוך כדי הלולאות והוא יעבוד כמו שצריך.

הפונקציה attachInterrupt מקבלת שלושה ערכים:

  • הראשון קובע באיזה פסיקה נשתמש כשפסיקה 0 משויכת לפין 2 ופסיקה 1 משויכת לפין 3. בארדואינו אונו יש רק שתי פינים שמסוגלים להיות משויכים לפסיקות, בארדואינו מגה יש יותר.
  • הערך השני הוא שם הפונקציה שתופעל במקרה של פסיקה.
  • הערך השלישי הוא התנייה מתי תתרחש הפסיקה ויש כמה אפשרויות:
  1. LOW – הפסיקה מתרחשת כשהפין ב- LOW
  2. HIGH – הפסיקה מתרחשת כשהפין ב- HIGH
  3. FALLING – מתרחשת כשהפין יורד מ- HIGH ל- LOW
  4. RISING – מתרחשת כשהפין עולה מ- LOW ל- HIGH
  5. CHANGE – מתרחשת בכל פעם שיש שינוי בפין של עלייה או ירידה

עוד כמה הערות על פסיקות:

  • בפונקציה שמופעלת בזמן פסיקה אין להפעיל השהיות(delay)
  • אם יש נתון שמשתנה בתוך הפונקציה צריך להצהיר עליו בתחילת הקוד כמשתנה נדיף(volatile)
  • מטרת הפסיקה להיות קצרה ולעניין אז עדיף לא לכתוב מגילות בתוך הפונקציה

פסיקות טיימר

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

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

#include <TimerOne.h>

void setup(){

  pinMode(3, OUTPUT);

  Timer1.initialize(1000000); // 1000000 microseconds = 1 second

  Timer1.attachInterrupt(buzz); //execute buzz function

} 
void loop(){

  for (int i = 0; i < 256; i++){

    analogWrite(3, i);

    delay(10);

  }

  for (int i = 255; i > 0; i--){

    analogWrite(3, i); delay(10);

  }

}

//Timer interrupt function

void buzz(){

  tone(13, 4000,5);

}

 

כל הזכויות שמורות להאקסטור – 2016

דרג מדריך

  1. איך קוראים קובץ מה SD לא ע"י הוצאתו ??
    וקריאת נתונים ישירות לזיכרון הארדואינו לא לתקשורת הטורית .

    תודה יואב

  2. השאלה מה אתה רוצה לקרוא ואיך זה מסודר בקובץ אבל בעקרון זה כמו קריאה מתקשורת טורית. כדי לקרוא שורה אחת ולשמור אותה במשתנה:
    if (myFile) {
    while (myFile.available()) {
    String line = myFile.readStringUntil('\n');
    }
    }
    אחרי זה אתה יכול לעשות מה שאתה רוצה עם המשתנה

  3. יש לי df player על מנת לשמע מוזיקה מכרטיס microsd
    האם אפשר להשתמש בזה כדי לכתוב קבצים?

  4. מדריכים מעולים חלק טיפה קשה להבנה אבל מאוד טובים ושאלה מתי תגיע הערכה שעליה נבנה המדריך?

  5. היי רציתי לשאול איך אפשר לבצע תיזמון של החלפת התנגדות כל מס' שניות האם חייב להשתמש בממסר או שיש אופציה אחרת

כתיבת תגובה

האימייל לא יוצג באתר.