Начало » Микроконтроллеры » Электронные часы-термометр с беспроводным датчиком через радиомодуль nRF24L01

 
 

Электронные часы-термометр с беспроводным датчиком через радиомодуль nRF24L01

📆29.03.22   ✒️ayan   🔎2.048   💬8  

Здравствуйте, уважаемые Датагорцы! Представляю вашему вниманию электронные часы с функцией измерения температуры, изготовленные мною в качестве подарка деду ко дню Советской Армии.
Особенностью проекта является использование радиомодуля nRF24L01 для беспроводного соединения с датчиком DS18B20. Это моя первая статья.


Камрад, рассмотри датагорские рекомендации



Часы состоят из двух отдельных модулей — периферийного (далее — «ПМ»), измеряющего температуру и передающего по воздуху её значение центральному (далее — «ЦМ») для отражения совместно с текущими датой и временем на экране дисплея.

Центральный модуль часов

Как видно из видео выше ЦМ — непосредственно часы с выведенными:
а) экраном дисплея — на переднюю панель корпуса ,
б) ручкой энкодера — на верхнюю панель корпуса,
в) USB-кабелем питания — через заднюю панель корпуса.

Детали и компоненты ЦМ

Для сборки ЦМ были использованы:
Arduino Nano на базе МК ATmega328P с частотой тактирования 16 МГц и предварительно удалённым бутлоадером
TFT-дисплей ST7735
Часы реального времени DS1307
Радиомодуль/трансивер nRF24L01
Энкодер

Принципиальная электрическая схема ЦМ

Схема соединений элементов ЦМ представлена на Рисунке 1.
Электронные часы-термометр с беспроводным датчиком через радиомодуль nRF24L01
Рисунок 1. Схема соединений центрального модуля


Вывод SQ модуля DS1307 подключён к пину PD3 МК, поскольку сигнал с частотой 1 Гц на указанном выводе RTC использован в качестве источника внешнего прерывания INT1 ATmega328P для обновления значений времени и даты на экране дисплее.

Сигнал о поступлении от ПМ радио-пакета с вывода IRQ nRF24L01 передаётся на пин PD2 МК, инициируя внешнее прерывание INT0, что обеспечивает своевременное чтение из трансивера нового значения температуры.

Для обмена данными с RTC, дисплеем и трансивером использованы пины ATmega328P не аппаратных I2C (PC5/PC4 для SCL/SDA, соответственно) и SPI (PB3/PB4/PB5 для MOSI/MISO/SCK, соответственно), а произвольные, поскольку в проекте реализованы программные версии указанных протоколов, а выбор пинов определялся из соображений топологии платы.

Источником питания ЦМ послужило зарядное устройство смартфона на 5В.

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

При включении ЦМ переходит в основной режим — отображения на экране дисплее текущих значений температуры, времени, даты и дня недели.
Рисунок 2. Значения, отражаемые на экране дисплея в основном режиме ЦМ


В основном режиме ЦМ реагирует на три события:
1. При поступлении сигнала с вывода SQ DS1307 микроконтроллер считывает из RTC текущие значения времени/даты, которые, в случае наличия изменений, обновляются на дисплее. Кроме того, символ двоеточия «:» в показаниях времени попеременно меняет цвет с белого на чёрный, т.е. блинкует с частотой 1 Гц.

2. В случае, когда nRF24L01 посредством прерывания INT0 сигнализирует о поступлении радио-пакета, МК считывает из трансивера текущее значение температуры и выводит на экран дисплея.

3. Длительное (более 4-х секунд) нажатие кнопки энкодера (далее - «Кнопка») переводит ЦМ в режим установки даты/времени. В указанном режиме, посредством вращения ротора энкодера (далее - «Ротор»), сопровождаемого перемещением рамки, и короткого нажатия кнопки можно выбирать между установкой времени, установкой даты, возвратом в основной режим.


Рисунок 3. Меню выбора установки времени/даты


При выборе пункта «time settings» на экран дисплея выводится следующее меню.
Рисунок 4. Меню установки времени

Здесь, вращая ротор и ориентируясь на текущее положение рамки, необходимо выбрать требуемый разряд (десятки или единицы часов/минут), после чего коротко нажать кнопку. Последующее вращение ротора приведёт к изменению значения выбранного разряда. Очередное нажатие кнопки возвращает вращению ротора функцию перемещения рамки для выбора того или иного параметра.

