1 2 3 4 5 6 7 8 9 10 10/10 9,84оценок: 31

Ракетный котел - 2

Тема в разделе "Котлы, горелки, котельное об-е своими руками", создана пользователем Perelesnik, 19.07.17.

Статус темы:
Закрыта.
  1. arsenty
    Регистрация:
    15.01.15
    Сообщения:
    3.100
    Благодарности:
    1.081

    arsenty

    Живу здесь

    arsenty

    Живу здесь

    Регистрация:
    15.01.15
    Сообщения:
    3.100
    Благодарности:
    1.081
    По мойму минимум Мега, зачем усложнять будущее. ...?!
     
  2. V757V
    Регистрация:
    23.11.11
    Сообщения:
    1.683
    Благодарности:
    633

    V757V

    Живу здесь

    V757V

    Живу здесь

    Регистрация:
    23.11.11
    Сообщения:
    1.683
    Благодарности:
    633
    Адрес:
    Москва
    Я на многие приблуды ставил блютуз модули. Удобно при отладке, а когда отлажено, то фактически нет необходимости. Ну и можно обойтись без встроенного в контроллер дисплея, информацию принимаешь на телефон или планшет и управляешь с него. Оно как бы есть, стоит недорого, есть некоторое полезное улучшение - но целесообразности особой нет. А по радиоканалу подключать исполнительные механизмы я боюсь, радиосвязь носит статистический характер.
     
  3. Perelesnik
    Регистрация:
    01.02.13
    Сообщения:
    991
    Благодарности:
    4.616

    Perelesnik

    Живу здесь

    Perelesnik

    Живу здесь

    Регистрация:
    01.02.13
    Сообщения:
    991
    Благодарности:
    4.616
    Адрес:
    Черкассы
    Да всё уже, "не вынесла душа поэта", сегодня с утра сел на маршрутку и поехал в магазин. Ну, по стоимости получилось ровно в 4 раза дороже, чем Nano... но если брать через Инет, то будет всего в 3 раза дороже.
    Ладно, не в этом суть. Малехо выскочил из запланированных габаритов прибора - так у меня и модуль контроллера, и БП, и радиомодуль и... что там еще, ну в общем, всё это хозяйство помещалось ровненько под экраном, по габаритам экрана. А теперь придется все строить в 3 этажа.
    20171225_145232.JPG
    Ну вот так, ATmega328 - всего чуть-чуть не хватало для нормального функционала, а ATmega2560 - ну уж точно в пару раз больше, чем нужно для котла даже при всей фантазии. Принцип разумной достаточности немного не соблюдается.
    Рано утром думал над тем, чтобы поместить в главный прибор на котле пару NANO, связать их по последовательному порту и распределить между ними задачи... но попробовав, осознал, что оно того явно не стоит.
    Ну еще и целых 4 аппаратных UART на Меге - вот это уж явно не лишнее здесь.
     
  4. alarin
    Регистрация:
    29.07.16
    Сообщения:
    8.662
    Благодарности:
    3.751

    alarin

    Живу здесь

    alarin

    Живу здесь

    Регистрация:
    29.07.16
    Сообщения:
    8.662
    Благодарности:
    3.751
    Адрес:
    Казахстан, Алма-Ата
    @Perelesnik, I/O или памяти не хватило?
     
  5. Perelesnik
    Регистрация:
    01.02.13
    Сообщения:
    991
    Благодарности:
    4.616

    Perelesnik

    Живу здесь

    Perelesnik

    Живу здесь

    Регистрация:
    01.02.13
    Сообщения:
    991
    Благодарности:
    4.616
    Адрес:
    Черкассы
    I/O можно бы было увеличить через сдвиговый регистр... но пришлось бы ставить еще одну печатную плату, чего мне как-то не очень хотелось. Да и мне нравится обращаться к выводам напрямую, так просто удобнее, особенно, когда тело программы объемное и на выводы навешено совершенно разное. Еще проблема с количеством ШИМ - выходов, еще с количеством доступных аппаратных прерываний...
    Сдвиговым регистром такое нормально не решается.
    Был вариант пустить периферию через I2c, но там тоже свои "грабли" имеются. + дополнительные платы...
    И в куче это все усложняет сам код и уменьшает надежность системы. Некоторые датчики вообще изначально предназначены для работы напрямую с контроллером, а при попытке работать с ними опосредованно, начинаются такие "танцы с бубном", что я вряд ли пожелаю себе такое.
    По памяти - памяти пока хватало, выше 80% на Нано я не перегружал... но приходилось отказываться от некоторых объемных вещей типа нескольких шрифтов, иконок и возможности динамического построения графиков прямо на экране контроллера. Без этого можно и обойтись.
    Однако... хотелось бы предусмотреть возможность выбора в меню нескольких предустановленных алгоритмов управления, настройка коэффициентов ПИД там же, логирование на флешку в контроллере... а это еще памяти требует. Немного, но в целом сказывается на общий объем.
    То есть, в ограничение памяти я всё равно уткнулся бы рано или поздно.

    А сейчас... а сейчас я уже второй день ищу нормальный протокол пакетной передачи данных. Желательно, уже прописанный в библиотеке и удобный для написания кода. Нужно одновременно передавать с десяток значений (некоторые из них весом 2 байта).

    Пока ничего адекватного не нашел.
     
  6. alarin
    Регистрация:
    29.07.16
    Сообщения:
    8.662
    Благодарности:
    3.751

    alarin

    Живу здесь

    alarin

    Живу здесь

    Регистрация:
    29.07.16
    Сообщения:
    8.662
    Благодарности:
    3.751
    Адрес:
    Казахстан, Алма-Ата
    @Perelesnik,
    А может не стоит заморачиваться по поводу пакетной передачи, это надо было сразу под Езернет затачивать. Последывательный порт же есть, поставьте флаги для разделения данных и сливайте в виде одного текстового файла. Потом можно будет макрос в Екселе сделать, и всю дату в таблицу свести. В макрос и математику можно будет забить, если какую либо функцию рассмотреть понадобится. Как макрос сделать подскажу. Программы бьющие файл по датам есть, так, что будет папки с суточными данными. Только флэшку надо будет приспособить, чтобы буфер по времени был
     
  7. Perelesnik
    Регистрация:
    01.02.13
    Сообщения:
    991
    Благодарности:
    4.616

    Perelesnik

    Живу здесь

    Perelesnik

    Живу здесь

    Регистрация:
    01.02.13
    Сообщения:
    991
    Благодарности:
    4.616
    Адрес:
    Черкассы
    В общем, нашел вариант.
    Приведу тут, вдруг кому для чего понадобится.
    Все нужные переменные гружу в структуру:

    struct Datamain{
    byte id;
    int settherm;
    int LCDled;
    long time;
    }text;

    text. id = id;
    text. LCDled = LCDled;
    text. settherm = settherm;
    text. time = time;
    radio. write(&text, sizeof (text);

    То есть, сначала задаем элементы структуры (пока их 4, но можно гораздо больше, включая код-идентификатор устройства и контрольные суммы)

    Затем наполняем элементы структуры.

    Ну а потом передаем (в данном случае, через радио, но можно и по проволоке через TX).

    В приемнике аналогично:

    struct Datamain {
    byte id;
    int settherm;
    int LCDled;
    long time;
    } text;

    if (radio.available() {

    radio. read(&text, sizeof (text);

    Описываем структуру, затем наполняем ее из приемника. А потом расшифровываем:

    Serial. print (text.id);
    Serial. print("; ");
    Serial. print (text.LCDled);
    Serial. print("; ");
    Serial. print (text.settherm);
    Serial. print("; ");
    Serial. println (text.time);

    В данном примере для вывода в COM-порт.
    Результат на приемнике такой:
    Снимок.JPG

    Но можно просто забить в переменные и пользоваться на свое усмотрение.
     
    Последнее редактирование: 26.12.17
  8. alarin
    Регистрация:
    29.07.16
    Сообщения:
    8.662
    Благодарности:
    3.751

    alarin

    Живу здесь

    alarin

    Живу здесь

    Регистрация:
    29.07.16
    Сообщения:
    8.662
    Благодарности:
    3.751
    Адрес:
    Казахстан, Алма-Ата
    @Perelesnik, Ну вот и получилось через последывательный порт, теперь текст в таблицу Екселя, а в первой строке по столбцам формула замены текстовых значений на числовые с вычислением функций, если необходимы, например выделение пиковых значений или выделение внережимных зон. Еще один момент, если интересно: Можно определить буфер времени (в памяти) и вести запись в этом буфере по принципу FIFO. Введенные вами переменные задают область значений, внутри которых действует нормализованная функция. При выходе функции за пределы значения, данные из буфера FIFOпереписываются на флэш, причем, таким образом, что например пара минут до события, пара после. Получится своеобразный Трап с историей "заболевания". Такой способ например применяли для регистрации аварийных ситуаций на ЛЭП, ну а я в телекоммуникациях ошибки ловил в системах передач, особенно на этапе, когда одновременно и аналоговые и цифровые системы действовали. За год в городе все косяки выявил на участке и большую часть устранил. Система писала, а я только параметры забивал и трапы анализировал, а так бы по городу мотаться пришлось с приборами...
     
  9. Perelesnik
    Регистрация:
    01.02.13
    Сообщения:
    991
    Благодарности:
    4.616

    Perelesnik

    Живу здесь

    Perelesnik

    Живу здесь

    Регистрация:
    01.02.13
    Сообщения:
    991
    Благодарности:
    4.616
    Адрес:
    Черкассы
    Проверил сегодня дальность связи на 2.4 ГГц без внешней антенны и с минимальной настройкой мощности: (-18dBm) получилось примерно то же, что и на 433 Мгц с антенной. Ну, частота WiFi - это каждый знает, насколько ее обычно хватает через стены. Получается примерно та же картина.
    Для использования в пределах дома через 1-2 стенки - вполне достаточно. А нужно дальше - то просто ставим радиомодуль с внешней антенной и увеличиваем мощность.

    В общем, скорее всего, контроллер сервоприводов буду связывать с главным контроллером не по проводам, а через 2.4 ГГц. Практически там получается около 2 метров проводов: контроллер сервоприводов ставится внизу котла, а основной - или на котле, или на стенке. Там же - усилители термопар бункера и райзера.

    Думаю, будет логично объединить обработку данных этих термопар и управление сервоприводами на одном контроллере, расположенном в нижней части котла, а с основным контроллером сделать двухстороннюю беспроводную связь. Тогда к "нижнему" контроллеру будет идти только 2 провода - питание. И провода будут идти не по стенке котла, а от ближайшей розетки.

    А то сейчас у меня по всей высоте котла идет с десяток проводов (если не больше) от главного контроллера к сервоприводам и усилителям термопар.
    20171213_122800.JPG
    Да и вообще, сейчас общая тенденция к переходу на беспроводную связь...

    То же самое и с "комнатным" сигнализатором. Пожалуй, пришло время избавить его от шнурков, поставить внутренний источник питания на Li-ion или Li-po и иметь возможность располагать в любом месте помещения. И вживить в него собственный экранчик, куда выводить всю цифирь.

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

    Основной код контроллера котла переписываю полностью, с нуля.
    Пока что такое:
    #include "U8glib.h"
    #include <TimerOne.h>
    #include <Button.h>
    #include <EEPROM.h>

    #include <SPI.h>
    #include <nRF24L01.h>
    #include <RF24.h>

    #define Butt 2 / пин кнопки

    RF24 radio (7, 8); / CE, CSN
    const byte address[6] = "00001";

    Button encoderA (3, 4); / сигнал A
    Button encoderB (4, 4); / сигнал B

    int pos = 0; / пооложение энкодера
    byte settherm = 60; / установка температуры воды
    byte presettherm = 60;
    bool buttflag = LOW; / перебираем положение кнопки
    bool thermmenuflag = LOW;
    int menu = 0; / входим в меню по такту кнопки
    int submenu = 0;
    int prepos = 0; / предыдущее положение
    int L = 0; / положение по вертикали на главном экране
    int LCDledPin = 44; / Подключен к выходу 44
    byte LCDled = 120;
    bool LCDflag = LOW;
    byte preLCDled = 120;
    int preposLED = 0;
    byte id = 1;

    long time;
    unsigned long currentTime; / таймер
    float water = 66;

    U8GLIB_ST7920_128X64 u8g (38, 40, 42, U8G_PIN_NONE); /иннициализация дисплея

    void Button() {

    if (digitalRead (Butt) = LOW) { /проверка нажатия на кнопку
    if (buttflag = LOW) {
    menu+;
    if (menu >= 3) {
    menu = 0;
    L = 0;
    EEPROM. write (0, settherm);
    EEPROM. write (1, LCDled);

    }
    if (menu = 1) {
    pos = 0;
    L = 0;
    }
    }
    buttflag = HIGH;

    }
    if (digitalRead (Butt) = HIGH) { /проверка нажатия на кнопку
    buttflag = LOW;
    }

    }

    / обработчик прерывания 250 мкс
    void timerInterrupt() {
    encoderA. filterAvarage(); / вызов метода фильтрации
    encoderB. filterAvarage(); / вызов метода фильтрации
    if (encoderA. flagClick = true) {
    encoderA. flagClick = false;
    if (encoderB. flagPress = true) {
    / против часовой стрелки
    pos-;
    if (menu = 0) {
    L-;
    }
    if (L < 0) {
    L = 0;
    }
    }
    else {
    / по часовой стрелке
    pos+;
    if (menu = 0) {
    L+;
    }
    }
    }
    }

    / рисуем меню
    void menudraw (void) {
    u8g.drawBox (0, submenu * 12, 5, 10);
    u8g.drawHLine (0, submenu * 12 + 10, 120);
    u8g.setFont (u8g_font_7x14Br);
    u8g.setPrintPos (10, 10);
    u8g.print("Back");
    u8g.setPrintPos (10, 22);
    u8g.print("Start");
    u8g.setPrintPos (10, 34);
    u8g.print("Set Therm");
    u8g.setPrintPos (10, 46);
    u8g.print("Brightness %");
    u8g.setPrintPos (98, 46);
    u8g.print (map (LCDled, 0, 255, 0, 100);

    if (thermmenuflag = LOW) {
    u8g.setPrintPos (98, 34);
    u8g.print (settherm);
    u8g.setPrintPos (62, 22);
    u8g.print (time / 60 / 60);
    u8g.setPrintPos (75, 22);
    u8g.print(":");
    u8g.setPrintPos (80, 22);
    u8g.print (time / 60) % 60);
    u8g.setPrintPos (93, 22);
    u8g.print(":");
    u8g.setPrintPos (98, 22);
    u8g.print (time % 60);
    }
    if (menu = 1) {
    submenu = pos;
    if (submenu >= 4) {
    pos = 0;
    }
    if (submenu < 0) {
    pos = 0;
    }
    }

    if (submenu = 0 && menu = 2) {
    menu = 0;
    submenu = 1;
    }
    if (submenu = 1 && menu = 2) {
    menu = 0;
    currentTime = millis();
    pos = 1;
    }
    if (pos = 2 && menu = 2 && thermmenuflag = LOW && LCDflag = LOW) {
    prepos = pos;
    presettherm = settherm;
    thermmenuflag = HIGH;
    }

    if (thermmenuflag = HIGH && LCDflag = LOW) {
    u8g.drawFrame (78, 6, 45, 28);
    u8g.drawFrame (77, 5, 47, 30);
    u8g.setFont (u8g_font_gdb20n);
    u8g.setPrintPos (84, 30);
    u8g.print (settherm);
    settherm = presettherm + pos - prepos;
    if (settherm >= 100 | settherm < 40) {
    prepos = pos;
    }

    }

    if (menu != 2) {
    thermmenuflag = LOW;
    LCDflag = LOW;
    }

    if (pos = 3 && menu = 2 && LCDflag = LOW && thermmenuflag = LOW) {
    preposLED = pos;
    preLCDled = LCDled;
    LCDflag = HIGH;
    }

    if (LCDflag = HIGH && thermmenuflag = LOW) {
    u8g.drawBox (120, submenu * 12, 5, 11);
    LCDled = preLCDled + (pos - preposLED) * 2.55);
    if (LCDled >= 255 | LCDled < 0) {
    preposLED = pos;
    }

    }
    }

    void workdraw (void) {
    u8g.setFont (u8g_font_7x14Br);
    u8g.setPrintPos (77, L + 12);
    u8g.print (time / 60 / 60);
    u8g.setPrintPos (90, L + 12);
    u8g.print(":");
    u8g.setPrintPos (95, L + 12);
    u8g.print (time / 60) % 60);
    u8g.setPrintPos (108, L + 12);
    u8g.print(":");
    u8g.setPrintPos (113, L + 12);
    u8g.print (time % 60);
    u8g.drawFrame (74, L + 0, 54, 14);
    u8g.drawFrame (0, L + 0, 34, 39);

    u8g.drawLine (35, L + 0, 72, L + 0);
    u8g.drawLine (35, L + 0, 35, L + 38);
    u8g.drawLine (72, L + 0, 72, L + 15);
    u8g.drawLine (72, L + 15, 127, L + 15);
    u8g.drawLine (35, L + 38, 127, L + 38);
    u8g.drawLine (127, L + 15, 127, L + 38);
    u8g.setPrintPos (4, L + 12);
    u8g.print("Set:");
    u8g.setPrintPos (37, L + 12);
    u8g.print("Water");
    u8g.setFont (u8g_font_gdb20n);
    u8g.setPrintPos (1, L + 36);
    u8g.print (settherm);
    u8g.setPrintPos (38, L + 36);
    u8g.print (water);

    u8g.setFont (u8g_font_7x14Br);
    u8g.drawFrame (0, L - 15, 128, 14);
    u8g.setPrintPos (2, L - 3);
    u8g.print("Riser:");
    u8g.drawFrame (0, L - 30, 128, 14);
    u8g.setPrintPos (2, L - 18);
    u8g.print("Bunker:");
    }

    void setup() {

    Serial. begin (9600);
    if (EEPROM.read (0) >= 100) {
    settherm = 60;
    }
    else {
    settherm = EEPROM. read (0);
    }

    LCDled = EEPROM. read (1);

    radio. begin();
    radio. openWritingPipe (address);
    radio. setPALevel (RF24_PA_MIN);
    radio. stopListening();

    pinMode (2, INPUT);
    pinMode (LCDledPin, OUTPUT);
    attachInterrupt (0, Button, CHANGE); /прерывание по изменению пина №2 (для Arduino UNO)
    Timer1.initialize (250); / инициализация таймера 1, период 250 мкс
    Timer1.attachInterrupt (timerInterrupt, 250); / задаем обработчик прерываний
    u8g.firstPage();
    do {
    workdraw();
    } while (u8g.nextPage();

    }

    void loop()
    {
    time = (millis() - currentTime) / 1000; / таймер времени горения закладки топлива
    analogWrite (LCDledPin, LCDled);

    if (menu = 0) {
    u8g.firstPage();
    do {
    workdraw();
    } while (u8g.nextPage();

    }

    if (menu >= 1) {
    u8g.firstPage();
    do {
    menudraw();
    } while (u8g.nextPage();
    }

    struct Datamain {
    byte id;
    int settherm;
    int LCDled;
    long time;
    } text;

    text. id = id;
    text. LCDled = LCDled;
    text. settherm = settherm;
    text. time = time;

    radio. write(&text, sizeof (text);

    delay (100);

    Serial. println (text.LCDled);
    Serial. println (text.settherm);
    }

    Так как код обещается быть объемным, то изначально делю его на отдельные функции. Иначе заблужусь)

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

    ЗЫ: стоит ли выносить работу над контроллером ракетного котла в отдельную тему? Просто для многих коллег это "китайская грамота", поэтому не сильно интересно...
    А я всю эту зиму планирую потратить именно на разработку такого контроллера. Ничего другого не предвидится по котлу.
     
  10. King1972
    Регистрация:
    12.06.12
    Сообщения:
    708
    Благодарности:
    267

    King1972

    Живу здесь

    King1972

    Живу здесь

    Регистрация:
    12.06.12
    Сообщения:
    708
    Благодарности:
    267
    Адрес:
    Донбасс
    Руслан, неудобно просить, но найдётся ли у вас возможность померить температуру
    в колпаке, над райзером. Не прям вот сейчас, но как-нибудь этой зимой).
    Чтобы знать параметры на обоих концах; аларин уже померил на своём агрегате,
    но для полноты картины хотелось бы знать и ваши цифры.
     
  11. arhiangel
    Регистрация:
    06.02.14
    Сообщения:
    39
    Благодарности:
    12

    arhiangel

    Участник

    arhiangel

    Участник

    Регистрация:
    06.02.14
    Сообщения:
    39
    Благодарности:
    12
    Адрес:
    город Чебоксары
  12. Supervintiks
    Регистрация:
    20.09.12
    Сообщения:
    9.168
    Благодарности:
    10.370

    Supervintiks

    Живу здесь

    Supervintiks

    Живу здесь

    Регистрация:
    20.09.12
    Сообщения:
    9.168
    Благодарности:
    10.370
    Адрес:
    Русь
  13. arhiangel
    Регистрация:
    06.02.14
    Сообщения:
    39
    Благодарности:
    12

    arhiangel

    Участник

    arhiangel

    Участник

    Регистрация:
    06.02.14
    Сообщения:
    39
    Благодарности:
    12
    Адрес:
    город Чебоксары
    @Supervintiks, испытание на устойчивость к перепадам температур (TWB), которое заключается в том, что испытательные образцы нагревают до 1000° С, а затем погружают в холодную водопроводную воду с температурой 5-15°С.
     
  14. Сергей247
    Регистрация:
    30.04.12
    Сообщения:
    6.161
    Благодарности:
    1.867

    Сергей247

    Живу здесь

    Сергей247

    Живу здесь

    Регистрация:
    30.04.12
    Сообщения:
    6.161
    Благодарности:
    1.867
    Адрес:
    Минск
    Применить (и применяют) шамотные трубы возможно в печах, где меньшая теплонапряжённость. Предварительно вдоль разрезают термокомпенсационным швом. Также можно модифицировать шамот обработав его азотной кислотой. Всё это было в первой теме и в теме Огнеупоры.
     
  15. Perelesnik
    Регистрация:
    01.02.13
    Сообщения:
    991
    Благодарности:
    4.616

    Perelesnik

    Живу здесь

    Perelesnik

    Живу здесь

    Регистрация:
    01.02.13
    Сообщения:
    991
    Благодарности:
    4.616
    Адрес:
    Черкассы
    Прошу прощения, полностью углублен в создание контроллера, поэтому не могу вникать в общий ход обсуждения (временно). У меня в голове однозадачная операционная система установлена :faq:

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

    Собственно, работал над двусторонней передачей данных между устройствами.
    "Нижний" контроллер уже умеет работать с термопарами и передавать их значения на "Основной" контроллер. Взамен должен получать значения для сервоприводов (пока получает не это, а данные, предназначенные для "комнатного" модуля, так как еще не прописал алгоритмы сервоприводов, а для теста что-то передавать нужно).
    Практически, пишу код сразу и для "нижнего" контроллера и для "комнатного модуля" сразу - потом просто уберу соответствующие лишние строки и так из одного общего кода сделаю два отдельных.
    Так что пока там прописана и работа с термопарами, и вывод данных от "Основного" контроллера в СОМ-порт, и передача с СОМ-порта установки по температуре воды.
    Винегрет получается, но всё работает.
    #include "max6675.h"
    #include <SPI.h>
    #include <nRF24L01.h>
    #include <RF24.h>
    RF24 radio (7, 8); / CE, CSN
    const byte address1[6] = "00001";
    const byte address2[6] = "00002";
    byte id = 2;
    int settherm;
    float riser;
    float bunker;
    char incomingBytes[7];

    int thermoDO1 = 2; /он же SO
    int thermoDO2 = 3; /он же SO
    int thermoCS = 5;
    int thermoCLK = 6; /он же SCK

    MAX6675 thermocouple1 (thermoCLK, thermoCS, thermoDO1);/ это организовываем подключение термопар
    MAX6675 thermocouple2 (thermoCLK, thermoCS, thermoDO2);

    void setup() {
    Serial. begin (9600);
    radio. begin();
    radio. openWritingPipe (address2);
    radio. openReadingPipe (1, address1);

    radio. setPALevel (RF24_PA_MIN);
    delay (500);
    }
    void loop() {

    struct Datamain {
    byte id;
    int settherm;
    int LCDled;
    long worktime;
    } text;

    struct LowDevice {
    byte id;
    int settherm;
    float riser;
    int bunker;
    } text1;

    riser = thermocouple1.readCelsius();
    bunker = thermocouple2.readCelsius();

    text1.id = id;
    text1.settherm = settherm;
    text1.riser = riser;
    text1.bunker = bunker;

    radio. startListening();

    if (radio.available() {

    radio. read(&text, sizeof (text);

    Serial. print (text.id);
    Serial. print("; ");
    Serial. print (text.LCDled);
    Serial. print("; ");
    Serial. print (text.settherm);
    Serial. print("; ");
    Serial. println (text.worktime);

    }
    delay (200);
    radio. stopListening();
    radio. write(&text1, sizeof (text1);
    delay (200);

    if (Serial.available() > 0) {

    Serial. readBytes (incomingBytes, 6);

    if (atoi (incomingBytes) > 40) {
    settherm = atoi (incomingBytes);
    text1.settherm = settherm;
    }
    }

    }

    И код "Основного" контроллера:
    #include "U8glib.h"
    #include <TimerOne.h>
    #include <Button.h>
    #include <EEPROM.h>

    #include <SPI.h>
    #include <nRF24L01.h>
    #include <RF24.h>

    #define Butt 2 / пин кнопки

    RF24 radio (7, 8); / CE, CSN
    const byte address1[6] = "00001";
    const byte address2[6] = "00002";

    Button encoderA (3, 4); / сигнал A
    Button encoderB (4, 4); / сигнал B

    int pos = 0; / пооложение энкодера
    byte settherm = 60; / установка температуры воды
    byte presettherm = 60;
    bool buttflag = LOW; / перебираем положение кнопки
    bool thermmenuflag = LOW;
    int menu = 0; / входим в меню по такту кнопки
    int submenu = 0;
    int prepos = 0; / предыдущее положение
    int L = 0; / положение по вертикали на главном экране
    int LCDledPin = 44; / Светодиод подключен к выходы 44
    byte LCDled = 120;
    bool LCDflag = LOW;
    byte preLCDled = 120;
    int preposLED = 0;
    byte id = 1;

    float riser;
    float bunker;

    long worktime;
    unsigned long currentTime; / таймер
    float water = 66;

    U8GLIB_ST7920_128X64 u8g (38, 40, 42, U8G_PIN_NONE); /иннициализация дисплея

    void Button() {

    if (digitalRead (Butt) = LOW) { /проверка нажатия на кнопку
    if (buttflag = LOW) {
    menu+;
    if (menu >= 3) {
    menu = 0;
    L = 0;
    EEPROM. write (0, settherm);
    EEPROM. write (1, LCDled);

    }
    if (menu = 1) {
    pos = 0;
    L = 0;
    }
    }
    buttflag = HIGH;

    }
    if (digitalRead (Butt) = HIGH) { /проверка нажатия на кнопку
    buttflag = LOW;
    }

    }

    / обработчик прерывания 250 мкс
    void timerInterrupt() {
    encoderA. filterAvarage(); / вызов метода фильтрации
    encoderB. filterAvarage(); / вызов метода фильтрации
    if (encoderA. flagClick = true) {
    encoderA. flagClick = false;
    if (encoderB. flagPress = true) {
    / против часовой стрелки
    pos-;
    if (menu = 0) {
    L-;
    }
    if (L < 0) {
    L = 0;
    }
    }
    else {
    / по часовой стрелке
    pos+;
    if (menu = 0) {
    L+;
    }
    }
    }
    }

    / рисуем меню
    void menudraw (void) {
    u8g.drawBox (0, submenu * 12, 5, 10);
    u8g.drawHLine (0, submenu * 12 + 10, 120);
    u8g.setFont (u8g_font_7x14Br);
    u8g.setPrintPos (10, 10);
    u8g.print("Back");
    u8g.setPrintPos (10, 22);
    u8g.print("Start");
    u8g.setPrintPos (10, 34);
    u8g.print("Set Therm");
    u8g.setPrintPos (10, 46);
    u8g.print("Brightness %");
    u8g.setPrintPos (98, 46);
    u8g.print (map (LCDled, 0, 255, 0, 100);

    if (thermmenuflag = LOW) {
    u8g.setPrintPos (98, 34);
    u8g.print (settherm);
    u8g.setPrintPos (62, 22);
    u8g.print (worktime / 60 / 60);
    u8g.setPrintPos (75, 22);
    u8g.print(":");
    u8g.setPrintPos (80, 22);
    u8g.print (worktime / 60) % 60);
    u8g.setPrintPos (93, 22);
    u8g.print(":");
    u8g.setPrintPos (98, 22);
    u8g.print (worktime % 60);
    }
    if (menu = 1) {
    submenu = pos;
    if (submenu >= 4) {
    pos = 0;
    }
    if (submenu < 0) {
    pos = 0;
    }
    }

    if (submenu = 0 && menu = 2) {
    menu = 0;
    submenu = 1;
    }
    if (submenu = 1 && menu = 2) {
    menu = 0;
    currentTime = millis();
    pos = 1;
    }
    if (pos = 2 && menu = 2 && thermmenuflag = LOW && LCDflag = LOW) {
    prepos = pos;
    presettherm = settherm;
    thermmenuflag = HIGH;
    }

    if (thermmenuflag = HIGH && LCDflag = LOW) {
    u8g.drawFrame (78, 6, 45, 28);
    u8g.drawFrame (77, 5, 47, 30);
    u8g.setFont (u8g_font_gdb20n);
    u8g.setPrintPos (84, 30);
    u8g.print (settherm);
    settherm = presettherm + pos - prepos;
    if (settherm >= 100 | settherm < 40) {
    prepos = pos;
    }

    }

    if (menu != 2) {
    thermmenuflag = LOW;
    LCDflag = LOW;
    }

    if (pos = 3 && menu = 2 && LCDflag = LOW && thermmenuflag = LOW) {
    preposLED = pos;
    preLCDled = LCDled;
    LCDflag = HIGH;
    }

    if (LCDflag = HIGH && thermmenuflag = LOW) {
    u8g.drawBox (120, submenu * 12, 5, 11);
    LCDled = preLCDled + (pos - preposLED) * 2.55);
    if (LCDled >= 255 | LCDled < 0) {
    preposLED = pos;
    }

    }
    }

    void workdraw (void) {
    u8g.setFont (u8g_font_7x14Br);
    u8g.setPrintPos (77, L + 12);
    u8g.print (worktime / 60 / 60);
    u8g.setPrintPos (90, L + 12);
    u8g.print(":");
    u8g.setPrintPos (95, L + 12);
    u8g.print (worktime / 60) % 60);
    u8g.setPrintPos (108, L + 12);
    u8g.print(":");
    u8g.setPrintPos (113, L + 12);
    u8g.print (worktime % 60);
    u8g.drawFrame (74, L + 0, 54, 14);
    u8g.drawFrame (0, L + 0, 34, 39);

    u8g.drawLine (35, L + 0, 72, L + 0);
    u8g.drawLine (35, L + 0, 35, L + 38);
    u8g.drawLine (72, L + 0, 72, L + 15);
    u8g.drawLine (72, L + 15, 127, L + 15);
    u8g.drawLine (35, L + 38, 127, L + 38);
    u8g.drawLine (127, L + 15, 127, L + 38);
    u8g.setPrintPos (4, L + 12);
    u8g.print("Set:");
    u8g.setPrintPos (37, L + 12);
    u8g.print("Water");
    u8g.setFont (u8g_font_gdb20n);
    u8g.setPrintPos (1, L + 36);
    u8g.print (settherm);
    u8g.setPrintPos (38, L + 36);
    u8g.print (water);

    u8g.setFont (u8g_font_7x14Br);
    u8g.drawFrame (0, L - 15, 128, 14);
    u8g.setPrintPos (2, L - 3);
    u8g.print("Riser:");
    u8g.setPrintPos (55, L - 3);
    u8g.print (riser);
    u8g.drawFrame (0, L - 30, 128, 14);
    u8g.setPrintPos (2, L - 18);
    u8g.print("Bunker:");
    u8g.setPrintPos (55, L - 18);
    u8g.print (bunker);
    }

    void setup() {

    Serial. begin (9600);
    if (EEPROM.read (0) >= 100) {
    settherm = 60;
    }
    else {
    settherm = EEPROM. read (0);
    }

    LCDled = EEPROM. read (1);

    radio. begin();
    radio. openWritingPipe (address1);
    radio. openReadingPipe (1, address2);
    radio. setPALevel (RF24_PA_MIN);
    / radio. stopListening();

    pinMode (2, INPUT);
    pinMode (LCDledPin, OUTPUT);
    attachInterrupt (0, Button, CHANGE); /прерывание по изменению пина №2 (для Arduino UNO)
    Timer1.initialize (250); / инициализация таймера 1, период 250 мкс
    Timer1.attachInterrupt (timerInterrupt, 250); / задаем обработчик прерываний
    u8g.firstPage();
    do {
    workdraw();
    } while (u8g.nextPage();

    }

    void loop()
    {
    worktime = (millis() - currentTime) / 1000; / таймер времени горения закладки топлива
    analogWrite (LCDledPin, LCDled);

    if (menu = 0) {
    u8g.firstPage();
    do {
    workdraw();
    } while (u8g.nextPage();

    }

    if (menu >= 1) {
    u8g.firstPage();
    do {
    menudraw();
    } while (u8g.nextPage();
    }

    struct Datamain {
    byte id;
    int settherm;
    int LCDled;
    long worktime;
    } text;

    struct LowDevice {
    byte id;
    int settherm;
    float riser;
    int bunker;
    } text1;

    text. id = id;
    text. LCDled = LCDled;
    text. settherm = settherm;
    text. worktime = worktime;

    radio. stopListening();

    radio. write(&text, sizeof (text);

    delay (20);
    radio. startListening();
    if (radio.available() {
    radio. read(&text1, sizeof (text1);
    if (text1.settherm > 40) {
    settherm = text1.settherm;
    EEPROM. write (0, settherm);
    }
    riser = text1.riser;
    bunker = text1.bunker;
    }
    delay (20);
    /Serial.println (text.LCDled);
    /Serial.println (text.settherm);
    }

    Завтра уже пропишу все остальные датчики по воде и управление сервоприводами.
    Внешне пока выглядит так:
    20171227_210643.JPG 20171227_210655.JPG

    ЗЫ: супруга очень быстро освоилась с автоматикой, уже знает, как подключить к ноуту, что включить, как посмотреть, и что означают цифры на экране: где температура бункера (и что она означает практически), где температура райзера... Особенно хорошо, что теперь можно прогнозировать время горения закладки топлива с точностью +- час. То есть, супруга в курсе, сколько дров нужно загрузить, допустим, в 15.00, чтобы на ночь грузить около 22.00 по времени.
    Раньше это было более непредсказуемо.

    Понятно, что пока Руслан сидит которую неделю над кучей проводков, физическим котлом (загрузки, чистки, нажимание на кнопочку) заниматься нет вдохновения. Поэтому занимается супруга.
     
    Последнее редактирование: 27.12.17
Статус темы:
Закрыта.