Продвинутый курс Arduino · Незнакомые детали
Урок 6. Шкала-градусник из ярких светодиодов
Последние жители коробки — три ярких светодиода — выстраиваются в светящийся столбик температуры. Учимся зажигать «полтора светодиода»: дробная часть уровня уходит в яркость.
Что понадобится
- Контроллер Uno и кабель USB
- Макетная плата
- 3 ярких светодиода и 3 резистора 470 Ом
- Датчик DHT11 и резистор 10 кОм
- Провода
Все детали есть в обучающем наборе, по которому идёт курс.
Финальный аккорд блока «Незнакомые детали» — три ярких светодиода, последние жители коробки, не побывавшие в макетке. Из них мы соберём светящуюся шкалу-градусник: чем теплее в комнате, тем длиннее огненный столбик. Датчик температуры у нас уже есть — DHT11 из метеостанции.
По дороге решим красивую задачу: как показать температуру 26,8 градуса шкалой из трёх лампочек? Округлять грубо — скучно. Мы зажжём «два с половиной светодиода» — и это не шутка.
Чем яркий светодиод отличается от обычного
Внутри — тот же кристалл, но колба прозрачная и работает как линза: свет собирается в узкий сноп и бьёт заметно сильнее. Из-за прозрачности не угадать цвет выключенного светодиода — включите каждый заранее, чтобы выстроить шкалу красиво. Подключаются они точно так же: длинная ножка — плюс, спил на юбке — минус, резистор 470 Ом обязателен.
Не смотрите в упор. Яркий светодиод на полной мощности неприятно бьёт по глазам с близкого расстояния. Собирайте шкалу так, чтобы она светила вбок или вверх, а не в лицо.
Собираем схему
Слева — знакомый по метеостанции DHT11 на выводе 8 с подтяжкой 10 кОм, справа — три светодиода на выводах 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. Полтора светодиода
А вот и обещанное чудо. Переведём температуру не в «сколько сегментов», а в уровень с дробной частью: 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 почти два десятка, но суммарный ток всех выводов тоже ограничен, поэтому длинную шкалу из десятков огней строят уже через транзисторы — как раз те, что вы освоили в прошлом уроке.