После окончательной установки значения времени достаточно выбрать пункт «save» меню, а затем коротким нажатием кнопки сохранить новые значения в EEPROM DS1307 и вернуться к меню из Рисунка 3.

Рисунок 5. Меню установки даты

Аналогичные действия для настройки даты понадобятся после выбора пункта «date settings» меню на Рисунке 3.

Периферийный модуль часов

Как следует из вышеприведённого видео, ПМ — выносной модуль измерения температуры с возможностью передачи её значения через радиоканал.

Детали и компоненты ПМ часов

Работу ПМ обеспечивают:
МК ATtiny85 с частотой тактирования 1 МГц
Радиомодуль/трансивер nRF24L01
Температурный датчик DS18B20
• Резистор номиналом 4.7 кОм, подтягивающий сигнальный вывод DS18B20 к питанию
Батарейка CR2032 в качестве источника питания

Электрическая схема ПМ

На рисунке 6 представлена схема соединений элементов ПМ.

Рисунок 6. Схема соединений периферийного модуля


Учитывая, что в ATtiny85 нет полноценной аппаратной поддержки требуемых протоколов обмена данными, в коде ПМ были использованы программные варианты 1-Wire (в случае с DS18B20) и SPI (в случае с nRF24L01), поэтому выбор соответствующих пинов МК — произвольный. Выводы IRQ и MISO трансивера не использовались, в связи с отсутствием необходимости.

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

Большую часть времени ПМ проводит в режиме сна. При этом, согласно даташитов, ATtiny85 потребляет 10 мкА, а nRF24L01 – 900 нА.
Один раз в час МК:
• считывает текущее значение температуры из DS18B20,
• будит трансивер и отправляет данные центральному модулю,
• вводит трансивер в режим сна и засыпает сам.

Потребление ATtiny85 в активном режиме вырастает до 0.55 мА , а nRF24L01 — до 11.3 мА. Учитывая длительность операций в активном режиме (миллисекунды), можно предполагать, что емкости 240 мА/ч батарейки хватает на 15-18 месяцев бесперебойной работы ПМ.

Программное обеспечение для часов-термометра

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

Программное обеспечение для ЦМ и ПМ написано на языке С++ в Visual Studio Code, скомпилировано посредством GCC и выложено в архив статьи. Прежде, чем перейти к особенностям кода каждого из модулей, остановлюсь на общих для обоих моментах.

Содержимое файла с основной функцией main() я предпочитаю ограничивать вызовом двух функций — deviceInit() и deviceControl() — которые прописываю уже в файле device.cpp. Такой подход даёт возможность хранить main.cpp, наряду с Makefile, в папке с шаблонами и переносить его без изменений из проекта в проект.

main.cpp


Makefile и вспомогательный variables.mk оформлены в соответствии с Главой 6 следующей статьи.

Makefile

variables.mk


Для обмена данными с внешними устройствами были применены программные версии соответствующих протоколов. См. подробнее в датагорских статьях:
1-Wire - "Визуализация для микроконтроллера. Часть 4. Android"
I2С, SPI - "Ассемблер для микроконтроллера с нуля. Часть 6. Протоколы обмена данными"
Трансивер nRF24L01 - "Беспроводной канал связи 2,4 ГГц на базе трансивера nRF24L01+ от Nordic Semiconductor"
Во всех вышеуказанных статьях даны подробные объяснения и комментарии к коду, поэтому не вижу смысла дублировать их текст в данной работе.

Код Центрального модуля

Для размещения кода ЦМ в МК потребуется 22.6 кБайт флэш-памяти, в т.ч. 3.1 кБайт — под шрифты. Кроме того, программа использует как минимум 982 байта ОЗУ, причём подавляющая часть этого объёма оперативной памяти выделяется под строковые переменные, применяемые при оформлении меню.

Учитывая большое количество перекрёстных ссылок, а также для удобства были вынесены:
• макроопределения состояний флагов энкодера и определения структур — в файл globals.h,
• распиновка соединений МК с внешними устройствами — в файл pinout.h.

globals.h


Несколько пояснений.

