Урок 7. Аналоговые входы и ШИМ — analogRead и analogWrite
Кнопка знает только два состояния: нажата или нет. Но многие датчики сообщают величину — сколько света, под каким углом повёрнута ручка, какая температура. Они выдают напряжение, и плата умеет его измерять. А в обратную сторону плата умеет не только включать и выключать светодиод, но и менять его яркость.
Аналоговый вход: analogRead
Выводы A0–A5 на Uno (на Nano ещё A6 и A7) подключены к АЦП — аналого-цифровому преобразователю. Он переводит напряжение от 0 до 5 В в число от 0 до 1023:
- 0 В → 0;
- 2,5 В → около 512;
- 5 В → 1023.
Один шаг — примерно 5 / 1024 ≈ 0,0049 В, то есть около 5 мВ. Функция analogRead(A0) возвращает это число; вызывать pinMode для аналогового входа не нужно.
На вход нельзя подавать больше 5 В и меньше 0 В (у плат на 3,3 В — больше 3,3 В): вывод и микроконтроллер могут сгореть. Большие напряжения, например от аккумулятора на 12 В, измеряют через делитель из двух резисторов.
Потенциометр
Потенциометр (переменный резистор) — резистор с ручкой и тремя выводами. Крайние подключите к 5V и GND, средний — к A0. Поворачивая ручку, вы меняете напряжение на среднем выводе от 0 до 5 В. Номинал 10 кОм — самый удобный.
void setup() {
Serial.begin(9600);
}
void loop() {
int value = analogRead(A0); // число 0–1023
float voltage = value * (5.0 / 1023.0); // перевести в вольты
Serial.print(value);
Serial.print(" ");
Serial.print(voltage);
Serial.println(" В");
delay(200);
}Откройте монитор порта и покрутите ручку — числа будут меняться, например так:
0 0.00 В
512 2.50 В
1023 5.00 ВОбратите внимание на 5.0 и 1023.0 с точкой. Если написать value * (5 / 1023), получится всегда 0: в C++ деление целых чисел отбрасывает дробную часть, и 5 / 1023 даёт 0. Число с точкой делает вычисление дробным.
Если к входу ничего не подключено, analogRead возвращает случайно меняющиеся значения — как и висящий цифровой вход. Это не поломка.
Делитель напряжения и фоторезистор
Многие простые датчики — это резистор, сопротивление которого меняется: фоторезистор (от света), терморезистор (от температуры). Плата измеряет напряжение, а не сопротивление, поэтому такой датчик ставят в делитель напряжения: 5V → фоторезистор → A0 → резистор 10 кОм → GND. Чем светлее, тем меньше сопротивление фоторезистора и тем больше число на A0. Скетч тот же, что для потенциометра.
ШИМ: analogWrite
Напряжение на цифровом выводе бывает только 0 или 5 В. Но если очень быстро включать и выключать вывод, светодиод будет казаться тусклее, а мотор — крутиться медленнее. Это ШИМ — широтно-импульсная модуляция (по-английски PWM). Важно, какую долю времени вывод включён: эта доля называется скважностью или коэффициентом заполнения.
analogWrite(вывод, значение) включает ШИМ: значение от 0 (всегда выключено) до 255 (всегда включено), 128 — включено примерно половину времени. Частота на Uno и Nano — около 490 раз в секунду, на выводах 5 и 6 — около 980.
ШИМ есть не на всех выводах — только на отмеченных ~: на Uno и Nano это 3, 5, 6, 9, 10, 11. Подробнее — в справке Что такое ШИМ.
Плавное мигание
Подключите светодиод с резистором к выводу 9, как в уроке Электричество для начинающих:
const int LED = 9; // вывод с ШИМ
int brightness = 0; // текущая яркость 0–255
int step = 5; // на сколько менять за один шаг
void setup() {
pinMode(LED, OUTPUT);
}
void loop() {
analogWrite(LED, brightness);
brightness = brightness + step;
if (brightness <= 0 || brightness >= 255) {
step = -step; // на краю — повернуть в обратную сторону
}
delay(30);
}Яркость растёт шагами по 5 от 0 до 255, затем убывает обратно. || значит «или»: условие выполняется, если верна хотя бы одна часть.
Ручка управляет яркостью: map
Соедините оба опыта: потенциометр на A0, светодиод на выводе 9. Остаётся перевести число 0–1023 в 0–255. Для этого есть функция map(значение, от_мин, от_макс, в_мин, в_макс) — она пересчитывает число из одного диапазона в другой:
const int POT = A0;
const int LED = 9;
void setup() {
pinMode(LED, OUTPUT);
}
void loop() {
int value = analogRead(POT); // 0–1023
int brightness = map(value, 0, 1023, 0, 255); // 0–255
analogWrite(LED, brightness);
}map(512, 0, 1023, 0, 255) даёт 127: функция работает с целыми числами и дробную часть отбрасывает. Она не ограничивает результат: если значение выйдет за исходный диапазон, результат выйдет за новый. Чтобы удержать число в пределах, есть constrain(x, мин, макс).
На глаз яркость меняется неравномерно: от 0 до 50 разница заметна сильно, от 200 до 255 — едва. Так устроено зрение, а не плата.
Коротко
analogRead(A0)переводит 0–5 В в число 0–1023; шаг около 5 мВ.- Больше 5 В на вход подавать нельзя; большие напряжения — через делитель.
analogWrite(вывод, 0–255)включает ШИМ — только на выводах~(3, 5, 6, 9, 10, 11 у Uno и Nano).mapпересчитывает число из диапазона в диапазон,constrainограничивает его.- Для дробных вычислений пишите числа с точкой:
5.0 / 1023.0.