Освой Arduino играючи
/* Моя кошка замечательно разбирается в программировании. Стоит мне объяснить проблему ей - и все становится ясно. */
John Robbins, Debugging Applications, Microsoft Press, 2000
Используем светодиод
Плавная регулировка светодиода
03.Analog: Calibration (Калибровка)
05.Control: switchCase
Фоторезистор (LDR, Light Depender Resistor) — компонент, меняющий сопротивление в зависимости от количества света падающего на него. В полной темноте он имеет максимальное сопротивление в сотни килоОм, а по мере роста освещённости сопротивление уменьшается до десятков килоОм.
Обозначение и рисунок на схемах.
Часто входит в стартовый набор.
Различаются фоторезисторы по диапазону сопротивления. Например:
Общее устройство.
Самый простой способ посмотреть на работу фоторезистора - подключить к нему мультиметр и смотреть за изменением сопротивления (1MΩ..1KΩ), закрывая фоторезистор рукой.
Так как это подвид резисторов, у него нет полярности. Можно подключать в любом направлении.
На уроке, посвящённому потенциометру, я упомянул, что пример чтения аналоговых выводов (File | Examples | 01.Basics | AnalogReadSerial) является универсальным. Проверим пример на фоторезисторе.
Соберём конструкцию по схеме.
Схема на макетной плате.
Опишем конструкцию словами. Из порта 5V идёт питание на первую ножку фоторезистора. Ко второй ножке присоединяются резистор, который соединяется с GND и отдельный провод, идущий на порт A0. Получается классический делитель напряжения.
Если запустить скетч и открыть окно Serial Monitor, то мы можем наблюдать изменения значений в зависимости от степени освещённости. Показания будут зависеть от второго резистора. Можете попробовать заменить резистор с другой маркировкой и проверить результат. В моём случае использовался резистор на 1 кОм. При этом показания менялись от 4 до 158 зимним днём, когда уже начинало темнеть, а свет в комнате ещё не включал. Если посветить на фоторезистор фонариком, то значение увеличивалось до 918 единиц.
Убедившись, что фоторезистор работает и выдаёт результат, можем написать какую-нибудь программу. Допустим, мы хотим, чтобы с наступлением темноты на даче включался фонарик, который осветит дорогу в баню. В качестве фонаря будем использовать встроенный светодиод. Перепишем код.
int ledPin = 13; // используем встроенный светодиод на выводе 13
void setup() {
pinMode(ledPin, OUTPUT);
}
void loop() {
// считываем показания с аналогового вывода A0
int sensorValue = analogRead(A0);
if(sensorValue < 50){
// Если потемнело, то включаем светодиод
digitalWrite(ledPin, HIGH);
}
else {
// Если светло, то выключаем светодиод
digitalWrite(ledPin, LOW);
}
}
Мы определяем определённую величину, которая будет соответствовать сумеркам и включаем светодиод при достижении этой величины. Теперь фонарь на даче будет включаться без нашего участия.
Если мы хотим менять яркость светодиода плавно, то встроенный светодиод не подойдёт. Нам понадобится вывод с символом ~. Мы уже проходили подобный урок 01.Basics: Fade (затухание светодиода), поэтому добавим свой светодиод с резистором на макетную плату.
Мы можем явно указать отслеживаемый диапазон, например, от 4 до 200. Но показания могут быть меньше или больше этих значений и нам нужно написать условия, которые учитывали бы эту ситуацию. К счастью, есть готовая функция constrain(), которая делает эту работу за нас. Далее эти значения нужно распределить между диапазоном от 0 до 255 с помощью функции map(), так как светодиод работает только в этом диапазоне. Но если мы оставим как есть, то 4 будет соответствовать 0, а 200 будет соответствовать 255. При таком решении светодиод будет гореть ярче при хорошем освещении и тусклее при плохом освещении. А нам нужна обратная ситуация. Поэтому в функции мы применяем обратный порядок от 255 до 0. Таким образом, код получится следующим.
int ledPin = 10; // используем светодиод с тильдой
void setup() {
pinMode(ledPin, OUTPUT);
}
void loop() {
// считываем показания с аналогового вывода A0
int sensorValue = analogRead(A0);
// только в этом диапазоне
sensorValue = constrain(sensorValue, 4, 200);
// Отобразим значения от 4 до 200 как от 255 до 0
int ledLevel = map(sensorValue, 4, 200, 255, 0);
analogWrite(ledPin, ledLevel);
}
Проверяем. У меня работает, а у вас?
Если датчик может работать в широких пределах, имеет смысл определить его настоящие возможности в реальной обстановке. Например, при работе с датчиком освещённости в коридоре мы можем оценить, сколько света обычно бывает при включённой лампе и в темноте и отталкиваться от полученных результатов, отсекая лишние показания.
Запустим скетч File | Examples | 03.Analog | Calibration.
В течение первых пяти секунд мы записываем данные с датчика. Наибольшее и наименьшее значения попадают в переменные. Затем работаем с полученными данными.
const int sensorPin = A0; // аналоговый вывод A0
const int ledPin = 9; // вывод 9 для светодиода
int sensorValue = 0; // значение датчика
int sensorMin = 1023; // минимальное значение
int sensorMax = 0; // максимальное значение
void setup() {
// включаем светодиод на время калибровки
pinMode(13, OUTPUT);
digitalWrite(13, HIGH);
// калибровка в течение 5 секунд
while (millis() < 5000) {
sensorValue = analogRead(sensorPin);
// записываем максимально полученный результат
if (sensorValue > sensorMax) {
sensorMax = sensorValue;
}
// записываем минимально полученный результат
if (sensorValue < sensorMin) {
sensorMin = sensorValue;
}
}
// выключаем светодиод
digitalWrite(13, LOW);
}
void loop() {
// снимаем показания датчика
sensorValue = analogRead(sensorPin);
// применяем показания с учётом минимального и максимального значений
sensorValue = map(sensorValue, sensorMin, sensorMax, 0, 255);
// если показания выходят за пределы калибровки, то срезаем лишнее
sensorValue = constrain(sensorValue, 0, 255);
// меняем интенсивность светодиода в зависимости от калиброванных показаний
analogWrite(ledPin, sensorValue);
}
Теперь вы без труда поймёте код из примера File | Examples | 05.Control | switchCase. Опытным путём выясняется, что показания фоторезистора колеблются от 0 до 600 (у вас могут быть другие значения, тогда измените). Делим интервал на четыре части при помощи map(): темно, дымка, средне, ярко. С помощью оператора выбора switch выбираем нужное значение и выводим сообщение. Схема остаётся прежней.
const int sensorMin = 0; // минимальное значение датчика
const int sensorMax = 600; // максимальное значение датчика
void setup() {
Serial.begin(9600);
}
void loop() {
// получаем данные от датчика
int sensorReading = analogRead(A0);
// делим данные на четыре интервала
int range = map(sensorReading, sensorMin, sensorMax, 0, 3);
// сравниваем значения и выводим нужное сообщение
switch (range) {
case 0: // рукой закрываем датчик
Serial.println("dark");
break;
case 1: // подаём немного света
Serial.println("dim");
break;
case 2: // ещё больше света
Serial.println("medium");
break;
case 3: // датчик под лампой
Serial.println("bright");
break;
}
delay(1); // пауза для стабильности
}
Может выпускаться в виде готового модуля. На рисунке пример от магазина "Амперка".
Есть также популярный китайский модуль KY-018.
У модуля между выводами «S» и выводом питания +5 В (средний вывод) впаян резистор 10 кОм, что вместе с самим фоторезистором образует делитель напряжения, который удобно подключить к аналоговому входу Arduino.
KY-018 | Arduino
-------------
- | GND
+ | 5V
S | D