Files
2026-10-31 08:06:35 +03:00

34 KiB
Raw Permalink Blame History

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

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

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

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

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

  1. Сверхнизкое энергопотребление — около 5 мкА в режиме сна.
  2. Измерение климата — температура, влажность и атмосферное давление датчиком BME280 по шине I2C.
  3. Автоматическое сопряжение (pairing) — запрос идентификатора устройства у шлюза по воздуху, хранение ID в EEPROM.
  4. Передача уровня заряда батареи — измерение напряжения через внутренний АЦП с опорным напряжением 1,1 В.
  5. Работа по протоколу nRF24L01+ — передача и приём через SPI, адресная доставка на шлюз, динамическая длина пакета.
  6. Поддержка нескольких МК — ATMega168/168P/168PB/328/328P/328PB.
  7. Пробуждение по watchdog-таймеру — WDT с интервалом ~8 секунд, цикл работы каждые WDT_WAKE_COUNT (38) прерываний ≈ 5 минут.
  8. Автономная работа — не требует внешних подтягивающих резисторов (используются внутренние pull-up).

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

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

Компонент не использует динамическое выделение памяти. Сырые показания хранятся в статических переменных, калибровочные коэффициенты BME280 — в массиве _bme280_calib[33]. Перед передачей данные сериализуются функцией zh_nrf24_sensor_build_payload() из внешней библиотеки zh_nrf24_config в буфер uint8_t[ZH_NRF24_MAX_PAYLOAD_SIZE] (32 байта) в формате little-endian.

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

Данные формируются в глобальной переменной _transmitted_data типа zh_nrf24_sensor_transmitted_data_t из библиотеки zh_nrf24_config, затем сериализуются в полезную нагрузку. Для типа ZH_NRF24_SENSOR_BME280 полный размер пакета — 12 байт (заголовок id + type + battery и три поля измерений, каждое int16_t в little-endian).

Поле Тип Описание
id int16_t Идентификатор устройства, назначенный шлюзом при сопряжении
type int16_t Тип устройства (ZH_NRF24_SENSOR_BME280)
battery int16_t Напряжение батареи × 100 (например, 330 = 3.30 В)
value_1 int16_t Влажность (% × 10, например 453 = 45.3 %)
value_2 int16_t Температура (°C × 10, например 253 = 25.3 °C)
value_3 int16_t Давление (мм рт. ст. × 10)

Тип устройства задаётся значением перечисления ZH_NRF24_SENSOR_BME280 из библиотеки zh_nrf24_config.

Формат пакета сопряжения

Пакет сопряжения — структура zh_nrf24_sensor_pairing_data_t (5 байт, ZH_NRF24_PAIRING_PACKET_SIZE):

Поле Тип Описание
type uint8_t Тип датчика (код ZH_NRF24_SENSOR_BME280)
magic uint8_t Маркер направления: ZH_NRF24_PAIRING_REQ_MAGIC (0xA5) в запросе, ZH_NRF24_PAIRING_ACK_MAGIC (0x5A) в ответе
token_hi uint8_t Старший байт псевдослучайного токена
token_lo uint8_t Младший байт псевдослучайного токена
id uint8_t Идентификатор, назначенный шлюзом (в ответе)

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

Макрос Значение Описание
GATEWAY_CHANNEL 120 Радиоканал шлюза
GATEWAY_ADDRESS 0xDDEEFF 3-байтовый адрес шлюза
EEPROM_DEVICE_ID_ADDR (uint8_t *)0x00 Адрес ячейки EEPROM для хранения ID устройства
DEVICE_ID_UNASSIGNED 0xFF Признак отсутствующего (несопряжённого) идентификатора
PAIRING_TIMEOUT_ATTEMPTS 7 Максимальное число попыток сопряжения
WDT_WAKE_COUNT 38 Количество прерываний WDT до цикла измерения (≈ 5 минут)
TWI_TWBR 32 Значение регистра TWBR для задания скорости аппаратного TWI
BME280_ADDR 0x76 7-битный адрес датчика BME280 на шине I2C

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

