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

מבואות תקביליים והתאמת אותות

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

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

בסוף הפרק הזה נדע:
  • נסביר דגימה וקוונטיזציה, ונחשב את Nmax ואת הרזולוציה בלוח Uno ובלוח ESP32.
  • נמיר ערך גולמי למתח בנוסחה V = N·VrefNmax ולהפך, ונימנע משגיאות חישוב במספרים שלמים.
  • נחבר חיישן התנגדותי במחלק מתח ונבחר לו נגד קבוע מתאים.
  • נקטין מתח הגבוה ממתח הייחוס במחלק מתח לפני שנקרא אותו.
  • נקטין את הרעש בעזרת ממוצע של כמה קריאות בתוכנה.
  • נמיר את הקריאה ליחידות הנדסיות לפי תחום החיישן שבדף הנתונים, ביחס ישר או בעזרת הפונקציה map().
  • נשווה בין Uno,‏ ESP32 ורספברי פיי: הממיר, תחום הערכים וההפרדה, ונקרא חיישן ברספברי פיי בפייתון.

הממיר התקבילי-ספרתי (Analog-to-Digital Converter)

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

ממיר תקבילי-ספרתי (ADC): מעגל שמודד את המתח במבוא שלו ונותן מספר שלם שעומד ביחס ישר אליו. מספר זה נקרא ערך גולמי ונסמן אותו באות N.

הממיר פועל בשני שלבים:

01.252.53.755tVהאות התקביליהערך אחרי קוונטיזציה
דגימה וקוונטיזציה בממיר של 3 סיביות: האות (כחול), הדגימות (נקודות) והערך אחרי הקוונטיזציה (אדום)
1234501234567VN0.625 V
העקום האופייני של ממיר של 3 סיביות עם Vref = 5 V: שמונה מדרגות, רוחב כל מדרגה 0.625 V

מספר סיביות, מתח ייחוס ורזולוציה:

את מספר המדרגות קובע מספר הסיביות n: ממיר של n סיביות נותן 2n ערכים, מ-0 עד Nmax. המתח הגבוה ביותר שהממיר מודד הוא מתח הייחוס Vref, והמרחק בין שתי מדרגות סמוכות הוא הרזולוציה (ההפרדה): השינוי הקטן ביותר במתח שהממיר מבחין בו. הערך הגולמי עומד ביחס ישר למתח: 0 V נותן N = 0, ו-Vref נותן N = Nmax.

ממיר תקבילי-ספרתי
Nmax = 2n − 1
Δ V = Vref2n
V = N·VrefNmax
סימןמשמעותיחידת מידה
n , Nמספר הסיביות של הממיר · הערך הגולמי (מ-0 עד Nmax)—
V , Vrefהמתח במבוא · מתח הייחוס (המתח הגבוה ביותר שהממיר מודד)[V]
Δ Vרזולוציה: רוחב מדרגה אחת[V]
הלוחnNmaxVrefרזולוציה Δ V
Arduino Uno (ATmega328P)1010235 V4.88 mV
ESP321240953.3 V0.806 mV

כדי לחשב את הערך הגולמי הצפוי למתח מסוים נהפוך את הנוסחה: N = V·NmaxVref, וניקח את החלק השלם. דף הנתונים של ATmega328P כותב במכנה 2n במקום Nmax; ההבדל אינו עולה על ערך גולמי אחד, ובספר אנו משתמשים ב-Nmax כי כך מתקבל בדיוק Vref עבור Nmax.

דוגמה 4.1
לוח Uno קורא N = 614.
(א) מהו המתח במבוא?
(ב) איזה ערך גולמי נצפה לקבל עבור מתח של 1.2 V?
פתרון:

(א) נציב בנוסחה:

V = N·VrefNmax = 614·51023 = 3.001 V

(ב) נהפוך את הנוסחה וניקח את החלק השלם:

N = V·NmaxVref = 1.2·10235 = 245.52 → N = 245
V = 3.001 V , N = 245
שאלה 4.1: חיישן המחובר ללוח ESP32 נותן 1.65 V. איזה ערך גולמי נצפה לקבל? ומהו המתח אם קראנו N = 1000?
ESP32: הרזולוציה של ESP32 קטנה פי 6.1 בערך מזו של Uno. אבל הממיר שלו אינו לינארי ליד שני קצות התחום (ליד 0 V וליד הגבול העליון), ולכן עדיף לעבוד באמצע התחום. ההדקים של ADC2 אינם פועלים כאשר רשת WiFi מופעלת, ולכן בפרויקטי רשת משתמשים בהדקי ADC1 (מ-GPIO32 עד GPIO39). ההדקים של ESP32 עובדים במתח 3.3 V ואינם עומדים ב-5 V.

שינוי מתח הייחוס: בלוח Uno בוחרים את הייחוס בפקודה analogReference(): DEFAULT פירושו 5 V, INTERNAL הוא ייחוס פנימי של 1.1 V (ערך טיפוסי לפי דף הנתונים), ו-EXTERNAL הוא המתח המחובר להדק AREF. עם 1.1 V מתקבל Δ V = 1.11024 = 1.07 mV; זה מועיל לחיישן שמתחו קטן, אבל כל מתח מעל 1.1 V נקרא 1023.

אזהרה: לא נחבר להדק AREF מתח נמוך מ-0 V או גבוה מ-5 V, ועם ייחוס חיצוני נכתוב analogReference(EXTERNAL) לפני הקריאה הראשונה של analogRead(), אחרת הבקר עלול להינזק. אחרי שינוי הייחוס נתעלם מן הקריאות הראשונות, כי הן אינן מדויקות.

קריאת מבוא תקבילי בתוכנית (analogRead)

10k

בלוח Uno יש שישה מבואות תקביליים, מ-A0 עד A5. הפקודה analogRead(A0) מחזירה את הערך הגולמי, בין 0 ל-1023. לקריאה תקבילית אין צורך ב-pinMode(). נתחיל בחיישן התקבילי הפשוט ביותר: הפוטנציומטר, שהוא מחלק מתח שאת היחס שלו משנים ביד.

Arduino Uno5VA0GND10 kΩPOT
פוטנציומטר 10 kΩ: שני הקצוות ל-5V ול-GND, והזחלן למבוא A0

הפונקציה map() ומלכודת המספרים השלמים:

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

קריאת הפוטנציומטר: map() לעומת חישוב עשרוני Arduino Uno · pot_read.ino
const int POT = A0;

void setup() { Serial.begin(9600); }

void loop() {
  int n = analogRead(POT);                // 0..1023
  long vMap = map(n, 0, 1023, 0, 5);      // whole volts only
  long mV = map(n, 0, 1023, 0, 5000);     // millivolts, integer
  float v = n * 5.0 / 1023.0;             // float math
  Serial.print("N = ");       Serial.print(n);
  Serial.print("  map V = "); Serial.print(vMap);
  Serial.print("  mV = ");    Serial.print(mV);
  Serial.print("  V = ");     Serial.println(v, 3);
  delay(500);
}
Serial Monitor · קריאה לדוגמה
N = 0  map V = 0  mV = 0  V = 0.000
N = 100  map V = 0  mV = 488  V = 0.489
N = 511  map V = 2  mV = 2497  V = 2.498
N = 1000  map V = 4  mV = 4887  V = 4.888
N = 1023  map V = 5  mV = 5000  V = 5.000

בשורה N = 1000 מחזירה map(n, 0, 1023, 0, 5) את המספר 4, והמתח האמיתי הוא 4.888 V: שגיאה של 0.89 V, כלומר כ-18% מן התחום! החישוב הנכון הוא בשורה n * 5.0 / 1023.0: הנקודה העשרונית גורמת לחישוב להתבצע במספרי float. אילו כתבנו n * 5 / 1023, היו מתקבלים רק מספרים שלמים מ-0 עד 5.

טעות נפוצה: בלוח Uno משתנה מסוג int מכיל מספרים עד 32767 בלבד. החישוב n * 5000 במשתנה מסוג int חורג מן הגבול הזה (למשל 512·5000 = 2,560,000), יש גלישה ומתקבל מספר חסר משמעות. הפתרון: נכתוב 5000L (הסיומת L פירושה long), או נחשב במספרי float.
שאלה 4.2: מה מחזירה map(n, 0, 1023, 0, 100) כאשר N = 700? ומהו האחוז המדויק?
על שלושת הלוחות: Uno: קצות הפוטנציומטר ל-5 V ול-GND. ESP32: הקצוות ל-3.3 V ולא ל-5 V, והזרוע להדק בין GPIO32 ל-GPIO39. רספברי פיי: רק דרך ממיר חיצוני כמו MCP3008 (סעיף 4.6).
▶ניסוי חי — הפוטנציומטר והמבוא התקבילינזיז את הזחלן ונראה יחד את המתח, את הערך הגולמי ואת הקריאה בצג הטורי.
⚠
המעבדה אינה זמינה כרגע. החומר בפרק שלם גם בלעדיה — ממשיכים לקרוא, וחוזרים לניסוי מאוחר יותר או פותחים אותו ישירות בקישור שמתחת למסגרת.
https://fahed-lab.com/micro/sensors_guide#pot
פתיחת המעבדה בדף נפרד ↗ fahed-lab.com/micro/sensors_guide#pot

חיישן התנגדותי במחלק מתח (Resistive Sensor in a Divider)

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

מחלק מתח: שני נגדים בטור בין VCC לאדמה; המתח בנקודת החיבור ביניהם הוא חלק מ-VCC שתלוי ביחס בין שני הנגדים, ואם אחד מהם הוא חיישן, המתח משתנה עם הגודל הנמדד.
מחלק מתח
Vout = VCC·RSRF + RS
סימןמשמעותיחידת מידה
Voutהמתח בנקודת החיבור, אל המבוא התקבילי[V]
RS , RFהתנגדות החיישן (למטה) · הנגד הקבוע (למעלה)[Ω]
Arduino Uno5VA0GNDNTCRF10 kΩRSVout
נגד תלוי-טמפרטורה (NTC) בחלק התחתון של מחלק המתח, נגד קבוע RF = 10 kΩ בחלק העליון, ונקודת החיבור אל A0

איך בוחרים את הנגד הקבוע? כלל אצבע: בוחרים RF קרוב להתנגדות החיישן באמצע תחום המדידה. כך Vout משתנה בערך כמה שיותר, ואינו "נדבק" ל-0 V או ל-5 V. לכן את הנגד תלוי-הטמפרטורה "10 kΩ" (זו ההתנגדות שלו ב-25 °C) מחברים עם נגד קבוע של 10 kΩ.

דוגמה 4.2
ההתנגדות של הנגד תלוי-הטמפרטורה שבסרטוט היא 10 kΩ ב-25 °C, וכ-3.6 kΩ ב-50 °C (ערך טיפוסי לפי דף הנתונים). נחשב את Vout ואת הערך הגולמי ב-Uno בשתי הטמפרטורות.
פתרון:
V25°C = 5·1010 + 10 = 2.5 V → N = 511
V50°C = 5·3.610 + 3.6 = 1.32 V → N = 270

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

V25°C = 2.5 V , V50°C = 1.32 V

התוכנית הבאה קוראת את A0, מחשבת את המתח כמו בסעיף 4.2, ואחר כך מחשבת ממנו את התנגדות החיישן. השורה שמחשבת את rs היא נוסחת מחלק המתח אחרי שבודדנו ממנה את RS. אם הממיר קורא 1023, כנראה שהחיישן מנותק.

חישוב התנגדות החיישן מן הקריאה Arduino Uno · divider_rs.ino
const int SENSOR = A0;
const float VCC = 5.0;
const float R_FIXED = 10000.0;    // ohm, top resistor

void setup() { Serial.begin(9600); }

void loop() {
  int n = analogRead(SENSOR);
  if (n >= 1023) {
    Serial.println("sensor open?");
  } else {
    float v = n * VCC / 1023.0;
    float rs = R_FIXED * v / (VCC - v);   // sensor at the bottom
    Serial.print("N = ");   Serial.print(n);
    Serial.print("  V = "); Serial.print(v, 2);
    Serial.print("  Rs = "); Serial.print(rs / 1000.0, 2);
    Serial.println(" kOhm");
  }
  delay(1000);
}
Serial Monitor · קריאה לדוגמה
N = 788  V = 3.85  Rs = 33.53 kOhm
N = 511  V = 2.50  Rs = 9.98 kOhm
N = 270  V = 1.32  Rs = 3.59 kOhm

