Files
zh_avr_touch_pad/wiki_ru.md
T
2026-10-21 20:02:24 +03:00

12 KiB
Raw Blame History

Описание компонента zh_avr_touch_pad

Общие сведения

zh_avr_touch_pad — прошивка для AVR-микроконтроллеров ATMega168/328, реализующая беспроводную сенсорную кнопку на базе трансивера nRF24L01+.

Компонент работает в режиме глубокого сна (Power-down), пробуждается по внешнему прерыванию от сенсорного датчика и передаёт на шлюз пакет с идентификатором устройства и уровнем заряда батареи.

Основные возможности

  1. Сверхнизкое энергопотребление — около 2 мкА в режиме сна.
  2. Передача уровня заряда батареи — измерение напряжения через внутренний АЦП с опорным напряжением 1,1 В.
  3. Работа по протоколу nRF24L01+ — передача через SPI, адресная доставка на шлюз.
  4. Поддержка нескольких МК — ATMega168/168P/168PB/328/328P/328PB.
  5. Минимальная обвязка — установка в стандартный корпус сенсорного выключателя.
  6. Пробуждение по внешнему прерыванию INT1 — rising edge на пине PD3.
  7. Автономная работа — не требует внешних подтягивающих резисторов.

Внутреннее устройство

Структура данных

Компонент не использует динамическое выделение памяти и сложные структуры данных. Все данные передаются как массив int16_t фиксированной длины.

Формат передаваемого пакета

Поле Тип Описание
data[0] int16_t Идентификатор устройства (DEVICE_ID = 6)
data[1] int16_t Тип устройства (DEVICE_TYPE = 4)
data[2] int16_t Напряжение батареи × 100 (например, 330 = 3.30 В)
data[3]–data[6] int16_t Зарезервированы (равны 0)

Конфигурационные макросы

Макрос Значение Описание
GATEWAY_CHANNEL 120 Радиоканал шлюза
GATEWAY_ADDRESS 0xDDEEFF 3-байтовый адрес шлюза
DEVICE_ID 6 Уникальный идентификатор устройства
DEVICE_TYPE 4 Код типа устройства (touch pad)

Управление памятью

Компонент не использует динамическую память. Все данные хранятся в стеке и регистрах микроконтроллера. Флаг send_request объявлен как static volatile uint8_t для корректного доступа из ISR и главного цикла.


API (интерфейс)

Все функции являются static и доступны только внутри модуля main.c.

Инициализация

Функция Описание
zh_pad_interrupt_init() Настройка внешнего прерывания INT1 (PD3, rising edge) для пробуждения по касанию
zh_spi_init() Инициализация аппаратного SPI в режиме мастера (Fosc/16)
zh_nrf24_init() Инициализация трансивера nRF24L01+ в режим передачи

Измерение

Функция Описание
zh_get_battery_voltage() Измерение напряжения батареи через внутренний АЦП с опорой 1,1 В

Передача данных

Функция Описание
zh_nrf24_send() Передача буфера через nRF24L01+ с полным циклом TX

Низкоуровневые SPI-операции

Функция Описание
zh_spi_transfer() Обмен одного байта по SPI (полный дуплекс)
zh_nrf24_write_register() Запись одного байта в регистр nRF24L01+
zh_nrf24_write_buff_register() Запись многобайтового буфера в регистр nRF24L01+
zh_nrf24_write_buffer() Запись буфера данных с указанной командой
zh_nrf24_send_command() Отправка однобайтовой команды и чтение статуса

Потокобезопасность

Компонент работает на bare-metal AVR без RTOS. Синхронизация между прерыванием и главным циклом реализуется следующим образом:

  1. volatile флаг — переменная send_request объявлена как volatile, что гарантирует чтение актуального значения из памяти при каждой проверке в главном цикле.
  2. Атомарная запись из ISR — обработка INT1 устанавливает флаг в единицу. Запись одного байта на AVR является атомарной операцией.
  3. Отключение прерываний при инициализации — cli() перед настройкой периферии исключает гонки при старте.

Алгоритмы

Алгоритм измерения напряжения батареи

  • ADC конфигурируется с внутренним опорным напряжением 1,1 В на канале AVcc (MUX[3:1] = 111).
  • Предделитель частоты: 64 (ADPS[2:0] = 111), что даёт ~125 кГц при 8 МГц.
  • Выполняются две последовательные конверсии: первая стабилизирует выборку, вторая даёт результат.
  • Формула расчёта: Vbat = (1024.0 × 1.1) / adc_value.
  • При обрыве датчика (adc == 0) возвращается 0.0.