Компонент не использует динамическую память. Все данные хранятся в статической области и регистрах микроконтроллера. Глобальная переменная _transmitted_data заполняется при старте (тип устройства, затем идентификатор из EEPROM или из сопряжения). В цикле обновляются поля battery, value_1 (влажность), value_2 (температура), value_3 (давление). Идентификатор устройства сохраняется в EEPROM адресом 0x00 (eeprom_update_byte).


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

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

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

Функция Описание
_zh_wdt_start() Запуск watchdog-таймера в режиме прерывания с указанным таймаутом (биты WDP3:0)
_zh_wdt_stop() Остановка watchdog-таймера
_zh_i2c_init() Инициализация аппаратного TWI (I2C) на пинах PC4 (SDA), PC5 (SCL), TWBR = 32
_zh_bme280_init() Инициализация датчика BME280: проверка CHIP_ID, сброс, чтение калибровки, настройка режима
_zh_spi_init() Инициализация аппаратного SPI в режиме мастера (Fosc/16)
_zh_nrf24_init() Инициализация трансивера nRF24L01+: адреса TX/RX, канал, ретрансмиты, динамические пакеты, CRC
_zh_nrf24_interrupt_init() Настройка внешнего прерывания INT0 (PD2, падающий фронт) для сигнала IRQ трансивера

Идентификатор устройства и сопряжение

Функция Описание
_zh_load_device_id() Чтение ID устройства из EEPROM (возвращает DEVICE_ID_UNASSIGNED при 0x00/0xFF)
_zh_save_device_id() Сохранение ID устройства в EEPROM через eeprom_update_byte
_zh_get_random_token() Генерация 16-битного псевдослучайного токена из MCUSR и шума АЦП (никогда не 0)
_zh_do_pairing() Неблокирующая процедура сопряжения: запрос → ожидание ACK в RX-режиме → backoff; возвращает назначенный ID
_zh_enter_final_sleep() Переход в постоянный сон Power-down до сброса (отключение прерываний, WDT, радио, тактов периферии)

Измерение

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

Чтение данных BME280

Функция Описание
_zh_bme280_read() Перевод BME280 в forced mode, чтение 8 сырых байт и распаковка ADC значений температуры, давления, влажности
_zh_bme280_compensate_temperature() Компенсация сырой температуры по калибровочным коэффициентам (результат в °C)
_zh_bme280_compensate_pressure() Компенсация сырого давления по калибровочным коэффициентам (результат в Па)
_zh_bme280_compensate_humidity() Компенсация сырой влажности по калибровочным коэффициентам (результат в %)

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

Функция Описание
_zh_nrf24_send() Передача буфера: Power Up, FLUSH_TX, W_TX_PAYLOAD, импульс CE, ожидание IRQ с таймаутом ~100 мс, сброс статуса
_zh_nrf24_send_no_wait() Запуск передачи без ожидания завершения (импульс CE 15 мкс), завершение сигнализируется IRQ
_zh_nrf24_enter_rx() Переход в режим приёма на pipe 0 (PRIM_RX, очистка FIFO, CE)
_zh_nrf24_enter_power_down() Перевод трансивера в режим Power Down

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

Функция Описание
_zh_spi_transfer() Обмен одного байта по SPI (полный дуплекс)
_zh_nrf24_write_register() Запись одного байта в регистр nRF24L01+
_zh_nrf24_write_buff_register() Запись многобайтового буфера в регистр nRF24L01+
_zh_nrf24_write_buffer() Запись буфера данных с указанной командой (CSN управляется вручную через PB2)
_zh_nrf24_send_command() Отправка однобайтовой команды и чтение статуса
_zh_nrf24_read_payload() Чтение принятой полезной нагрузки из RX FIFO (R_RX_PAYLOAD)
_zh_nrf24_read_payload_width() Чтение длины пакета в RX FIFO (R_RX_PL_WID)

Низкоуровневые TWI-операции (аппаратный I2C)

