Глава 3. Разработка общих для всех локальных контроллеров аппаратной и программной частей.

Умный дом

Все локальные контроллеры подключаются к информационной сети системы “Умный дом”.

Предыдущая глава     Список статей     Следующая глава

Поэтому у всех контроллеров есть совершенно одинаковая часть электронной схемы, отвечающая за подключение к сети RS-485. Для программной поддержки сети в резидентных программах устройств также есть одинаковые блоки. Существует еще несколько однотипных задач, связанных с сетевыми функциями.

 

Логично один раз написать одинаковую часть программы, разработать общую часть схемы, а потом использовать их во всех локальных контроллерах.  Давайте этим и займемся.

 

Функциональная схема.

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

У меня получилось так.

Функциональная схема

Прежде всего, необходимо управлять драйвером интерфейса RS-485. Это сигналы RX, TX и DE. Последний разрешает работу передатчика драйвера. Рядом с сигналами показан активный уровень. Например, для сигнала DE это высокий уровень. Передатчик будет работать при логической 1 на выводе 2 платы Ардуино.

Этот же вывод будем использовать для управления светодиодом ОБМЕН. Светодиод должен помигивать в момент передачи ответных данных от устройства. Это будет означать, что центральный контроллер обратился именно к нашему контроллеру.

Для работы с сетью необходимы какие-то параметры. Как минимум сетевой адрес. Параметры будут храниться в EEPROM микроконтроллера, и сопровождаться контрольным кодом. Значит, данные могут быть неправильными. Неплохо бы индицировать, что устройство не способно работать или функционирует в ограниченном режиме. Добавим для этого светодиод ОШИБКА, подключим к выводу 3, определим, что он будет светиться при высоком уровне.

Еще необходимо задавать сетевой адрес локального контроллера. Добавим для этого кнопку, как задавать решим позже. При нажатой кнопке на выводе 4 будет низкий уровень.

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

 

Принципиальная схема.

Драйвер MAX485, светодиоды, кнопки мы уже подключали к плате Ардуино. Функциональная схема легко трансформируется в принципиальную.

Принципиальная схема

Отмечу, что на предыдущих схемах вывод RE микросхемы MAX485 был подключен к земле. В новом варианте при передаче данных (сигнал DE высокого уровня), запрещается работа приемника, и микроконтроллер не принимает ненужные данные. Хотя, все будет работать и при подключенном к земле выводе RE.

Мы используем выводы аппаратного UART микроконтроллера RX и TX. Но эти выводы применяются для загрузки резидентной программы из Arduino IDE. Для того чтобы не происходил конфликт в разрыв  сигнала RX я поставил переключатель.

Разрыв цепи RX

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

Для проверки контроллера и отладки программы я подключил макет к конвертеру UART – RS-485 из предыдущей статьи. Просто соединил между устройствами соответствующие сигналы (A и B). Каждый контроллер подключил к компьютеру штатными USB-кабелями. Питание устройства получают от компьютера.

Макет системы Умный дом

 

Общий алгоритм программного обеспечения.

Для начала надо решить, какие общие регистры будут использоваться в локальных контроллерах и определить их формат. Возможно, кто-то не согласится с моим видением этого вопроса. Я постарался выдержать компромисс между универсальностью системы и минимальной нагрузкой на ресурсы микроконтроллера.

Я выбрал такой формат общих данных. Напомню, что минимальная единица данных в сети с протоколом ModBus это 16ти разрядное слово или регистр хранения (2 байта).

Регистр 0. Идентификационная информация.

15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
2 1 0 4 3 2 1 0 7 6 5 4 3 2 1 0
Резерв Версия ПО Тип  контроллера

Регистр 1. Идентификационная информация.

15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
Заводской номер

Регистр 2. Идентификационная информация.

15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
3 2 1 0 3 2 1 0 3 2 1 0 3 2 1 0
десятки единицы десятки единицы
Год Месяц
Дата  выпуска устройства

