Порти мікроконтролерів

Як мікроконтролер взаємодіє із зовнішнім світом

Мікроконтролери призначені для керування електронікою пристроїв найрізноманітнішого призначення — від побутових приладів до дронів і роботів. Вони отримують інформацію від датчиків, кнопок чи інших елементів, обробляють її за допомогою програми й віддають команди виконавчим пристроям, наприклад двигунам, світлодіодам або дисплеям. Інколи мікроконтролери також передають дані іншим системам, наприклад через інтерфейси UART, I²C або SPI.
Зв’язок чіпа мікроконтролера з іншими електронними компонентами забезпечують порти вводу-виводу (I/O-порти).

Порт мікроконтролера — це набір фізичних ніжок-виводів (пінів), якими можна керувати з програми. Кожен пін може працювати в одному з двох основних режимів:

  • вивід (output) — коли програма керує вихідною напругою на піну, встановлюючи високий або низький рівень (наприклад, щоб вмикати-вимикати світлодіод),

  • ввід (input) — коли пін «слухає» зовнішній сигнал, наприклад натискання кнопки.

Таким чином, через порти мікроконтролер обмінюється інформацією з зовнішнім світом. Зазвичай він має кілька портів (A, B, C тощо), кожен з яких містить певну кількість пінів (часто 8).

На малюнку показано приклад мікроконтролера. Праворуч розташовані піни порту A, що працює в режимі виводу. До кожного піна через резистор під’єднано світлодіод. У програмі можна керувати цими пінами, вмикаючи або вимикаючи відповідні світлодіоди. Зверніть увагу, що тут назви пінів складаються з літери порту та номера піна — наприклад, PA0 означає «пін 0 порту A». У реальних мікроконтролерах порти та їхні позначення відрізняються. Тому для роботи з конкретним чіпом варто звертатися до його документації — datasheet, де вказано повну розпіновку, характеристики портів і можливі режими роботи.

Кожен порт мікроконтролера складається з кількох пінів, і керування ними здійснюється через спеціальні регістри.

  • DDRx (Data Direction Register) — задає напрямок піну: ввід чи вивід.

  • PORTx — встановлює логічний рівень на вихідних пінах або вмикає внутрішні підтягувальні резистори для вводу.

  • PINx — дозволяє зчитувати поточний стан піну.

Тут x — літера порту (B, C, D тощо). Саме через ці регістри мікроконтролер отримує інформацію від зовнішніх пристроїв і керує ними. Таким чином на кожен порт є свій набір регістрів DDRx, PORTx і PINx

Щоб спростити сприйняття, далі ми будемо використовувати приклади на платі Arduino. На перший погляд здається, що тут немає портів, бо ми працюємо з цифровими пінами D0–D13. Насправді порти все одно присутні — Arduino просто приховує складність регістрів і робить роботу з піном більш дружньою: замість DDRx/PORTx/PINx ми використовуємо функції pinMode(), digitalWrite() і digitalRead().

Таким чином, основна концепція GPIO лишається тією ж: пін може працювати як ввідний або вивідний, а плата обмінюється сигналами зі світом через ці піни. Arduino дозволяє зосередитися на практичних прикладах без потреби заглиблюватися в деталі регістрів.

Режими вводу і виводу

Робота з пінами — це основа взаємодії програми з реальним світом електроніки. Через них плата отримує сигнали від кнопок і сенсорів або керує світлодіодами, двигунами та іншими пристроями.

На платі Arduino ми працюємо з пінами D0–D13 (а також A0–A5). Кожен пін може працювати в одному з двох основних режимів:

  • OUTPUT — пін відправляє сигнал (керує пристроєм);

  • INPUT — пін зчитує зовнішній сигнал.

Режим виводу (OUTPUT)

Припустимо, до піна 13 під’єднано світлодіод (на Arduino Uno він уже вбудований). Найпростіший приклад:

void setup() {    //функція викликається 1 раз на старті програми
  pinMode(13, OUTPUT); // встановлюємо режим виводу
}

void loop() {    //основний цикл програми
  digitalWrite(13, HIGH); // увімкнути світлодіод
  delay(200);
  digitalWrite(13, LOW); // вимкнути
  delay(200);
}

Що відбувається в коді:

  • Виклик функції pinMode(13, OUTPUT) налаштовує пін 13 як вихід. На рівні мікроконтролера це означає, що в регістрі напрямку (DDRx) відповідний біт встановлюється в 1.
  • Виклик digitalWrite(13, HIGH) - на піні з’являється логічна 1 (близько 5 В або 3.3 В залежно від плати). На рівні регістрів це запис у PORTx.
  • digitalWrite(13, LOW) - встановлює логічний 0 на виході 13.

Таким чином ми керуємо світлодіодом, змінюючи логічний рівень на піні.

Можна під’єднати кілька світлодіодів до різних пінів і керувати ними незалежно:

void setup() {
  pinMode(8, OUTPUT);
  pinMode(9, OUTPUT);
  pinMode(10, OUTPUT);
  pinMode(11, OUTPUT);
}

void loop() {
  digitalWrite(8, HIGH);
  digitalWrite(9, LOW);
  digitalWrite(10, LOW);
  digitalWrite(11, LOW);
  delay(200);

  digitalWrite(8, LOW);
  digitalWrite(9, HIGH);
  delay(200);
}

Arduino дозволяє керувати кожним піном окремо, хоча на рівні мікроконтролера ці піни можуть належати до одного й того самого порту. Тобто порти фізично існують, але Arduino приховує їх від нас і дає зручний інтерфейс для роботи з окремими пінами.

Режим вводу (INPUT)

Окрім керування пристроями, плата повинна отримувати сигнали. Найпростіший приклад — кнопка. Під’єднаємо кнопку до піна 2 так, щоб при натисканні вона з’єднувала пін із землею.

void setup() {
  pinMode(2, INPUT_PULLUP); // ввід із внутрішнім підтягуванням
  pinMode(13, OUTPUT);
}

void loop() {
  if (digitalRead(2) == LOW) {
    digitalWrite(13, HIGH); // кнопка натиснута
  } else {
    digitalWrite(13, LOW); // кнопка не натиснута
  }
}

Зверніть увагу на виклик pinMode(2, INPUT_PULLUP), він вмикає режим вводу і одночасно активує внутрішній підтягувальний резистор.

На рівні регістрів біт у DDRx встановлюється в 0 (ввід) і у PORTx записується 1 — це і вмикає підтягування.

Чому потрібен підтягувальний резистор?

Без нього пін залишався б у “підвішеному стані” — він міг би випадково змінювати значення через електричні шуми. Підтягування забезпечує стабільний логічний рівень, коли кнопка не натиснута. У такій схемі: кнопка не натиснута → пін читає HIGH, кнопка натиснута → пін з’єднаний із землею → LOW.

Детальніше про підключення приладів до пінів можна почитати в статті Підключення приладів вводу/виводу до мікроконтролера

Альтернативні функції портів

Розглянуті вище піни називаються GPIO (General Purpose Input/Output) — піни загального призначення. Вони керуються одночасно, тому їх ще називають паралельними портами.

Але кожен пін може виконувати не лише базові функції вводу-виводу. У сучасних мікроконтролерах один і той самий пін може мати декілька призначень:

  • Аналогові входи — для вимірювання напруги за допомогою вбудованого АЦП.

  • PWM-виходи (ШІМ) — мікроконтролер швидко вмикає і вимикає сигнал, створюючи «псевдоаналогову» напругу. Це дозволяє керувати, наприклад, яскравістю світлодіода або швидкістю двигуна.

  • Комунікаційні лінії — ті самі піни можуть передавати дані через UART, I²C або SPI.

Таким чином, фізично один і той самий пін може виконувати різні ролі, і потрібну функцію зазвичай обирають у програмі при налаштуванні плати, але це вже тема для іншої статті...