Функция Описание
_zh_i2c_wait() Ожидание флага TWINT с таймаутом 65535 итераций (возвращает false при зависании шины)
_zh_i2c_start() Генерация стартового (или повторного стартового) условия, проверка статусов 0x08/0x10
_zh_i2c_stop() Генерация стоп-условия с ограниченным ожиданием сброса бита TWSTO
_zh_i2c_write() Передача одного байта через TWDR, проверка статусов ACK (0x18, 0x28, 0x40)
_zh_i2c_read_ack() Чтение байта из TWDR с подтверждением ACK (возвращает 0xFF при таймауте)
_zh_i2c_read_nack() Чтение последнего байта из TWDR без подтверждения NACK (возвращает 0xFF при таймауте)

Служебные TWI-функции BME280

Функция Описание
_zh_bme280_write_reg() Запись одного байта в регистр BME280 (start, адрес, регистр, данные, stop, задержка 2 мс)
_zh_bme280_read_reg() Чтение нескольких байт из регистров BME280 (repeated-start, ACK/NACK)

Статические переменные модуля

Все переменные объявлены static и доступны только внутри модуля.

Переменная Объявление Описание
_wdt_wake_count static volatile uint8_t Счётчик прерываний WDT, инкрементируется в ISR(WDT_vect) до предела WDT_WAKE_COUNT
_nrf_event static volatile bool Флаг события трансивера, выставляется в ISR(INT0_vect) и сбрасывается в машине состояний сопряжения
_bme280_calib static uint8_t [33] Калибровочные коэффициенты BME280, загружаются при инициализации датчика
_bme280_temp_fine static int32_t Промежуточное значение t_fine, общее для компенсаторов давления и влажности
_bme280_present static bool Признак доступности датчика BME280 (сбрасывается при ошибке чтения, восстанавливается повторной инициализацией)
_transmitted_data zh_nrf24_sensor_transmitted_data_t Глобальная (в пределах модуля) структура формируемого пакета

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

Компонент работает на bare-metal AVR без RTOS. Точки синхронизации — два ISR:

  • ISR(WDT_vect) — увеличивает _wdt_wake_count (объявлен как static volatile uint8_t, инкремент защищён проверкой верхнего предела), заново включает бит WDIE.
  • ISR(INT0_vect) — выставляет флаг _nrf_event (static volatile bool) при фронте на пине IRQ трансивера.

Главный цикл и машина состояний сопряжения проверяют эти флаги после выхода из сна. Атомарная запись одного байта на AVR гарантирует отсутствие состояний гонки. Весь остальной обмен с периферией (I2C, SPI, АЦП) выполняется последовательно в главном цикле.


Алгоритмы

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

  • При старте читается ID из EEPROM (eeprom_read_byte, адрес 0x00); значения 0x00 и 0xFF считаются признаком несопряжённого устройства.
  • При отсутствии ID выполняется _zh_do_pairing() — неблокирующая машина состояний (ZH_NRF24_PAIR_SEND → ZH_NRF24_PAIR_TX_WAIT → ZH_NRF24_PAIR_RX_WAIT → ZH_NRF24_PAIR_BACKOFF):
    • генерируется токен (_zh_get_random_token() из MCUSR и шума АЦП);
    • отправляется запрос zh_nrf24_sensor_pairing_data_t (magic 0xA5) без ожидания (_zh_nrf24_send_no_wait);
    • после TX_DS трансивер переводится в RX-режим, ожидание ответа со сном и WDT-таймаутом 250 мс;
    • ответ валидируется по magic 0x5A, типу, токену и ненулевому ID; ширина пакета проверяется через R_RX_PL_WID;
    • при неудаче — backoff-пауза ~4 с (WDT), не более PAIRING_TIMEOUT_ATTEMPTS (7) попыток.
  • Назначенный ID сохраняется в EEPROM и записывается в _transmitted_data.id.
  • После инициализации выполняется пробная сборка пакета zh_nrf24_sensor_build_payload(); при нулевом результате (неизвестный тип) — переход в постоянный сон.

