feat!: added support some dimmers on one device

This commit is contained in:
aZholtikov committed 2026-08-29 21:04:17 +03:00
1 parent 0e9f663a8d
commit dbe7fce7ce
7 files changed
+466 -265

No files matched your search

+92 -48
View File
@@ -18,7 +18,7 @@
`zh_ac_dimmer` - это легковесный компонент ESP-IDF для управления освещением переменного тока. Он предоставляет простой API для управления мощностью нагрузки переменного тока с использованием детекции перехода через ноль и управления TRIAC. Компонент разработан специально для микроконтроллеров ESP32 и использует драйверы ESP-IDF v5.0+ (GPTimer, GPIO).
Компонент поддерживает частоту переменного тока 400Гц и использует аппаратные таймеры для точного управления временем.
Компонент поддерживает частоту переменного тока 400 Гц и использует аппаратные таймеры для точного управления временем.
---
@@ -26,36 +26,37 @@
1. **Управление мощностью переменного тока**: Управление мощностью нагрузки от 0% до 100%
2. **Детекция перехода через ноль**: Использует прерывание GPIO для точного тайминга
3. **Управление TRIAC**: Управление затвором TRIAC с точным таймингом
4. **Аппаратный таймер**: Использует GPTimer для точного управления затуханием
5. **Обработка ошибок**: Комплексная проверка ошибок и валидация
6. **Потокобезопасность**: Использует драйверы ESP-IDF (потокобезопасно)
7. **Минимальный объем памяти**: Низкие накладные расходы на память
8. **Простой API**: Легкое в использовании интерфейс
3. **Управление TRIAC**: Управление затвором TRIAC с точным таймингом через GPTimer
4. **Аппаратный таймер**: Использует GPTimer с разрешением 1 МГц (1 мкс)
5. **IRAM-safe ISR и callback**: Прерывания и колбэки размещаются в IRAM для надёжной работы
6. **Обработка ошибок**: Комплексная проверка ошибок и валидация конфигурации
7. **Потокобезопасность**: Использует драйверы ESP-IDF (потокобезопасно)
8. **Минимальный объем памяти**: Низкие накладные расходы на память
9. **Простой API**: Легковесный интерфейс с поддержкой start/stop/set/get
---
## Установка
1. Перейдите в каталог компонентов вашего проекта:
Перейдите в каталог компонентов вашего проекта:
```bash
cd ../ваш_проект/components
```
2. Клонируйте репозиторий:
Клонируйте репозиторий:
```bash
git clone https://github.com/aZholtikov/zh_ac_dimmer.git
```
3. В вашем приложении подключите заголовочный файл:
В вашем приложении подключите заголовочный файл:
```c
#include "zh_ac_dimmer.h"
```
4. Компонент будет автоматически собран вместе с вашим проектом.
Компонент будет автоматически собран вместе с вашим проектом.
### Необходимая конфигурация
@@ -89,28 +90,43 @@ typedef struct
---
### Структура zh_ac_dimmer_handle_t
```c
typedef struct _zh_ac_dimmer_handle_t zh_ac_dimmer_handle_t;
```
Непрозрачный дескриптор экземпляра устройства.
---
### zh_ac_dimmer_init()
Инициализирует управление освещением переменного тока.
Выделяет память для handle, валидирует конфигурацию, инициализирует GPIO пины (TRIAC как выход, переход через ноль как вход с прерыванием по положительному фронту), устанавливает ISR-сервис и создаёт экземпляр gptimer.
**Параметры:**
- `config` - Указатель на структуру конфигурации инициализации освещения переменного тока
- `config` - Указатель на структуру конфигурации инициализации. Не должен быть NULL
- `handle` - Указатель на указатель для получения созданного handle. Должен быть NULL
**Возвращает:**
- `ESP_OK` - Успех
- `ESP_ERR_INVALID_ARG` - Неверный аргумент (NULL config или неверный GPIO)
- `ESP_ERR_INVALID_ARG` - Неверный аргумент (NULL handle или неверный GPIO)
- `ESP_ERR_INVALID_STATE` - Освещение переменного тока уже инициализировано
- `ESP_FAIL` - Ошибка инициализации (GPIO или таймер)
- `ESP_ERR_NO_MEM` - Не удалось выделить память
- `ESP_FAIL` - Ошибка инициализации (GPIO, ISR-сервис или таймер)
**Пример:**
```c
zh_ac_dimmer_handle_t *dimmer = NULL;
zh_ac_dimmer_init_config_t config = ZH_AC_DIMMER_INIT_CONFIG_DEFAULT();
config.zero_cross_gpio = GPIO_NUM_16;
config.triac_gpio = GPIO_NUM_17;
zh_ac_dimmer_init(&config);
esp_err_t err = zh_ac_dimmer_init(&config, &dimmer);
```
---
@@ -119,11 +135,19 @@ zh_ac_dimmer_init(&config);
Деинициализирует управление освещением переменного тока и освобождает ресурсы.
Останавливает и удаляет gptimer, удаляет ISR-обработчик GPIO, сбрасывает пины GPIO в режим ввода, освобождает handle и устанавливает выходной указатель в NULL.
**Параметры:**
- `handle` - Указатель на handle. Не должен быть NULL
**Возвращает:**
- `ESP_OK` - Успех
- `ESP_ERR_INVALID_STATE` - Освещение переменного тока не инициализировано
- `ESP_FAIL` - Ошибка деинициализации (GPIO или деинициализация таймера)
- `ESP_ERR_INVALID_ARG` - handle или *handle равен NULL
- `ESP_FAIL` - Ошибка остановки таймера, отключения или удаления, или сброса GPIO
**Важно:** После вызова этой функции handle становится недействительным. Для повторной инициализации вызовите `zh_ac_dimmer_init()` заново.
---
@@ -131,10 +155,16 @@ zh_ac_dimmer_init(&config);
Запускает работу освещения переменного тока.
Включает диммер, чтобы события перехода через ноль запускали срабатывание TRIAC в соответствии с текущим значением затухания.
**Параметры:**
- `handle` - Указатель на handle. Не должен быть NULL
**Возвращает:**
- `ESP_OK` - Успех
- `ESP_ERR_INVALID_STATE` - Освещение переменного тока не инициализировано
- `ESP_ERR_INVALID_ARG` - handle или *handle равен NULL
---
@@ -142,10 +172,16 @@ zh_ac_dimmer_init(&config);
Останавливает работу освещения переменного тока.
Отключает срабатывание TRIAC на событиях перехода через ноль. Диммер может быть перезапущен с помощью `zh_ac_dimmer_start()`.
**Параметры:**
- `handle` - Указатель на handle. Не должен быть NULL
**Возвращает:**
- `ESP_OK` - Успех
- `ESP_ERR_INVALID_STATE` - Освещение переменного тока не инициализировано
- `ESP_ERR_INVALID_ARG` - handle или *handle равен NULL
---
@@ -153,15 +189,17 @@ zh_ac_dimmer_init(&config);
Устанавливает значение затухания освещения переменного тока.
Устанавливает процент затухания, который будет применён на следующем событии перехода через ноль.
**Параметры:**
- `value` - Значение затухания (0 до 100, где 0 = выкл, 100 = полная мощность)
- `handle` - Указатель на handle. Не должен быть NULL
- `value` - Уровень затухания от 0 (выключено) до 100 (полная мощность)
**Возвращает:**
- `ESP_OK` - Успех
- `ESP_ERR_INVALID_STATE` - Освещение переменного тока не инициализировано
- `ESP_ERR_INVALID_ARG` - Неверное значение затухания
- `ESP_ERR_INVALID_ARG` - handle, *handle или value недействительны
---
@@ -171,13 +209,13 @@ zh_ac_dimmer_init(&config);
**Параметры:**
- `value` - Указатель для хранения значения затухания
- `handle` - Указатель на handle. Не должен быть NULL
- `value` - Указатель для получения текущего уровня затухания (0–100). Не должен быть NULL
**Возвращает:**
- `ESP_OK` - Успех
- `ESP_ERR_INVALID_STATE` - Освещение переменного тока не инициализировано
- `ESP_ERR_INVALID_ARG` - Неверный аргумент (NULL value)
- `ESP_ERR_INVALID_ARG` - handle, *handle или value равен NULL
---
@@ -191,28 +229,29 @@ zh_ac_dimmer_init(&config);
void app_main(void)
{
esp_log_level_set("zh_ac_dimmer", ESP_LOG_ERROR);
zh_ac_dimmer_handle_t *dimmer = NULL;
zh_ac_dimmer_init_config_t config = ZH_AC_DIMMER_INIT_CONFIG_DEFAULT();
config.zero_cross_gpio = GPIO_NUM_16;
config.triac_gpio = GPIO_NUM_17;
zh_ac_dimmer_init(&config);
zh_ac_dimmer_start();
zh_ac_dimmer_init(&config, &dimmer);
zh_ac_dimmer_start(&dimmer);
uint8_t value = 0;
for (uint8_t i = 0; i <= 100; ++i)
{
zh_ac_dimmer_set(i);
zh_ac_dimmer_get(&value);
zh_ac_dimmer_set(&dimmer, i);
zh_ac_dimmer_get(&dimmer, &value);
printf("Значение затухания: %d.\n", value);
vTaskDelay(100 / portTICK_PERIOD_MS);
}
for (uint8_t i = 100; i > 0; --i)
{
zh_ac_dimmer_set(i);
zh_ac_dimmer_get(&value);
zh_ac_dimmer_set(&dimmer, i);
zh_ac_dimmer_get(&dimmer, &value);
printf("Значение затухания: %d.\n", value);
vTaskDelay(100 / portTICK_PERIOD_MS);
}
zh_ac_dimmer_stop();
zh_ac_dimmer_deinit();
zh_ac_dimmer_stop(&dimmer);
zh_ac_dimmer_deinit(&dimmer);
}
```
@@ -228,15 +267,17 @@ void app_main(void)
#define BUTTON_GPIO GPIO_NUM_0
static uint8_t dimmer_value = 50;
static zh_ac_dimmer_handle_t *dimmer = NULL;
static void IRAM_ATTR button_isr_handler(void *arg)
{
(void)arg;
dimmer_value = (dimmer_value + 10) % 110;
if (dimmer_value > 100)
{
dimmer_value = 0;
}
zh_ac_dimmer_set(dimmer_value);
zh_ac_dimmer_set(&dimmer, dimmer_value);
printf("Значение затухания: %d\n", dimmer_value);
}
@@ -247,7 +288,7 @@ void app_main(void)
zh_ac_dimmer_init_config_t config = ZH_AC_DIMMER_INIT_CONFIG_DEFAULT();
config.zero_cross_gpio = ZERO_CROSS_GPIO;
config.triac_gpio = TRIAC_GPIO;
zh_ac_dimmer_init(&config);
zh_ac_dimmer_init(&config, &dimmer);
// Инициализация кнопки
gpio_config_t button_config = {
.intr_type = GPIO_INTR_POSEDGE,
@@ -260,13 +301,13 @@ void app_main(void)
gpio_install_isr_service(ESP_INTR_FLAG_DEFAULT);
gpio_isr_handler_add(BUTTON_GPIO, button_isr_handler, NULL);
// Запуск затухания
zh_ac_dimmer_start();
zh_ac_dimmer_start(&dimmer);
printf("Затухание инициализировано. Кнопка на GPIO %d меняет значение затухания.\n", BUTTON_GPIO);
for (;;)
{
vTaskDelay(1000 / portTICK_PERIOD_MS);
uint8_t current_value;
zh_ac_dimmer_get(&current_value);
zh_ac_dimmer_get(&dimmer, &current_value);
printf("Текущее значение затухания: %d\n", current_value);
}
}
@@ -278,12 +319,13 @@ void app_main(void)
| Параметр | Значение |
|----------|----------|
| **Диапазон затухания** | 0 - 100% |
| **Частота переменного тока** | 400 Гц (поддерживается только) |
| **Диапазон затухания** | 0–100% (0 = выкл, 100 = полная мощность) |
| **Частота переменного тока** | 400 Гц (период перехода через ноль: 1250 мкс) |
| **Детекция перехода через ноль** | Прерывание GPIO (положительный фронт) |
| **Управление TRIAC** | Выход GPIO |
| **Разрешение таймера** | 1 МГц (1 мкс) |
| **Время измерения** | ~1250 мкс на цикл |
| **Время измерения** | ~1250 мкс на полупериод |
| **Базовая задержка TRIAC** | 330 мкс (измерено логическим анализатором) |
| **Версия ESP-IDF** | >= 5.0 |
| **Платформа** | Семейство ESP32 |
| **Язык** | C (C99) |
@@ -296,8 +338,9 @@ void app_main(void)
|------------|----------|
| `ESP_OK` | Операция выполнена успешно |
| `ESP_ERR_INVALID_ARG` | Неверный аргумент (NULL указатель, неверный GPIO или неверное значение затухания) |
| `ESP_ERR_INVALID_STATE` | Освещение переменного тока не инициализировано |
| `ESP_FAIL` | Общая ошибка (GPIO или инициализация/деинициализация таймера) |
| `ESP_ERR_INVALID_STATE` | Освещение переменного тока уже инициализировано (только для `zh_ac_dimmer_init`) |
| `ESP_ERR_NO_MEM` | Не удалось выделить память (только для `zh_ac_dimmer_init`) |
| `ESP_FAIL` | Общая ошибка (GPIO, ISR-сервис, инициализация/деинициализация таймера) |
---
@@ -339,12 +382,13 @@ void app_main(void)
## Дополнительные заметки
- **Частота переменного тока**: В настоящее время поддерживается только частота 400Гц
- **Тайминг перехода через ноль**: 1250 мкс период (400Гц) с компенсацией 330 мкс для задержки таймера
- **Прерывание GPIO**: Детекция перехода через ноль использует прерывание положительного фронта
- **Требования IRAM**: Для правильной работы включите `GPIO_CTRL_FUNC_IN_IRAM`, `CONFIG_GPTIMER_ISR_HANDLER_IN_IRAM`, `CONFIG_GPTIMER_CTRL_FUNC_IN_IRAM` и `CONFIG_GPTIMER_ISR_CACHE_SAFE` в menuconfig
- **Потокобезопасность**: Компонент использует драйверы ESP-IDF, которые являются потокобезопасными
- **Частота переменного тока**: В настоящее время поддерживается только частота 400 Гц (авиационная частота). Период между переходами через ноль составляет 1250 мкс.
- **Тайминг перехода через ноль**: 1250 мкс период (400 Гц) с компенсацией 330 мкс для задержки таймера. Формула расчёта: `alarm_count = (((1250 - 330) / 100) * (100 - dimmer_value)) + 330`.
- **Прерывание GPIO**: Детекция перехода через ноль использует прерывание положительного фронта с защитой от дребезга (игнорируются прерывания, пришедшие ранее 90% от периода).
- **Требования IRAM**: Для правильной работы включите `GPIO_CTRL_FUNC_IN_IRAM`, `CONFIG_GPTIMER_ISR_HANDLER_IN_IRAM`, `CONFIG_GPTIMER_CTRL_FUNC_IN_IRAM` и `CONFIG_GPTIMER_ISR_CACHE_SAFE` в menuconfig.
- **Потокобезопасность**: Компонент использует драйверы ESP-IDF, которые являются потокобезопасными.
- **Безопасность**: Данный модуль взаимодействует с сетевым напряжением. Неправильное подключение или недостаточная изоляция могут привести к поражению электрическим током или повреждению оборудования. Убедитесь в наличии правильной оптоизоляции и соблюдении требований безопасности перед развёртыванием.
---
*Сгенерировано для zh_ac_dimmer v1.0.0*
*Сгенерировано для zh_ac_dimmer v3.0.0*