שלוש השורות מתאימות לנגד תלוי-הטמפרטורה ב-0 °C, ב-25 °C וב-50 °C. הערך המחושב קרוב מאוד להתנגדות האמיתית; ההבדל הקטן נובע מן הקוונטיזציה. בנגד תלוי-הטמפרטורה נעסוק עוד בפרק 5.

הקטנת מתח גבוה במחלק מתח:

כדי למדוד מתח גבוה מ-Vref, למשל מצבר של 12 V, נקטין אותו במחלק מתח כך שלא יעלה על 5 V גם במקרה הגרוע ביותר. עם R1 = 22 kΩ ו-R2 = 10 kΩ נחשב את היחס ואת המתח הגבוה ביותר שנוכל למדוד:

R2R1 + R2 = 1022 + 10 = 0.3125
Vbat,max = 50.3125 = 16 V
Arduino UnoA0GND+−R122 kΩR210 kΩVbat
מדידת מתח של מצבר במחלק מתח: R1 = 22 kΩ, R2 = 10 kΩ. האדמה משותפת למצבר וללוח
דוגמה 4.3
המצבר במעגל טעון ל-12.6 V. מהו המתח ב-A0, ומהו הערך הגולמי?
פתרון:
VA0 = Vbat·R2R1 + R2 = 12.6·1022 + 10 = 3.9375 V
N = 3.9375·10235 = 805.6 → N = 805
VA0 = 3.938 V , N = 805

בתוכנית נחשב את המתח v ב-A0 כמו בסעיף 4.2, ואחר כך נכפיל ביחס R1 + R2R2 כדי "לבטל" את מחלק המתח:

float vBat = v * (22.0 + 10.0) / 10.0;   // volts at the battery
הערה: בוחרים נגדים שבין כמה קילו-אוהם לכמה עשרות קילו-אוהם: נגדים קטנים מדי צורכים מן המצבר זרם מיותר, ונגדים גדולים מדי (מגה-אוהם) גורמים לקריאה לא מדויקת של הממיר.
אזהרה: מחלק מתח אינו מתאים בשום אופן למדידת מתח הרשת 230 V: את הרשת מודדים רק ביחידת מדידה מבודדת ומאושרת ובפיקוח המורה (פרק 9). ולפני החיבור נוודא בחישוב שהמתח הגבוה ביותר האפשרי של המקור אינו מעלה את המבוא מעל 5 V.
שאלה 4.3: מהו המתח ב-A0 ומהו הערך הגולמי במעגל המצבר, אם מתח המצבר ירד ל-9 V?

רעש ומיצוע בתוכנה (Noise and Averaging)

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

ממוצע של שמונה קריאות Arduino Uno · average8.ino
const int SENSOR = A0;
const int COUNT = 8;

void setup() { Serial.begin(9600); }

void loop() {
  int raw = analogRead(SENSOR);         // one single reading
  long sum = raw;
  for (int i = 1; i < COUNT; i++) {
    sum += analogRead(SENSOR);
  }
  float avg = sum / (float)COUNT;       // average of 8 readings
  Serial.print("raw = ");    Serial.print(raw);
  Serial.print("  avg = ");  Serial.println(avg, 1);
  delay(500);
}
Serial Monitor · קריאה לדוגמה
raw = 516  avg = 511.4
raw = 522  avg = 513.1
raw = 506  avg = 511.9
raw = 519  avg = 511.6
raw = 524  avg = 513.5

בניסוי הזה מתח קבוע נותן N = 512. הקריאות הבודדות נעות בין 500 ל-524 בגלל הרעש, ואילו הממוצעים נשארים רק בין 511.4 ל-513.5. המחיר: כל תוצאה דורשת שמונה קריאות. לחיישן טמפרטורה איטי אפשר למצע קריאות רבות; ללחצן או לחיישן הגנה מהיר נמצע מעט קריאות.