Алгоритм инициализации BME280

  • Задержка 100 мс после включения.
  • Проверка CHIP_ID (регистр BME280_REG_ID, ожидается 0x60).
  • Сброс записью 0xB6 в регистр BME280_REG_RESET, задержка 10 мс.
  • Чтение калибровочных коэффициентов: 26 байт из BME280_REG_CALIB00 и 7 байт из BME280_REG_CALIB26 (всего 33 байта, массив _bme280_calib).
  • Конфигурация влажности: ctrl_hum = 0x01 (oversampling x1).
  • Конфигурация режима: config = 0x00 (фильтр off, standby off).
  • Запуск измерения: ctrl_meas = 0x25 (temp/pressure oversampling x16, forced mode) в _zh_bme280_read() перед каждым чтением.

Алгоритм компенсации BME280

Сырые ADC-значения пересчитываются в физические величины по алгоритмам производителя из datasheet BME280.

  • Температура: _zh_bme280_compensate_temperature() — вычисляет _bme280_temp_fine (используется для давления и влажности), возвращает результат в °C.
  • Давление: _zh_bme280_compensate_pressure() — возвращает результат в Па. При var1 == 0 (знаменатель ноль) возвращает 0.0.
  • Влажность: _zh_bme280_compensate_humidity() — результат ограничивается диапазоном [0, 419430400] на промежуточном шаге, затем делится на 1024.0 и возвращается в процентах.

Алгоритм аппаратного TWI

  • Инициализация: TWSR = 0x00 (предделитель 1), TWBR = TWI_TWBR (32), включение модуля битом TWEN. Скорость: F_CPU / (16 + 2·TWBR·prescaler) ≈ 100 кГц при 8 МГц.
  • Стартовое/повторное стартовое условие: установка TWSTA, ожидание TWINT, проверка статуса (0x08 — START, 0x10 — REPEATED START).
  • Передача байта: запись в TWDR, сброс TWINT, ожидание завершения, проверка статусов подтверждения (0x18/0x28 — данные, 0x40 — адрес чтения).
  • Приём байта: установка TWEA для всех байт кроме последнего, чтение TWDR после TWINT.
  • Останов: установка TWSTO, ограниченное ожидание (1000 итераций) сброса бита аппаратно.
  • Обработка ошибок: каждая операция возвращает false при таймауте ожидания или неверном статусе, вызывающая сторона выполняет _zh_i2c_stop().

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

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

Для процедуры сопряжения используется вариант без блокировки (_zh_nrf24_send_no_wait, импульс CE 15 мкс) с завершением по прерыванию INT0.

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

  • Инициализация WDT: прерывание по таймауту ~8 секунд (WDT_T_8S), без сброса MCU.
  • ISR WDT_vect: увеличивает _wdt_wake_count (до предела WDT_WAKE_COUNT), заново включает бит WDIE.
  • Главный цикл: переход в Power-down (sleep_cpu()). После пробуждения проверяется _wdt_wake_count >= WDT_WAKE_COUNT (38 × 8 с ≈ 5 минут).
  • При достижении порога: обнуление счётчика, повторная инициализация BME280 (если датчик недоступен), чтение показаний, сериализация пакета и передача через nRF24L01+.
  • Первое измерение выполняется сразу после инициализации и сопряжения, до входа в цикл.
  • _zh_enter_final_sleep() — аварийный постоянный сон: отключение прерываний, WDT, радио, АЦП, TWI, SPI и тактов всей неиспользуемой периферии (PRR).

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

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