1. Поле структуры device:
encoderButtonFlag отражает факт нажатия кнопки и принимает значения ENCODER_BUTTON_PUSH_TIME_SHORT или ENCODER_BUTTON_PUSH_TIME_LONG при коротком или длительном нажатии, соответственно. Сбрасывается в состояние ENCODER_BUTTON_PUSH_TIME_NO_PUSH при инициализации энкодера и перед реакцией МК на нажатие.
encoderRotorFlag отражает факт поворота ротора и принимает значения ENCODER_ROTOR_TURNED_CLOCK_WISE или ENCODER_ROTOR_TURNED_COUNTER_CLOCK_WISE при повороте по или против часовой стрелки, соответственно. Сбрасывается в состояние ENCODER_ROTOR_STOPPED при инициализации энкодера и перед реакцией МК на поворот.
payloadReceivedFlag принимает значение 1 в обработчике прерывания от nRF24L01 при поступлении радио-пакета от ПМ. Сбрасывается в 0 при инициализации трансивера и перед реакцией МК на поступление пакета.
colonBlinkFlag принимает значение 1 в обработчике прерывания при поступлении сигнала от DS1307. Сбрасывается в 0 при инициализации RTC и перед реакцией МК на поступление сигнала.
colonState отражает текущий цвет символа двоеточия «:» в значении времени на экране дисплея (1 — белый, 0 — чёрный). Меняет состояние на противоположное при очередной прорисовке значения времени.

2. Поле структуры menu:
state используется для выбора действия на экране дисплея при повороте ротора энкодера: 0 — движение рамки, 1 — изменение значения параметра (десятки/единицы времени и даты, день недели и т.д.).
name определяет, какое именно меню будет прорисовано на экране дисплея в данный момент.
Item идентифицирует элемент меню, на который в данный момент указывает рамка в тех меню, где предполагается её наличие и движение.
TSsaveFlag и DSsaveFlag устанавливаются в 1 при выборе пункта «save» в меню «time settings» и «date settings», соответственно, что является сигналом для МК к сохранению установленных в указанных меню новых значений времени и даты в EEPROM DS1307.

Остальные поля структуры menu предназначены для хранения текущих и предыдущих параметров рамки, времени, даты и температуры.

pinout.h


Остановлюсь на деталях кода контроля за внешними устройствами, входящими в состав ЦМ:
• энкодер,
• RTC DS1307,
• трансивер nRF24L01,
• дисплей ST7735.

Работа с энкодером

Контроль энкодера осуществляется посредством кода из одноимённых cpp- и хидер- файлов, содержимое которых представлено ниже.
encoder.h


Пара пояснений:
1. Поле структуры encoder:
а) rotorTurnCounter обеспечивает подсчёт количества шагов ротора при его повороте в одном направлении.
б) counter предназначено для подсчёта длительности нажатия кнопки.
в) buttonState отражает текущее состояние кнопки и может принимать одно из четырёх значений, определённых в том же файле выше:
• ENCODER_BUTTON_IS_RELEASED (или 1, когда кнопка отпущена),
• ENCODER_BUTTON_IS_PUSHED_BEFORE_BOUNCE (или 2, когда кнопка нажата, но время дребезга не истекло),
• ENCODER_BUTTON_IS_PUSHED_AFTER_BOUNCE (или 3, когда кнопка нажата, и время дребезга истекло),
• ENCODER_BUTTON_IS_RELEASED_BEFORE_BOUNCE (или 4, когда кнопка отпущена, но время дребезга не истекло).

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

encoder.cpp


Несколько слов о том, как всё это работает.
Для полноценного функционирования ЦМ необходимо обеспечить корректную реакцию МК на четыре события, генерируемые энкодером:
1. Длительное (более 4-х секунд) нажатие кнопки.
2. Короткое (менее 4-х секунд) нажатие кнопки.
3. Поворот ротора по часовой стрелке.
4. Поворот ротора против часовой стрелке.

При этом, следует иметь в виду, что производителем модуля энкодера, использовавшегося в проекте, не предусмотрены цепи подавления дребезга.

Учитывая вышеизложенное, было принято решение использовать в коде обработки сигналов от кнопки:
а) прерывание с периодом 32.8 мс по переполнению счётчика таймера TIMER1, входящего в состав МК, с целью:
• организации задержки при нажатии кнопки для исключения дребезга, длительность которого, как правило, не превышает указанный период,
• подсчёта времени удержания кнопки в нажатом состоянии.

