map()
map() линейно пересчитывает число из одного диапазона в другой — например, показания analogRead() (0–1023) в диапазон analogWrite() (0–255).
Полная статья
Описание
map() выполняет линейное масштабирование: значение fromLow отображается в toLow, значение fromHigh — в toHigh, а все промежуточные значения пересчитываются пропорционально.
Это удобно, когда нужно привести данные одного диапазона к шкале другого — например, перевести показания АЦП (0–1023) в диапазон ШИМ (0–255) или в градусы поворота сервопривода.
Функция не ограничивает результат границами целевого диапазона: если value выходит за пределы исходного диапазона, результат тоже выйдет за пределы целевого. Это сделано намеренно — иногда именно такое поведение нужно. Если же вы хотите жёстко удержать результат в границах, примените constrain() до или после вызова map().
Границы диапазонов могут быть заданы в любом порядке: «нижняя» граница не обязана быть меньше «верхней». Это позволяет инвертировать диапазон. Например, следующий вызов разворачивает шкалу:
y = map(x, 1, 50, 50, 1);
Функция корректно работает с отрицательными числами:
y = map(x, 1, 50, 50, -100);
Важно понимать, что map() использует целочисленную арифметику. Дробная часть результата просто отбрасывается — без округления. Если математически должно получиться 1.7, функция вернёт 1. Для проектов, где важна точность (например, пересчёт напряжения с несколькими знаками после запятой), лучше реализовать формулу вручную с использованием float.
Синтаксис
map(value, fromLow, fromHigh, toLow, toHigh)
Параметры
value— число, которое нужно пересчитать.fromLow— нижняя граница исходного диапазона.fromHigh— верхняя граница исходного диапазона.toLow— нижняя граница целевого диапазона.toHigh— верхняя граница целевого диапазона.
Все параметры и возвращаемое значение имеют тип long, поэтому передавать дробные числа не имеет смысла — они будут усечены ещё до вычислений.
Возвращает
Пересчитанное значение. Тип данных: long.
Пример кода
Следующий скетч читает аналоговый сигнал (0–1023) с вывода A0 и масштабирует его в диапазон 0–255 для управления яркостью светодиода через ШИМ на выводе 9. Оба значения выводятся в Serial Monitor.
/* Преобразование аналогового значения в 8 бит (от 0 до 255) */
void setup() {
Serial.begin(9600);
}
void loop() {
int val = analogRead(0);
Serial.print("Input value: ");
Serial.print(val);
val = map(val, 0, 1023, 0, 255); // функция преобразования диапазона
Serial.print(", Output value: ");
Serial.println(val);
analogWrite(9, val); // вывод PWM
delay(200);
}
Если подключить потенциометр к аналоговому выводу (A0), а светодиод — к выводу 9, поворот ручки потенциометра будет плавно менять яркость светодиода.
Формула
Для тех, кто хочет понять математику:
long map(long x, long in_min, long in_max, long out_min, long out_max) {
return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}
Где применяется
- Управление сервоприводом — перевод угла поворота (например, 0–180°) в значение для
writeMicroseconds()(1000–2000 мкс). - Масштабирование АЦП — приведение показаний
analogRead()(0–1023) к диапазонуanalogWrite()(0–255). - Инверсия сигнала — когда нужно, чтобы максимальное входное значение давало минимальный выход, и наоборот.
- Пересчёт показаний датчика — например, перевод сырых данных датчика температуры в градусы Цельсия по известной линейной характеристике.
Практические замечания
map()не блокирует выполнение программы — это просто математическая функция, результат возвращается мгновенно.- Если
valueвыходит за пределыfromLow–fromHigh, результат тоже выйдет за пределыtoLow–toHigh. Чтобы этого избежать, оберните вызов вconstrain(). - Не передавайте одинаковые значения в
fromLowиfromHigh: в формуле появится деление на ноль. - Целочисленное усечение заметно при маленьких диапазонах. Например, при масштабировании 0–5 в 0–3 несколько входных значений будут давать одинаковый результат — это нормально, но стоит учитывать при проектировании интерфейса.
- Дроби вида 3/2, 4/3, 5/4 возвращаются как 1 — это не ошибка, а следствие целочисленной арифметики.
- Если точность важна, вычислите результат вручную через
float:float result = (float)(value - fromLow) * (toHigh - toLow) / (fromHigh - fromLow) + toLow; - При отладке выводите в Serial Monitor одновременно исходное и пересчитанное значение — это быстро покажет, правильно ли заданы границы диапазонов.