// 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);
}
// 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);
}
// 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);
}
}
}
// 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);
}
// 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);
}
// 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);
}
// 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
}
#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);
}
#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);
}