Регистр 3. Состояние локального контроллера.

15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
Состояние контроллера (пока неопределенно)

Регистр 4. Доступ к EEPROM

15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0
Данное 1 Данное 0

Регистр 5. Доступ к EEPROM.

15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
признаки 11 10 9 8 7 6 5 4 3 2 1 0
- слово запись чтение Адрес EEPROM

В регистре с адресом 0 хранится самая главная идентификационная информация – тип локального контроллера. В зависимости от типа устройства меняются форматы данных, алгоритм управления и т.п. Центральный контроллер должен знать, к какому устройству он обращается.

В регистрах с адресами 1 и 2 содержатся заводской номер и дата выпуска устройства. Можно обойтись без этой информации, но иногда она бывает полезной.

Регистр 3 содержит слово состояния контроллера. Это всевозможные ошибки, этапы алгоритмов, состояние датчиков. В регистре есть общая часть для всех контроллеров и индивидуальные для каждого типа устройства признаки. Определим его формат позже, по мере необходимости.

Регистры 4 и 5 используются для доступа к EEPROM. О них я напишу ниже.

Формат данных, который я определил, играет очень важную роль. Если он выбран неудачно, то изменить его в будущем очень проблематично. Представьте, что мы разработали, отладили, испытали на объекте несколько контроллеров, а затем решили изменить формат общих данных. Придется заново корректировать программное обеспечение и испытывать все устройства.

 

Программа обмена данными по сети RS-485.

Для реализации протокола ModBus будем использовать мою библиотеку Tiny_ModBusRTU_Slave (урок 57).

Я ее немного подправил. Добавил метод setAdress(), позволяющий оперативно устанавливать адрес сетевого устройства. Если у вас старая версия, то загрузите библиотеку по этой ссылке Tiny_ModBusRTU_Slave или ссылке из урока 57. Новая версия появилась 31 марта 2018 года. Новые файлы запишите поверх старых.

Реализуем обмен данными по сети. Используем программу из урока 57.

// локальный контроллер
// обмен по RS-485

#include <Tiny_ModBusRTU_Slave.h>
#include <TimerOne.h>

unsigned int regHoldTable[20];
Tiny_ModBusRTU_Slave slaveRS485(254, 8, regHoldTable, 20, 2); // создаем объект, адрес 1, таймаут 4 мс, массив regHoldTable, размер 10, вывод DE 2

void setup() {
Timer1.initialize(500); // таймера 1, 500 мкс
Timer1.attachInterrupt(timerInterrupt500, 500); // обработчик прерываний
Serial.begin(9600);
}

void loop() {
}

// обработчик прерывания
void timerInterrupt500() {
slaveRS485.update();
}

Загрузить скетч можно по ссылке Glava_3_1 .

Мы просто создали массив регистров хранения и запустили функцию библиотеки Tiny_ModBusRTU_Slave. Получилось удаленное запоминающее устройство. По сети можно записывать и считывать содержимое регистров хранения.

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

Загрузить программу можно по ссылке HoldingReg .

В программе единственное окно.

HoldingReg

Позволяет считывать данные из контроллера, записывать в контроллер. В полях ”Считанные данные” и ”Данные для записи” используется шестнадцатеричная система исчисления, в остальных – десятичная.

Я проверил работу первого скетча. Данные правильно записываются и считываются.

 

Доступ к EEPROM.

Мы собираемся хранить в EEPROM самые разные параметры. Необходимо создать инструмент для записи и чтения данных в этот тип памяти.

Для доступа к EEPROM используются 2 регистра.

Регистр 4. Доступ к EEPROM

15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0
Данное 1 Данное 0

Регистр 5. Доступ к EEPROM.

15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
признаки 11 10 9 8 7 6 5 4 3 2 1 0
- слово запись чтение Адрес EEPROM

