PCF8574: вісім додаткових виводів по I2C — кнопки, світлодіоди і переривання
Той самий чип, що стоїть на платі LCD 1602 I2C, можна використати як розширювач виводів. Розбираємося з «квазідвонаправленими» портами, чому світлодіод треба вмикати LOW, і як вивід INT позбавляє від постійного опитування шини.
Про проєкт
PCF8574 додає 8 цифрових виводів P0–P7 до будь-якої плати, у якої є I2C. До однієї шини можна під'єднати до 8 таких чипів (адреси 0x20–0x27) і ще 8 PCF8574A (0x38–0x3F) — тобто до 128 виводів на двох проводах. У цьому проєкті чотири кнопки перемикають чотири світлодіоди, а мікроконтролер дізнається про натискання через переривання.
Що потрібно
- ESP32 DevKit (або Arduino)
- Модуль PCF8574 (синя плата з перемичками A0–A2)
- 4 кнопки, 4 світлодіоди, 4 резистори 330 Ом
Схема
| PCF8574 | ESP32 |
|---|---|
| VCC | 3V3 |
| GND | GND |
| SDA | GPIO21 |
| SCL | GPIO22 |
| INT | GPIO4 |
| P0–P3 | світлодіоди: 3V3 → резистор → анод, катод → P0…P3 |
| P4–P7 | кнопки: P4…P7 → кнопка → GND |
Перемички A0–A2 задають три молодші біти адреси: усі на GND — 0x20.
Квазідвонаправлений порт
У PCF8574 немає pinMode(). Кожен вивід або тягне до GND сильним транзистором (до 25 мА), або, якщо записати 1, ледь підтягує до VCC струмом ~100 мкА. З цього випливають два правила:
- Вхід — це вивід, у який записано 1. Кнопка на GND легко переважає слабку підтяжку, і
read()повертає 0. - Світлодіод вмикається LOW. Підключайте його від VCC через резистор до виводу: при
0чип забирає струм на себе. Якщо підключити світлодіод від виводу на GND, він ледве жевріє від тих 100 мкА. Симулятор помітить таку схему і підкаже.
Загальний струм через GND чипа — до 80 мА, тож вісім світлодіодів по 10 мА він витримує.
Навіщо INT
Опитувати I2C у кожному loop() — зайвий трафік і затримки. Вихід INT (відкритий стік, активний LOW) падає, щойно зміниться будь-який вхід, і повертається в HIGH після читання порту. Під'єднайте його до GPIO з підтяжкою і читайте PCF8574 лише в перериванні або за прапорцем.
Код
// 4 кнопки і 4 світлодіоди на двох проводах I2C: розширювач PCF8574
#include <Wire.h>
#include <PCF8574.h>
PCF8574 pcf(0x20);
const int INT_PIN = 4; // INT модуля: відкритий стік, активний LOW
volatile bool changed = true; // true: прочитати стан одразу після старту
void IRAM_ATTR onChange() { changed = true; }
uint8_t leds = 0; // біт = світлодіод увімкнено
uint8_t lastButtons = 0;
void setup() {
Serial.begin(115200);
Wire.begin();
pcf.begin(0xFF); // усі виводи в 1: входи з підтяжкою, світлодіоди вимкнені
if (!pcf.isConnected()) {
Serial.println("PCF8574 не знайдено");
while (true) delay(1000);
}
pinMode(INT_PIN, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(INT_PIN), onChange, FALLING);
}
void loop() {
if (!changed) return; // нічого не змінилося — шину не чіпаємо
changed = false;
uint8_t buttons = (~pcf.read8() >> 4) & 0x0F; // P4..P7, 1 = натиснута
uint8_t pressedNow = buttons & ~lastButtons; // щойно натиснуті
lastButtons = buttons;
if (!pressedNow) return;
leds ^= pressedNow; // кожна кнопка перемикає свій світлодіод
pcf.write8(0xF0 | (~leds & 0x0F)); // P4..P7 лишаються входами (1), світлодіод горить при 0
Serial.printf("Світлодіоди: %d %d %d %d\n", leds & 1, (leds >> 1) & 1, (leds >> 2) & 1, (leds >> 3) & 1);
}
Зверніть увагу на write8(0xF0 | …): старші біти завжди пишемо одиницями, інакше кнопки перестануть бути входами.
Інша бібліотека — інший синтаксис
Під назвою PCF8574.h існує ще бібліотека Renzo Mischianti з «ардуїнівським» API: pcf8574.pinMode(P0, OUTPUT); pcf8574.begin(); pcf8574.digitalWrite(P0, LOW);. Під капотом це ті самі квазідвонаправлені порти, тож правило «світлодіод вмикається LOW» діє і там. Симулятор підтримує обидва варіанти.
Що далі
- Клавіатура 4×4 на одному PCF8574: рядки — виходи, стовпці — входи.
- Реле-модулі з активним LOW підходять до PCF8574 ідеально.
- LCD 1602 I2C — це той самий PCF8574, припаяний до дисплея. Якщо I2C-сканер знаходить 0x27 або 0x3F — це він.