מבוא למיקרו-מחשבים — ESP32

✦ בנוי על ידי פהד גאנם ✦

Vlogic = 3.3 V   |   Ipin,max = 40 mA   |   ADC1 → 32…39   |   ADC2 → 0, 2, 4, 12…15, 25…27Wi-Fi
GPIO 34
ADC1_6
6

8 − 2 = 6  →  6 − 5 = 1

Ipull = 3.3 V45 kΩ = 73 µA     Vpin = 3.3 · RbtnRpull + Rbtn
בינוני
1
0
?
0
// Three identical buttons, three different wirings.
const int BTN_UP   = 4;    // button to GND, internal pull-up ON
const int BTN_DOWN = 18;   // button to 3V3, internal pull-down ON
const int BTN_AIR  = 5;    // button to GND, NO resistor at all
const int LED      = 2;

void setup() {
  Serial.begin(115200);
  pinMode(BTN_UP,   INPUT_PULLUP);
  pinMode(BTN_DOWN, INPUT_PULLDOWN);
  pinMode(BTN_AIR,  INPUT);          // this one is the trap
  pinMode(LED, OUTPUT);
}

void loop() {
  int up   = digitalRead(BTN_UP);    // rest = 1, pressed = 0
  int down = digitalRead(BTN_DOWN);  // rest = 0, pressed = 1
  int air  = digitalRead(BTN_AIR);   // rest = anything

  digitalWrite(LED, up == LOW ? HIGH : LOW);

  Serial.print("up=");   Serial.print(up);
  Serial.print(" down="); Serial.print(down);
  Serial.print(" air=");  Serial.println(air);
  delay(150);
}

Rmax = 3.3 − 2.21 µA = 1.1 MΩ
Ipress = 3.3 V10 kΩ = 0.33 mA

Ishort = VCCRon,H + Ron,L = 3.325 + 25 = 66 mA   |   Ipull = 3.34.7 kΩ = 0.70 mA
4.7 kΩ
3.30 V
1
0.00 mA
0.7 µs
// One shared line. HIGH does not drive high - it lets go.
const int LINE = 21;

void setup() {
  Serial.begin(115200);
  pinMode(LINE, OUTPUT_OPEN_DRAIN);
}

void loop() {
  digitalWrite(LINE, LOW);       // pull the whole line down, hard
  delay(400);

  digitalWrite(LINE, HIGH);      // let go - the resistor lifts it
  delay(50);

  // Reading now tells us whether SOMEBODY ELSE is still pulling.
  int busy = (digitalRead(LINE) == LOW);
  Serial.print("line free = ");
  Serial.println(busy ? 0 : 1);

  delay(350);
}

I = 3.3 V4.7 kΩ = 0.70 mA
τ = R · C = 4700 · 120 · 10−12 = 0.56 µs
Ishort = 3.325 + 25 = 66 mA

τ = R · C = 10 kΩ · 100 nF = 1 ms   |   tquiet > tbounce   |   tquiet < 1fpress,max
1.5 ms
25 ms
1.0 ms
0
0
0
0
// Same button on two pins: raw, and through an RC network.
const int RAW = 4;
const int RCF = 5;
const int LED = 2;
const unsigned long QUIET = 25;   // ms of silence that make an edge real

int prevRaw = HIGH, prevRc = HIGH, stable = HIGH;
unsigned long lastEdge = 0;
long nRaw = 0, nRc = 0, nClean = 0;

void setup() {
  Serial.begin(115200);
  pinMode(RAW, INPUT_PULLUP);
  pinMode(RCF, INPUT_PULLUP);
  pinMode(LED, OUTPUT);
}

void loop() {
  int a = digitalRead(RAW);
  int b = digitalRead(RCF);

  if (a != prevRaw) {              // every bounce lands here
    if (a == LOW) nRaw++;
    prevRaw = a;
    lastEdge = millis();           // restart the quiet window
  }

  if (b != prevRc) {               // the RC network already smoothed it
    if (b == LOW) nRc++;
    prevRc = b;
  }

  // Compare times. Never delay() here - it would freeze everything else.
  if (millis() - lastEdge > QUIET && a != stable) {
    stable = a;
    if (stable == LOW) {
      nClean++;
      digitalWrite(LED, nClean % 2);
      Serial.print("press ");   Serial.print(nClean);
      Serial.print("  raw=");   Serial.print(nRaw);
      Serial.print("  rc=");    Serial.println(nRc);
    }
  }
}

τ = 5 · 2 ms = 10 ms  →  C = τR = 10 · 10−310 · 103 = 1 µF
t = τ · ln10.25 = 10 · 1.386 = 13.9 ms
fmax = 130 ms = 33 1s

D = tonT   |   Vavg = D · VCC   |   D = duty2N − 1   |   f · 2N ≤ fclk
50 %
1000 Hz
10 bit
50.0 %
511
1.65 V
0.50 ms
// The PWM unit is independent of the CPU. Set it once, then walk away.
const int LED  = 18;
const int POT  = 34;
const int FREQ = 1000;   // Hz  - not the brightness, only the flicker
const int BITS = 10;     // resolution -> top = 1023