б) внешнее прерывание PCINT8 от пина PC0 МК, к которому, как видно из Рисунка 1, подключен выходной контакт SW кнопки, для обеспечения немедленной реакции на её нажатие/отпускание.

Алгоритм действий МК при нажатии/отпускании кнопки можно понять из Рисунка 9.

Рисунок 9. Реакция МК на нажатие/отпускание кнопки

Проследим за событиями от точки А до точки G на Рисунке 9, помня о том, что время между двумя соседними из них составляет 32.8 мс.

A. Происходит нажатие кнопки, в связи с чем в обработчике прерывания PCINT8:
• записывается соответствующее значение (2 — кнопка нажата, но время дребезга не истекло) в поле buttonState структуры device, отражающее текущее состояние кнопки,
• локально запрещается прерывание PCINT8 на период дребезга,
• включается тактирование таймера,

B. Генерируется первое, после нажатия кнопки, прерывание таймера, в обработчике которого:
• записывается соответствующее значение (3 — кнопка нажата и время дребезга истекло) в поле buttonState,
• сбрасывается записью в него 1 флаг PCIF1, поднятый дребезгом после нажатия кнопки,
• локально разрешается прерывание PCINT8 для фиксации отпускания кнопки,
• инкрементируется поле counter структуры device, призванное считать длительность нажатия кнопки.

C – E. Инкрементируется поле counter.

F. Кнопка отпускается, вследствие чего генерируется прерывание PCINT8, в обработчике которого:
• записывается соответствующее значение (4 — кнопка отпущена, но время дребезга не истекло) в поле buttonState,
• локально запрещается прерывание PCINT8 на период дребезга,
• в последний раз инкрементируется поле counter, после чего его значение анализируется (если оно меньше 125, значит длительность нажатия — меньше 32.8 мс х 125 = 4 секунд, в противном случае — больше 4 секунд) и обнуляется, а в поле encoderButtonGlag структуры device при этом записывается соответствующее значение (ENCODER_BUTTON_PUSH_TIME_SHORT или ENCODER_BUTTON_PUSH_TIME_LONG),
• обнуляется счётчик TCNT1 таймера, чтобы обеспечить корректное время задержки на период дребезга.

G. По завершению задержки на время дребезга генерируется прерывание таймера, в обработчике которого:
• записывается начальное (1 — кнопка отпущена) значение в поле buttonState,
• тактирование таймера отключается до следующего нажатия кнопки,
• сбрасывается записью в него 1 флаг PCIF1, поднятый дребезгом после отпускания кнопки,
• локально разрешается прерывание PCINT8 для фиксации следующего нажатия кнопки.

Точки A – G из Рисунка 9 указаны, для полноты понимания, в коде обработчиков прерываний таймера и PCINT8 в тексте приведённого выше файла encoder.c.

Алгоритм интерпретации сигналов от ротора основан на том факте, что комбинация логических уровней на его выходных контактах в любой момент времени составляет, как видно из Рисунка 10, одно из четырёх чисел — 0, 1, 2 или 3.


Рисунок 10. Тайминг сигналов на выходных контактах ротора энкодера


Соответствующей код оформлен в виде функции getEncoderRotorState() в encoder.cpp и подробно прокомментирован, поэтому ограничусь лишь короткими пояснениями:
1. Выбор соседних пинов одного и того же порта МК (в нашем случае — PC2, PC1) для подключения контактов ротора позволяет заметно упростить код. При этом макроопределение ENCODER_ROTOR_PIN_LS в pinout.h обязательно должно быть дано пину с меньшим порядковым номером (в нашем случае — PC1).

2. Применение двойного сдвига влево предыдущего значения числа, формируемого комбинацией логических уровней на пинах PC2 и PC1, снижает влияние дребезга. Вследствие сдвига и последующей операции ИЛИ с текущим значением, окончательное число для определения направления поворота будет не 0, 1, 2, 3, а 1, 7, 8 14 при повороте по часовой стрелке или 2, 4, 11, 13 при повороте против часовой стрелки.

3. Накопление до 4 количества шагов поворота ротора в одном направлении так же, как и в предыдущем случае, помогает в борьбе с дребезгом.

Код для часов реального времени

Содержимое файлов контроля за RTC DS1307 представлено ниже.

DS1307.h

DS1307.cpp