שאלה 4.4: מחשבים ממוצע של 16 קריאות, וכל קריאה ב-Uno נמשכת כ-100 µs (סעיף 4.1). כמה זמן דורשת תוצאה אחת?
▶ניסוי חי — עיבוד אותותנוסיף רעש לאות החיישן ונשווה בין האות הגולמי לבין האות אחרי הסינון והמיצוע.
⚠
המעבדה אינה זמינה כרגע. החומר בפרק שלם גם בלעדיה — ממשיכים לקרוא, וחוזרים לניסוי מאוחר יותר או פותחים אותו ישירות בקישור שמתחת למסגרת.
https://fahed-lab.com/hashmal/sensors#signal
פתיחת המעבדה בדף נפרד ↗ fahed-lab.com/hashmal/sensors#signal

המרה ליחידות הנדסיות (Converting to Engineering Units)

הערך הגולמי N אינו אומר דבר למשתמש. אנו רוצים להציג יחידות הנדסיות: °C, cm, bar. דף הנתונים של החיישן נותן את תחום המדידה ואת המתח שמתאים לו: הערך הקטן ביותר בתחום נותן את המתח הקטן ביותר, והערך הגדול ביותר נותן את המתח הגדול ביותר. בחיישן לינארי הקשר ביניהם הוא קו ישר, ולכן מספיק יחס ישר פשוט. כל הדרך היא שלושה צעדים:

  1. קוראים את הערך הגולמי N בפקודה analogRead().
  2. ממירים את הערך הגולמי למתח: V = N·VrefNmax (סעיף 4.1).
  3. ממירים את המתח לגודל הנמדד ביחס ישר, לפי דף הנתונים.
דוגמה 4.4
חיישן הטמפרטורה LM35 נותן 10 mV לכל 1 °C (ערך טיפוסי לפי דף הנתונים): 0 V ב-0 °C, ו-1 V ב-100 °C. לוח Uno קורא N = 62. מהי הטמפרטורה?
פתרון:

נמיר את הערך הגולמי למתח, ואחר כך את המתח למעלות ביחס ישר:

V = N·VrefNmax = 62·51023 = 0.303 V = 303 mV
T = 303 mV10 mV/°C = 30.3 °C
T = 30.3 °C

המרה בעזרת הפונקציה map():

כאשר תחום החיישן מתאים לכל התחום של הממיר, כלומר מ-0 V עד 5 V, מספיקה שורה אחת עם הפונקציה map(): כותבים בה את הערך הגולמי, אחר כך את תחום הממיר (0 ו-1023), ואחר כך את הערך הקטן ביותר ואת הערך הגדול ביותר בתחום החיישן. דוגמה: חיישן מפלס תקבילי נותן 0 V כשהמכל ריק, ו-5 V כשהמים מגיעים לגובה 200 cm (זו דוגמה להמחשה; את התחום האמיתי קוראים בדף הנתונים של החיישן). התוכנית מחשבת את הגובה ואת אחוז המילוי:

מערך גולמי לסנטימטרים ולאחוזים בעזרת map() Arduino Uno · level_map.ino
const int LEVEL = A0;
const int H_MAX = 200;      // cm at 5 V, from the datasheet

void setup() { Serial.begin(9600); }

void loop() {
  int n = analogRead(LEVEL);
  long h = map(n, 0, 1023, 0, H_MAX);       // whole cm
  long fill = map(n, 0, 1023, 0, 100);      // percent
  Serial.print("N = ");    Serial.print(n);
  Serial.print("  h = ");  Serial.print(h);
  Serial.print(" cm  fill = "); Serial.print(fill);
  Serial.println(" %");
  delay(1000);
}
Serial Monitor · קריאה לדוגמה
N = 0  h = 0 cm  fill = 0 %
N = 256  h = 50 cm  fill = 25 %
N = 512  h = 100 cm  fill = 50 %
N = 1023  h = 200 cm  fill = 100 %
200400600800100050100150200Nh [cm]0–5 V1–5 V
ההמרה היא קו ישר: הקו הכחול לחיישן שמוצאו מ-0 V עד 5 V, והקו המקווקו לחיישן שמוצאו מ-1 V עד 5 V באותו תחום

