Введение
Фоторезистор и микрофонный модуль датчика звука — два простых аналоговых датчика окружающей среды, часто используемые вместе для проектов вроде автоматического ночника или звукового триггера. В статье разберём считывание обоих датчиков и передачу данных для визуализации и реагирования на стороне Qt.
Концепция
Фоторезистор меняет своё электрическое сопротивление в зависимости от освещённости — в типичной схеме делителя напряжения (фоторезистор плюс постоянный резистор, обычно 10 кОм из комплекта) это изменение сопротивления преобразуется в изменение напряжения, считываемое через analogRead(). Микрофонный модуль обычно содержит встроенный усилитель и компаратор, выдающий либо аналоговый уровень громкости звука (через analogRead()), либо цифровой сигнал превышения порога громкости (через digitalRead()) — конкретное поведение зависит от модели модуля и часто настраивается потенциометром чувствительности непосредственно на самой плате модуля.
Пример кода
// firmware/src/main.cpp — фоторезистор и датчик звука
#define LIGHT_SENSOR_PIN A3
#define SOUND_SENSOR_PIN A4
void setup()
{
Serial.begin(9600);
delay(100);
Serial.println("READY");
}
void loop()
{
static unsigned long lastLightTime = 0, lastSoundTime = 0;
static int soundPeak = 0;
if (millis() - lastLightTime >= 500) {
const int lightValue = analogRead(LIGHT_SENSOR_PIN);
// Инверсия — у делителя напряжения с фоторезистором рост освещённости
// часто соответствует УМЕНЬШЕНИЮ считываемого значения, в зависимости от схемы подключения
const int lightPercent = map(lightValue, 0, 1023, 100, 0);
Serial.print("LIGHT:");
Serial.println(lightPercent);
lastLightTime = millis();
}
// Звук считывается значительно чаще, поскольку громкие события могут быть короткими
const int soundValue = analogRead(SOUND_SENSOR_PIN);
soundPeak = max(soundPeak, soundValue);
if (millis() - lastSoundTime >= 100) {
Serial.print("SOUND:");
Serial.println(soundPeak);
soundPeak = 0; // сброс пикового значения для следующего интервала измерения
lastSoundTime = millis();
}
}
Пояснения к коду
map(lightValue, 0, 1023, 100, 0) — обратное масштабирование (конечный диапазон указан в обратном порядке, 100 затем 0), что используется, когда физическая схема подключения даёт инвертированную зависимость (меньше света → выше сопротивление фоторезистора → определённое изменение напряжения в делителе, в зависимости от того, к какому плечу делителя подключён АЦП) — конкретное направление инверсии зависит от точной схемы подключения, и при первой настройке стоит эмпирически проверить, действительно ли увеличение освещённости даёт ожидаемое увеличение процента, корректируя порядок аргументов map() при необходимости.
Для звукового датчика используется паттерн накопления пикового значения (soundPeak = max(soundPeak, soundValue)) внутри каждого короткого интервала (100 мс) перед отправкой — поскольку звуковые события (хлопок, стук) часто очень короткие, считывание значения только в фиксированные, редкие моменты времени легко «пропустит» сам пик громкости; накопление максимума за интервал гарантирует, что короткий, но громкий звук будет зафиксирован, даже если он произошёл между двумя точками обычного периодического считывания.
Подводные камни
- Прямая зависимость показаний фоторезистора от конкретной схемы делителя напряжения (значение второго резистора в паре с фоторезистором) — без знания точного номинала использованного резистора (10 кОм в типичном наборе) и точной схемы подключения сложно заранее предсказать направление и диапазон изменения считываемого значения; эмпирическая проверка (закрыть датчик рукой и посмотреть, увеличилось или уменьшилось считанное значение) — самый практичный способ определить корректное направление инверсии для конкретной собранной схемы.
- Чувствительность микрофонного модуля, регулируемая физическим потенциометром на самой плате модуля, может быть выставлена слишком высоко или слишком низко при первой настройке — слишком высокая чувствительность приводит к постоянным ложным срабатываниям даже от фонового шума, а слишком низкая — к пропуску реальных звуковых событий; начальная физическая калибровка чувствительности модуля обязательна перед программной отладкой, поскольку программный код не может компенсировать совершенно неправильно настроенную аппаратную чувствительность.
- Считывание звукового сигнала только в отдельные, дискретные моменты времени (без накопления пикового значения, как показано в исправленном примере) — частая первая, наивная реализация, которая просит надёжно отображать «уровень громкости в реальном времени», но реально пропускает короткие, важные события; необходимость явного накопления максимума за интервал — не всегда очевидна новичкам до того, как они на практике замечают, что громкие, но короткие звуки «не замечаются» датчиком.
- Постоянное считывание звукового датчика без какой-либо периодичности внутри
loop()(как в примере, в отличие от датчика освещённости, опрашиваемого только раз в 500 мс) добавляет небольшую, но не нулевую постоянную нагрузку на каждую итерацию цикла — для проектов с очень большим количеством одновременных задач вloop()это нужно явно учитывать в общем бюджете времени одной итерации, особенно если в том же проекте присутствует требовательное к времени мультиплексирование.