Embedded HandbookПриложения
Все разделы › XI. Датчики: подключение, схемы, драйверы
STM32F103, STM32F407 · уровень средний · 9 мин чтения
Открыть в интерактивном справочнике

103. Свет и газ: фоторезистор, BH1750, MQ

Три датчика с разной судьбой. Фоторезистор — просто сопротивление, которое падает на свету: делитель, вход АЦП и формула. BH1750 — готовый цифровой люксметр на I²C, но без карты регистров: ему шлют команды, а он отвечает двумя байтами. Газовый датчик MQ — чувствительный слой, который работает только горячим: внутри нагреватель на 5 В, и от него зависит всё остальное — питание, прогрев и показания.

Внутренний АЦП — раздел 14, шина I²C — раздел 17, подключение модулей и уровни — раздел 95.

Как это называется в документации

Оригинал Перевод
photoresistor, LDR (light-dependent resistor) фоторезистор
illuminance, lux (lx) освещённость, люкс
gamma (γ) наклон характеристики фоторезистора в логарифмическом масштабе
ambient light sensor датчик внешней освещённости
measurement time register (MTreg) время интегрирования BH1750
continuous / one-time measurement непрерывное / однократное измерение
heater нагреватель
sensing resistance, Rs сопротивление чувствительного слоя
load resistance, RL нагрузочный резистор
preheat, burn-in прогрев
cross-sensitivity чувствительность к посторонним газам
hysteresis гистерезис

103.1 Фоторезистор в делителе

Свет и газ: фоторезистор в делителе, BH1750 на I²C и модуль MQ через делитель

Сопротивление фоторезистора падает с освещённостью по степенному закону: R = R10 · (E / 10 лк)^(−γ), где R10 — сопротивление при 10 лк, а γ — наклон. Числа для примера — R10 = 15 кОм, γ = 0,7; у каждой серии свои, и разброс между экземплярами большой. Фоторезистор — к +3,3 В, резистор 10 кОм — к земле, середина — на вход АЦП: чем светлее, тем больше код.

Освещённость Примерно так Сопротивление Код АЦП
1 лк глубокие сумерки 75 кОм 481
10 лк сумерки 15 кОм 1638
100 лк очень пасмурный день 3,0 кОм 3152
1000 лк пасмурный день 597 Ом 3864
10 000 лк дневной свет в тени 119 Ом 4047

Делитель сжимает яркий конец шкалы. От 1 до 10 лк код проходит 1157 шагов, от 1000 до 10 000 лк — всего 183. Чувствительнее всего делитель там, где фоторезистор равен постоянному резистору: для 10 кОм это около 18 лк — комната с тусклым светом. Для яркого света резистор берут меньше: с 270 Ом на участок от 1000 до 10 000 лк приходится 1566 кодов, зато от 1 до 10 лк остаётся 57.

Код АЦП делителя с фоторезистором по освещённости от 0,1 до 100 000 лк для резисторов 10 кОм и 270 Ом: кривая круче всего там, где фоторезистор равен резистору, — около 18 лк и около 3,1 тыс. лк


103.2 Код — в люксы

Перевод обратный: сопротивление из кода, освещённость из сопротивления.

float ldr_lux(uint16_t code)
{
    if (code == 0)
        return 0.0f;
    if (code >= 4095)
        return -1.0f;
    float r = LDR_RF * (4095 - code) / code;
    return 10.0f * powf(r / LDR_R10, -1.0f / LDR_GAMMA);
}

Код для 100 лк переводится обратно в 100,1 лк, для 1000 лк — в 998,4 лк: у 1000 лк один код — это 0,66 % показания. Крайние коды — не освещённость, а неисправность. Код 0 функция отдаёт как 0 лк, но при этом делителе это почти всегда обрыв фоторезистора: даже 0,01 лк даёт код около 21. Код 4095 — замыкание, и функция отвечает −1.

Фоторезистор медленный: на свет он откликается за десятки миллисекунд, на темноту — дольше. Да и R10 с γ известны приблизительно. Поэтому он хорош для решения «темно — светло» с гистерезисом, а люксы честнее мерить BH1750.


103.3 BH1750: команды вместо регистров

