חיישנים ומפעילים למיקרו-בקרים · פרק 13 — חיווי, תצוגה וממשק אדם-מכונהסמלי מקצוע 33.102 ו-33.002⌂📚🏠
פרק 13

חיווי, תצוגה וממשק אדם-מכונה

כיתות י״א–י״ב · 5 שעות לימוד

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

בסוף הפרק הזה נדע:
  • לכל צבע של נורית חיווי יש משמעות קבועה לפי התקן IEC 60204-1, והבהוב מבקש תשומת לב.
  • נפעיל זמזם אקטיבי או פסיבי, וניצור דפוס התרעה בעזרת millis() בלי לעצור את התוכנית.
  • ההתרעה מהבהבת עד שהאדם מאשר אותה, ואחר כך דולקת באור קבוע עד שהמצב חולף.
  • נחשב את קודי הספרות בתצוגת שבעה מקטעים, ונבין את עקרון ריבוב התצוגה.
  • נכתוב על צג 16×2 ועל צג OLED דרך אפיק I2C, ונשרטט מראש מה יופיע עליהם.
  • נבנה תפריט בשלושה לחצנים לפי תרשים מצבים, ונשמור את הערך הרצוי ב-EEPROM.
  • נבחין בין ממשק אדם-מכונה לממשק מכונה-מכונה, ונכיר את פנל המגע התעשייתי ואת מערכת SCADA.

חיווי, התרעה ונוריות חיווי (Indication, Alarm, Indicator Lamps)

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

אמצעי החיווי הפשוט ביותר הוא נורית חיווי: בלוח החשמל זו נורה במתח 24 V, ובמערכת עם בקר זו דיודה פולטת אור (LED) עם נגד על הדק ספרתי. כדי שכל אדם יבין כל צבע באותה משמעות בכל מכונה, התקן IEC 60204-1 (בטיחות חשמלית של מכונות) קובע את המשמעות של כל צבע:

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

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

נורית שדולקת באור קבוע מתארת מצב. לעומת זאת הבהוב משמש לפי IEC 60204-1 למשיכת תשומת הלב ולדרישה לפעולה מיידית, וגם לציון הבדל בין הפקודה לבין המצב בפועל (פקדנו על השסתום להיפתח והוא עדיין לא נפתח). מידע בעדיפות גבוהה יותר מהבהב מהר יותר. בפרק הזה נאמץ את הכלל המקובל בתעשייה: אדום מהבהב עם זמזם = התרעה חדשה, אדום קבוע = האדם אישר אותה והמצב עדיין קיים, כבוי = המצב חלף.

אישור התרעה: לחיצה של האדם על לחצן ACK כדי לומר למערכת: "ראיתי את ההתרעה". האישור משתיק את הזמזם והנורית עוברת לאור קבוע, אבל אינו מבטל את ההתרעה כל עוד המצב המסוכן קיים.
נגד טורי לנורית
R = VCC − VFIF
סימןמשמעותיחידת מידה
Rהתנגדות הנגד שבטור עם ה-LED[Ω]
VCCמתח ההדק במצב HIGH (5 V ב-Uno)[V]
VF , IFהמתח הקדמי והזרם הקדמי של ה-LED[V] , [A]
דוגמה 13.1
נחשב את הנגד לנוריות חיווי בקוטר 5 mm, לזרם של 10 mA (הרבה פחות מ-20 mA המותרים להדק של Uno). המתח הקדמי: אדום 2.0 V, צהוב 2.1 V, ירוק 2.2 V (ערך טיפוסי לפי גיליון הנתונים).
פתרון:
R = 5 − 2.20.01 = 280 Ω

לאדום 300 Ω ולצהוב 290 Ω. לכולן נבחר את הערך התקני 330 Ω, ואז הזרם: אדום 9.09 mA, צהוב 8.79 mA, ירוק 8.48 mA.

R = 330 Ω
שאלה 13.1: נורית ירוקה עם נגד של 220 Ω על הדק של 5 V. מהו הזרם שלה? האם הוא מותר להדק של Uno?

זמזם ודפוס התרעה (Buzzer and Alarm Pattern)

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

למשל הזמזם האקטיבי TMB12A05: 5 V, עד 30 mA, כ-2300 Hz (ערך טיפוסי לפי גיליון הנתונים). הפונקציה tone() מוציאה גל ריבועי שמחזור העבודה שלו 50 % וזמן המחזור שלו Tp = 1f, עד שנקרא ל-noTone(). לפי התיעוד של Arduino: רק צליל אחד בכל רגע, לא פחות מ-31 Hz, וב-Uno היא משבשת את אפנון רוחב הפולס בהדקים 3 ו-11. הזרם 30 mA גבוה מן המומלץ להדק, ולכן נפעיל את הזמזם דרך טרנזיסטור כמפסק עם נגד בסיס 1 kΩ (פרק 10). בזמזם המגנטי יש סליל, ולכן נוסיף לו דיודת חופש.