void setup() {
  Serial.begin(115200);
  ledcAttach(LED, FREQ, BITS);
  analogReadResolution(12);
}

void loop() {
  int raw  = analogRead(POT);            // 0 .. 4095
  int top  = (1 << BITS) - 1;            // 255, 1023, 4095 ...
  int duty = (long)raw * top / 4095;     // rescale, never assume 8 bits

  ledcWrite(LED, duty);

  Serial.print("duty=");  Serial.print(duty);
  Serial.print("/");      Serial.print(top);
  Serial.print("  avg="); Serial.print(3.3 * duty / top, 2);
  Serial.println(" V");
  delay(150);
}

top = 28 − 1 = 255  →  D = 64255 = 0.251 = 25.1 %
Vavg = 0.251 · 12 = 3.01 V
T = 120000 = 50 µs  →  ton = 0.251 · 50 = 12.5 µs
duty = 0.251 · 4095 = 1028   |   D' = 644095 = 1.56 %

ΔVripple = VCC · D(1 − D)f · R · C   |   tsettle ≈ 5τ   |   ΔVDAC = 3.3255 = 12.9 mV
1.65 V
1000 Hz
10 ms
1.65 V
1.65 V
82 mV
50 ms
// Same requested voltage, sent to two very different outputs.
const int PWM  = 18;    // any pin - a ratio of TIME
const int DAC  = 25;    // only 25 or 26 - a ratio of VOLTAGE
const int POT  = 34;
const int FREQ = 1000;
const int BITS = 10;

void setup() {
  Serial.begin(115200);
  ledcAttach(PWM, FREQ, BITS);
  analogReadResolution(12);
}

void loop() {
  int raw  = analogRead(POT);              // 0 .. 4095
  int top  = (1 << BITS) - 1;

  int duty = (long)raw * top / 4095;       // 0 .. 1023  -> time share
  int code = (long)raw * 255 / 4095;       // 0 .. 255   -> voltage step

  ledcWrite(PWM, duty);
  dacWrite(DAC, code);

  Serial.print("want ");   Serial.print(3.3 * raw / 4095, 2);
  Serial.print(" V  |  duty "); Serial.print(duty);
  Serial.print("  |  dac ");    Serial.print(code);
  Serial.print(" -> ");         Serial.print(3.3 * code / 255, 2);
  Serial.println(" V");
  delay(200);
}

D = 1.53.3 = 0.4545  →  D(1 − D) = 0.2479
R · C = 3.3 · 0.24795000 · 0.010 = 16.4 ms  →  C = 16.4 · 10−310 · 103 = 1.64 µF
tsettle = 5 · 22 ms = 110 ms
ΔVDAC = 3.3255 = 12.9 mV  >  10 mV

V = raw · Vref2N − 1   |   ΔV = 3.34095 = 0.806 mV   |   σavg = σn
1.650 V
±6 LSB
16
2048
1.650 V
0.806 mV
1.5 LSB
// The converter returns a count, never volts. We do the conversion.
const int SENS = 34;      // ADC1 - the unit that survives Wi-Fi
const int N    = 16;      // samples to average
const int BITS = 12;

void setup() {
  Serial.begin(115200);
  analogReadResolution(BITS);
  analogSetAttenuation(ADC_11db);   // full 0 .. 3.3 V range
}

void loop() {
  long sum = 0;
  for (int i = 0; i < N; i++) {
    sum += analogRead(SENS);        // each read carries a few LSB of noise
  }
  int raw = sum / N;

  int   top   = (1 << BITS) - 1;    // 4095 for 12 bits
  float volts = raw * 3.3 / top;    // THIS line is the conversion
  float degC  = volts * 100.0;      // LM35 gives 10 mV per degree

  Serial.print("raw=");  Serial.print(raw);
  Serial.print("/");     Serial.print(top);
  Serial.print("  V=");  Serial.print(volts, 3);
  Serial.print("  T=");  Serial.print(degC, 1);
  Serial.println(" C");
  delay(250);
}

ΔV = 3.34095 = 0.806 mV  →  ΔT = 0.80610 = 0.081 °C
Tmax = 3.3 V10 mV/°C = 330 °C
6 · 0.081 = 0.48 °C
n = 0.480.10 = 4.8  →  n = 23

Pmisstblindtloop   |   tblind = tloop − tread   |   tpulse > tloop   |   tpulse < tloop
0.5 ms
180 ms
20 ms
0
0
0
99 %
// A gas sensor pulses LOW for a fraction of a millisecond.
const int SENS = 4;      // frequent short pulses
const int FIRE = 5;      // rare, and must never wait
const int LED  = 2;
const int WORK = 20;     // ms of other work inside the loop

volatile unsigned long byIsr = 0;   // touched by the interrupt
volatile int fireFlag = 0;
unsigned long byPoll = 0;
int prev = HIGH;

void IRAM_ATTR onPulse() {
  byIsr++;               // short. no Serial, no delay, nothing else.
}

