12 KiB
Описание компонента zh_avr_touch_pad
Общие сведения
zh_avr_touch_pad — прошивка для AVR-микроконтроллеров ATMega168/328, реализующая беспроводную сенсорную кнопку на базе трансивера nRF24L01+.
Компонент работает в режиме глубокого сна (Power-down), пробуждается по внешнему прерыванию от сенсорного датчика и передаёт на шлюз пакет с идентификатором устройства и уровнем заряда батареи.
Основные возможности
- Сверхнизкое энергопотребление — около 2 мкА в режиме сна.
- Передача уровня заряда батареи — измерение напряжения через внутренний АЦП с опорным напряжением 1,1 В.
- Работа по протоколу nRF24L01+ — передача через SPI, адресная доставка на шлюз.
- Поддержка нескольких МК — ATMega168/168P/168PB/328/328P/328PB.
- Минимальная обвязка — установка в стандартный корпус сенсорного выключателя.
- Пробуждение по внешнему прерыванию INT1 — rising edge на пине PD3.
- Автономная работа — не требует внешних подтягивающих резисторов.
Внутреннее устройство
Структура данных
Компонент не использует динамическое выделение памяти и сложные структуры данных. Все данные передаются как массив 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. Синхронизация между прерыванием и главным циклом реализуется следующим образом:
volatileфлаг — переменнаяsend_requestобъявлена какvolatile, что гарантирует чтение актуального значения из памяти при каждой проверке в главном цикле.- Атомарная запись из ISR — обработка INT1 устанавливает флаг в единицу. Запись одного байта на AVR является атомарной операцией.
- Отключение прерываний при инициализации —
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 (вход сенсорного датчика)
Ограничения
- Только передача (TX-only) — компонент не принимает данные, шлюз не может отправить подтверждение на уровне приложения.
- Отсутствие шифрования — CRC включён, но AES-шифрование не используется. Пакеты могут быть перехвачены.
- Жёстко зашитый адрес шлюза — смена адреса требует перепрошивки.
- Таймаут передачи 100 мс — если шлюз недоступен, пакет теряется без повторной попытки на уровне приложения (аппаратные ретрансмиты настроены через
SETUP_RETR = 0xFF: 15 попыток с максимальным интервалом). - Одно сенсорное событие за цикл — несколько касаний во время передачи будут потеряны (флаг — один бит).
- Точность измерения батареи — зависит от стабильности внутреннего опорного напряжения 1,1 В и может отличаться от реального напряжения на ±3%.
- Нет механизма глубокого сна для периферии — АЦП полностью отключается после измерения (
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"