Алгоритм операций следующий. Для чтения:

  • В регистр 5 записать код, содержащий:
    • адрес чтения EEPROM;
    • признак “чтение” (бит 12) должен быть установлен.
  • Считать данные из регистра 4.

Информация в EEPROM хранится в байтах. Поэтому при чтении считываются 2 соседних байта. Если будут использоваться оба байта, то адрес должен быть четным.

Для записи:

  • В регистр 4 записать данные для записи.
  • В регистр 5 записать код, содержащий:
    • адрес записи EEPROM;
    • признак “запись” (бит 13) должен быть установлен;
    • если необходимо записать 2 байта, то должен быть установлен признак ”слово”.
  • После этого произойдет загрузка данных в EEPROM.

Запись в EEPROM длительная операция, поэтому она “подвешивает”  микроконтроллер и нарушает ответ сети ModBus. В программах может индицироваться ошибка обмена. Я решил с этим не бороться, поскольку запись в EEPROM редкая операция, необходима только при смене параметров. Да и всегда можно проверить, что записалось.

После чтения или записи одноименные биты в регистре 5 (биты 13 и 12) сбрасываются автоматически после выполнения операции.

Для реализации этого  алгоритма я добавил к предыдущему скетчу блок ”доступ к EEPROM”.

Новый скетч можно загрузить по ссылке Glava_3_2 .

Проверим его работу программой HoldingReg. Это потребует определенного терпения.

Я проверял так:

  • регистр 4 <- 0x5a (данное для записи);
  • регистр 5 <- 0x2000 (адрес 0, признак записи);
  • можно (но необязательно) прочитать регистр 5 и убедиться, что признак записи сбросился;
  • регистр 5 <- 0x1000 (адрес 0, признак чтения);
  • регистр 4 -> считанное данное.

Для записи двух байтов последовательность будет такая:

  • 4 <- 0x1234;
  • 5 <- 0x6008;
  • 5 -> 0x4008;
  • 5 <- 0x5008;
  • 4 -> данное.

HoldingReg

 

Формат адресов EEPROM.

Раз у нас появился доступ к EEPROM, надо решить, что и как мы будем там хранить. Т.е. определить формат общих данных.

Некоторые данные явно недопустимо менять в рабочем режиме контроллера. Например, если мы от центрального контроллера будем записывать адрес локального устройства или его код типа, то наступит хаос. У контроллеров будут “плясать” адреса, меняться функциональные типы. Система разрушится.

Значит, часть данных необходимо защитить, разрешить запись только в отладочном режиме, например, когда нажата кнопка ”Установка адреса”. Поэтому в адресном пространстве EEPROM определим две зоны: защищенная область и адреса общего назначения.

Я назначил такие адреса и форматы.

Адрес EEPROM Назначение Защита
0 Защищенная
область
32 байта
1
2 Адрес контроллера
3 Адрес контроллера  ^ e5
4 Заводской номер, младший байт
5 Заводской номер, старший байт
6 Заводской номер, младший байт ^ 0xe5
7 Заводской номер, старший байт ^ 0xa3
8 Дата выпуска, младший байт
9 Дата выпуска, старший байт
10 Дата выпуска, младший байт ^ 0xe5
11 Дата выпуска, старший байт ^ 0xa3
. . .
31
32 Общего
назначения
224 байта
. . .
255

В защищенной области пока хранятся:

  • сетевой адрес устройства;
  • заводской номер;
  • дата выпуска.

Все данные для защиты целостности сопровождаются контрольными кодами.

Для работы с EEPROM я написал программу верхнего уровня. Вот ссылка для загрузки EEPROM .

Программа позволяет считывать и записывать 1 или 2 байта в память EEPROM.

Доступ к EEPROM

При операциях с 2 байтами адрес EEPROM должен быть четным.

 

Идентификационная информация.

Следующим этапом добавим в программу контроллера идентификационные данные  и обработку адреса устройства.