int main(void)
{
    _transmitted_data.type = ZH_NRF24_SENSOR_BME280;
    MCUSR &= ~(1 << WDRF);
    wdt_disable();
    cli();
    _zh_i2c_init();
    _bme280_present = _zh_bme280_init();
    _zh_spi_init();
    _zh_nrf24_init();
    set_sleep_mode(SLEEP_MODE_PWR_DOWN);
    sei();

    uint8_t device_id = _zh_load_device_id();
    if (device_id == DEVICE_ID_UNASSIGNED) {
        device_id = _zh_do_pairing();
    }
    _transmitted_data.id = (int16_t)device_id;

    // Пробная сборка пакета: неизвестный тип — переход в постоянный сон
    {
        uint8_t probe[ZH_NRF24_MAX_PAYLOAD_SIZE];
        if (zh_nrf24_sensor_build_payload(&_transmitted_data, probe,
                                          sizeof(probe)) == 0) {
            _zh_enter_final_sleep();
        }
    }

    _zh_wdt_start(WDT_T_8S);
    int32_t adc_t = 0, adc_p = 0, adc_h = 0;

    // Первое измерение сразу после инициализации и сопряжения
    if (_bme280_present == true) {
        if (_zh_bme280_read(&adc_t, &adc_p, &adc_h) == true) {
            _transmitted_data.battery =
                (int16_t)lroundf(_zh_get_battery_voltage() * 100.0);
            _transmitted_data.value_2 =
                (int16_t)lroundf(_zh_bme280_compensate_temperature(adc_t) * 10.0);
            _transmitted_data.value_3 =
                (int16_t)lroundf(_zh_bme280_compensate_pressure(adc_p) * 0.00750062 * 10.0);
            _transmitted_data.value_1 =
                (int16_t)lroundf(_zh_bme280_compensate_humidity(adc_h) * 10.0);
            uint8_t payload[ZH_NRF24_MAX_PAYLOAD_SIZE];
            uint8_t size = zh_nrf24_sensor_build_payload(&_transmitted_data,
                                                      payload, sizeof(payload));
            if (size > 0) {
                _zh_nrf24_send(payload, size);
            }
        } else {
            _bme280_present = false;
        }
    }

    for (;;)
    {
        sleep_enable();
        sleep_cpu();
        sleep_disable();
        if (_wdt_wake_count >= WDT_WAKE_COUNT) {
            _wdt_wake_count = 0;
            if (_bme280_present == false) {
                _bme280_present = _zh_bme280_init();
            }
            if (_bme280_present == true) {
                if (_zh_bme280_read(&adc_t, &adc_p, &adc_h) == true) {
                    _transmitted_data.battery =
                        (int16_t)lroundf(_zh_get_battery_voltage() * 100.0);
                    _transmitted_data.value_2 =
                        (int16_t)lroundf(_zh_bme280_compensate_temperature(adc_t));
                    _transmitted_data.value_3 =
                        (int16_t)lroundf(_zh_bme280_compensate_pressure(adc_p) * 0.00750062);
                    _transmitted_data.value_1 =
                        (int16_t)lroundf(_zh_bme280_compensate_humidity(adc_h));
                    uint8_t payload[ZH_NRF24_MAX_PAYLOAD_SIZE];
                    uint8_t size = zh_nrf24_sensor_build_payload(&_transmitted_data,
                                                              payload, sizeof(payload));
                    if (size > 0) {
                        _zh_nrf24_send(payload, size);
                    }
                } else {
                    _bme280_present = false;
                }
            }
        }
    }
}

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

// Идентификатор устройства назначается шлюзом при сопряжении
// и хранится в EEPROM (адрес 0x00). Для повторного сопряжения
// обнулите ячейку EEPROM.
#define GATEWAY_CHANNEL 120
#define GATEWAY_ADDRESS 0xDDEEFF
// Тип устройства задаётся перечислением ZH_NRF24_SENSOR_BME280

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

// Назначение пинов AVR:
// nRF24L01+ (SPI):
// PB2        -> CSN (управление SPI-селектом, выход)
// PB3        -> MOSI (назначается аппаратным SPI)
// PB5        -> SCK  (назначается аппаратным SPI)
// PB1        -> CE   (управление передачей, выход)
// PD2        -> IRQ  (вход, активный низкий, INT0, с подтяжкой к VCC)
// BME280 (I2C, аппаратный TWI):
// PC4        -> SDA (аппаратный TWI, внутренний pull-up)
// PC5        -> SCL (аппаратный TWI, внутренний pull-up)

Логирование

Логирование отсутствует.


Ошибки

