Система Arduino поддерживает обработку аналоговых сигналов. Для входных сигналов мы имеем АЦП (аналогово-цифровой преобразователь), в случае выходного сигнал — возможна модуляция ШИМ (широтно-импульсная модуляция).
В Arduino, сердцем которой является микроконтроллер Atmega, имеется один 10-битный АЦП. Это означает, что считанное значение напряжения может находиться в диапазоне от 0 — 1023. В зависимости от опорного напряжения 1024 значений будут распределены на соответствующий диапазон. В результате мы можем получить различную точность и различный диапазон напряжений, считываемых аналого-цифровым преобразователем.
Если выбрать опорное напряжение равное 1,024В, то каждое последующее значение, считанное с аналогового входа будет соответствовать 1мВ. Если опорное напряжение задать равным 5В, то каждое последующее значение будет соответствовать приблизительно 5 мВ.
Следует отметить, что аналого-цифровые преобразователи не имеют идеальной линейной характеристики. Это означает, что в определенных интервалах может быть разница между фактическим и считанным значением напряжения. Из вышеизложенного вытекает, что увеличивая диапазон измерения, мы теряем на качестве измерения, уменьшая диапазон, мы увеличиваем точность измерения.
Примечание: Arduino имеет несколько (в зависимости от версии) аналоговых входов, однако АЦП в ней только один. Это означает, что одновременно может быть считано значение только с одного из датчиков, подключенных к аналоговым входам A0… A5 (A0… A15 для Arduino MEGA).
Функция analogReference()
Для правильной работы АЦП требуется опорное напряжение (эталон). Для Arduino опорное напряжение может быть в диапазоне 0…5В (или 0… 3,3В для Arduino с напряжением питания 3,3В). В зависимости от типа используемого микроконтроллера у нас могут быть разные виды опорного напряжения.
Мы можем использовать внутренний или внешний источник опорного напряжения. Функция AnalogReference() предназначена для того, чтобы установить соответствующий источник опорного напряжения. Доступны следующие параметры этой функции:
- DEFAULT: опорное напряжение составляет 5В или 3,3В (в зависимости от питания) — то есть, оно равно напряжению питания микроконтроллера;
- INTERNAL: опорное напряжения составляет 1,1В для ATmega168, ATmega328 и 2,56В для ATmega8;
- INTERNAL1V1: опорное напряжение составляет 1,1В — только для Arduino MEGA;
- INTERNAL2V56: опорное напряжение составляет 2,56В — только для Arduino MEGA;
- EXTERNAL: внешнее опорное напряжение, приложенное к выводу AREF — от 0 до 5В.
Параметр DEFAULT выбираем, когда хотим воспользоваться опорным напряжением 5В (питание системы). Это самый простой и одновременно наименее точный способ. Здесь требуется хорошая стабильность питания.
Использование INTERNAL является хорошим вариантом, в ситуации, когда мы создаем проект, предназначенный для конкретной версии Arduino. Внутренние опорное напряжение является относительно стабильным и достаточным в большинстве случаев.
Наиболее точным вариантом является использование внешнего источника опорного напряжения. Существуют специальные источники опорного напряжения (ИОН). Плюсом является возможность получения необходимого точного опорного напряжения, например, 1,024В или 2,048В, что облегчает интерпретацию данных, считываемых АЦП. К недостаткам применения внешнего источника опорного напряжения можно отнести возможное увеличение стоимости проекта.
Синтаксис функции analogReference() показан в следующем примере:
[slh lang=»php»]
analogReference(DEFAULT); //опорное напряжение = напряжение питания
analogReference(INTERNAL); //опорное напряжение = 1,1В или 2,56В
analogReference(EXTERNAL); //опорное напряжение = напряжение на AREF выводе
[/slh]
Функция analogRead()
Функция analogRead() обеспечивает считывание значения с одного из аналоговых входов. Считанное значение находится в диапазоне 0 — 1023 (10-битный АЦП). Необходимо указать номер аналогового входа, с которого будет происходить чтение данных.
Следующий пример иллюстрирует использование аналоговых входов:
[slh lang=»php»]
#define analogPin 0 // потенциометр подключен к A0
int val = 0; // val — переменная, хранящая считанное значение
void setup()
{
Serial.begin(9600); // инициализация последовательного порта
}
void loop()
{
val = analogRead(analogPin); // чтение значения напряжения с порта A0
Serial.println(val); // отправка измеренной величины на терминал
}
[/slh]
Как видно, на приведенном выше примере, считанное значение напряжения передается через последовательный порт на компьютер.
В примере не использована функция analogReference(), так как по умолчанию система использует опорное напряжение от источника питания. Однако, лучше указывать в функции setup() явный выбор опорного напряжения (в нашем случае это analogReference(DEFAULT)), так как это облегчает понимание кода и его модификацию в будущем.
Функция analogWrite()
Функция analogWrite() позволяет управлять выходом с помощью сигнала ШИМ. ШИМ часто используется в качестве замены обычного аналогового сигнала. Количество доступных выводов ШИМ зависит от типа используемого микроконтроллера в Arduino.
Так у Arduino на микроконтроллере:
- Atmega8 — выводы 9, 10, 11;
- Atmega128, Atmega168 и Atmega328 — выводы 3, 5, 6, 9, 10, 11;
- Atmega1280 — выводы 2…13 и 44…46.
Частота переключения ШИМ большинства контактов составляет 490 Гц. Степень заполнения формируется числом от 0 до 255 (0 — без заполнения, 255 – полное заполнение).
Если мы подключим светодиод к контакту PWM и будем менять заполнение ШИМ, мы увидим изменение интенсивности свечения светодиода. Ниже приведен пример программы изменения свечения светодиода при помощи потенциометра:
[slh lang=»php»]
#define ledPin 11 // светодиод подключен к контакту 11
#define analogPin 0 // потенциометр на А0
int val = 0; // val — переменная, хранящая значение A0
void setup()
{
pinMode(ledPin, OUTPUT); // устанавливаем контакт 9 как выход
}
void loop()
{
val = analogRead(analogPin); // чтение с потенциометра
analogWrite(ledPin, val / 4); // пишем в ШИМ
}
[/slh]
Как вы можете видеть, значение, считанное с аналогового входа, преобразуется в соответствующее значение ШИМ.
Чтобы ШИМ работал пропорционально вращению потенциометра, значение, полученное с A0, следует разделить на четыре. Это связано с тем, что данные с потенциометра лежат в диапазоне от 0 до 1024, а ШИМ принимает диапазон данных от 0 до 255.
В этом примере используется простое деление. В Arduino IDE имеется специальная функция map(), которая предназначена для пропорционального преобразования данных в новый диапазон значений.
Молодой человек, нужно питать 3 лампы, 1-40%, 2-30%, 3-30%.
Как 255÷100% ?
Есть предположение питать от 2 источников, но это не легко, не мобильно и чревато спотыканиями в будущем, можно ли сделать всё легко и просто? Или 40% записать как 102 255ых, 30 как 76?