void IRAM_ATTR onFire() {
  fireFlag = 1;             // raise a flag - the work happens in loop()
}

void setup() {
  Serial.begin(115200);
  pinMode(SENS, INPUT_PULLUP);
  pinMode(FIRE, INPUT_PULLUP);
  pinMode(LED, OUTPUT);
  attachInterrupt(digitalPinToInterrupt(SENS), onPulse, FALLING);
  attachInterrupt(digitalPinToInterrupt(FIRE), onFire,  FALLING);
}

void loop() {
  int now = digitalRead(SENS);          // the polling way
  if (prev == HIGH && now == LOW) byPoll++;
  prev = now;

  if (fireFlag) {
    fireFlag = 0;
    Serial.println("FIRE - shutting the valve");
  }

  digitalWrite(LED, byIsr % 2);

  Serial.print("isr=");    Serial.print(byIsr);
  Serial.print("  poll="); Serial.print(byPoll);
  Serial.print("  lost="); Serial.println(byIsr - byPoll);

  delay(WORK);            // the other work - and the whole problem
}
// Nothing outside the chip triggers this one. The counter does.
hw_timer_t *tick = NULL;
volatile unsigned long ticks = 0;

void IRAM_ATTR onTick() {
  ticks++;
}

void setup() {
  Serial.begin(115200);
  tick = timerBegin(1000000);            // count at 1 MHz -> 1 us per step
  timerAttachInterrupt(tick, &onTick);
  timerAlarm(tick, 1000000, true, 0);    // fire every 1 000 000 steps = 1 s
}

void loop() {
  Serial.println(ticks);
  delay(3000);            // the count keeps rising while we sleep here
}

Pcatch = 0.3 ms25 ms = 0.012 = 1.2 %
Pmiss = 1 − 0.012 = 98.8 %
Pall miss = 0.98810 = 0.886 = 88.6 %

Iavg = Isleep + Itx · ttxT   |   tlife = QbatIavg
−58 dBm
0.0 s
טובה
#include <WiFi.h>

void setup() {
  Serial.begin(115200);
  delay(200);

  WiFi.begin("lab-net", "12345678");
  Serial.print("connecting");

  // status() is not a yes/no. It is a state machine, and it takes seconds.
  while (WiFi.status() != WL_CONNECTED) {
    Serial.print(".");
    delay(300);
  }

  Serial.println();
  Serial.print("ip   = ");  Serial.println(WiFi.localIP());
  Serial.print("rssi = ");  Serial.print(WiFi.RSSI());
  Serial.println(" dBm");
}

void loop() {
  if (WiFi.status() != WL_CONNECTED) {
    Serial.println("link lost - reconnecting");
    WiFi.begin("lab-net", "12345678");
    delay(1000);
    return;
  }
  Serial.print("alive, rssi = ");
  Serial.println(WiFi.RSSI());
  delay(2000);
}
#include <BluetoothSerial.h>

BluetoothSerial SerialBT;
const int LED = 2;

void setup() {
  Serial.begin(115200);
  pinMode(LED, OUTPUT);
  SerialBT.begin("ESP32-LAB");        // this name appears on the phone
  Serial.println("pair with ESP32-LAB");
}

void loop() {
  // A serial port that happens to be wireless. Same read/write as UART.
  if (SerialBT.available()) {
    char c = SerialBT.read();
    if (c == '1') digitalWrite(LED, HIGH);
    if (c == '0') digitalWrite(LED, LOW);
    SerialBT.print("led = ");
    SerialBT.println(c);
  }
  delay(20);
}

t = 220 mAh12 mA = 18.3 h
D = 50 ms600 s = 8.33 · 10−5
Iavg = 0.010 + 15 · 8.33 · 10−5 = 0.010 + 0.00125 = 11.25 µA
t = 220 mAh0.01125 mA = 19556 h = 2.2 y

I2C: 2   |   SPI: 3 + n   |   1-Wire: 1   |   tbyte = 9fSCL
100 kHz
0x27
0x01
יש
90 µs
#include <Wire.h>

const int EXP = 0x27;      // PCF8574 port expander
byte pattern = 1;

void setup() {
  Serial.begin(115200);
  Wire.begin(21, 22);      // SDA, SCL

  // The scanner: talk to every address and see who answers.
  Serial.println("scanning...");
  for (int addr = 1; addr < 127; addr++) {
    Wire.beginTransmission(addr);
    if (Wire.endTransmission() == 0) {   // 0 = somebody pulled SDA low
      Serial.print("found 0x");
      Serial.println(addr, HEX);
    }
  }
}

void loop() {
  Wire.beginTransmission(EXP);   // start + 7 address bits + write bit
  Wire.write(pattern);           // one data byte
  Wire.endTransmission();        // stop

  Serial.print("wrote 0x");
  Serial.println(pattern, HEX);

  pattern = pattern << 1;        // running light on the expander
  if (pattern == 0) pattern = 1;
  delay(500);
}

t2 = 32000 · 9105 = 2.88 s   |   t4 = 32000 · 8107 = 25.6 ms
N2 = 2   |   N4 = 3 + 10 = 13
🏠