Думаю, вы легко догадаетесь о назначении большинства полей и методов класса DS1307, исходя из их названий. Отмечу лишь, что:
• методы On() и Off() включают и выключают, соответственно, тактирование микросхемы часов реального времени,
• методы SQWEon() и SQWEoff() призваны разрешать и запрещать, соответственно, сигнал заданной частоты на выводе SQ RTC,
• методы decToBcd() и bcdToDec() необходимы для преобразования десятичного числа в двоично-десятичное и обратно, соответственно,
• в конструкторе класса осуществляется лишь включение тактирования.

Управление трансивером nRF24L01

Работу трансивера обеспечивают, помимо упомянутого выше pinout.h, представленные ниже файлы.

SPI.h

SPI.cpp

nRF24.h

nRF24.cpp


Поясню основные моменты.
1. При оформлении кода приняты во внимание требования спецификации nRF24L01, выложенной в архив статьи.

2. Метод begin():
• настраивает соответствующим образом пины МК, к которым подключены выводы CSN и CE трансивера,
• переводит nRF24L01 в режим передатчика (как в случае с ПМ) или приёмника (как в случае с ЦМ), в зависимости от значения входного аргумента mode.
• очищает регистры STATUS и FIFO трансивера.

3. Методы setPTX() и setPRX() обеспечивают перевод трансивера в режим передатчика и приёмника, соответственно, используя маски, определённые в хидер-файле.

4. Методы powerUp() и powerDown() позволяют реализовать режим сна nRF24L01.

5. Методы transmit() и receive() предназначены для передачи и чтения радио-пакета размером PAYLOAD_SIZE.

Управление дисплеем на ST7735

Даташит ST7735 выложен в архив статьи. В проекте использовалась версия дисплея, поддерживающая SPI, в связи с чем для обмена данными с ним применялась та же библиотека протокола, что и в случае с nRF24L01.

В основу кода легли материалы, представленные в статьях "Визуализация для микроконтроллера. Часть 2. TFT дисплей 1.8" (128х160) на ST7735" и "Визуализация для микроконтроллера. Часть 5. Графика".

Помимо упомянутых выше SPI.h и SPI.cpp работу дисплея обеспечивают нижеследующие файлы.

ST7735.h

ST7735.cpp


В вышеуказанной статье вы найдёте подробнейшие объяснения и комментарии. Остановлюсь лишь на двух наиболее важных моментах:
а) Метод begin() осуществляет инициализацию дисплея, включая:
• настройку пинов МК, связанных с выводами дисплея,
• включение дисплея,
• установку ориентации дисплея,
• окрашивание экрана дисплея в выбранный цвет (в нашем случае — чёрный).

б) Функция drawPixel() позволяет нарисовать точку размером 1х1 пиксель с учётом заданных параметров — цвета и координат. Именно на этой функции построены методы графической библиотеки GFX, файлы которой приведены ниже.

Кроме файлов ST7735, графическая библиотека GFX использует вспомогательные файлы iconsFonts, в которых содержатся:
• константные строковые переменные — «time settings», «datee settings», «exit» и «save»,
• шрифты для отражения значения времени (Arial36), а так же температуры, даты и других параметров (Arial16), сгенерированные посредством LCD Image Converter.

iconsFonts.h

iconsFonts.cpp


Сама графическая библиотека была модифицирована для работы с пропорциональным шрифтом.

GFX.h

GFX.cpp


В конечном итоге, с использованием всех описанных выше файлов был оформлен графический интерфейс проекта. Причём, было решено разбить его на две части:
• прорисовка значений времени, даты и температуры (файлы text.h и text.cpp).
• общая прорисовка меню и управляющий интерфейс (файлы display.h и display.cpp).

Такое разбиение обусловлено не только объёмом кода, но и соображениями о возможности использования файлов text в других проектах без внесения особых изменений.

text.h

text.cpp

Думаю, из комментариев и названий функций не сложно понять их назначение.

display.h

display.cpp


Рассмотрим детальнее функции из device.cpp.
1. diaplayInit():
• инициализирует ST7735,
• присваивает значение 0x0f полям структуры menu, хранящим предыдущие значения времени, даты и температуры для предотвращения непрорисовки соответствующего параметра в случае, если при первом считывании его значение равно нулю,
• прорисовывает меню из Рисунка 2.

