Files
zh_bh1750/wiki_ru.md
T
2026-10-18 06:31:28 +03:00

261 lines
14 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Описание компонента zh_bh1750
## Общие сведения
**zh_bh1750** — это компонент ESP-IDF, реализующий драйвер цифрового датчика освещённости BH1750, подключаемого по шине I2C.
Компонент предоставляет простой API для инициализации, чтения освещённости в люксах и диагностики ошибок.
## Основные возможности
1. **Интерфейс I2C** — поддержка стандартного и быстрого режимов с частотой до 400 кГц.
2. **Два I2C-адреса** — `0x23` (ADDR на GND) и `0x5C` (ADDR на VCC).
3. **Однократное измерение H-разрешения** — шаг 1 лк без внешней калибровки.
4. **Автоматический пересчёт в люксы** — из сырых данных по формуле `lux = raw / 1.2`.
5. **Проверка присутствия датчика** — I2C-пробирование при инициализации.
6. **Сбор статистики ошибок** — счётчик ошибок драйвера I2C со сбросом для диагностики.
7. **Несколько датчиков на одном устройстве** — через мультиплексор [zh_pca9548a](https://github.com/aZholtikov/zh_pca9548a).
---
## Внутреннее устройство
### Структура `zh_bh1750_handle_t`
Непрозрачная структура, описывающая экземпляр датчика. Объявлена как `struct _zh_bh1750_handle_t`, доступна пользователю только через указатель.
| Поле | Тип | Описание |
|------|-----|----------|
| `dev_handle` | `i2c_master_dev_handle_t` | Уникальный дескриптор I2C-устройства, полученный при регистрации на шине |
### Структура `zh_bh1750_init_config_t`
Параметры инициализации, передаваемые пользователем.
| Поле | Тип | Описание |
| ------ | ----- | ---------- |
| `i2c_handle` | `i2c_master_bus_handle_t` | Дескриптор уже инициализированной I2C-шины |
| `i2c_address` | `uint8_t` | I2C-адрес датчика (`0x23` или `0x5C`) |
| `i2c_frequency` | `uint32_t` | Частота шины I2C в герцах (до 400000) |
Для подстановки значений по умолчанию (`400000` Гц, `0x23`) служит макрос `ZH_BH1750_INIT_CONFIG_DEFAULT()`.
### Структура `zh_bh1750_stats_t`
Глобальный накопитель диагностической статистики.
| Поле | Тип | Описание |
|------|-----|----------|
| `i2c_driver_error` | `uint32_t` | Счётчик ошибок передачи/приёма драйвера I2C |
### Управление памятью
- Дескриптор датчика выделяется одной операцией `heap_caps_calloc()` с флагом `MALLOC_CAP_8BIT` и обнуляется. Это гарантирует, что при частичной инициализации все поля равны нулю.
- При любой ошибке после выделения памяти дескриптор освобождается тем же `heap_caps_free()`, а пользовательский указатель обнуляется — утечка исключена.
- `zh_bh1750_deinit()` снимает устройство с шины и освобождает дескриптор.
- Статистика `_stats` — статическая глобальная переменная уровня модуля, не требует аллокации и живёт всё время работы программы.
### Вспомогательные данные и макросы
- `_bh1750_read_command` (`uint8_t` = `0x20`) — команда однократного измерения H-разрешения, отправляемая перед каждым чтением.
- `_stats` — глобальный экземпляр `zh_bh1750_stats_t`, накапливающий ошибки I2C-драйвера.
- Макросы `ZH_ERROR_CHECK` / `ZH_ERROR_CHECK_CONT` — инкапсулируют проверку условия, логирование ошибки с именем функции и строкой, выполнение очистки и возврат кода ошибки.
---
## API (интерфейс)
### Инициализация и освобождение
| Функция | Описание |
|---------|----------|
| `zh_bh1750_init()` | Валидирует конфигурацию, выделяет дескриптор, регистрирует датчик на I2C-шине и проверяет его доступность пробированием. Требует `*handle == NULL`. |
| `zh_bh1750_deinit()` | Удаляет устройство с I2C-шины, освобождает дескриптор и устанавливает пользовательский указатель в `NULL`. |
### Чтение данных
| Функция | Описание |
|---------|----------|
| `zh_bh1750_read()` | Отправляет команду однократного измерения, ожидает ~180 мс, считывает 2 байта и возвращает освещённость в люксах. Блокирующий вызов. |
### Получение информации и сброс статистики
| Функция | Описание |
|---------|----------|
| `zh_bh1750_get_stats()` | Возвращает read-only указатель на глобальную структуру статистики ошибок. |
| `zh_bh1750_reset_stats()` | Обнуляет все счётчики в структуре статистики. |
---
## Потокобезопасность
Компонент **не** использует механизмы синхронизации (мьютексы, критические секции, атомарные операции).
1. **Дескриптор датчика** защищён только на уровне инициализации: `zh_bh1750_init()` требует `*handle == NULL` и возвращает `ESP_ERR_INVALID_STATE` при повторном вызове, что предотвращает двойную регистрацию устройства.
2. **Глобальная статистика** `_stats` не имеет защиты — инкремент `i2c_driver_error` из разных задач может привести к гонке данных.
3. **Чтение** `zh_bh1750_read()` не атомарно: одновременные вызовы из разных задач для одного дескриптора недопустимы.
Подробности — в разделе «Ограничения».
---
## Алгоритмы
### Валидация конфигурации (`_zh_bh1750_validate_config`)
Проверяются три условия, при нарушении любого возвращается `ESP_ERR_INVALID_ARG`:
- `i2c_address` равен `0x23` или `0x5C`;
- `0 < i2c_frequency <= 400000`;
- `i2c_handle != NULL`.
### Регистрация устройства и пробирование (`_zh_bh1750_i2c_init`)
1. Формируется `i2c_device_config_t` с 7-битным адресом и заданной частотой.
2. Устройство добавляется на шину через `i2c_master_bus_add_device()`.
3. Выполняется `i2c_master_probe()` на адресе датчика.
4. Если пробирование не удалось, только что добавленное устройство снимается с шины (`i2c_master_bus_rm_device`), и возвращается `ESP_ERR_NOT_FOUND` — «висящего» устройства на шине не остаётся.
### Чтение освещённости (`zh_bh1750_read`)
1. Отправка команды `_bh1750_read_command` (`0x20`).
2. Ожидание `vTaskDelay(180 / portTICK_PERIOD_MS)` — время преобразования для H-разрешения.
3. Приём 2 байт сырых данных.
4. Пересчёт: `lux = (data[0] << 8 | data[1]) / 1.2`.
---
## Примеры использования
### Базовый пример
```c
#include "zh_bh1750.h"
zh_bh1750_handle_t *bh1750_handle = NULL;
void app_main(void)
{
// Инициализируем I2C-шину
i2c_master_bus_config_t i2c_bus_config = {
.clk_source = I2C_CLK_SRC_DEFAULT,
.i2c_port = I2C_NUM_MAX - 1,
.scl_io_num = GPIO_NUM_22,
.sda_io_num = GPIO_NUM_21,
.glitch_ignore_cnt = 7,
.flags.enable_internal_pullup = true,
};
i2c_master_bus_handle_t i2c_bus_handle;
i2c_new_master_bus(&i2c_bus_config, &i2c_bus_handle);
// Инициализируем датчик конфигурацией по умолчанию
zh_bh1750_init_config_t config = ZH_BH1750_INIT_CONFIG_DEFAULT();
config.i2c_handle = i2c_bus_handle;
zh_bh1750_init(&config, &bh1750_handle);
// Читаем освещённость
float lux = 0.0;
zh_bh1750_read(&bh1750_handle, &lux);
printf("Lux %0.2f\n", lux);
// Освобождаем ресурсы
zh_bh1750_deinit(&bh1750_handle);
}
```
### Работа со статистикой ошибок
```c
#include "zh_bh1750.h"
void check_sensor_health(zh_bh1750_handle_t **handle)
{
float lux = 0.0;
if (zh_bh1750_read(handle, &lux) != ESP_OK) {
// Считываем накопленную статистику сбоев I2C
const zh_bh1750_stats_t *stats = zh_bh1750_get_stats();
printf("I2C driver errors: %lu\n", (unsigned long)stats->i2c_driver_error);
}
// Сбрасываем счётчики перед новым циклом измерений
zh_bh1750_reset_stats();
}
```
### Подключение датчика с адресом 0x5C
```c
#include "zh_bh1750.h"
void init_addr_high(i2c_master_bus_handle_t bus, zh_bh1750_handle_t **handle)
{
// Датчик с ADDR на VCC использует адрес 0x5C
zh_bh1750_init_config_t config = {
.i2c_handle = bus,
.i2c_address = 0x5C,
.i2c_frequency = 100000, // Стандартный режим I2C
};
zh_bh1750_init(&config, handle);
// ... работа с датчиком ...
zh_bh1750_deinit(handle);
}
```
---
## Логирование
Компонент использует ESP-IDF логирование с тегом `"zh_bh1750"`.
Уровень по умолчанию позволяет видеть ход инициализации и чтения (`ESP_LOGI`), а также ошибки с указанием файла, строки и имени функции ошибки (`ESP_LOGE`).
```c
// Приглушить informational-сообщения, оставить только ошибки
esp_log_level_set("zh_bh1750", ESP_LOG_ERROR);
```
---
## Ошибки
| Код | Описание |
| ----- | ---------- |
| `ESP_OK` | Операция выполнена успешно |
| `ESP_ERR_INVALID_ARG` | Неверный аргумент: NULL-указатель, недопустимый адрес/частота, неинициализированная шина |
| `ESP_ERR_INVALID_STATE` | Датчик уже инициализирован (`*handle != NULL` при вызове `zh_bh1750_init()`) |
| `ESP_ERR_NO_MEM` | Не удалось выделить память под дескриптор |
| `ESP_ERR_NOT_FOUND` | Датчик не отвечает на пробировании I2C (не подключён или неверный адрес) |
| `ESP_FAIL` | Ошибка регистрации устройства на шине либо сбой передачи/приёма I2C |
---
## Ограничения
1. **Отсутствие потокобезопасности** — компонент не использует мьютексы; одновременные вызовы `zh_bh1750_read()` и работа со статистикой из разных задач приводят к гонке данных.
2. **Глобальная статистика** — `_stats` общая для всех экземпляров датчиков: счётчик `i2c_driver_error` суммирует ошибки всех устройств.
3. **Два допустимых адреса** — аппаратное ограничение BH1750: принимаются только `0x23` и `0x5C`.
4. **Частота I2C не выше 400 кГц** — ограничение Fast Mode datasheet BH1750.
5. **Блокирующее чтение** — `zh_bh1750_read()` задерживает задачу примерно на 180 мс (`vTaskDelay`) ради преобразования H-разрешения.
6. **Только H-разрешение** — жёстко зашита команда `0x20` (однократное измерение); режимы H-Res 2, L-Res и автоматического измерения не поддерживаются.
7. **Предварительная инициализация шины** — `i2c_handle` в конфигурации должен быть получен через `i2c_new_master_bus()` до вызова `zh_bh1750_init()`.
---
## Требования для сборки
- ESP-IDF версии **5.0** и выше.
- Зависимость от компонента I2C-драйвера: `driver` (ESP-IDF 5.x) либо `esp_driver_i2c` (ESP-IDF 6.x) — выбирается автоматически в `CMakeLists.txt`.
- FreeRTOS (входит в состав ESP-IDF) — используется `vTaskDelay`.
---
## Установка
```bash
cd ../your_project/components
git clone https://github.com/aZholtikov/zh_bh1750.git
```
```c
#include "zh_bh1750.h"
```