אם המוצא של החיישן הוא מ-1 V עד 5 V באותו תחום, נכתוב ב-map() במקום האפס את הערך הגולמי של 1 V, שהוא N = 204 (הקו המקווקו בגרף):

long h = map(n, 204, 1023, 0, H_MAX);   // sensor output 1..5 V
טעות נפוצה: הפונקציה map() קוצצת את השבר (סעיף 4.2): היא מתאימה לסנטימטרים שלמים ולאחוזים, אבל לערך כמו 30.3 °C נחשב ביחס ישר במספרי float, כמו בדוגמה של LM35.
שאלה 4.5: חיישן לחץ נותן מ-0 V עד 5 V בתחום של 0 עד 6 bar. לוח Uno קורא N = 600.
(א) מה מחזירה map(n, 0, 1023, 0, 6)?
(ב) מהו הלחץ המדויק?

שלושה לוחות, שלושה ממירים (Uno, ESP32 and Raspberry Pi)

אותו חיישן מתחבר לשלושה לוחות נפוצים במעבדה: Arduino Uno,‏ ESP32 ורספברי פיי. הלוח קובע שלושה דברים: איזה מתח מותר בהדק, אם יש בכלל ממיר תקבילי-ספרתי, וכמה סיביות יש בו. וההבדל הגדול ביותר: ברספברי פיי אין ממיר תקבילי-ספרתי באף דגם, ולכן הוא קורא חיישן תקבילי רק דרך ממיר חיצוני, למשל הרכיב MCP3008 (עשר סיביות, שמונה ערוצים, מתחבר לאפיק SPI).

Arduino UnoESP32Raspberry Pi
מתח בהדקים5 V3.3 V — אינו עומד ב-5 V3.3 V — אינו עומד ב-5 V
ממיר תקבילי-ספרתימובנה, 10 סיביותמובנה, 12 סיביותאין — רק MCP3008 חיצוני (10 סיביות)
תחום הערכים הגולמיים0 עד 10230 עד 40950 עד 1023 (דרך MCP3008)
מתח הייחוס5 Vכ-3.3 V3.3 V
הפרדה4.88 mV0.81 mV3.22 mV
שפת התכנותארדואינו (C++)ארדואינו או מיקרו-פייתוןפייתון
דוגמה 4.5
חיישן LM35 בטמפרטורה של 25 °C מוציא 0.25 V. מהו הערך הגולמי בכל לוח? (רספברי פיי דרך MCP3008 עם מתח ייחוס של 3.3 V.)
פתרון:

משתמשים באותה נוסחה בשלושתם, N = V·NmaxVref, ולוקחים את החלק השלם:

NUno = 0.25·10235 → 51
NESP32 = 0.25·40953.3 → 310
NPi = 0.25·10233.3 → 77

אותו מתח נותן שלושה מספרים שונים, כי מספר הסיביות ומתח הייחוס שונים. לכן בכל תוכנית כותבים את Nmax ואת Vref הנכונים ללוח.

NUno = 51 , NESP32 = 310 , NPi = 77
שאלה 4.6: רספברי פיי קורא LM35 דרך MCP3008 (Vref = 3.3 V) ומקבל N = 155. מהו המתח? ומהי הטמפרטורה?
מ-Uno ל-ESP32: התוכניות בספר נכתבו ללוח Uno, ורובן עוברות הידור גם ל-ESP32 כמו שהן. אבל כדי שהקריאה תהיה נכונה משנים שלושה דברים: את מספר ההדק (המבוא התקבילי בין GPIO32 ל-GPIO39), את המספר 1023 ל-4095, ואת המתח 5 V ל-3.3 V. ובתוכנית של מנוע הסרוו משתמשים בספרייה ESP32Servo במקום Servo.

חיישנים ברספברי פיי בפייתון:

ברספברי פיי לא כותבים תוכנית ארדואינו אלא תוכנית בשפת פייתון. החיישנים הספרתיים מתחברים ישירות להדקי GPIO (במתח של 3.3 V), והתקביליים דרך MCP3008. הנה ארבע דוגמאות קצרות לחיישנים מן הספר הזה. הספרייה gpiozero כבר מותקנת במערכת Raspberry Pi OS, ואת ספריית DHT22 מתקינים פעם אחת בפקודה:

pip install adafruit-circuitpython-dht
לחצן רגעי על GPIO17: הנגד המושך פנימי, כמו בפרק 3
from gpiozero import Button
from signal import pause

btn = Button(17)              # GPIO17, internal pull-up

btn.when_pressed = lambda: print("pressed")
btn.when_released = lambda: print("released")
pause()
LM35 דרך MCP3008 בערוץ 0: אותה נוסחה כמו ב-Uno, עם 3.3 V במקום 5 V
from gpiozero import MCP3008
from time import sleep

lm35 = MCP3008(channel=0)     # SPI, Vref = 3.3 V

while True:
    n = lm35.raw_value        # 0 .. 1023
    v = n * 3.3 / 1023
    t = v / 0.010             # 10 mV per degree C
    print("N = %d  V = %.3f V  T = %.1f C" % (n, v, t))
    sleep(1)
DHT22 על GPIO27: לא קוראים מהר יותר מפעם בשתי שניות (פרק 5)
import time
import board
import adafruit_dht

dht = adafruit_dht.DHT22(board.D27)      # GPIO27

while True:
    try:
        print("T = %.1f C  RH = %.1f %%" % (dht.temperature, dht.humidity))
    except RuntimeError:
        pass                  # a missed reading: try again
    time.sleep(2)
DS18B20 על GPIO4: מערכת ההפעלה קוראת את אפיק 1-Wire אחרי שמפעילים אותו, והתוכנית רק קוראת קובץ
import glob, time

dev = glob.glob("/sys/bus/w1/devices/28-*/temperature")[0]

while True:
    with open(dev) as f:
        t = int(f.read()) / 1000      # millidegrees C
    print("T = %.2f C" % t)
    time.sleep(1)
רספברי פיי: לפני ההרצה מפעילים בהגדרות של רספברי פיי (raspi-config) את ממשק SPI בשביל MCP3008 ואת ממשק 1-Wire בשביל DS18B20. את MCP3008 ואת מתח הייחוס שלו מזינים מ-3.3 V, ואת LM35 מזינים מההדק 5 V שבלוח (הוא צריך לפחות 4 V); המוצא שלו נמוך מ-1.5 V, ולכן אין סכנה ל-MCP3008.
3.3 V: ההדקים של רספברי פיי, כמו של ESP32, עובדים ב-3.3 V ואינם עומדים ב-5 V. חיישן שהמוצא שלו 5 V, למשל ההדק ECHO ב-HC-SR04, מחברים דרך מחלק מתח כמו בפרק 3.

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

החוקהנוסחה
הערך הגולמי הגדול ביותרNmax = 2n − 1
רזולוציהΔ V = Vref2n
מערך גולמי למתחV = N·VrefNmax
ממתח לערך גולמיN = V·NmaxVref
מחלק מתח, החיישן למטהVout = VCC·RSRF + RS
LM35: ממתח לטמפרטורהT = V10 mV/°C

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

עבריתEnglishالعربية
ממיר תקבילי-ספרתי (ADC)Analog-to-digital converterالمحوّل التماثلي-الرقمي
דגימהSamplingأخذ العيّنات
קוונטיזציהQuantizationالتكميم
מספר סיביותNumber of bitsعدد البتات
ערך גולמיRaw value (count)القيمة الخام
מתח ייחוסReference voltageجهد المرجع
רזולוציה (הפרדה)Resolutionدقّة التمييز
מחלק מתחVoltage dividerمُجزِّء الجهد
התאמת אותותSignal conditioningملاءمة الإشارة
רעשNoiseالضجيج
סינוןFilteringالترشيح
תחום מדידהMeasuring rangeمدى القياس
יחידות הנדסיותEngineering unitsالوحدات الهندسية

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