2. drawMenu() — непосредственно функция прорисовки меню, результат исполнения которой зависит от текущего значения menu.name.

3. drawFrame() — функция прорисовки рамки в тех меню, где предполагается её наличие.

4. MAINcontrol() вызывается при каждом прерывании от DS1307 или nRF24L01 и ответственна за обновление в меню из Рисунка 2 значений времени, даты, температуры, а также цвета символа двоеточия.

5. TDEcontrol() вызывается для обеспечения:
• первоначальной прорисовки меню из Рисунка 3 — при длительном нажатии на кнопку в основном режиме ЦМ,
• для обеспечения движения рамки в указанном меню — при повороте ротора,
• перехода к меню из Рисунка 4 или 5, либо возврата к меню из Рисунка 2 — при коротком нажатии на кнопку.

6. TScontrol() через вложенные в неё TScontrolButtonPressedShort(), TScontrolRotorTurnedCW(), TScontrolRotorTurnedCCW() обеспечивает:
• изменение на экране дисплея значений того или иного параметра, а также движение рамки в меню из Рисунка 4 — при повороте ротора и коротком нажатии на кнопку.
• установку в 1 значения поля menu.TSsaveFlag и возврат к меню из Рисунка 3 при выборе пункта «save» меню из Рисунка 4.

7. DScontrol() и вложенные в неё DScontrolButtonPressedShort(), DScontrolRotorTurnedCW(), DScontrolRotorTurnedCCW() ответственны за те же действия, что и функции из п.6, но для меню из Рисунка 5.

Общее управление Центральным модулем

Общее управление ЦМ осуществляется функциями из файлов device.

device.h

device.cpp


Как видите:
1. В обработчиках прерываний от nRF24L01 и DS1307 лишь устанавливаются в 1 значения полей device.payloadReceivedFlag и device.colonBlinkFlag, соответственно.

2. В функции deviceInit() при подаче питания/сбросе:
• инициализируются все внешние устройства,
• локально и глобально разрешаются прерывания.

3. В функции deviceControl() прописана реакция МК на:
• прерывания от RTC и трансивера,
• нажатия кнопки и поворот ротора,
• выбор пункта «save» меню из Рисунков 4 и 5.

4. Функция getTime() считывает из DS1307 текущее значение времени, а затем помещает значения десятков и единиц часов и минут в соответствующие поля структуры menu.

5. Функция setTime() «склеивает» значения десятков и единиц часов и минут, выбранных в меню из Рисунка 4, а затем записывает их в RTC.

6. Функции getDate() и setDate() производят те же действия, что и две предыдущие, только по отношению к значениям даты.

7. Функция getTemperature() вычленяет из двух полученных от ПМ байтов значения знака, десятков, единиц и десятых долей текущей температуры и размещает их в соответствующих полях структуры menu.

Код Периферийного модуля

Код управления ПМ занимает 4.8 кБайт флэш-памяти и 10 байт ОЗУ.

Контроль за температурным датчиком

За корректную работу DS18B20, даташит которого выложен в архив статьи, отвечает код следующих файлов.

OneWire.h

OneWire.cpp

DS18B20.h

DS18B20.cpp

Поясню детали работы метода readTemperature():
1. Поскольку в ПМ используется лишь один датчик, для обращения к нему выбрана общая команда SKIP ROM.

2. Посредством команды CONVERT T запускается измерение датчиком температуры. При этом, требуется задержка в 750 мс, поскольку дефолтное разрешение DS18B20 – 12 бит (смотрите Таблицу 2 даташита).

3. Команда READ SCRATCHPAD позволяет считать данные из памяти датчика. В рамках проекта достаточно чтения первых двух байт, в которых и содержится значение температуры.

4. Результат измерения возвращается в формате float. Однако, при необходимости можно воспользоваться и непосредственно значениями считанных байтов, для хранения которых предусмотрено поле data класса. Именно этот вариант и реализован в проекте.

Код для трансивера ПМ

Для контроля за трансивером ПМ применялась та же библиотека nRF24, что и в случае с ЦМ.

Отличия в реализации следующие:
а) Входной аргумент метода begin()PTX,

б) Большую часть времени трансивер посредством метода powerDown() погружён в сон, из которого выводится с помощью метода powerUp() лишь для передачи текущего значения температуры.

