Пульт дистанционного управления на базе чипа nRF24L01+ и микроконтроллера ATmega48PA


Автор: Погребняк Дмитрий

Самара, 2015.


В этой статье описывается проект универсального пульта дистанционного управления на базе чипа nRF24L01+, описание которого приводится в другой статье.


Это пульт для ближнего радиуса действия, может быть использован для управления игрушками, или в системах умного дома.


Пульт может быть настроен на передачу практически для любых настроек радиоканала, а значит, в качестве приёмника легко может выступить любое оборудование использующее модули на таких же радио-чипах.

"Универсальным" пульт делает протокол обмена, который без особых трудностей позволяет отслеживать и обрабатывать со стороны приёмника следующие события:

- Нажатие кнопки

- Отпускание кнопки

- Любая комбинация зажатых кнопок

- Удержание кнопок в течение заданного промежутка времени (долгое нажатие)

- Двойное нажатие в течение заданного промежутка времени (двойной щелчок)

- Так же позволяет обеспечить контроль в условиях нестабильной связи.


Одновременно с этим эффективное использование энергосберегающих режимов позволяет обеспечить долгую работу пульта от батареи.


Схема устройства


Схема пульта
Схема пульта


Фактически схема включает в себя микроконтроллер, четыре кнопки, батарейку и радио-модуль.

Конденсатор C5 сглаживает пульсации по питания.

Конденсаторы C1-C4 сглаживают дребезг кнопок. В принципе, можно обойтись и без них.

Если чип радиосвязи устанавливается на одну плату с микроконтроллером, т.е., как в примере ниже, используется вне готового радио-модуля, то всю обвязку нужно также реализовать самостоятельно. Она показана на схеме. Самый простой вариант - купить модуль на ebay и выпаять из него чип и компоненты обвязки, используя паяльный фен.


Пример готового устройства =


Части корпуса Gainta G1402-4B, батарейка и обратная сторона платы
Части корпуса Gainta G1402-4B, батарейка и обратная сторона платы


Реализованное устройство изготовлено в виде платы для корпуса Gainta G1402-4B.

Батарейка удерживается припаянным к плате держателем BTH-W39-20 (он же BC-2001). Контактная площадка под минус батарейки представляет собой просто залуженный медный круг на плате.


Лицевая сторона платы
Лицевая сторона платы


Плата изготовлена на стеклотекстолите толщиной 1.5мм.

Кнопки - DTSM-13-5.0N, smd 6x3,6мм, 5мм в высоту.

Микроконтроллер ATmega48PA-AU, в корпусе TQFP.

Для тактирования чипа радиосвязи использован керамический smd резонатор размера 3225 (3.2 x 2.5мм) на 16 МГц.

Все конденсаторы размера 0805.

В качестве антенны - небольшой кусок провода.


Алгоритм работы


Информация передаётся каждый раз когда кнопки нажимаются, отпускаются, а также в режиме повтора 5 раз в секунду (по умолчанию), пока кнопки нажаты.


Структура пакета


Данные, передаваемые в пакете, имеют размер два байта.


Первый байтВторой байт
7654321076543210
D4D3D2D1B4B3B2B1LсчётчикC4C3C2C1

Если плату повернуть антенной вверх, то кнопки нумеруются так: 1 - верхняя, 2 - нижняя, 3 - левая, 4 - правая

Младшие 4 бита первого байта, B1-B4, кодируют текущее состояние кнопок. Если бит принимает значение 1, то кнопка в данный момент нажата, если 0 - то отпущена.

Старшие 4 бита первого байта, D1-D4, кодируют признак двойного щелчка. Если бит принимает значение 1, это значит, что последнее нажатие было сделано спустя интервал времени меньше заданного (0.75 с по-умолчанию) с момента предыдущего нажатия. Иначе говоря, был сделан двойной щелчок. Эти биты сохраняют своё значение и после отпускания кнопки, по ним также можно определить, что двойной щелчок был сделан на кнопке, которая уже отпущена.


Старший бит второго байта, L, указывает, что текущая комбинация зажатых кнопок удерживается больше заданного (по умолчанию 2 секунды) интервала времени. По этому биту можно определить удержание кнопки.

Три бита "счётчик" с 4 по 6й, меняют своё значение каждый раз, когда кнопка нажата, или отпущена. При удержании кнопки периодически передаются повторы. Если значение младших 7 бит второго байта не менялось с прошлого раза, значит, кнопки не отпускались и не нажимались. Изменение этого поля позволяет отследить ситуации, когда кнопка была отпущена, а затем нажата вновь, но пакет с информацией об отпускании был утерян.

Младшие 4 бита второго байта, C1-C4, кодируют какие кнопки изменили своё состояние (т.е. были нажаты, или отпущены) в последний раз.


Обработка данных


Пример кода обработки полученного от пульта пакета:

// buf - буфер с принятым пакетом
// prevbuf1 - сохранённое предыдущее значение buf[1]
// prevbuttons - предыдущее известное состояние нажатых кнопок

uint8_t buttons = buf[0] & 0x0F; // Какие кнопки нажаты сейчас
uint8_t changed = (((buf[1] & 0x7F) == (prevbuf1 & 0x7F)) ? 0 : (buf[1] & 0x0F)) | (buttons ^ prevbuttons);
  // Какие кнопки изменились с прошлого раза, включая те, по которым информация была потеряна
                                                                                