У BH1750 нет карты регистров: каждый записанный байт — команда, а чтение двух байтов отдаёт последний результат, старший байт первым. Адрес задаёт вывод ADDR: к земле — 0x23, к питанию — 0x5C. Модуль питают от 3,3 В; подтяжки SDA и SCL на нём обычно уже есть (раздел 95).

Команда Код Что делает
включить 0x01 ждать команды измерения
сброс 0x07 обнулить результат; только во включённом состоянии
непрерывно, высокое разрешение 0x10 мерить без остановки, около 120 мс на измерение
однократно, высокое разрешение 0x20 одно измерение, затем сон
int bh_start(uint32_t mt)
{
    const uint8_t cmd[4] = { BH_POWER_ON, BH_MT_HI(mt), BH_MT_LO(mt), BH_CONT_H };
    for (unsigned i = 0; i < 4; i++)
        if (!i2c_send(BH_ADDR, &cmd[i], 1))
            return 0;
    return 1;
}

int bh_read(uint32_t mt, uint32_t *lux_x10)
{
    uint8_t b[2];
    if (!i2c_recv(BH_ADDR, b, 2))
        return 0;
    *lux_x10 = bh_lux_x10((uint16_t)(b[0] << 8 | b[1]), mt);  /* старший байт первым */
    return 1;
}

Каждая команда — отдельная запись в один байт. Модель на шине получила ровно 0x01, 0x42, 0x65, 0x10, а код 1000 драйвер перевёл в 833,3 лк: при времени интегрирования 69 освещённость — это код, делённый на 1,2. Первое измерение готово через 120 мс, в худшем случае через 180 мс; прочитанное раньше — ноль или старое значение. Лампы от сети 50 Гц мерцают с частотой 100 Гц, и за 120 мс проходит ровно 12 периодов — мерцание усредняется.


103.4 Время интегрирования

MTreg — время интегрирования: от 31 до 254, по умолчанию 69. Его задают двумя командами: старшие три бита — в 0x40, младшие пять — в 0x60; для 69 это 0x42 и 0x65. Люксов на один код — 69 / (1,2 · MTreg):

#define BH_MT_HI(mt) ((uint8_t)(0x40u | ((mt) >> 5)))
#define BH_MT_LO(mt) ((uint8_t)(0x60u | ((mt) & 0x1Fu)))

uint32_t bh_lux_x10(uint16_t raw, uint32_t mt)
{
    return ((uint32_t)raw * 6900u + 6u * mt) / (12u * mt);
}
MTreg Люксов на код Предел шкалы Время измерения
31 1,85 121 556,9 лк около 54 мс
69 0,83 54 612,5 лк около 120 мс
254 0,23 14 835,7 лк около 442 мс

Прямое солнце бывает ярче 54 612 лк, и при MTreg 69 код упирается в 65535: на улице ставят 31. В темноте наоборот: 254 даёт 0,23 лк на код ценой почти полсекунды на измерение. Считают в десятых долях люкса целыми числами, с округлением: FPU не нужен, а у F103 его и нет.


103.5 MQ: сначала нагреватель

Чувствительный слой датчиков MQ — оксид олова, и газ меняет его сопротивление, только пока слой горячий. Нагреватель у MQ-2 и MQ-135 — 33 Ом при 5 В: это 152 мА и 0,76 Вт, больше, чем всё остальное на плате. Отсюда правила:

MQ-7 и MQ-9 греют ещё и циклами — высоким и низким напряжением попеременно, как велит их документация: там без ключа на нагревателе не обойтись.


103.6 Сопротивление слоя и делитель на 3,3 В

Слой Rs и нагрузочный резистор RL модуля образуют делитель от 5 В: чем больше газа, тем меньше Rs и тем выше напряжение на выходе AO. Отсюда Rs = RL · (Vc − Vout) / Vout. RL у каждого модуля свой, его номинал читают по маркировке на плате; в примере 10 кОм:

Выход модуля Rs
0,5 В 90 кОм
1,0 В 40 кОм
2,5 В 10 кОм
4,0 В 2,5 кОм

Выход доходит до 5 В, а вход АЦП STM32 — до 3,3 В, и в аналоговом режиме вывод 5 В не терпит. Между ними делитель 10 кОм и 20 кОм: на вход приходят 2/3 напряжения, мерить можно до 4,95 В, и код 3309 — это 4000 мВ на выходе модуля.

