← До всіх проєктів
Основи Середній

PCF8574: вісім додаткових виводів по I2C — кнопки, світлодіоди і переривання

Той самий чип, що стоїть на платі LCD 1602 I2C, можна використати як розширювач виводів. Розбираємося з «квазідвонаправленими» портами, чому світлодіод треба вмикати LOW, і як вивід INT позбавляє від постійного опитування шини.

Складність
Середній
Час
45 min
Категорія
Основи
Оновлено

Про проєкт

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. Вхід — це вивід, у який записано 1. Кнопка на GND легко переважає слабку підтяжку, і read() повертає 0.
  2. Світлодіод вмикається 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 — це він.