Продвинутый курс Arduino · Незнакомые детали

Урок 6. Шкала-градусник из ярких светодиодов

Последние жители коробки — три ярких светодиода — выстраиваются в светящийся столбик температуры. Учимся зажигать «полтора светодиода»: дробная часть уровня уходит в яркость.

Урок 6 из 8⏱ примерно 40 минутОбновлено: 14 августа 2026

Что понадобится

  • Контроллер Uno и кабель USB
  • Макетная плата
  • 3 ярких светодиода и 3 резистора 470 Ом
  • Датчик DHT11 и резистор 10 кОм
  • Провода

Все детали есть в обучающем наборе, по которому идёт курс.

Финальный аккорд блока «Незнакомые детали» — три ярких светодиода, последние жители коробки, не побывавшие в макетке. Из них мы соберём светящуюся шкалу-градусник: чем теплее в комнате, тем длиннее огненный столбик. Датчик температуры у нас уже есть — DHT11 из метеостанции.

По дороге решим красивую задачу: как показать температуру 26,8 градуса шкалой из трёх лампочек? Округлять грубо — скучно. Мы зажжём «два с половиной светодиода» — и это не шутка.

Чем яркий светодиод отличается от обычного

Обычный: цветная колбацвет виден до включенияЯркий: колба прозрачнаяцвет узнаете, только включивспил на юбке —по-прежнему минус
У обычного светодиода колба цветная и матовая, у яркого — прозрачная, как стеклышко. Спил-минус на месте.

Внутри — тот же кристалл, но колба прозрачная и работает как линза: свет собирается в узкий сноп и бьёт заметно сильнее. Из-за прозрачности не угадать цвет выключенного светодиода — включите каждый заранее, чтобы выстроить шкалу красиво. Подключаются они точно так же: длинная ножка — плюс, спил на юбке — минус, резистор 470 Ом обязателен.

Не смотрите в упор. Яркий светодиод на полной мощности неприятно бьёт по глазам с близкого расстояния. Собирайте шкалу так, чтобы она светила вбок или вверх, а не в лицо.

Собираем схему

Слева — знакомый по метеостанции DHT11 на выводе 8 с подтяжкой 10 кОм, справа — три светодиода на выводах 9, 10 и 11. Выводы выбраны не случайно: все три умеют ШИМ, и это скоро сыграет главную роль. Ни сервопривода, ни зуммера в схеме нет — таймеры свободны, ШИМ работает на всех троих.

++abcdefghij1101520253012341DHT11 решёткой к себе в столбики 5–8: «+», данные (→ вывод 8), пусто, «−».2Подтяжка 10 кОм — через канавку в столбике 6, нижний конец — к шине «+».3Три ярких светодиода: выводы 9, 10, 11 → резисторы 470 Ом → длинные ножки.4Питание: 5V → нижняя «+», GND → нижняя «−»; перемычка поднимает «−» наверх.
DHT11 в столбиках 5–8, шкала из трёх светодиодов — правее. Нижний сегмент — вывод 9, средний — 10, верхний — 11.

Шаг 1. Проверяем шкалу

// Продвинутый курс, урок 6. Шаг 1: проверяем три ярких светодиода.

const int LEDS[3] = {9, 10, 11};   // снизу вверх: все три вывода с ШИМ

void setup() {
  for (int i = 0; i < 3; i++) {
    pinMode(LEDS[i], OUTPUT);
  }
}

void loop() {
  for (int i = 0; i < 3; i++) {
    digitalWrite(LEDS[i], HIGH);
    delay(200);
    digitalWrite(LEDS[i], LOW);
  }
}

Бегущий огонёк из шестого урока — теперь как пятиминутка проверки: все три должны мигать по очереди. Если какой-то молчит — проверьте спил и резистор именно его канала.

Шаг 2. Спрашиваем температуру

// Продвинутый курс, урок 6. Шаг 2: спрашиваем температуру у DHT11.

#include <iarduino_DHT.h>

iarduino_DHT sensor(8);   // датчик на выводе 8, как в метеостанции

void setup() {
  Serial.begin(9600);
}

void loop() {
  delay(2000);            // DHT11 отвечает не чаще раза в две секунды

  if (sensor.read() == DHT_OK) {
    Serial.print("Температура: ");
    Serial.print(sensor.tem, 0);
    Serial.println(" C");
  } else {
    Serial.println("Датчик не ответил, пробую снова...");
  }
}

Всё как в уроке о DHT11: библиотека iarduino_DHT, опрос не чаще раза в две секунды, проверка ответа. Посмотрите свои числа в мониторе и выберите границы шкалы — в скетчах дальше стоят 22 и 28 градусов, но ваша комната может жить в другом диапазоне. Правило из урока о датчике света работает и тут: чужие пороги не работают, измерьте свои.

Шаг 3. Температура столбиком

// Продвинутый курс, урок 6. Шаг 3: температура столбиком.

#include <iarduino_DHT.h>

iarduino_DHT sensor(8);

const int LEDS[3] = {9, 10, 11};
const int T_MIN = 22;   // здесь и ниже — шкала пустая
const int T_MAX = 28;   // здесь и выше — все три горят

void setup() {
  Serial.begin(9600);
  for (int i = 0; i < 3; i++) {
    pinMode(LEDS[i], OUTPUT);
  }
}

void loop() {
  delay(2000);
  if (sensor.read() != DHT_OK) {
    return;               // не ответил — попробуем в следующий раз
  }

  Serial.println(sensor.tem, 0);

  // Сколько сегментов зажечь: 0, 1, 2 или 3.
  int lit = map(sensor.tem, T_MIN, T_MAX, 0, 3);
  lit = constrain(lit, 0, 3);

  for (int i = 0; i < 3; i++) {
    if (i < lit) {
      digitalWrite(LEDS[i], HIGH);
    } else {
      digitalWrite(LEDS[i], LOW);
    }
  }
}

Первый вариант шкалы — честный и грубый: map превращает температуру в число сегментов от 0 до 3, цикл зажигает первые lit штук. Подышите на датчик — столбик подрастёт. Работает! Но следите за ним минуту: сегменты прыгают — то два, то три. Между «двумя» и «тремя» нет ничего, а температура-то меняется плавно.

Шаг 4. Полтора светодиода

22°24°26°28°сейчас 26,8°(26,8 − 22) ÷ (28 − 22) × 3 = 2,4 — «два целых сегмента и четыре десятых».горит целикомнижнийгорит целикомсреднийяркость 40 %верхний
26,8° на шкале 22…28 — это уровень 2,4: два сегмента целиком и 40 % третьего.

А вот и обещанное чудо. Переведём температуру не в «сколько сегментов», а в уровень с дробной частью: 26,8 градуса — это 2,4 сегмента. Два горят целиком, а третий... горит на 40 % — яркостью! ШИМ из восьмого урока наконец встретился с дробными числами из четырнадцатого.

// Продвинутый курс, урок 6. Шаг 4: шкала с «наливающимся» сегментом.

#include <iarduino_DHT.h>

iarduino_DHT sensor(8);

const int LEDS[3] = {9, 10, 11};
const float T_MIN = 22.0;
const float T_MAX = 28.0;

void setup() {
  Serial.begin(9600);
  for (int i = 0; i < 3; i++) {
    pinMode(LEDS[i], OUTPUT);
  }
}

void loop() {
  delay(2000);
  if (sensor.read() != DHT_OK) {
    return;
  }

  // Температура → «уровень» от 0.0 до 3.0. Например, 25 градусов — это 1.5:
  // один сегмент горит целиком, второй налит наполовину.
  float level = (sensor.tem - T_MIN) / (T_MAX - T_MIN) * 3.0;
  level = constrain(level, 0.0, 3.0);

  Serial.print(sensor.tem, 0);
  Serial.print(" C -> уровень ");
  Serial.println(level);

  for (int i = 0; i < 3; i++) {
    float part = constrain(level - i, 0.0, 1.0);   // доля этого сегмента
    analogWrite(LEDS[i], part * 255);
  }
}

Вся магия — в строке constrain(level - i, 0.0, 1.0): для каждого сегмента она отвечает на вопрос «какая доля меня закрашена?». У нижнего при уровне 2,4 выходит 1,0 — полная яркость, у среднего тоже 1,0, у верхнего — 0,4, а у несуществующего четвёртого вышло бы 0. Одна формула — и шкала стала плавной, как ртутный столбик: подышите на датчик и смотрите, как верхний сегмент наливается.

Шаг 5. Сторож тепла

// Продвинутый курс, урок 6. Шаг 5: сторож тепла.
// Шкала показывает температуру, а при перегреве мигает вся линейка.

#include <iarduino_DHT.h>

iarduino_DHT sensor(8);

const int LEDS[3] = {9, 10, 11};
const float T_MIN = 22.0;
const float T_MAX = 28.0;
const float T_ALARM = 30.0;    // тревога: жарче тридцати
const float T_CALM = 28.5;     // отбой: остыло ниже — гистерезис из урока 15

bool alarmOn = false;
float lastTem = 0;
unsigned long lastRead = 0;
bool blinkPhase = false;
unsigned long lastBlink = 0;

void setup() {
  Serial.begin(9600);
  for (int i = 0; i < 3; i++) {
    pinMode(LEDS[i], OUTPUT);
  }
}

void loop() {
  // Датчик спрашиваем по расписанию, не останавливая мигание.
  if (millis() - lastRead >= 2000) {
    lastRead = millis();
    if (sensor.read() == DHT_OK) {
      lastTem = sensor.tem;

      if (lastTem >= T_ALARM) {
        alarmOn = true;
      }
      if (lastTem <= T_CALM) {
        alarmOn = false;
      }
    }
  }

  if (alarmOn) {
    // Тревога: вся шкала мигает дважды в секунду.
    if (millis() - lastBlink >= 250) {
      lastBlink = millis();
      blinkPhase = !blinkPhase;
    }
    for (int i = 0; i < 3; i++) {
      digitalWrite(LEDS[i], blinkPhase);
    }
  } else {
    // Покой: обычная плавная шкала.
    float level = (lastTem - T_MIN) / (T_MAX - T_MIN) * 3.0;
    level = constrain(level, 0.0, 3.0);
    for (int i = 0; i < 3; i++) {
      float part = constrain(level - i, 0.0, 1.0);
      analogWrite(LEDS[i], part * 255);
    }
  }
}

Осталось добавить характер: пусть при жаре выше 30 градусов вся шкала тревожно мигает. Заметьте два приёма из базового курса, которые тут встретились. Первый — гистерезис из урока о датчике света: тревога включается на 30°, а выключается только на 28,5° — иначе на границе шкала истерила бы. Второй — опрос датчика по расписанию millis(): мигать надо четыре раза в секунду, а DHT11 отвечает лишь раз в две — delay(2000) здесь всё бы заморозил.

Испытание: зажмите датчик пальцами (не дыханием — так честнее) и дождитесь тревоги. Отпустите: мигание продолжится, пока температура не упадёт ниже 28,5°, — гистерезис не даёт тревоге дребезжать. Настройте пороги под свою комнату и поставьте сторожа рядом с рассадой, аквариумом или 3D-принтером.

Частые проблемы

  • Столбик всегда полный или всегда пустой. Ваши границы шкалы не совпадают с комнатой: посмотрите реальные числа в мониторе (шаг 2) и подвиньте T_MIN и T_MAX.
  • Верхний сегмент не «наливается», а щёлкает. Проверьте, что светодиоды стоят именно на 9, 10 и 11 — на выводах без ШИМ analogWrite работает как грубый выключатель, вы помните это по уроку о плавной яркости.
  • «Датчик не ответил» через раз. DHT11 нельзя дёргать чаще раза в две секунды. И проверьте подтяжку 10 кОм — без неё линия данных «висит».
  • Шкала мигает не в такт: то часто, то с паузами. Значит, где-то прокрался delay. В скетче сторожа блокирующих задержек нет — сверьтесь с ним.

Задания для тренировки

  • РазминкаПереверните шкалу: пусть она показывает не жару, а холод — чем прохладнее, тем длиннее столбик. Достаточно тронуть одну формулу.
  • ПосложнееСделайте шкалу влажности: у DHT11 есть и она — sensor.hum. А если хочется по-настоящему — пусть кнопка переключает «градусник ↔ влагомер», и плавность при переключении сохраняется.
  • Со звёздочкой ⭐Вспомните вечную память: пусть сторож раз в час записывает минимум и максимум суток, а при старте показывает их «пробежкой» по шкале. Все инструменты у вас уже есть — EEPROM.put, millis и карта адресов.

Что вы теперь умеете

  • обращаться с яркими светодиодами и знать их два секрета: линзу и прозрачную колбу;
  • превращать измерение в шкалу: map для грубой, дробный уровень — для плавной;
  • зажигать «полтора светодиода» — дробная часть уходит в ШИМ;
  • строить сторожей: пороги, гистерезис и мигание без delay;
  • выбирать выводы с умом: шкале нужны три ШИМ — и они у вас есть.

Блок «Незнакомые детали» закрыт: теперь в наборе не осталось ни одной детали, которую вы не держали в руках. Впереди финальный блок — «Большие проекты 2». Первым будет устройство, которое просится на тумбочку у кровати: часы-будильник с экраном, кнопками и будильником, который не забывается при выключении.

Частые вопросы

Можно ли собрать шкалу из обычных цветных светодиодов?

Конечно: схема и скетчи не изменятся ни на строчку. Яркие выбраны, чтобы дать поработать последним нетронутым деталям набора, и потому что столбик из них видно через всю комнату.

Почему для шкалы важны именно выводы 9, 10 и 11?

Ради плавного «наливания» сегментов: дробная часть уровня превращается в яркость через ШИМ, а он есть не на всех выводах. В этой схеме нет ни сервопривода, ни зуммера, поэтому таймеры свободны и ШИМ работает на всех трёх выводах сразу.

Сколько светодиодов можно повесить на плату?

Каждый вывод отдаёт до 20 мА — это один светодиод с резистором 470 Ом. Таких выводов у Uno почти два десятка, но суммарный ток всех выводов тоже ограничен, поэтому длинную шкалу из десятков огней строят уже через транзисторы — как раз те, что вы освоили в прошлом уроке.

← Все уроки курса