|
Проекты GitHub SourceForge |
BtMesh /
PlumbingControllerКонтроллер водопроводаЗа основу буду брать систему защиты от протечки для стиральной машины. Задачи контроллера:
Характеристики:
Структурная схема![]() Структурно, устройство состоит из 3-х модулей:
На самом деле, отдельный модуль сенсоров не нужен, но из-за ограничения размеров корпуса, все необходимые разъемы не помещаются в один ряд, поэтому их нужно размещать в два этажа отдельными платами. Поэтому, конструктивно удобнее разместить на второй плате контроллер и передавать данные со счетчиков по SPI интерфейсу. Одновременно, на модуле сенсоров будет размещена EEPROM для хранения значения счетчиков. Необходимое количество GPIO портов
Выбор микроконтроллеров
* Atmega8515 не имеет контроллера I2C, поэтому для связи будет использована шина SPI. Конфигурация узлов и моделей BLE MeshПостановка задачи.Чем мы хотим управлять и что хотим контролировать:
Для управления вентилями, разумеется, проще использовать Generic On/Off сервер. Датчики и диагностику вентилей хотелось бы реализовать в Sensor сервере, но тут имеется проблема: в списке Device Property ID спецификации BLE Mesh отсутствуют сенсор протечки и счетчик расхода. Добавлять кастомные параметры совсем не хочется, а вот остаться в рамках спецификации хочется. Поэтому, после небольшого мозгового штурма, было принято волевое решение добавить два Vendor Specific сервера: Volume Consumption Server и Leak Sensor Server. Диагностику вентилей можно повесить на Health Server, код 0x32 (Mechanism Jammed Error). Предлагается управлять не каждым вентилем в отдельности, а организовать их в группы: ввод холодной воды, ввод горячей воды, полотенцесушитель и бойлер. Таким образом, для управления вентилей, вместо 6 элементов в узле можно обойтись 4-мя. Также, запрет одновременного открытия групп бойлера и ввода горячей воды будет в этом случае выглядеть более логичным, нежели какая-то абстрактная карта запретов. Можно, также, объединить группу полотенцесушителя и ввода горячей воды, и сократить количество элементов узла до 3-х, но я все-же хочу оставить возможность управлять полотенцесушителем отдельно, на тот случай, если мне понадобится время от времени его отключать. Таким образом, конфигурация узла видится следующим образом:
В первом (главном) узле, помимо управления вентилем ввода холодной воды, будут серверы состоянии резервной батареи питания (Generic Battery Server) и общий сервер для всех датчиков протечки. Изначально, когда я предполагал использовать для датчиков протечки Sensor Server, для каждого датчика должен был выделяться отдельный элемент узла, но, поскольку у нас будет вендорный сервер, то его протокол будет поддерживать список датчиков, и элемент нужен будет только один. Управление группами вентилей ввода холодной и горячей воды располагается в первых двух элементах. Там же расположены серверы сенсоров температуры и давления, а также, сервер счетчика расхода для соответсвующих каналов холодной и горячей воды. Третий и четвертый элементы отвечают за группы вентилей полотенцесушитея и бойлера, соответственно. Никаких датчиков и счетчиков на их каналах не предусмотрено. В сервере Health планируется отображать следующие параметры:
Протокол взаимодействия BLE Mesh модуля и основного микроконтроллера.В качестве протокола взаимодействия был выбран протокол Tuya, но с немного модифицированными командами для поддержки BLE Mesh сети. Поддерживаемые команды и ответы
Поддерживаемые Data Point IDs
SPI интерфейсВ устройстве имеются две дочерние платы, которые подключаются к основной через SPI интерфейс. Благодаря тому, что в некоторых контроллерах Atmega USART умеет работать в режиме SPI Master, можно использовать SPI не привлекая интерфейс программирования. К сожалению, SPI Slave реализован только в AVR SPI и используется совместно в интерфейсом внутрисхемного программирования, что несколько усложняет отладку ПО. Для простоты, протокол обмена данными для обеих плат унифицирован. С точки зрения мастера, подчиненные устройства представляют собой память с максимальным объемом 256 байт, в котором расположены регистры, через которые и происходит управление. В регисты могут быть только для чтения, только для записи (и тогда из них читаются только FFh) и для чтения/записи одновременно. Протокол SPI интерфейсаВ процессе разработки прошивки для платы сенсоров выяснилась одна неприятная деталь: опрос сенсоров (в особенности датчиков DS18B20) приводило к пропускам приема по SPI, даже если использовались прерывания. Причина так и осталась непонятной: то ли сбой в процессе передачи, то ли библиотека 1Wire блокировала прерывания (хотя в коде я этого не нашел). Время от времени пропадали 1-2 байта, но в целом, данные по SPI как-то передавались. Однако, пропуски вели к срыву statе-машин приемника и передатчика, из-за чего гораздо больше данных передавалось неверно. Было решено разработать протокол передачи данных по SPI таким образом, чтобы как можно раньше обнаружить пропуск, заново синхронизировать автоматы master'а и slave'а и повторить передачу. Изначально, протокол был очень простым и состоял из двух фаз: адрес и данные. Master передавал адрес, в котором (установкой старшего бита) кодировалась команда: чтение/запись. Далее, второй фазой, в зависимости от команды, либо master передавал байт данных при записи, либо slave - в случае чтения. Между фазами обязательно нужно было делать паузу, чтобы slave успевал подготовить данные для отправки. Если одна из сторон должна принимать данные, то в этот момент она передавала пустой байт FFh. Естественно, что в случае пропуска байта slave'ом, происходил рассинхрон и вместо адреса, получался адрес и наоборот. В новом протоколе было решено:
Подробности можно увидеть в таблице ниже.
Благодаря этим двум решениям, у обоих автоматов: master'а и slave'а появляется возможность оперативно выявить рассинхронизацию: однозначно - в начале и конце передачи, и, иногда, в середине. Если ошибку обнаружил master, то он переходит в фазу 1 и делает паузу, равную периоду сброса у slave'а. После этого, передача повторяется. Если передачу не удалось осуществить 10 раз, то передача считается не успешной. Если ошибку обнаружил slave, то он переводи автомат в состояние ошибки, из которой можно выйти только с помощью процедуры сброса, описанной выше. Порядок передачи бит, полярность тактового сигнала и т.д. значения особого не имеют: важно чтобы они совпадали у master'а и slave'а. Испытания подтвердили эффективность данного решения. Количество повторных передач не превышало 3. Этот протокол был реализован в обоих модулях, подключаемых по SPI: в плате управления и в плате сенсоров. Модуль индикации и управления![]() Состоит из трех частей: алфавитно-цифрового LED дисплея (одна строка, 20 символов), дополнительного модуля светодиодной индикации и модуля управления с энкодером и тремя кнопками: Select, Ок и Cancel. Элементы управления и индикации![]()
SPI интерфейс блока UI: светодиоды и кнопкиКарта памятиВсе значения хранятся в формате Little Endian.
СтатусФлаговый регистр "Статус" показывает текущий статус модуля. К сожалению, у модуля отсутствует отдельная линия прерываний, поэтому необходимо периодически опрашивать состояние этого регистра. Значение регистра автоматически сбрасывается при чтении.
События от клавиатуры
Команды светодиодов
* Инвертированное мигание нужно для двухцветных светодиодов, чтобы они по очереди мигали то одним, то другим цветом. Плата сенсоровПоскольку на основную плату поместились только разъемы для подключения вентилей и датчиков протечки, все-равно пришлось бы делать дополнительную плату с разъемами остальных датчиков и расположить ее вторым этажом. Исходя из этого, было разумным на этой плате разместить собственный контроллер, опрашивающий эти датчики, чтобы снять нагрузку с контроллера основной платы и упростить физическую шину подключения. ![]() К плате сенсоров возможно подключить следующие датчики:
Значения счетчиков хранятся в отдельной энергонезависимой памяти и автоматически восстанавливаются при перезагрузки платы. Значения счетчиков можно изменить через SPI интерфейс. Остальные параметры, передаваемые через SPI интерфейс в энергонезависимой памяти не сохраняются и нуждаются в восстановлении основной платой. Имеется механизм, позволяющий основной плате определить нештатную перезагрузку платы сенсоров. EEPROM счетчиковEEPROM счетчиков расположен на отдельной микросхеме 24C02, которую должно быть легко заменить в случае выхода ее из строя. Он имеет емкость 256 байт и должен хранить текущие значения двух счетчиков расхода воды. Поскольку, обновлять значения счетчиков необходимо на каждый импульс, а ресурс EEPROM ограничен, нужен некий трюк, чтобы этот ресурс увеличить. Предлагается разбить весь EEPROM на 16 блоков по 16 байт в каждом и записывать значения в эти блоки циклически. Чтобы модуль мог определить, какой блок записывался последним, то в сам блок нужно добавить счетчик, который бы увеличивался при каждой записи. Таким образом, блок, у которого это поле будет наибольшим и будет последним. Этим самым, мы увеличим ресурс EEPROM в 16 раз. Предлагается следующая структура блока: #define EEPROM_SIGN 0xA500 typedef struct { uint16_t sign; uint16_t cnt; uint32_t val_fs1; uint32_t val_fs2; uint8_t rsvd0; uint8_t rsvd1; uint8_t rsvd2; uint8_t rsvd3; } eeprom_block; Поле sign должно быть равно: EEPROM_SIGN + block_index, где: block_index - это порядковый номер блока, определяющий его положение в адресном пространстве EEPROM. Таким образом, каждый блок имеет уникальный идентификатор, который показывает, что он инициализирован и его поля имеют валидные значения. Хранимые параметрыПараметры настройки модуля хранятся во внутреннем EEPROM микроконтроллера, так как изменяются не часто и быстрая деградация ему не грозит.
SPI интерфейсКарта памятиВсе значения хранятся в формате Little Endian.
Статус прерыванияФлаговый регистр "Статус прерывания" показывает причину, по которой была поднята линия прерывания. Значение регистра автоматически сбрасывается при чтении.
Формат значений.
Калибровочные значения датчиков давления:Модель: XIDIBEI SENSOR XDB401 SERIES Выход: 0.5-4.5В Диапазон измерения: 1МПа (10Бар)
Основная плата![]() Ошибки версии 1.0Кроме минорных ошибок, вроде неверных размеров SMD компонентов, была обнаружена только одна ошибка: неверная схема измерения напряжения линии питания. В целях экономии я решил брать его с вывода EN преобразователя напряжения MP1584, так как штатный делитель напряжения прекрасно подходит для этого случая. Я предполагал, что вывод ADC микроконтроллера обладает высоким сопротивлением и никак не повлияет на работу преобразователя. Однако, выяснилось, что высоким сопротивлением он обладает, когда микроконтроллер включен, а когда выключен, этот вывод очень сильно занижал напряжение на делителе и преобразователь не запускался. Пришлось добавлять на плату "дохлого паучка": еще один делитель напряжения специально для измерений. В версии платы 1.1 данный делитель уже добавлен штатно и внесены другие исправления, но плату я решил не перезаказывать, так как количество исправлений допустимо для устройства, которое будет изготовлено в единственном экземпляре. Еще одно ошибкой можно признать неправильный размер звукового излучателя, но тут ошибка была в заказе, а не в плате: я заказал не тот динамик. Вместо перезаказа или переделки платы я распечатал на 3D принтере переходник и вышло вполне сносно. 21.05.2026г. плата прошла процедуру Poweron'а: все системы были успешно запущены и протестированы. Плата готова к разработке прошивки. ПитаниеДля измерения напряжения на линии питания и на батареи можно использовать опорный источник напряжения 1.1В микроконтроллера или напряжение питания микроконтроллера. Первое нужно калибровать, так как реальное значение опорного напряжения ни разу не точное и имеет разброс: 1.0В - 1.2В. Напряжение же питания регулируется DC/DC преобразователем и, в текущей схеме, настраивается подстроечным резистором и дополнительной программной калибровки в этом случае не требуется. Но напряжение может гулять в зависимости от нагрузки (а может и не гулять, если я все спроектировал верно), поэтому, предпочтительней использовать внутренний линейный стабилизатор с программной калибровкой. Спецификация на прошивку основной платы.Меню настройки и управленияСтруктура
Информация на главном экране
Ссылки
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||