Arduino Uno5VA0GNDD25V D9D5D6D7GND LM35+VSVOUTGND10 mV/°CACKINPUT_PULLUPRYG330 Ω+1 kΩ2N2222BZ
מערכת התרעה: LM35 על A0, לחצן האישור על D2, הנוריות על D5, D6 ו-D7, והזמזם דרך טרנזיסטור על D9

דפוס התרעה שאינו עוצר את התוכנית. אילו כתבנו את ההבהוב בעזרת delay(250), התוכנית הייתה נעצרת בכל פעם, ולא הייתה רואה את הלחיצה על לחצן האישור בזמן. במקום זאת נחשב את מצב ההבהוב מן השעון: השארית millis() % 500 חוזרת על עצמה כל 500 ms, והיא קטנה מ-250 במחצית מן הזמן. הלולאה רצה אלפי פעמים בשנייה ורואה כל לחצן מיד.

התרעה בשלושה צבעים, זמזם מהבהב ואישור — בלי delay Arduino Uno · alarm_ack.ino
const int SENSOR = A0;                    // LM35: 10 mV per degree C
const int GREEN_LED = 5, YELLOW_LED = 6, RED_LED = 7;
const int BUZZER = 9, ACK_BTN = 2;        // buzzer via NPN, button to GND
const float T_WARN = 45.0, T_ALARM = 50.0;

bool alarmOn = false, acked = false, buzzing = false;
float t = 0;
unsigned long tRead = 0;

void setup() {
  Serial.begin(9600);
  for (int p = 5; p <= 7; p++) pinMode(p, OUTPUT);   // three lamps
  pinMode(ACK_BTN, INPUT_PULLUP);
}

void loop() {
  unsigned long now = millis();
  if (now - tRead >= 1000) {              // one reading per second
    tRead = now;
    t = analogRead(SENSOR) * 500.0 / 1023.0;
    if (t >= T_ALARM && !alarmOn) { alarmOn = true; acked = false; }
    if (t < T_ALARM && acked) alarmOn = false;
    Serial.print("T = "); Serial.print(t, 1);
    if (!alarmOn) Serial.println(t < T_WARN ? "  GREEN" : "  YELLOW");
    else Serial.println(acked ? "  RED steady" : "  RED flashing + beep");
  }
  if (alarmOn && digitalRead(ACK_BTN) == LOW) acked = true;
  bool blink = (now % 500) < 250;         // 2 Hz, 50 %
  digitalWrite(GREEN_LED, !alarmOn && t < T_WARN);
  digitalWrite(YELLOW_LED, !alarmOn && t >= T_WARN);
  digitalWrite(RED_LED, alarmOn && (acked || blink));
  bool beep = alarmOn && !acked && blink;
  if (beep != buzzing) {                  // call tone() only on a change
    buzzing = beep;
    if (beep) tone(BUZZER, 2000); else noTone(BUZZER);
  }
}

נחמם את החיישן ואחר כך ניתן לו להתקרר. הטמפרטורה האמיתית בכל שנייה (°C): 41, 44, 46, 48, 51, 53, 54, 52, 49, 47, 44, ונלחץ על לחצן האישור ב-t = 7.4 s. הקריאה עוברת דרך הממיר התקבילי-ספרתי, ולכן היא שונה מעט מן האמיתית:

Serial Monitor · קריאה לדוגמה
T = 40.6  GREEN
T = 44.0  GREEN
T = 45.9  YELLOW
T = 47.9  YELLOW
T = 50.8  RED flashing + beep
T = 52.8  RED flashing + beep
T = 53.8  RED flashing + beep
T = 51.8  RED steady
T = 48.9  YELLOW
T = 46.9  YELLOW
T = 44.0  GREEN
4550T [°C]ירוקצהובאדוםזמזםACK024681012t [s]
דיאגרמת זמנים מאותו מודל: הטמפרטורה הנקראת, שלוש הנוריות, הזמזם ולחצן האישור
שאלה 13.2: א. מהו הערך הגולמי N הקטן ביותר שמפעיל את ההתרעה?
ב. T עולה ל-52 °C ואחר כך יורד ל-47 °C, ואיש לא לחץ על הלחצן. מה רואה מפעיל המכונה?
טעות נפוצה: קריאה ל-tone() בכל מחזור מאפסת את הטיימר אלפי פעמים בשנייה, והצליל יוצא מעוות. נקרא לה רק כשהמצב משתנה (המשתנה buzzing).
אזהרה: זמזם לימודי אינו מחליף מערכת מאושרת להתרעת אש או גז. וצופר רשת של 230 V אינו מתחבר לבקר אלא דרך מודול ממסר מאושר וסגור, בהשגחת המורה.

תצוגת שבעה מקטעים (Seven-Segment Display)