Но делитель сам нагружает выход: его 30 кОм встают параллельно RL, и в формулу идёт 7,5 кОм, а не 10. Код 3309 — это Rs = 1875 Ом, а не 2500: с RL = 10 кОм сопротивление вышло бы на 33,3 % больше настоящего.

#define MQ_RL      10000u               /* нагрузочный резистор модуля — по маркировке на плате */
#define MQ_DIV     30000u               /* делитель к АЦП нагружает выход */
#define MQ_RL_EFF  (MQ_RL * MQ_DIV / (MQ_RL + MQ_DIV))

uint32_t mq_rs(uint32_t vout_mv, uint32_t vc_mv, uint32_t rl_ohm)
{
    if (vout_mv == 0)
        return UINT32_MAX;              /* слой оборван или нагреватель холодный */
    if (vout_mv >= vc_mv)
        return 0;                       /* выход у питания: замыкание */
    return (uint32_t)((uint64_t)rl_ohm * (vc_mv - vout_mv) / vout_mv);
}

Делитель из 10 и 20 кОм — это 6,7 кОм на входе АЦП: время выборки нужно побольше (раздел 14). Цифровой выход DO модуля — компаратор с подстроечным резистором, обычно с подтяжкой к питанию модуля: при 5 В его подключают к выводу, терпимому к 5 В, и не в аналоговом режиме.


103.7 Чистый воздух и тревога

Концентрацию в ppm дешёвый MQ не даст: слой реагирует сразу на несколько газов, на влажность и на температуру, а сопротивление в чистом воздухе у каждого экземпляра своё. Надёжнее отношение: Rs к сопротивлению того же датчика в чистом воздухе после прогрева. В отношении RL сокращается: 2,5 В против 1,0 В — это 25 % и с RL 10 кОм, и с 7,5 кОм. Графики в документации обычно построены от R0 — сопротивления при эталонной концентрации газа, а не в чистом воздухе: прежде чем снимать с них концентрацию, проверьте, от чего они отсчитаны.

Тревогу включают по порогу, а выключают по другому, повыше:

int mq_alarm(int alarm, uint32_t rs, uint32_t r_air, uint32_t on_pct, uint32_t off_pct)
{
    uint32_t pct = (uint32_t)((uint64_t)rs * 100u / r_air);
    if (!alarm && pct < on_pct)
        return 1;
    if (alarm && pct > off_pct)
        return 0;
    return alarm;
}

Модель: в чистом воздухе 40 кОм, газ нарастает и спадает, а отсчёты дрожат у порога — 100, 65, 52, 48, 51, 49, 57, 53, 61 и 75 % от чистого воздуха. Тревога с одним порогом 50 % переключается 4 раза. С гистерезисом — включение ниже 50 %, отбой выше 60 % — 2 раза: включилась на 48 %, погасла на 61 %.

Тревога MQ: один порог дребезжит, два порога — нет


103.8 Грабли

Фоторезистор показывает 0 или 4095. Это не свет, а обрыв или замыкание в делителе: у краёв шкалы люксов нет.

На солнце BH1750 застыл на 54 612 лк. Код упёрся в 65535 при MTreg 69. Уменьшить MTreg до 31.

Первое чтение BH1750 — ноль. Прочитали раньше, чем закончилось первое измерение. После команды ждать 180 мс.

BH1750 не отвечает по адресу 0x23. ADDR подтянут к питанию — адрес 0x5C.

Показания MQ плывут первые минуты. Слой не прогрелся. Отсчётам после включения не доверять, новый датчик — прогреть сутки.

Rs у MQ на треть больше, чем должно быть. Забыли, что делитель к АЦП стоит параллельно RL.

Код MQ упёрся в 4095, а соседние каналы АЦП врут. Выход модуля подан на вход без делителя: больше 3,3 В на аналоговом входе — ток через защитные диоды, и он сбивает соседние каналы.

Аккумулятор сел за полдня. Нагреватель MQ — 152 мА без перерыва.


103.9 Итоги

Дальше: раздел 103а «Пульсоксиметр MAX30102: фотоплетизмограмма по I2C, FIFO, выделение пульса и оценка SpO₂ — и почему это не медицинский прибор» — пульс и отношение R по свету через палец: MAX30102 на I2C, FIFO и обработка на F103; учебный пример, не медицинский прибор.

Открыть в интерактивном справочнике