Компонент не возвращает коды ошибок. Функции _zh_bme280_init, _zh_bme280_read, _zh_bme280_write_reg, _zh_bme280_read_reg возвращают bool (true при успехе). _zh_load_device_id возвращает DEVICE_ID_UNASSIGNED при отсутствии сохранённого ID. Остальные функции имеют тип void или возвращают однобайтовый статус SPI (uint8_t).

Условие Поведение
Нулевое показание АЦП _zh_get_battery_voltage() возвращает 0.0
Неверный CHIP_ID BME280 _zh_bme280_init() возвращает false, флаг _bme280_present = false, при следующем цикле предпринимается повторная попытка инициализации
Таймаут ожидания TWINT _zh_i2c_wait() возвращает false, операция TWI прерывается
Неверный статус TWI (NACK, ошибка шины) _zh_i2c_start() / _zh_i2c_write() возвращают false, вызывающая функция выполняет _zh_i2c_stop()
Таймаут при чтении TWI _zh_i2c_read_ack() / _zh_i2c_read_nack() возвращают 0xFF
Ошибка чтения BME280 _zh_bme280_read() возвращает false, пакет не формируется, _bme280_present = false
var1 == 0 при компенсации давления _zh_bme280_compensate_pressure() возвращает 0.0
Превышение таймаута передачи (~100 мс) Цикл ожидания IRQ прерывается, передача может быть неполной
Нет ответа шлюза при сопряжении После 7 попыток (PAIRING_TIMEOUT_ATTEMPTS) — переход в постоянный сон до сброса
Ширина принятого пакета ≠ 5 байт / > 32 байт FIFO очищается, состояние сопряжения переходит в backoff
zh_nrf24_sensor_build_payload() вернул 0 Неизвестный тип датчика или слишком мал буфер — переход в постоянный сон

Ограничения

  1. Широковещательная передача данных — приём используется только на этапе сопряжения; шлюз не подтверждает пакеты измерений на уровне приложения.
  2. Отсутствие шифрования — CRC включён, но AES-шифрование не используется. Пакеты могут быть перехвачены.
  3. Жёстко зашитый адрес шлюза — смена адреса или канала требует перепрошивки (ID устройства при этом хранится в EEPROM).
  4. Таймаут передачи ~100 мс — если шлюз недоступен, передача прерывается. Аппаратные ретрансмиты nRF24L01+ (SETUP_RETR = 0xFF: 15 попыток с интервалом до 500 мс) включены.
  5. Точность измерения батареи — зависит от стабильности внутреннего опорного напряжения 1,1 В.
  6. Программные задержки в TWI — обмен с BME280 выполняется на аппаратном TWI, но ожидание TWINT реализовано поллингом с таймаутом; прерывания TWI не используются.
  7. Задержка между измерениями ~5 минут — определяется произведением WDT_WAKE_COUNT (38) на интервал WDT (~8 секунд). В течение этого времени пакет не передаётся.
  8. Давление в мм рт. ст. — _zh_bme280_compensate_pressure() возвращает давление в Паскалях, для перевода в пакет умножается на 0.00750062 (коэффициент пересчёта Па → мм рт. ст.).
  9. Масштабирование значений ×10 только в первом цикле — при первом измерении температура, влажность и давление умножаются на 10 (одна дробная цифра); в цикле пробуждения значения записываются без масштабирования (см. main).
  10. Сопряжение требует шлюза — без ответившего шлюза устройство после 7 попыток уходит в постоянный сон до сброса/перепрошивки.

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

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

Установка

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

pio run -e ATmega328P -t upload

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

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

; platformio.ini
lib_deps =
    https://github.com/aZholtikov/zh_nrf24_config#dev
// Зависимости: стандартные заголовки AVR-libc, математика и конфигурация протокола
#include "avr/io.h"
#include "avr/interrupt.h"
#include "avr/sleep.h"
#include "avr/eeprom.h"
#include "avr/wdt.h"
#include "util/delay.h"
#include "stdbool.h"
#include "math.h"
#include "zh_nrf24_config.h"