Алгоритм передачи через nRF24L01+

  • Переход в Power Up (бит PWR_UP в CONFIG).
  • Ожидание 5 мс (время стартования осциллятора).
  • Очистка TX FIFO командой FLUSH_TX.
  • Загрузка полезной нагрузки командой W_TX_PAYLOAD.
  • Импульс CE (установка в 1) для запуска передачи.
  • Ожидание завершения по пину IRQ (PD2) с таймаутом 100 мс.
  • Сброс флагов статуса, очистка FIFO, переход в Power Down.

Алгоритм сна и пробуждения

  • Главный цикл проверяет флаг send_request.
  • Если флаг не установлен — вызывается sleep_cpu() (режим Power-down).
  • Пробуждение происходит по аппаратному прерыванию INT1 (rising edge на PD3).
  • ISR устанавливает send_request = 1, цикл просыпается и выполняет передачу.

Примеры использования

Типовой цикл работы (main)

int main(void)
{
    // Отключаем прерывания на время инициализации
    cli();
    // Настраиваем периферию
    zh_pad_interrupt_init();
    zh_spi_init();
    zh_nrf24_init();
    // Конфигурируем режим сна Power-down
    set_sleep_mode(SLEEP_MODE_PWR_DOWN);
    sleep_enable();
    // Включаем прерывания
    sei();

    for (;;)
    {
        if (send_request == 1)
        {
            // Собираем и отправляем пакет
            send_request = 0;
            int16_t data[] = {DEVICE_ID, DEVICE_TYPE,
                              (int16_t)(zh_get_battery_voltage() * 100.0),
                              0, 0, 0, 0};
            zh_nrf24_send((uint8_t *)data, sizeof(data));
        }
        else
        {
            // Спим до следующего прерывания
            sleep_cpu();
        }
    }
}

Изменение конфигурации под другое устройство

// Измените идентификатор и тип для нового устройства
#define DEVICE_ID 7       // Уникальный ID в сети
#define DEVICE_TYPE 4     // 4 = touch pad
#define GATEWAY_CHANNEL 120
#define GATEWAY_ADDRESS 0xDDEEFF

Подключение по SPI (схема выводов)

// Назначение пинов AVR для nRF24L01+:
// PB2 (SS)   -> CE  (через резистор, или напрямую)
// PB3 (MOSI) -> MOSI
// PB5 (SCK)  -> SCK
// PB1        -> CE (управление передачей)
// PD2        -> IRQ (вход, активный низкий)
// PD3        -> INT1 (вход сенсорного датчика)

Ограничения

  1. Только передача (TX-only) — компонент не принимает данные, шлюз не может отправить подтверждение на уровне приложения.
  2. Отсутствие шифрования — CRC включён, но AES-шифрование не используется. Пакеты могут быть перехвачены.
  3. Жёстко зашитый адрес шлюза — смена адреса требует перепрошивки.
  4. Таймаут передачи 100 мс — если шлюз недоступен, пакет теряется без повторной попытки на уровне приложения (аппаратные ретрансмиты настроены через SETUP_RETR = 0xFF: 15 попыток с максимальным интервалом).
  5. Одно сенсорное событие за цикл — несколько касаний во время передачи будут потеряны (флаг — один бит).
  6. Точность измерения батареи — зависит от стабильности внутреннего опорного напряжения 1,1 В и может отличаться от реального напряжения на ±3%.
  7. Нет механизма глубокого сна для периферии — АЦП полностью отключается после измерения (ADEN = 0), но SPI остаётся включённым в режиме сна.

Требования для сборки

  • PlatformIO с плагином platform-atmelavr
  • AVR-GCC (входит в состав PlatformIO)
  • Программатор USBasp (или совместимый)
  • Фьюзы: LFUSE=0xE2, HFUSE=0xDF, EFUSE=0x07 (8 МГц, без делителя)

Установка

Сборка и прошивка через PlatformIO

pio run -e ATmega328P -t upload

Подключение в проекте

Компонент является самодостаточной прошивкой — не подключается как библиотека. Для интеграции в другой проект скопируйте src/main.c и адаптируйте макросы конфигурации.

// Зависимости — только стандартные заголовки AVR-libc:
#include "avr/io.h"
#include "avr/sleep.h"
#include "avr/fuse.h"
#include "avr/interrupt.h"
#include "util/delay.h"