Управление энергопотреблением МК

С целью максимально снизить энергопотребление ATtiny85 оформлены файлы sleep, представленные ниже.

sleep.h

Следует пояснить, что переменная wdtCounter предназначена для подсчёта количества прерываний сторожевого таймера, а макроопределение WDT_COUNTER_MAX задаёт её максимальное значение.

sleep.cpp

Как видите:
а) В функции sleepInit():
• для МК выбирается режим сна Power Down,
• включается сторожевой таймер с периодом счёта 8 секунд, а так же разрешается его прерывание,

б) Функция sleepOn() погружает МК в сон посредством ассемблерной инструкции «sleep».

Общее управление ПМ

Общий контроль за работой ПМ осуществляется посредством файлов device, код которых приведён ниже.
device.h

device.cpp


Коротко о том, как работает код.При инициализации ПМ микроконтроллер переводится в режим сна Power Down, из которого выводится посредством прерывания сторожевого таймера. Поскольку максимальный период счёта последнего составляет 8 секунд, в обработчике прерывания происходит инкремент переменной wdtCounter и лишь по достижению ею значения 450 (т.е. один раз в час) микроконтроллер:
• выводится из состояния сна,
• измеряет посредством DS18B20 температуру,
• будит трансивер и отправляет ЦМ 2 байта со значением температуры,
• возвращает трансивер в режим сна,
• сам погружается в сон.

Внешнее оформление часов

Все элементы ЦМ уместились в корпусе размером 66х66х50 мм, а ПМ — 53х53х25 мм. Детали корпусов обоих модулей и ручка энкодера были смоделированы в онлайн-среде Tinkercad и распечатаны на 3-D принтере ANYCUBIC I3 MEGA, а их объектные файлы выложены в архив статьи.


Рисунок 7. 3-D модели корпуса, крышки и ручки энкодера для ЦМ


Рисунок 8. 3-D модели корпуса и крышки для ПМ


Файлы

🎁Файлы к статье. Исходный код; корпуса для 3D-печати  218.94 Kb ⇣ 14

Благодарю за внимание!
 

Читательское голосование

Нравится

Статью одобрили 19 читателей.

Для участия в голосовании зарегистрируйтесь и войдите на сайт с вашими логином и паролем.
 

Поделись с друзьями!

 

 

Связанные материалы

 

Схема на Датагоре. Новая статья Часы на ГРИ и К155ИД1. Нужна помощь... Доброго времени суток! Сделал часы на газоразрядных индикаторах с динамической индикацией на...
Схема на Датагоре. Новая статья Электронные самоделки. Кашкаров А. П.... Кашкаров А. П. Электронные самоделки. — СПб.: БХВ-Петербург, 2007. −304 с: ил. Представлены...
Схема на Датагоре. Новая статья Электронные усилители. Г. С. Рамм... Электронные усилители. Г. С. Рамм, 1966г. Ламповые и полупроводниковые усилители рассматриваются с...
Схема на Датагоре. Новая статья Электронные регуляторы громкости, баланса и тембра... Электронные регуляторы громкости, баланса и тембра. Безымянная брощюра, но не менее ценная от...
Схема на Датагоре. Новая статья Электронные устройства для дома. Евсеев А. Н.... Евсеев Андрей Николаевич Электронные устройства для дома. — М.: Радио и связь, 1994г. — 144 с: ил....
Схема на Датагоре. Новая статья 6Ф5П. Триод-пентод... Не хватает в нашем справочнике даташитов на электронные Лампы. Попробую исправить положение. 6Ф5П....
Схема на Датагоре. Новая статья Радиоэлектроника для чайников. Гордон Мак-Комб, Эрл Бойсен... Мечтаете ли вы конструировать свои собственные электронные штучки? Хотите ли вы знать, как...
Схема на Датагоре. Новая статья Микрорепортаж: часы из датагорского кита Simplex Clock в кухонном гарнитуре... Привет, дрУги! Я коротко и по делу. Всего пара «говорящих» фоток. Порадовал жену. В реале смотрится...
Схема на Датагоре. Новая статья Помощь в создании скетча Arduino часов-термометра DS1302... Здравствуйте жители Датагора! Решил я попробовать себя в Arduino Купил Arduino UNO, светодиодом...
Схема на Датагоре. Новая статья Даташит DS1307, DS1307N, DS1307Z datasheet... Часы реального времени с последовательным интерфейсом DS1307 – это малопотребляющие полные...
Схема на Датагоре. Новая статья 3 в 1 для Самоделкина. Кашкаров А. П.... 3 в 1 для Самоделкина. Кашкаров А. П. Издательство: НТ Пресс Год: 2008 Страниц: 257 Язык: Русский...
Схема на Датагоре. Новая статья Сборка и программирование мобильных роботов в домашних условиях. Жимарши Ф.... Сборка и программирование мобильных роботов в домашних условиях. Фредерик Жимарши. Издательство: НТ...
 

