Функция map(): перекладываем диапазоны
Датчик говорит «687». Светодиод понимает «0–255». Сервопривод — «0–180 градусов». Нужен переводчик — и это функция map().
map() — это пропорция в одну строку. Она растягивает или сжимает один числовой диапазон в другой, сохраняя соотношения. Без неё датчики и моторы говорят на разных языках.
Сейчас свяжем потенциометр (0–1023) с яркостью светодиода (0–255): крутишь ручку — меняется свет. Для этого числа надо «перевести». Это самая используемая функция в реальных проектах.
Что делает map
Вход: 0 ......................... 1023 (потенциометр)
| |
v v
Выход: 0 ......................... 255 (яркость ШИМ)
Пример: 512 (середина входа) -> ~127 (середина выхода)
Синтаксис: map(значение, изНач, изКонец, вНач, вКонец). Она вычисляет, где значение стоит во входном диапазоне, и ставит его в ту же относительную точку выходного.
Код
const int LED = 9;
void setup() {
pinMode(LED, OUTPUT);
}
void loop() {
int raw = analogRead(A0); // 0..1023
int bright = map(raw, 0, 1023, 0, 255); // -> 0..255
analogWrite(LED, bright);
}
Как работает под капотом
map — это просто пропорция: выход = вНач + (значение − изНач) * (вКонец − вНач) / (изКонец − изНач). Важно: map работает с целыми числами и отбрасывает дробную часть (не округляет!). Поэтому иногда результат на единицу «не дотягивает». Ещё map не обрезает выход: если вход вышел за границы, выход тоже вылетит за пределы. Для защиты используют constrain.
# Та же логика на Python: своя реализация map() и constrain()
def arduino_map(x, in_min, in_max, out_min, out_max):
# как в Arduino: целочисленно, без округления
return (x - in_min) * (out_max - out_min) // (in_max - in_min) + out_min
def constrain(x, low, high):
return max(low, min(high, x))
for raw in (0, 256, 512, 768, 1023, 1100):
b = arduino_map(raw, 0, 1023, 0, 255)
b = constrain(b, 0, 255) # защита от выхода за диапазон
print("потенциометр", raw, "-> яркость", b)
Запусти и заметь: вход 1100 (выше максимума) без constrain дал бы >255, но мы его подрезали. Это спасает analogWrite от мусора.
Частые ошибки
- Путают порядок аргументов. Сначала весь входной диапазон, потом весь выходной. Перепутаешь — абсурдные значения.
- Забыли constrain. Шумный датчик выдаёт 1025 — map выдаёт 256 — analogWrite «срывается».
- Ждут округления. map режет дробную часть. Для точности считай во float вручную.
Best practices
- Почти всегда оборачивай map в constrain:
constrain(map(...), мин, макс). - map можно «переворачивать»:
map(raw, 0, 1023, 255, 0)— больше крутишь, тусклее свет. - Один и тот же приём свяжет датчик с градусами сервопривода (0–180) — запомни шаблон.
Калибровка: подгоняем под реальность
В жизни датчик почти никогда не выдаёт идеальные 0 и 1023. Реальный потенциометр может давать, скажем, от 8 до 1015; фоторезистор в твоей комнате — от 200 (темно) до 750 (ярко). Если в map() подставить теоретические 0–1023, ты не используешь весь диапазон выхода. Поэтому опытные мейкеры калибруют: смотрят в монитор порта реальные минимум и максимум своего датчика и подставляют именно их: map(raw, 200, 750, 0, 255). Тогда вся шкала работает «от края до края».
Это подводит к важному принципу: числа из теории — отправная точка, а не истина. Реальная электроника всегда чуть отличается от учебника из-за разброса деталей, температуры и наводок. Хороший проект почти всегда включает короткий этап калибровки — пару минут с монитором порта, чтобы узнать настоящие границы. После связки analogRead + калибровка + constrain(map(...)) твои датчики будут вести себя предсказуемо, а не «как повезёт».
Итоги
map() — это пропорция, переводящая один диапазон в другой; работает целочисленно и не обрезает выход, поэтому дружит с constrain. Теперь потенциометр управляет яркостью. Со связкой analogRead + map + analogWrite ты готов к настоящим датчикам.