תצוגת שבעה מקטעים: שבע נוריות LED מוארכות (מקטעים) בצורת הספרה 8, ששמותיהן a עד g, ולרוב יש גם נקודה DP. נקראת גם "תצוגת 7 סגמנטים".
agdfbecDP
שמות המקטעים a – g והנקודה DP
abcdefgCOM
קתודה משותפת: COM לאדמה, והמקטע נדלק ב-HIGH
abcdefgCOM
אנודה משותפת: COM ל-5 V, והמקטע נדלק ב-LOW

בתצוגה עם קתודה משותפת (CC) נחבר את COM לאדמה, והמקטע נדלק ב-HIGH; בתצוגה עם אנודה משותפת (CA) נחבר את COM ל-5 V, והמקטע נדלק ב-LOW (למשל 5161AS היא בעלת קתודה משותפת ו-5161BS בעלת אנודה משותפת). לכל ספרה נכתוב בית: סיבית 0 למקטע a … סיבית 6 למקטע g, ו-1 = דולק בקתודה משותפת. באנודה משותפת נהפוך את שבע הסיביות:

הספרהabcdefgהקוד (CC)הקוד (CA)
011111100x3F0x40
101100000x060x79
211011010x5B0x24
311110010x4F0x30
401100110x660x19
510110110x6D0x12
610111110x7D0x02
711100000x070x78
811111110x7F0x00
911110110x6F0x10
דוגמה 13.2
נחשב את הקוד של הספרה 4 בקתודה משותפת ובאנודה משותפת.
פתרון:

הספרה 4 מדליקה את b, c, f, g, כלומר את הסיביות 1, 2, 5, 6:

CC = 21 + 22 + 25 + 26 = 102 = 0x66
CA = 127 − 102 = 25 = 0x19
CC = 0x66 ; CA = 0x19
Arduino UnoD2D3D4D5D6D7D8GND5161ASabcdefgCOM7 × 330 Ω(CC)
תצוגה עם קתודה משותפת: המקטעים a – g אל D2 – D8, כל מקטע עם 330 Ω

לכל מקטע נגד משלו: נגד אחד ב-COM היה גורם לספרה 1 להיות בהירה ולספרה 8 להיות עמומה. עם VF ≈ 2 V (ערך טיפוסי לפי גיליון הנתונים ל-LED אדום) זרם המקטע הוא I = 5 − 2330 ≈ 9.1 mA. בתוכנית, bitRead(x, i) קוראת את הסיבית i, והביטוי on != COMMON_ANODE הופך את הלוגיקה: לאנודה משותפת משנים שורה אחת, COMMON_ANODE = true.

ספירה מ-0 עד 9, והקודים במערך Arduino Uno · seven_segment_digit.ino
const int SEG_PIN[7] = {2, 3, 4, 5, 6, 7, 8};   // segments a..g
const bool COMMON_ANODE = false;                // 5161AS: common cathode
// bit 0 = a ... bit 6 = g ; 1 = segment lit
const byte DIGIT[10] = {0x3F, 0x06, 0x5B, 0x4F, 0x66,
                        0x6D, 0x7D, 0x07, 0x7F, 0x6F};

void showDigit(int d) {
  for (int i = 0; i < 7; i++) {
    bool on = bitRead(DIGIT[d], i);
    digitalWrite(SEG_PIN[i], on != COMMON_ANODE);  // anode: lit = LOW
  }
}

void setup() {
  for (int i = 0; i < 7; i++) pinMode(SEG_PIN[i], OUTPUT);
}

void loop() {
  for (int d = 0; d < 10; d++) {
    showDigit(d);
    delay(1000);
  }
}
ריבוב תצוגה: הפעלה של כמה ספרות דרך אותם הדקי מקטעים: מדליקים ספרה אחת בכל רגע ועוברים מהר לספרה הבאה, והעין רואה את כל הספרות דולקות יחד. נקרא גם "ריבוב בזמן".

לארבע ספרות נצטרך 7 + 4 = 11 הדקים במקום 28. הדק ה-COM של כל ספרה עובר דרך טרנזיסטור: הזרם של הספרה 8 הוא 7·9.09 ≈ 63.6 mA, יותר מ-40 mA, הגבול המרבי המוחלט להדק של Uno.

למשל, בתצוגה של ארבע ספרות שבה כל ספרה דולקת 4 ms, כל ספרה חוזרת אחרי 4·4 = 16 ms, כלומר כ-62.5 פעמים בשנייה: מהר יותר ממה שהעין מבחינה, ולכן לא נראה ריצוד. אבל כל ספרה דולקת רק רבע מן הזמן, ולכן היא נראית עמומה יותר מהדלקה קבועה. בתוכנית אמיתית נעבור לספרה הבאה בעזרת millis() ולא בעזרת delay(), או נשתמש בשבב סריקה מוכן כמו MAX7219.

