doc: added wiki
This commit is contained in:
1 parent
7672975ba4
commit
b6e49ca147
1 file changed
+260
+260
@@ -0,0 +1,260 @@
|
||||
# Описание компонента 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"
|
||||
```
|
||||
Reference in new issue
Block a user