uint8_t clicked = changed & buttons; // Какие кнопки только что были нажаты
uint8_t released = changed & ~buttons; // Какие кнопки только что были отпущены
uint8_t dblclick = (buf[0] >> 4) & 0x0F; // Какие кнопки были с двойным щелчком нажаты последний раз

uint8_t is_long = buf[1] & 0x80; // Признак долгого нажатия
uint8_t is_long_appears = is_long && !(prevbuf1 & 0x80); // Признак что нажатие только что стало долгим
prevbuf1 = buf[1]; // Сохранение значения на следующий раз
prevbuttons = buttons;

// Далее mask = (1 << (номер кнопки - 1)), т.е.:
//   1 - 1я кнопка
//   2 - 2я кнопка
//   4 - 3я кнопка
//   8 - 4я кнопка


if (clicked & mask) { // Состояние кнопки изменилось
  if (dblclick & mask) { // Обнаружено двойное нажатие
      // Здесь обработчик двойного щелчка
    } else {
      // Здесь обработчик одинарного щелчка
    }
}
if (released & mask) {
  // Здесь обработчик отпускания кнопки
}

if (buttons & mask) {
  // Здесь обработчик повторяемого действия, пока кнопка держится нажатой
}

if (is_long_appears) {
  if (buttons & mask) {
    // Здесь обработчик долгого удержания кнопки
  }
}

Если при удержании кнопки выполняется некоторое продолжительное действие, то может случиться ситуация, когда пакет с информацией об отпускании кнопки был потерян. На этот случай хорошей идеей будет предусмотреть некий таймер, срабатывающий через 2,5 периода повтора, и если пакет подтверждающий удержание кнопки не пришёл в течение этого периода времени, то считать кнопку отпущенной.


Алгоритмы энергосбережения


В неактивном состоянии микроконтроллер пульта и чип nRF24L01+ находятся в состоянии power-down, потребляя около 1 микроампера. Заряда типичной батарейки CR2032 хватит на более чем 25 лет пребывания в таком режиме.

В момент нажатия, удержания кнопок и до истечения времени ожидания двойного щелчка после отпускания всех кнопок, nRF24L01+ между отправками пакетов переводится в режим standby-I, потребляя около 26мкА, микроконтроллер же ожидает события в режиме power-save. При нажатии кнопок, отправках со средней частотой 5 пакетов при максимальных повторах передачи, потребление тока не превышает 650мкА. Если же удалённая сторона принимает пакеты и высылает подтверждения о приёме, то есть повторов не происходит, потребление тока не превышает 300мкА. Заряда батареи хватит на месяц непрерывной работы в таком режиме.


На случай если пульт положен на хранение с кнопками в зажатом положении (например, придавлен чем-то) реализован алгоритм защиты. Если состояние кнопок не меняется, но подтверждений от удалённой стороны не приходит подряд заданное количество раз (по умолчанию - 40). То микроконтроллер отключает передатчик, отключает подтягивающие резисторы на зажатых кнопках и переходит в режим power-down. В этом случае пульт может не среагировать на отпускание и нажатие этой кнопки и для вывода пульта из спящего режима может потребоваться нажатие на кнопку, которая не была зажата. Если такая ситуация произошла, когда все кнопки оказались зажаты, то подтягивающий резистор оставляется включенным на кнопке 1 (верхней). Отпускание и нажатие на неё сможет перевести пульт в нормальный режим, однако в этой ситуации ток утечки через подтягивающий резистор может составить до 80 мкА.



Прошивка


Прошивка и исходный код доступны для скачивания по ссылке: zip-архив, 141кБ.


Помещённый здесь код является свободным для некоммерческого использования, при условии указания ссылки на автора (Погребняк Дмитрий, http://aterlux.ru/).


Настройки пульта


Настройки nRF24L01+ и пульта задаются в EEPROM. Если настройки в EEPROM не заданы, то применяются настройки по умолчанию. При этом настройки nRF24L01+ соответствуют настройкам принимающей стороны по-умолчанию: адрес длиной 5 байт, 0xC2C2C2C2C2, радио-канал 2, CRC 8 бит, скорость 2мбит/с.


Фьюзы (ATmega48PA): extended 0xFF, high 0xD6, low 0x62

Отличие от настроек по-умолчанию: включен BOD на 1.8 Вольт, включена опция EESAVE


Интерактивная форма ниже поможет сформировать файл .hex (или .eep) для загрузки в EEPROM микроконтроллера.


Настройки nRF24L01+
Адрес (шестнадцатиричный)
Длина адреса
Номер радиоканала (0 - 125)
Размер поля CRC
Скорость передачи
Мощность передатчика
Максимальное количество повторов
Пауза между повторами
Настройки пульта
При удержании, повторная отправка через ± 0.016 с
Флаг долгого нажатия выставляется после ± 0.016 c
Двойной щелчёк, не позже чем через ± 0.016 c
Повторов без подтверждения до перехода в режим энергосбережения
Содержимое файла EEPROM
Байты в EEPROM:



34 ms; mod: Sat, 06 May 2017 20:41:51 GMT; gen: Thu, 23 Nov 2017 13:00:58 GMT