צג גביש נוזלי 16×2 באפיק I2C (Character LCD over I2C)

צג גביש נוזלי: צג טקסט: בצג 16×2 יש שתי שורות, ובכל אחת 16 תאים, וכל תא הוא מטריצה של 5×8 נקודות. הוא נשלט על ידי הבקר הפנימי HD44780, ויש לו תאורה אחורית. נקרא גם LCD.

מאחורי הצג יש כרטיס עם השבב PCF8574, ולכן מספיקים ארבעה חוטים: ההזנה, האדמה ואפיק I2C — שני חוטים בלבד, SDA לנתונים ו-SCL לשעון, שכמה רכיבים חולקים וכל אחד מהם עם כתובת משלו; ב-Uno SDA הוא A4 ו-SCL הוא A5. הכתובת של הכרטיס היא 0x27 עם PCF8574 ו-0x3F עם PCF8574A (ערך טיפוסי לפי גיליון הנתונים). הפקודות: init(), backlight() לתאורה, setCursor(c, r) לעמודה c ולשורה r (הספירה מ-0), ו-print().

Arduino UnoGND5VA4A55V A0GND LCD I2CGNDVCCSDASCLPCF8574 · 0x27 / 0x3FLM35+VSVOUTGND
הצג על אפיק I2C (A4, A5), והחיישן LM35 על A0
הטמפרטורה והערך הרצוי על צג 16×2 Arduino Uno · lcd_temperature.ino
#include <Wire.h>
#include <LiquidCrystal_I2C.h>

const int SENSOR = A0;                // LM35: 10 mV per degree C
const float SET_POINT = 30.0;         // [C]
LiquidCrystal_I2C lcd(0x27, 16, 2);   // 0x3F on some modules

void setup() {
  lcd.init();
  lcd.backlight();
}

void loop() {
  float t = analogRead(SENSOR) * 500.0 / 1023.0;
  bool heat = t < SET_POINT;          // heater demand
  lcd.setCursor(0, 0);                // column 0, row 0
  lcd.print("T  = "); lcd.print(t, 1);
  lcd.print((char)223); lcd.print("C    ");   // 223 = degree sign
  lcd.setCursor(0, 1);
  lcd.print("SP = "); lcd.print(SET_POINT, 1);
  lcd.print((char)223); lcd.print(heat ? "C  ON " : "C  OFF");
  delay(500);
}
T=24.4°CSP=30.0°CON
כאשר N = 50: קר יותר מן הרצוי, נדרש חימום
T=31.3°CSP=30.0°COFF
כאשר N = 64: חם יותר מן הרצוי, החימום כבוי

שני הציורים מחושבים תא אחר תא מאותן מחרוזות: למשל N = 50 נותן T = 50·5001023 = 24.438 °C, ו-print(t, 1) מעגלת ל-24.4. התו 223 בטבלת התווים של HD44780 הוא "°". נכתוב רווחים בסוף השורה: הצג אינו מוחק את מה שנכתב קודם, ואם הטקסט מתקצר (מ-100.0 ל-99.5) נשאר תו ישן. ולא נקרא ל-lcd.clear() בכל מחזור: היא מוחקת את כל הצג ונראה ריצוד.

שאלה 13.3: הצג מואר אבל אינו מציג אף תו, והחיבור תקין. מהן שתי הסיבות הנפוצות ביותר?

צג OLED גרפי 128×64 (Graphic OLED Display)

צג OLED: צג גרפי שבו כל נקודה (פיקסל) היא דיודה אורגנית שמאירה בעצמה, ולכן אין לו צורך בתאורה אחורית. הצג הנפוץ הוא של 128×64 פיקסלים, נשלט על ידי SSD1306, וכתובתו באפיק I2C היא 0x3C (או 0x3D).

הנקודה (0, 0) נמצאת בפינה השמאלית העליונה; x גדל ימינה עד 127, ו-y גדל כלפי מטה עד 63. הספרייה Adafruit_SSD1306 (עם Adafruit_GFX) מציירת קודם בזיכרון של הבקר, ואחר כך שולחת את כל התמונה בעזרת display(). כל פיקסל הוא סיבית, ולכן התמונה תופסת 128·648 = 1024 בתים: מחצית מזיכרון ה-Uno (2048 בתים). הספרייה מקצה אותה בתוך begin(), ולכן היא אינה מופיעה בדוח ההידור, ואם לא נשאר מקום begin() מחזירה false.

Arduino UnoGND5VA4A55V A0GND OLED 0x3CGNDVCCSDASCLSSD1306 · 128×6410 kΩ
צג OLED על הדקי I2C, ופוטנציומטר על A0 במקום חיישן מפלס
מפלס המיכל כמספר וכעמודה אופקית Arduino Uno · oled_bar_graph.ino
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

const int SENSOR = A0;                      // potentiometer as a level sensor
Adafruit_SSD1306 oled(128, 64, &Wire, -1);  // -1: no reset pin

void setup() {
  if (!oled.begin(SSD1306_SWITCHCAPVCC, 0x3C))
    while (true) {}                         // no screen or no RAM: stop
}

void loop() {
  int pct = map(analogRead(SENSOR), 0, 1023, 0, 100);
  int w = map(pct, 0, 100, 0, 124);           // bar width [pixels]
  oled.clearDisplay();
  oled.setTextColor(SSD1306_WHITE);
  oled.setTextSize(1); oled.setCursor(0, 0);
  oled.print("TANK LEVEL");
  oled.setTextSize(2); oled.setCursor(0, 16);
  oled.print(pct); oled.print(" %");
  oled.drawRect(0, 40, 128, 20, SSD1306_WHITE);  // frame
  oled.fillRect(2, 42, w, 16, SSD1306_WHITE);    // bar
  oled.display();                           // send the buffer
  delay(200);
}
TANK LEVEL68 %
הצג כאשר N = 700

הציור מחושב פיקסל אחר פיקסל מאותן פקודות. תו בגופן הבסיסי הוא 5×7 פיקסלים בתוך תא של 6×8, ו-setTextSize(2) מכפילה את הממדים. בחלק מן המודולים שש-עשרה שורות הפיקסלים העליונות צהובות והשאר כחולות, ולכן הכותרת נמצאת ב-y < 16.

דוגמה 13.3
נחשב את האחוז ואת רוחב העמודה כאשר N = 700.
פתרון:
pct = ⌊700·1001023⌋ = 68
w = ⌊68·124100⌋ = 84

הפונקציה map() מחשבת במספרים שלמים ומשמיטה את השבר. העמודה מתחילה ב-x = 2 ומסתיימת ב-x = 85, בתוך המסגרת.

pct = 68 ; w = 84
שאלה 13.4: צג LCD (0x27) וצג OLED (0x3C) מחוברים יחד להדקים A4 ו-A5. האם זה עובד?
טעות נפוצה: על מודולים רבים כתוב 0x78: זו הכתובת כפול 2 יחד עם סיבית הקריאה/כתיבה (0x3C·2 = 0x78). בתוכנית נכתוב את הכתובת בת שבע הסיביות, 0x3C.

ממשק קטן: שלושה לחצנים וערך רצוי ב-EEPROM (Mini HMI with EEPROM)

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

RUNהצגת הערכיםEDITשינוי הערך הרצויEEPROM.getהפעלהOKspEdit = spOKEEPROM.put10 שניות בלי לחיצה: בלי שמירהUP / DOWN±0.5 °CspEdit
תרשים המצבים של התפריט: שני מצבים, והמעבר ביניהם בלחצנים או בתום הזמן הקצוב
זיכרון EEPROM: זיכרון בתוך הבקר שהנתונים נשמרים בו גם אחרי ניתוק ההזנה. ב-ATmega328P (Uno) גודלו 1024 בתים, וכל תא עומד בכ-100000 כתיבות (ערך טיפוסי לפי גיליון הנתונים). בתא חדש רשום 0xFF.

נשמור את הערך בעשיריות מעלה, כמספר שלם int (שני בתים): 25.5 °C נשמר כ-255. הפונקציה EEPROM.get() קוראת, ו-EEPROM.put() כותבת רק את הבתים שהשתנו. בזיכרון חדש הקריאה מחזירה −1, ולכן נבדוק את התחום ונציב ערך ברירת מחדל.

Arduino UnoGND5VA4A5D2D3D4GND A05V LCD I2CGNDVCCSDASCL0x27 · 16×2UPDOWNOKLM35GNDVOUT+VSINPUT_PULLUP
שלושה לחצנים לאדמה על D2, D3, D4, הצג על I2C והחיישן על A0
תפריט בשלושה לחצנים, זמן קצוב ושמירת הערך הרצוי ב-EEPROM Arduino Uno · mini_hmi_eeprom.ino
#include <Wire.h>
#include <EEPROM.h>
#include <LiquidCrystal_I2C.h>

const int BTN[3] = {2, 3, 4};             // UP, DOWN, OK (to GND)
const int SENSOR = A0, ADDR = 0;          // LM35 ; EEPROM address
const int SP_MIN = 100, SP_MAX = 600, STEP = 5;   // tenths of C
const unsigned long TIMEOUT = 10000;      // ms without a key
LiquidCrystal_I2C lcd(0x27, 16, 2);
int sp, spEdit;                           // set-point x 10: 255 = 25.5 C
bool editing = false;
unsigned long tKey = 0;
int last[3] = {HIGH, HIGH, HIGH};

bool pressed(int i) {                     // HIGH -> LOW edge
  int now = digitalRead(BTN[i]);
  bool edge = (last[i] == HIGH && now == LOW);
  last[i] = now;
  return edge;
}