Код типа устройства у нас содержится в коде программы, и неправильным быть не может. Если в EEPROM исказятся заводской номер и дата выпуска, особой беды не будет. Передадим центральному контроллеру нули, и он поймет, что данные недостоверны.

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

Сделаем так. Если контрольный код сетевого адреса контроллера показывает, что параметр неверен, то мы вычисляем его по формуле:

сетевой адрес = 192 + (код типа контроллера) & 0x3f

Т.е. мы отводим область адресов 192 … 253 для ”залетевших” контроллеров. А адрес в этой области равен коду типа устройства. Если у нас испортятся адреса у контроллеров разных типов, то система будет работать. Центральный контроллер знает, где искать их. Если в системе ни один тип контроллера не используется дважды, то адреса из этой области могут быть базовыми, они никогда не пересекутся.

Подкорректируем слово состояния контроллера, назначим два признака.

Регистр 3. Состояние локального контроллера.

15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
F E
Состояние контроллера
  • F – фатальная ошибка (контроллер работать не может);
  • E – ошибка защищенной области EEPROM.

Признак F (фатальная ошибка) означает, что устройство не может работать нормально. Например, оторвался датчик или в EEPROM испортился важный параметр. Признак показывает, что человеку нужно вмешаться, переустановить параметры, проверить датчик и т.п.

Признак E говорит, что какой-то параметр в защищенной области EEPROM испорчен.

Очередной скетч можно загрузить по ссылке Glava_3_3 .

В нем добавлена функция reloadIdent(). Она загружает данные для идентификации в первые 3 регистра хранения. При ошибке данных, функция загружает нули, а адрес вычисляет по описанному выше алгоритму.

Программой HoldingReg проверяем, что контроллер стал отвечать на адрес 193 (резервный адрес). В регистрах идентификации правильные данные только в первом: код – 1, версия ПО – 1. Для остальных данных в EEPROM  контрольные коды неправильные, программа подставила нули.

HoldingReg

Запишем в EEPROM правильный адрес и контрольный код к нему. Используем программу верхнего уровня EEPROM.

адрес EEPROM 2 <- 0x32 <-0xd7

0x32 это шестнадцатеричное представление числа 50, а 0xd7 – правильный контрольный код к нему.

Перезапускаем, и видим, что контроллер стал отвечать на адрес 50.

Аналогичным способом запишем в EEPROM правильные данные идентификации:

  • Заводской номер  3458:
    • E 4 < 0x82 < 0xd;
    • E 6 < 0x67 < 0xae;
  • Дату выпуска 03.18:
    • E 8 < 0x03 < 0x18;
    • E 10 < 0xe6 < 0xbb.

Перезапускаем и видим.

HoldingReg

В первых 3х регистрах правильная информация.

 

Циклическая перезагрузка регистров идентификации, светодиод, кнопка.

После изменения данных идентификации мы перезагружали контроллер. Это было необходимо потому, что функцию reloadIdent() разместили в блоке начальных установок setup().

  • Сейчас сделаем так, чтобы перезагрузка происходила циклически раз в секунду.
  • Неизвестно, что “придет в голову “ центральному контроллеру, не запишет ли он что-нибудь в регистры идентификации. Локальный контроллер вернет правильные данные.
  • Обработаем состояние кнопки УСТАНОВКА, используя цифровую фильтрацию. Если кнопка нажата, то активен будет признак buttonPress.
  • Реализуем индикацию состояния контроллера с помощью светодиода ОШИБКА:
    • светодиод мигает с высокой частотой (5 раз в секунду), если нажата кнопка УСТАНОВКА;
    • светодиод редко подмигивает (с периодом секунда горит 0.1 секунду), если ошибка данных защищенной области  EEPROM;
    • светодиод мигает раз в секунду (скважность 0,5) при фатальной ошибке.

Все вышеописанное реализует скетч Glava_3_4 .

При желании, можете проверить.

 

Защита области EEPROM.

Осталось реализовать защиту от записи первых 32 байтов EEPROM и добавить сторожевой таймер.