1.
לוח Uno קורא N = 300. מהו המתח במבוא?
תשובות: V = 1.466 V
2.
ממיר של 8 סיביות, ומתח הייחוס שלו 5 V.
(א) מהו Nmax?
(ב) מהי הרזולוציה?
(ג) מהו הערך הגולמי עבור מתח של 2 V?
תשובות: (א) 255 (ב) 19.53 mV (ג) N = 102
3.
ב-ESP32 קוראים N = 2500. מהו המתח? ומדוע לא משתמשים בהדק של ADC2 בפרויקט ששולח את הקריאה ברשת WiFi?
תשובות: V = 2.015 V; הדקי ADC2 אינם פועלים כאשר רשת WiFi מופעלת
4.
מה מדפיסה התוכנית בכל מקרה כאשר N = 800 (המשתנה n מסוג int):
(א) n / 1023 * 5
(ב) map(n, 0, 1023, 0, 5)
(ג) n * 5.0 / 1023.0 עם שלוש ספרות אחרי הנקודה?
תשובות: (א) 0 (ב) 3 (ג) 3.910
5.
במחלק מתח יש נגד RF = 4.7 kΩ למעלה וחיישן RS = 12 kΩ למטה, ו-VCC = 5 V. חשבו את Vout ואת הערך הגולמי ב-Uno.
תשובות: Vout = 3.593 V, N = 735
6.
במעגל הנגד תלוי-הטמפרטורה (RF = 10 kΩ למעלה, NTC למטה) הטמפרטורה יורדת ל-0 °C, והתנגדות ה-NTC עולה לכ-33.6 kΩ.
(א) האם Vout גדל או קטן לעומת 25 °C?
(ב) חשבו את Vout ואת הערך הגולמי.
תשובות: (א) גדל, כי התנגדות החיישן גדלה (ב) Vout = 3.85 V, N = 788
7.
מודדים מתח של מצבר 24 V במחלק מתח עם R1 = 47 kΩ ו-R2 = 10 kΩ.
(א) מהו המתח ב-A0?
(ב) מהו הערך הגולמי?
(ג) מהו המתח הגבוה ביותר שאפשר למדוד במחלק הזה?
תשובות: (א) VA0 = 4.21 V (ב) N = 861 (ג) 28.5 V
8.
התוכנית average8 סכמה את שמונה הקריאות: 410 , 402 , 418 , 406 , 430 , 426 , 414 , 410. איזה ערך של avg היא מדפיסה? ואיזה ערך של raw?
תשובות: avg = 414.5, raw = 410
9.
חיישן LM35 (10 mV/°C) מחובר ללוח Uno, והלוח קורא N = 82. מהו המתח, ומהי הטמפרטורה?
תשובות: V = 0.401 V, T = 40.1 °C
10.
חיישן טמפרטורה המחובר ללוח ESP32 נותן מ-0 V עד 3.3 V בתחום של 0 עד 50 °C. הקריאה היא N = 3000.
(א) כתבו את שורת map() המתאימה.
(ב) מה היא מחזירה?
(ג) מהי הטמפרטורה המדויקת?
תשובות: (א) map(n, 0, 4095, 0, 50) (ב) 36 (ג) T = 36.6 °C
11.
חיישן טמפרטורה תעשייתי נותן מ-1 V עד 5 V בתחום של 0 עד 100 °C, והוא מחובר ללוח Uno.
(א) מהו הערך הגולמי ב-1 V וב-5 V?
(ב) כתבו את שורת map() המתאימה.
(ג) מהי הטמפרטורה כאשר N = 614?
תשובות: (א) 204 ו-1023 (ב) map(n, 204, 1023, 0, 100) (ג) T = 50 °C
תשובות סופיות לשאלות הפרק
4.1 N = 2047, V = 0.806 V
4.2 map נותנת 68, והאחוז המדויק 68.43%
4.3 VA0 = 2.812 V, N = 575
4.4 1.6 ms
4.5 (א) 3 (ב) P = 3.52 bar
4.6 V = 0.5 V, T = 50 °C
נוסחאון הספר: כל נוסחאות הפרק הזה מרוכזות, עם סרטוטיהן וטבלאות הסמלים שלהן, בפרק 15 — נוסחאון הספר.