void setup() {
  Serial.begin(9600);
  for (int i = 0; i < 3; i++) pinMode(BTN[i], INPUT_PULLUP);
  lcd.init(); lcd.backlight();
  EEPROM.get(ADDR, sp);
  if (sp < SP_MIN || sp > SP_MAX) sp = 250;   // new EEPROM reads -1
  Serial.print("SP from EEPROM = "); Serial.println(sp / 10.0, 1);
}

void loop() {
  bool up = pressed(0), down = pressed(1), ok = pressed(2);
  if (up || down || ok) tKey = millis();
  if (!editing) {
    if (ok) { editing = true; spEdit = sp; Serial.println("EDIT"); }
  } else {
    if (up)   spEdit = min(spEdit + STEP, SP_MAX);
    if (down) spEdit = max(spEdit - STEP, SP_MIN);
    if (up || down) {
      Serial.print("SP* = "); Serial.println(spEdit / 10.0, 1);
    }
    if (ok) {                             // save only on OK
      sp = spEdit; editing = false; EEPROM.put(ADDR, sp);
      Serial.print("SAVED SP = "); Serial.println(sp / 10.0, 1);
    } else if (millis() - tKey > TIMEOUT) {
      editing = false; Serial.println("TIMEOUT: no change");
    }
  }
  float t = analogRead(SENSOR) * 500.0 / 1023.0;
  lcd.setCursor(0, 0); lcd.print("T  = "); lcd.print(t, 1); lcd.print(" C  ");
  lcd.setCursor(0, 1); lcd.print(editing ? "SP*= " : "SP = ");
  lcd.print((editing ? spEdit : sp) / 10.0, 1); lcd.print("  ");
  delay(20);                              // 20 ms sampling: no bounce
}

נפעיל את הבקר בפעם הראשונה (EEPROM חדש) ונלחץ לפי הסדר: OK ‏← UP ‏← UP ‏← UP ‏← DOWN ‏← OK ‏← OK ‏← UP ‏← המתנה 11 s:

Serial Monitor · קריאה לדוגמה
SP from EEPROM = 25.0
EDIT
SP* = 25.5
SP* = 26.0
SP* = 26.5
SP* = 26.0
SAVED SP = 26.0
EDIT
SP* = 26.5
TIMEOUT: no change
T=23.0CSP*=26.5
הצג במצב EDIT אחרי שלוש לחיצות UP (N = 47)

אחרי ניתוק ההזנה והחזרתה התוכנית מדפיסה "SP from EEPROM = 26.0": הערך נשמר. הלולאה ממתינה 20 ms בכל מחזור; זה ארוך מקפיצות המגע ולכן מספיק לסינון קפיצות, ועדיין מהיר מאוד לאדם.

דוגמה 13.4
תוכנית שגויה כותבת את הערך ל-EEPROM בכל שנייה. אחרי כמה שעות עלול התא להיהרס? וכמה שנים יחזיק אם נכתוב רק בלחיצה על OK, 20 פעמים ביום?
פתרון:
t = 100000·1 s = 27.8 h

עם 20 כתיבות ביום: t = 10000020 = 5000 ימים, כלומר כ-13.7 שנים.

לכן נכתוב ל-EEPROM רק כשהאדם מאשר, ולא בכל מחזור של loop().

t ≈ 27.8 h
טעות נפוצה: הלחצנים מחוברים לאדמה עם INPUT_PULLUP, ולכן לחיצה היא LOW. נזהה את החזית (מ-HIGH ל-LOW) ולא את הרמה: אחרת הערך יעלה 50 פעמים בשנייה כל עוד הלחצן לחוץ.
▶ניסוי חי — ממשק אדם-מכונהנתנסה בממשק הפעלה: נוריות חיווי, התרעה ואישור, ושינוי הערך הרצוי.
⚠
המעבדה אינה זמינה כרגע. החומר בפרק שלם גם בלעדיה — ממשיכים לקרוא, וחוזרים לניסוי מאוחר יותר או פותחים אותו ישירות בקישור שמתחת למסגרת.
https://fahed-lab.com/hashmal/sensors#hmi
פתיחת המעבדה בדף נפרד ↗ fahed-lab.com/hashmal/sensors#hmi

ממשק אדם-מכונה וממשק מכונה-מכונה (HMI and M2M)

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