Алгоритм защиты понятен. Операции записи в EEPROM с адресом меньше 32 разрешаются только в случае, если нажата кнопка УСТАНОВКА.

Установка адреса контроллера происходит загрузкой данных в EEPROM. Но для того, чтобы загрузить данные надо знать адрес устройства. А он может быть неизвестен. Проблема решается так. При нажатии на кнопку УСТАНОВКА сетевой адрес контроллера становится равным 254. Таким образом, все операции с защищенной областью EEPROM производятся по адресу 254.

Все это реализовано в последнем скетче этого урока Glava_3_5 .

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

  • Нажать кнопку контроллера УСТАНОВКА. Устройство прейдет на работу с адресом 254.
  • По нажатию кнопки (стрелочка вниз) программа загружает адрес с контрольным кодом в устройство с сетевым адресом 254.

SetAdress

Программу можно загрузить по ссылке SetAdress .

 

Окончательная проверка.

Мы разработали своеобразный скелет для локальных контроллеров. В принципе это можно назвать даже операционной системой. Для каждого устройства будем добавлять свои функции.

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

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

Сейчас в основной отладочной программе один тип устройства. Это типовой контроллер с общими функциями.

Тестирование Умного дома SmartHouseTest

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

Программу можно загрузить по ссылке SmartHouseTest_1 .

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

 

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

Предыдущая глава     Список статей     Следующая глава

7 комментариев на «Глава 3. Разработка общих для всех локальных контроллеров аппаратной и программной частей.»

  1. Здравствуйте. Шикарные уроки, доходчиво, особенно для таких как я тугодумов. Есть желание создать что то вроде умного дома только функций по меньше заявленных в данном проекте. Скажите каким материалом запасаться, пока изучаю ваш проект, подойдут из Китая (ограничение в финансировании) комплектующие. Почему ваш проект? Потому что все проекты либо на ИК, Блютузе и.т.д. не внушают доверия. Жду с нетерпением следующих уроков-практиков. Удачи Вам и терпения, а главное здоровья!

    • Здравствуйте! Спасибо за приятные слова.
      Не только я определяю функциональность и элементную базу устройства. Я не знаю, какие датчики планирует использовать Михаил.
      В качестве локальных контроллеров используются платы Arduino Nano. Можно заменить на вариант дешевле — Arduino Pro Mini, но к ним надо добавить хотя бы один конвертер USB-UART, например, CH340. Необходимы модули или микросхемы MAX-485. В качестве центрального контроллера планируется использовать MEGA 2560.

      • С контролерами разобрался. В уроке у Вас написано про витую пару, это спец провода с определенным сопротивлением или любые? Кабель с роутера на ПК идет такой же?

        • В зависимости от расстояния, от уровня помех. Я думаю, в доме достаточно простой витой пары. Свивать провода обязательно. Но можно применить кабель для сети Ethernet.

  2. сейчас появились контроллеры esp с встроенным WI FI, я думаю они отлично подадут для умного дома

  3. Не судите строго, я не волшебник, а только учусь… Вопрос: Если я правильно понял смысл интерфейса 485 соединять датчики, контролеры и.т.д. между собой с минимальными искажениям? Если так, то к примеру датчик температуры вывешиваю на улицу, а соединяю его с контролером витой парой через МАХ485, расстояние примерно 2 метра, или 2 метра можно соединить обычными проводами? В интернете примеры все в тестовом режиме ( рукой нагрели во работает!), а на практике нет примеров. Как быть с реальным подключением датчиков?

    • Здравствуйте!
      Интерфейс RS-485 предназначен для создания цифровых сетей. Обычно им объединяют в сеть микроконтроллеры, хотя бывают и датчики с таким интерфейсом. Думаю, что 2 м можно подключить простыми проводами, но почему бы их не свить.
      RS-485 подробно расписан у уроке 60, а в следующем уроке есть пример его использования.

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *