Летний стол с ноутбуком перегревался так, что я поставил рядом 80-миллиметровый вентилятор на 5 вольт и паяльную макетку с Uno. Включать в розетку через кнопку было неудобно: обдув нужен не всегда на максимум, а вставать из-за стола ради тумблера я быстро устал. ИК-приёмник лежал в ящике с прошлого проекта, пульт — тоже, и через полчаса скорость обдува переключалась клавишами 1, 2 и 3 с расстояния вытянутой руки. Кнопка ноль гасила мотор — получилось точь-в-точь как на напольном вентиляторе, только с собственной таблицей скоростей.
Здесь соберём этот проект целиком. Кнопки 1, 2 и 3 выставят три уровня ШИМ — 80, 160 и 255, ноль остановит крыльчатку, разгон пойдёт плавно по одной единице каждые 8 миллисекунд, чтобы мотор не дёргал питание рывком. Светодиод повторит текущую яркость, как тахометр. Заодно честно посчитаем токи, поговорим про порог старта — ниже трети мощности крыльчатка только дёргается — и разберём, почему мотор живёт на пине 9, а пины 3 и 11 при живом ИК-приёмнике для ШИМ закрыты.
Коды кнопок возьмите из собственной карты: как собрать её читалкой и почему чужие таблицы с интернета подводят, я расписывал в уроке про карту кодов. У пульта из моего набора цифры живут на командах 12, 24 и 94, у вашего могут быть другие — карта подскажет точные числа.
Три уровня: массив скоростей вместо трёх case
Скорость вентилятора — это скважность ШИМ на пине 9: analogWrite от 0 до 255, про саму механику сигнала я уже писал в уроке про ШИМ. Уровни я сложил в массив const int SPEEDS[4] = {0, 80, 160, 255} — нулевая ячейка под стоп, дальше три скорости. Кнопка приносит номер уровня, скетч читает SPEEDS[level] — и никакой лестницы из трёх case с тремя константами внутри. Когда через месяц захочется перестроить шкалу — скажем, сдвинуть первую скорость со 80 на 60, потому что на 80 слишком ветрено для бумаг, — правится одно число в одном месте.
С пином для мотора выбор небогат, и это надо принять сразу. Приёмник IRremote на Uno держит Timer2, а ШИМ пинов 3 и 11 генерируется тем же таймером — при живом приёме эти пины для analogWrite мертвы, о чём предупреждал ещё урок про конфликт таймеров. Timer1 отдавать мотору жалко, если в планах есть серво, но у вентилятора серво нет — берём пин 9, таймер Timer1, штатные 490 Гц. Простой моторчик с крыльчаткой на такой частоте живёт спокойно: гудит тихо, греется умеренно. Отдельная история — компьютерные четырёхпроводные вентиляторы: по спецификации Intel их управляющий вход ждёт 25 кГц, и на 490 Гц они мурлыкать откажутся; для них нужен свой таймерный сетап, и это материал отдельного разговора.
Про электрику — одна строка, но строгая: пин Uno отдаёт максимум 40 мА, а вентилятор на полном ходу съедает 180–250 мА. Между ними стоит транзистор или модуль драйвера, как у робота из урока про ИК-робот на L298N: пин командует затвором, мотор питается своим толстым проводом, земля общая. В симуляторе моторчик прицеплен к пину напрямую — это условность стенда, на настоящей макетке без транзистора не собирайте.
#include <IRremote.hpp> const int IR_PIN = 11;const int MOTOR_PIN = 9; // Timer1: ШИМ жив при приёмнике на Timer2const int LED_PIN = 10; // индикатор уровня — тоже ШИМ, см. note const int SPEEDS[4] = {0, 80, 160, 255}; // у пульта из набора: 1, 2, 3 и 0 int level = 0;int pwmNow = 0;unsigned long tStep = 0; void setup() { Serial.begin(9600); IrReceiver.begin(IR_PIN, ENABLE_LED_FEEDBACK); pinMode(MOTOR_PIN, OUTPUT); pinMode(LED_PIN, OUTPUT); analogWrite(MOTOR_PIN, 0); Serial.println("ventilyator: 1/2/3 - skorosti, 0 - stop");} void loop() { if (IrReceiver.decode()) { int cmd = IrReceiver.decodedIRData.command; int newLevel = -1; if (cmd == 12) newLevel = 1; // клавиша 1 — сверьте со своей картой кодов if (cmd == 24) newLevel = 2; // клавиша 2 if (cmd == 94) newLevel = 3; // клавиша 3 if (cmd == 22) newLevel = 0; // клавиша 0 — стоп if (newLevel >= 0 && newLevel != level) { level = newLevel; Serial.print("uroven "); Serial.println(level); } IrReceiver.resume(); } int target = SPEEDS[level]; if (pwmNow < target) { // разгон: +1 единица каждые 8 мс if (millis() - tStep >= 8) { tStep = millis(); pwmNow = pwmNow + 1; analogWrite(MOTOR_PIN, pwmNow); analogWrite(LED_PIN, pwmNow); } } else if (pwmNow > target) { // вниз — сразу: крыльчатка докрутится по инерции pwmNow = target; analogWrite(MOTOR_PIN, pwmNow); analogWrite(LED_PIN, pwmNow); }}Плавный разгон и зеркало уровня
Разгон — приём доезда, знакомый по уроку про яркость с пульта, только с двумя отличиями по сути. Первое: мотору нужен разгон сильнее, чем светодиоду — пусковой рывок с нуля до полной скважности просаживает питание и иногда не раскручивает крыльчатку вовсе, а плавный подъём за две секунды заводит её щадяще. Второе: вниз я мотор не плавлю, а ставлю на цель сразу — у крыльчатки есть выбег, она докручивается по инерции сама, и пилить её ШИМом вниз — только занимать loop() лишней работой. Разгоняется вентилятор по одной единице каждые 8 мс: от нуля до 255 — чуть больше двух секунд, от 0 до 80 — две трети секунды.
Удержание цифровой клавиши здесь безвредно и в этом его прелесть: повторы NEC летят каждые 108–110 мс, каждая повторная команда натыкается на проверку newLevel != level и съедается молча — уровень уже стоит. Тот же автоповтор, о котором писали в уроке про кадры NEC, в регуляторе с конечным числом ступеней защищает себя сам. Хотите плавную подстройку между ступенями — разрешите повторам менять target мелкими шагами, но тогда добавьте гистерезис, иначе подкрутка уедет за пределы шкалы.
Индикация уровня сделана зеркалом: светодиод получает тот же ШИМ, что и мотор, и глаз читает скорость по яркости без монитора порта. В симуляторе это честный analogWrite на пин 12, а на настоящей Uno у пина 12 ШИМ нет вовсе — отсюда выбор пина 10 в скетче для платы: Timer1 управляет парами 9 и 10, и индикатор живёт на одной шине с мотором. Хотите индикацию миганиями-счётом на любом пине — можно, но яркость-зеркало я нахожу честнее: она показывает текущую скважность, а не номер ступени.
| Кнопка | ШИМ | Что делает вентилятор | Ток моего 80-мм на 5 В |
|---|---|---|---|
| 0 | 0 | стоит, крыльчатка докручивается по инерции пару секунд | 0 мА |
| 1 | 80 (~31%) | тихий фон: пыль гонит, бумаги не сдувает | 60–90 мА |
| 2 | 160 (~63%) | рабочий обдув: чувствуется ладонью на полметра | 130–170 мА |
| 3 | 255 (100%) | максимум: слышен гул, охватывает весь стол | 180–250 мА |
Токи в таблице — с моего вентилятора, и это осреднённые показания мультиметра в разрыве плюсового провода, а не паспортные: у вашего экземпляра числа будут другими, замеряйте сами. Обратите внимание на непропорциональность: ШИМ вырос вдвое с 80 до 160, а ток — примерно вдвое; но с 160 до 255 прирост уже скромнее, потому что крыльчатка выходит на свой потолок оборотов и лишняя мощность уходит в гул. Ещё практичнее порог старта: ниже примерно 60–70 единиц мой мотор не трогается вовсе — крыльчатка дёргается и стоит, трение побеждает. Поэтому нижняя ступень у меня 80, а не 40: уровень, который «почти работает», в реальном обдуве не работает никак. У чужих экземпляров порог гуляет от 40 до 90 — подберите свою нижнюю ступень экспериментом, а не из таблицы.
- 1. Почему мотор ставят на пин 9, а не на 3 или 11?
- 2. Что даёт плавный разгон по одной единице каждые 8 мс?
- 3. Сколько займёт разгон с 0 до 255 по одной единице каждые 8 мс?
- 4. Светодиод-индикатор в симуляторе горит вполсилы на уровне 2, а на настоящей Uno — всегда полным накалом. В чём дело?
- 5. Кнопку 1 держат три секунды. Что делает скетч?
- Уровни скорости — массив SPEEDS {0, 80, 160, 255}: перестройка шкалы правится одним числом
- Мотор — на пин 9 (Timer1): пины 3 и 11 при живом ИК-приёмнике ШИМ не выдают
- Разгон — +1 единица каждые 8 мс по millis: до полного хода чуть больше двух секунд, вниз ШИМ ставится сразу — крыльчатка докручивается сама
- Светодиод-зеркало показывает скважность; на Uno индикатору нужен ШИМ-пин — 10, 5 или 6, но не 12
- Транзистор обязателен: пин даёт 40 мА, вентилятор ест 180–250 мА; ниже порога старта крыльчатка не трогается
Поворот потока из стороны в сторону, как у напольных вентиляторов, строится сверху этой же схемы: серво с растяжкой угла на тех же millis-гейтах, и команду «качание вкл/выкл» вешают на свободную клавишу пульта — готовый поворотный узел по ИК разобран в уроке про серво-поворот по команде пульта. Мой стол обошёлся без качания: направленный обдув на второй скорости решил вопрос нагрева. Если соберёте свою версию — начните с трёх уровней из этого урока, прожмите токи и только потом добавляйте движущиеся части: каждая новая ось добавляет и новый способ застрять.
Частые вопросы по теме урока
- Почему мотор ставят на пин 9, а не на 3 или 11?
- ШИМ Uno делают три таймера: приёмник занимает Timer2 (пины 3 и 11), Timer0 держит millis (пины 5 и 6), Timer1 остаётся мотору (пины 9 и 10). приёмник IRremote держит Timer2, который кормит ШИМ пинов 3 и 11, — при живом приёме они мертвы
- Что даёт плавный разгон по одной единице каждые 8 мс?
- Рывок со 0 до 255 просаживает питание и может не стронуть крыльчатку. Ступенчатый подъём заводит мотор мягко, а гейт на millis не мешает приёму команд. щадящий пуск без рывка питания и незаблокированный loop — decode живёт между шагами
- Сколько займёт разгон с 0 до 255 по одной единице каждые 8 мс?
- 255 единиц по 8 мс — примерно 2040 мс. Столько же займёт разгон до 160 с нуля: около 1,3 секунды, а до 80 — две трети секунды. чуть больше двух секунд — 255 шагов по 8 мс
- Светодиод-индикатор в симуляторе горит вполсилы на уровне 2, а на настоящей Uno — всегда полным накалом. В чём дело?
- ШИМ живёт на пинах 3, 5, 6, 9, 10, 11. Пин 12 умеет только вкл/выкл: переносите индикатор на 10 (общий Timer1 с мотором) или показываете уровень миганиями. у пина 12 на Uno нет аппаратного ШИМ — analogWrite с любым значением даёт полный HIGH
- Кнопку 1 держат три секунды. Что делает скетч?
- Автоповтор NEC шлёт ту же команду каждые 108–110 мс, но переключение происходит только при смене уровня. Регулятор с конечными ступенями защищает себя сам. повторные кадры NEC съедаются проверкой newLevel != level — уровень уже стоит