Комментарии, вопросы, ответы, дополнения, отзывы

 

<
Читатель Датагора

Maroc

Комментарий # 1 от 30-03-22, 16:58.
  • С нами с 7.12.2014
  • 22 комментария
  • 0 публикаций
 
Подобные миниатюрные устройства все плотнее окружают нас и мы уже не задумываемся, каким концентратом знаний они являются. Автору спасибо за интересную экскурсию и подробный рассказ как есть устроены современные "ходики" и "градусники"))).

Ну, а фраза " ...использовался код.., который, при необходимости, перекладывался мною с ассемблера или С на С++" вынуждает меня, человека так и не покорившего асм, снять шляпу!
Скажите, Аян, как долго Вы этому волшебству учились?

<
Читатель Датагора

AYAN

Комментарий # 2 от 30-03-22, 20:03.
  • С нами с 3.01.2022
  • 4 комментария
  • 1 публикация
 
Спасибо, Виталий!🙂
Начиналось с детства, когда отец делал для меня всякие устройства на МК и привлекал сначала в качестве наблюдателя, а потом - помощника. Потом, всё это перешло в увлечение. Последние полтора года занимаюсь программированием достаточно плотно.

<
Читатель Датагора

Datagor

Комментарий # 3 от 30-03-22, 21:02.
  • С нами с 26.02.2006
  • 2 494 комментария
  • 275 публикаций
 
Присоединяюсь к Виталию.
Поздравляю Аяна с первой публикацией.

Аян, молоток! И не удивительно при таком бате! 😉
Сорвём покровы, это камрад Ербол, постоянный автор на Датагоре.

<
Читатель Датагора

AYAN

Комментарий # 4 от 30-03-22, 21:17.
  • С нами с 3.01.2022
  • 4 комментария
  • 1 публикация
 
Спасибо, уважаемый Игорь!
Да, с наставником мне повезло!🙂

<
Читатель Датагора

Maroc

Комментарий # 5 от 31-03-22, 17:47.
  • С нами с 7.12.2014
  • 22 комментария
  • 0 публикаций
 
Цитата Datagor
😉 Сорвём покровы...
Терзали меня смутные догадки....🤨.
Это ж замечательно, что такая преемственность существует!
Отдельно хочется стиль статьи похвалить: грамотная техническая речь - она же как поэзия, только инженерная! Браво, Аян!👍

<
Читатель Датагора

AYAN

Комментарий # 6 от 31-03-22, 21:11.
  • С нами с 3.01.2022
  • 4 комментария
  • 1 публикация
 
Виталий, боюсь, что комплимент - не по адресу🙂.
Первоначальный текст статьи подвергся тотальной корректировке со стороны отца. Так что, именно в плане технической грамотности изложения мне есть над чем работать.

<
Читатель Датагора

geldiev

Комментарий # 7 от 17-04-22, 16:36.
  • С нами с 6.04.2015
  • 63 комментария
  • 0 публикаций
 
Круто! Большое спасибо за материалы. Один вопрос - интерфейс на латинице уважаемому пользователю часто будет нужен? Мне самому, изучавшему интерфейсы в 90х, до сих пор латиница привычнее, иногда, садясь за чужой компьютер с кириллической локализацией ничего не понимаю...

<
Читатель Датагора

AYAN

Комментарий # 8 от 17-04-22, 17:25.
  • С нами с 3.01.2022
  • 4 комментария
  • 1 публикация
 
Цитата geldiev
...интерфейс на латинице уважаемому пользователю часто будет нужен?

Спасибо!
На самом деле, по просьбе деда я изменил интерфейс на кириллицу 🙂.

Информация
Вы не можете участвовать в комментировании.