ממשק אדם-מכונה (HMI): הממשק בין האדם למכונה: הלחצנים, הנוריות, הצגים והזמזמים. מטרתו שהאדם יבין את מצב התהליך מהר ובלי טעות, וייתן את הפקודות שלו בבטחה.
ממשק מכונה-מכונה (M2M): ממשק שבו התקנים מחליפים מידע בעצמם, בלי אדם: בקר שקורא חיישן באפיק I2C, לולאת זרם 4–20 mA, או שני בקרים מתוכנתים (PLC) שמחליפים ערכים ברשת תעשייתית.
▶ניסוי חי — לוחות בקרהנכיר את לוחות הבקרה בתעשייה: הלחצנים, נוריות החיווי והצבעים שלהם.
⚠
המעבדה אינה זמינה כרגע. החומר בפרק שלם גם בלעדיה — ממשיכים לקרוא, וחוזרים לניסוי מאוחר יותר או פותחים אותו ישירות בקישור שמתחת למסגרת.
https://fahed-lab.com/hashmal/sensors#panels
פתיחת המעבדה בדף נפרד ↗ fahed-lab.com/hashmal/sensors#panels
ממשק אדם-מכונהממשק מכונה-מכונה
צורת המידעצבעים, סמלים, טקסטים, ציורים, צליליםמספרים ואותות לפי פרוטוקול
המהירותמהירות האדם: חלקי שנייה מספיקיםממיקרו-שניות ועד שניות
דוגמאותהנוריות, התצוגה, LCD, OLED, הלחצניםI2C, חוט יחיד, לולאת זרם
מכונה 1חיישנים ומפעיליםמכונה 2חיישנים ומפעיליםבקר / PLC 1בקר / PLC 2ממשק מכונה-מכונהנתונים בלי אדםפנל מגע HMIליד המכונהאדם-מכונהSCADAחדר הבקרה: פיקוח, תיעוד, התרעותרשת תעשייתית
שכבות המפעל: המכונות, הבקרים, פנל המגע ליד המכונה, ו-SCADA בחדר הבקרה

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

עקרונות תכנון ממשק:

  1. בהירות ומשוב: כל מסך עונה על שאלה אחת, הערכים מוצגים עם היחידות שלהם (°C, bar), וכל לחיצה נראית או נשמעת.
  2. צבעים עקביים: אדום לסכנה בלבד וירוק למצב תקין בלבד, בכל המסכים והנוריות. ולא נסתמך על הצבע לבדו: נוסיף טקסט או סמל, כי יש אנשים שאינם מבחינים בין אדום לירוק.
  3. אישור פעולות מסוכנות: פקודה שעלולה לגרום נזק ("ריקון המיכל") דורשת שני צעדים: הפקודה, ואחריה "האם אתם בטוחים?". ועצירת חירום לעולם אינה על המסך: זה לחצן נפרד במעגל הבטיחות.
  4. אישור התרעות: התרעה חדשה מהבהבת ונשמעת עד שמאשרים אותה, ומספרת מה קרה, איפה, ומה עושים. ומספר ההתרעות קטן ומדורג לפי עדיפויות: מאה התרעות בדקה — איש אינו קורא אותן.
שאלה 13.5: בפנל מגע צויר הלחצן "הפעלת המשאבה" באדום, וגם הנורית "המשאבה פועלת כרגיל" צוירה באדום. מהן שתי הטעויות?

סיכום נוסחאות הפרק:

החוקהנוסחה
נגד טורי לנורית חיוויR = VCC − VFIF
זמן המחזור של צליל הזמזםTp = 1f
המרת הערך הגולמי של LM35 למעלותT = N·5001023
קוד הספרה באנודה משותפתCA = 127 − CC
זיכרון התמונה של OLEDbuffer = W·H8

מילון מונחים:

עבריתEnglishالعربية
חיוויIndicationالبيان
התרעהAlarmالإنذار
נורית חיוויIndicator lampمصباح البيان
הבהובFlashingالوميض
אישור התרעהAlarm acknowledgeالإقرار بالإنذار
מפעיל המכונהMachine operatorالعامل على الآلة
זמזם אקטיבי · פסיביActive · passive buzzerالطنّان (البازر) فعّال · سلبي
תצוגת שבעה מקטעיםSeven-segment displayالعارض سباعي المقاطع
קתודה משותפת · אנודה משותפתCommon cathode · common anodeالمهبط المشترك · المصعد المشترك
ריבוב תצוגהDisplay multiplexingالمسح المتعدّد (تعدّد الإرسال الزمني)
צג גביש נוזליLiquid crystal displayشاشة الكريستال السائل (LCD)
אפיק I2C · כתובתI2C bus · addressناقل I2C · العنوان
צג OLEDOLED displayشاشة OLED
ערך רצויSet-pointالقيمة المطلوبة
תרשים מצביםState diagramمخطّط الحالات
זיכרון EEPROMEEPROMذاكرة EEPROM
ממשקInterfaceالواجهة
ממשק אדם-מכונהHuman-machine interface (HMI)واجهة الإنسان والآلة
ממשק מכונה-מכונהMachine-to-machine interface (M2M)واجهة آلة-آلة
פנל HMI / מסך מגע תעשייתיIndustrial touch panelلوح اللمس الصناعي
בקר מתוכנת (PLC)Programmable logic controllerالمتحكّم المنطقي المبرمج
מערכת SCADASupervisory control and data acquisitionنظام SCADA

שאלות לתרגול:

1.
במכונה דולקת נורית צהובה באור קבוע. מה משמעותה לפי IEC 60204-1, ומה עושה מפעיל המכונה? ומה המשמעות של נורית כחולה?
תשובות: מצב חריג או מצב קריטי מתקרב: מעקב ו/או התערבות. כחול: פעולת חובה שנדרשת ממפעיל המכונה
2.
נורית צהובה עם VF = 2.1 V על הדק של 5 V, והזרם הרצוי 10 mA.
א. חשבו את הנגד.
ב. בחרו את הערך התקני הגדול הבא וחשבו את הזרם בפועל.
תשובות: א. R = 290 Ω. ב. 330 Ω, IF ≈ 8.79 mA
3.
זמזם פסיבי מופעל בעזרת tone(9, 2500). חשבו את זמן המחזור ואת זמן מצב ה-HIGH בכל מחזור, ביחידות µs.
תשובות: Tp = 400 µs, tHIGH = 200 µs
4.
דפוס התרעה: הזמזם פועל 150 ms ושותק 350 ms, וחוזר חלילה.
א. כמה צפצופים יש בשנייה?
ב. מהו מחזור העבודה?
ג. כתבו את התנאי בעזרת millis().
תשובות: א. 2 בשנייה. ב. 30 %. ג. (millis() % 500) < 150
5.
כתבו את הקוד של האות H (המקטעים b, c, e, f, g) בקתודה משותפת ובאנודה משותפת.
תשובות: CC = 0x76, CA = 0x09
6.
בתצוגה עם קתודה משותפת כל מקטע מחובר עם 470 Ω, ו-VF = 2 V.
א. חשבו את זרם המקטע.
ב. חשבו את הזרם ב-COM כשמוצגת הספרה 8.
ג. האם אפשר לחבר את COM ישירות להדק של Uno?
תשובות: א. I ≈ 6.38 mA. ב. 44.7 mA. ג. לא: יותר מ-40 mA, נשתמש בטרנזיסטור
7.
תצוגה של שש ספרות בריבוב, וכל ספרה דולקת 2.5 ms. אחרי כמה מילי-שניות כל ספרה חוזרת? כמה פעמים בשנייה היא נדלקת? האם נראה ריצוד?
תשובות: אחרי 15 ms, כ-66.7 פעמים בשנייה; אין ריצוד
8.
בתוכנית lcd_temperature קרא הבקר N = 63. מה ייכתב בשתי השורות?
תשובות: בשורה הראשונה "T = 30.8°C", ובשורה השנייה "SP = 30.0°C OFF"
9.
בתוכנית oled_bar_graph האחוז הוא 45 %.
א. מהו רוחב העמודה בפיקסלים?
ב. כמה בתים דורשת התמונה של צג 128×32?
תשובות: א. w = 55. ב. 512 בתים
10.
תוכנית שומרת את הערך הרצוי ב-EEPROM כל 30 s.
א. אחרי כמה ימים עלול התא להיהרס?
ב. הציעו שינוי בתוכנית.
תשובות: א. כ-34.7 ימים. ב. נכתוב רק בלחיצה על OK (או כשהערך משתנה)
11.
הוסיפו לתרשים המצבים של הממשק מצב שלישי, ALARM: נכנסים אליו מ-RUN כאשר T ≥ 50 °C, ויוצאים ממנו ל-RUN אחרי האישור וחלוף המצב. סרטטו את התרשים החדש וכתבו על כל חץ את תנאי המעבר.
תשובות: שלושה מצבים, RUN, EDIT, ALARM; RUN→ALARM כאשר T ≥ 50, ALARM→RUN כאשר ACK ו-T < 50
12.
תכננו דף בפנל מגע עבור מיכל מים. ציינו שלושה עקרונות תכנון ויישמו כל אחד מהם בדף.
תשובות: למשל: מפלס במספרים עם היחידה; ירוק למצב תקין ואדום לגלישה, עם טקסט; אישור לפני "ריקון המיכל"
תשובות סופיות לשאלות הפרק
13.1 IF ≈ 12.7 mA, מותר (פחות מ-20 mA)
13.2 א. N = 103 (כי 50·1023500 = 102.3). ב. האדום עדיין מהבהב והזמזם פועל עד האישור
13.3 הכתובת שגויה (ננסה 0x3F במקום 0x27), או שהניגודיות אינה מכוונת (הפוטנציומטר שבכרטיס האחורי)
13.4 כן: לכל התקן כתובת שונה על אותו אפיק
13.5 לחצן הפעלה אינו אדום; והמצב התקין ירוק (אדום לסכנה בלבד)
נוסחאון הספר: כל נוסחאות הפרק הזה מרוכזות, עם סרטוטיהן וטבלאות הסמלים שלהן, בפרק 15 — נוסחאון הספר.