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

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

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

Статус темы:
Закрыта.
  1. StarykovMih
    Регистрация:
    13.11.12
    Сообщения:
    522
    Благодарности:
    176

    StarykovMih

    Живу здесь

    StarykovMih

    Живу здесь

    Регистрация:
    13.11.12
    Сообщения:
    522
    Благодарности:
    176
    Адрес:
    Киев
    Возникает желание "основной контроллер" перенести вниз к сервоприводам и всю математику и управление делать там, а экран вынести вверх "на проводочках"...
     
  2. Оксфорд
    Регистрация:
    12.04.12
    Сообщения:
    9.428
    Благодарности:
    1.871

    Оксфорд

    Живу здесь

    Оксфорд

    Живу здесь

    Регистрация:
    12.04.12
    Сообщения:
    9.428
    Благодарности:
    1.871
    Адрес:
    Уфа
    Столько глупостей про шаговики написали. А промсервы на ЧПУ это совсем не те китайские игрушки, что у вас.
    Применительно к бытовому котлу должно интересовать только ресурс и надежность при сравнительной стоимости.
     
    Последнее редактирование: 12.01.18
  3. Оксфорд
    Регистрация:
    12.04.12
    Сообщения:
    9.428
    Благодарности:
    1.871

    Оксфорд

    Живу здесь

    Оксфорд

    Живу здесь

    Регистрация:
    12.04.12
    Сообщения:
    9.428
    Благодарности:
    1.871
    Адрес:
    Уфа
    В наше время проводочки стоят дороже радио. Про удобство пользования можно вообще помолчать.
     
  4. Perelesnik
    Регистрация:
    01.02.13
    Сообщения:
    991
    Благодарности:
    4.616

    Perelesnik

    Живу здесь

    Perelesnik

    Живу здесь

    Регистрация:
    01.02.13
    Сообщения:
    991
    Благодарности:
    4.616
    Адрес:
    Черкассы
    Код нового проекта на данный момент:
    #define INTERVAL_GET_DATA 1000 / интервала измерений, мс
    #define DS18B20PIN 23 / пин подключения контакта DATA
    #include <OneWire.h>

    #include "U8glib.h"
    #include <TimerOne.h>
    #include <Button.h>
    #include <EEPROM.h>

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

    #include <SdFat.h>

    OneWire ds (DS18B20PIN); / подключаем "далласы"

    int speakerPin = 5; / выход на динамик

    unsigned long millis_int1 = 0; / переменная для таймера "далласов"
    float temp; / данные с какого-то "далласа", котрый сейчас читаем
    float pretemp; / предыдущее значение, считанное с "далласов"
    float rew_water = 0; / обратка
    float forv_water = 0; / подача
    float pre_forv_water = 0; / предыдущее занчение подачи

    / выводы для подключения SD модуля (софтверный SPI)
    const uint8_t SOFT_MISO_PIN = 12;
    const uint8_t SOFT_MOSI_PIN = 11;
    const uint8_t SOFT_SCK_PIN = 13;

    const uint8_t SD_CHIP_SELECT_PIN = 9;
    const uint8_t RF_CHIP_SELECT_PIN = 7;

    byte inSD; / флаг наличия карточки SD

    / SdFat software SPI template
    SdFatSoftSpi<SOFT_MISO_PIN, SOFT_MOSI_PIN, SOFT_SCK_PIN> sd;

    / Test file.
    SdFile file;
    char fnm[30]; / создаем имя файла
    int filenum; / порядковый номер файла

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

    RF24 radio (RF_CHIP_SELECT_PIN, 8); / CE, CSN

    const byte address1[6] = "00001"; / адреса "труб" дл радио
    const uint64_t pipe01 = 0xF0F1F2F3F4LL;
    const uint64_t pipe02 = 0xF0F1F2F3F1LL;

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

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

    int counter = 0; / счетчик для тайминга событий
    int counterwrite = 0; / счетчик тайминга записи на карточку

    float riser; / температура райзера
    float bunker; / температура бункера

    float temperature;

    byte servoprim = 11; / угол сервы первички
    byte servosec = 22; / угол сервы вторички

    long worktime; / счетчик времени горения
    unsigned long currentTime; / таймер загрузки

    unsigned long presentTime;
    unsigned long preMillisRadioWrite;
    long RadioWriteOFF = 900; / время приема радио
    long RadioWriteON = 100; / время передачи радио

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

    / иконки для дисплея:
    static unsigned char u8g_sd_bits[] = {0xFC, 0x03, 0xAA, 0x02, 0xA9, 0x02, 0x01, 0x02, 0x01, 0x02, 0x69, 0x02, 0xA5, 0x02, 0xA9, 0x02, 0x65, 0x02, 0x01, 0x02, 0xFF, 0x03, 0x00, 0x00};
    static unsigned char u8g_rize_bits[] = {0x00, 0x00, 0x38, 0x00, 0x44, 0x08, 0x44, 0x14, 0x44, 0x22, 0x44, 0x08, 0x44, 0x14, 0x54, 0x22, 0x54, 0x08, 0x92, 0x14, 0xBA, 0x22, 0x92, 0x08, 0x44, 0x14, 0x38, 0x22, 0x00, 0x00, 0x00, 0x00};
    static unsigned char u8g_foll_bits[] = {0x00, 0x00, 0x78, 0x00, 0x84, 0x00, 0x84, 0x44, 0x84, 0x28, 0x84, 0x10, 0x84, 0x44, 0x84, 0x28, 0x84, 0x10, 0x84, 0x44, 0x02, 0x29, 0x32, 0x11, 0x32, 0x45, 0x84, 0x28, 0x78, 0x10, 0x00, 0x00};
    static unsigned char u8g_fire_bits[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0xC0, 0x00, 0xC0, 0x01, 0xE8, 0x0B, 0x78, 0x0F, 0x78, 0x1E, 0xDC, 0x1C, 0x9C, 0x18, 0x0C, 0x18, 0x08, 0x08, 0x10, 0x04, 0x00, 0x00};
    static unsigned char u8g_snow_bits[] = {0x00, 0x00, 0xFE, 0x0F, 0xFE, 0x0F, 0x0E, 0x0E, 0xAE, 0x0E, 0x06, 0x0C, 0x56, 0x0D, 0x06, 0x0C, 0xAE, 0x0E, 0x0E, 0x0E, 0xFE, 0x0F, 0xFE, 0x0F, 0x00, 0x00, 0x00, 0x00};

    void Button() {

    if (digitalRead (Butt) = LOW) { /проверка нажатия на кнопку
    if (buttflag = LOW) {
    menu+;
    tone (speakerPin, 800, 200);

    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-;
    tone (speakerPin, 1200, 100);

    if (menu = 0 && pos < 0) {
    pos = 0;
    }

    }
    else {
    / по часовой стрелке
    pos+;
    tone (speakerPin, 1400, 100);

    }
    }
    }

    / рисуем меню
    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();
    filenum = EEPROM. read (2);
    filenum+;
    EEPROM. write (2, filenum);
    sprintf (fnm, "%02d.log", filenum);
    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, 12);
    u8g.print (worktime / 60 / 60);
    u8g.setPrintPos (90, 12);
    u8g.print(":");
    u8g.setPrintPos (95, 12);
    u8g.print (worktime / 60) % 60);
    u8g.setPrintPos (108, 12);
    u8g.print(":");
    u8g.setPrintPos (113, 12);
    u8g.print (worktime % 60);
    u8g.drawFrame (74, 0, 54, 14);
    u8g.drawFrame (0, 0, 34, 38);
    u8g.drawLine (35, 0, 72, 0);
    u8g.drawLine (35, 0, 35, 37);
    u8g.drawLine (72, 0, 72, 15);
    u8g.drawLine (72, 15, 127, 15);
    u8g.drawLine (35, 37, 79, 37);
    u8g.drawLine (79, 37, 79, 51);
    u8g.drawLine (79, 51, 127, 51);
    u8g.drawLine (127, 15, 127, 51);

    u8g.setPrintPos (4, 12);
    u8g.print("Set:");
    u8g.setPrintPos (37, 12);
    u8g.print("Water");
    u8g.setFont (u8g_font_gdb20n);
    u8g.setPrintPos (1, 36);
    u8g.print (settherm);
    u8g.setPrintPos (38, 36);
    u8g.print (forv_water);
    u8g.setFont (u8g_font_7x14Br);
    u8g.setPrintPos (86, 49);
    u8g.print (rew_water);

    if (rew_water >= 1) {
    u8g.drawBox (81, 50 - (int (forv_water) - int (rew_water) / 2, 4, (int (forv_water) - int (rew_water) / 2);
    u8g.drawBox (122, 50 - (int (forv_water) - int (rew_water) / 2, 4, (int (forv_water) - int (rew_water) / 2);
    }

    if (riser - bunker >= 20) {
    u8g.drawXBM (78, 50, 15, 15, u8g_fire_bits);
    }
    else {
    u8g.drawXBM (78, 52, 13, 14, u8g_snow_bits);
    }

    if (inSD = HIGH) {
    u8g.drawXBM (118, 53, 11, 12, u8g_sd_bits);
    }
    else {

    u8g.print(" ");
    }

    if (pre_forv_water <= forv_water) {
    u8g.drawXBM (111, 18, 16, 16, u8g_rize_bits);
    }
    else {
    u8g.drawXBM (111, 18, 16, 16, u8g_foll_bits);
    }

    u8g.drawFrame (0, 39, 78, 25);

    u8g.setFont (u8g_font_5x7r);
    u8g.setPrintPos (2, 49);
    u8g.print("Bunker");
    u8g.setPrintPos (2, 60);
    u8g.print("Riser");

    u8g.setPrintPos (92, 64);
    u8g.print (temperature);

    u8g.setFont (u8g_font_7x14Br);
    u8g.setPrintPos (35, 51);
    u8g.print (bunker);
    u8g.setPrintPos (28, 62);
    u8g.print (riser);

    }

    float get_data_ds18b20() { / функция дляя работы с "далласами"
    byte i;
    byte present = 0;
    byte data[12];
    byte addr[8];
    int Temp;
    float fTemp = 0.0;

    if (!ds.search (addr) {
    ds. reset_search();
    }

    ds. reset();
    ds. select (addr);
    ds. write (0x44, 1);
    present = ds. reset();
    ds. select (addr);
    ds. write (0xBE);

    for (i = 0; i < 3; i+) {
    data = ds. read();
    }
    Temp = (data[1] < 8) + data[0]);

    fTemp = 1.0 * Temp / 16 + (float (Temp % 16) * 1.0 / 16;
    return fTemp;
    }

    void ServoPrim () {

    }

    void setup() {

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

    LCDled = EEPROM. read (1);

    radio. begin();
    radio. setChannel (9); / канал (0-127)
    radio. setDataRate (RF24_1MBPS);
    radio. setPALevel (RF24_PA_HIGH);
    radio. openWritingPipe (address1);
    radio. openReadingPipe (1, pipe01); / открываем трубу с индитификатором "pipe01"
    radio. openReadingPipe (2, pipe02); / открываем трубу с индитификатором "pipe02"

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

    pinMode (SD_CHIP_SELECT_PIN, OUTPUT);
    pinMode (RF_CHIP_SELECT_PIN, OUTPUT);

    analogWrite (LCDledPin, LCDled);

    u8g.firstPage();
    do {
    workdraw();
    } while (u8g.nextPage();
    sd. begin (SD_CHIP_SELECT_PIN, SPI_HALF_SPEED);
    filenum = EEPROM. read (2);
    sprintf (fnm, "%02d.log", filenum);

    pinMode (speakerPin, OUTPUT);
    }

    void loop()
    {
    uint8_t pipeNum = 0;
    float temp = get_data_ds18b20();

    if (millis() - millis_int1 >= INTERVAL_GET_DATA) {
    if (temp < 100) {
    if (pretemp - temp >= 2) {
    rew_water = temp;
    }

    if (temp - pretemp >= 2) {
    pre_forv_water = forv_water;
    forv_water = temp;
    }

    pretemp = temp;
    }

    millis_int1 = millis();
    }

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

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

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

    if (pos < 0) {
    pos = 0;
    }

    struct Datamain {
    byte id;
    long worktime;
    float riser;
    float bunker;
    int settherm;
    float forv_water;
    float rew_water;
    byte servoprim;
    byte servosec;
    } text;

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

    struct HomeDevice {
    byte id;
    float temperature;
    int setthermfromhome;
    } text2;

    text. id = id;
    text. worktime = worktime;
    text. riser = riser;
    text. bunker = bunker;
    text. settherm = settherm;
    text. forv_water = forv_water;
    text. rew_water = rew_water;
    text. servoprim = servoprim;
    text. servosec = servosec;

    if (presentTime - preMillisRadioWrite >= RadioWriteOFF) {

    digitalWrite (SD_CHIP_SELECT_PIN, HIGH);
    digitalWrite (RF_CHIP_SELECT_PIN, LOW);
    radio. stopListening();

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

    if (presentTime - preMillisRadioWrite >= RadioWriteOFF + RadioWriteON) {

    radio. startListening();
    if (radio.available(&pipeNum) {
    if (pipeNum = 1) {
    radio. read(&text1, sizeof (text1);
    riser = text1.riser;
    bunker = text1.bunker;
    }
    if (pipeNum = 2) {
    radio. read(&text2, sizeof (text2);
    temperature = text2.temperature;
    }

    }
    preMillisRadioWrite = presentTime;
    counter+;
    }

    if (counter >= 2) {
    counterwrite+;
    digitalWrite (RF_CHIP_SELECT_PIN, HIGH);
    digitalWrite (SD_CHIP_SELECT_PIN, LOW);

    if (counterwrite >= 30) {

    file. open (fnm, FILE_WRITE);

    if (worktime / 60 / 60 < 10) {
    file. print ("0");
    }
    file. print (worktime / 60 / 60);
    file. print (":");
    if (worktime / 60 % 60 < 10) {
    file. print ("0");
    }
    file. print (worktime / 60) % 60);
    file. print (":");
    if (worktime % 60 < 10) {
    file. print ("0");
    }
    file. print (worktime % 60);

    file. print("; ");
    file. print (riser);

    file. print("; ");
    if (bunker > 0 && bunker < 1030) {
    file. print (bunker);
    }
    else {
    file. print("0");
    }

    file. print("; ");
    file. print (settherm);

    file. print("; ");
    file. print (forv_water);

    file. print("; ");
    if (rew_water < 100 && rew_water > 0) {
    file. print (rew_water);
    }
    else {
    file. print("0");
    }

    file. print("; ");
    file. print (servoprim);

    file. print("; ");
    file. print (servosec);

    file. print("; ");
    file. println (temperature);

    file. close();
    counterwrite = 0;
    }

    file. open (fnm, FILE_READ);

    if (file.read() >= 0) {
    inSD = HIGH;
    }
    else {
    inSD = LOW;
    sd. begin (SD_CHIP_SELECT_PIN, SPI_HALF_SPEED);
    file. close();
    file. open (fnm, FILE_WRITE);

    if (worktime / 60 / 60 < 10) {
    file. print ("0");
    }
    file. print (worktime / 60 / 60);
    file. print (":");
    if (worktime / 60 % 60 < 10) {
    file. print ("0");
    }
    file. print (worktime / 60) % 60);
    file. print (":");
    if (worktime % 60 < 10) {
    file. print ("0");
    }
    file. println (worktime % 60);
    file. close();
    }
    file. close();

    counter = 0;
    }
    }

    }



    К сожалению, скрипт форума "упрощает" два повторяющихся символа до одного, так что там где должно быть 2 символа "=" или "/", будет всего один символ и код, ясное дело, компилироваться не пожелает.

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

    Что из нового в кодах:

    - Теперь лог каждой загрузки пишется в отдельный файл, а не все последовательно в единственный файл - так удобнее разбираться в логах. Имена файлов создаются методом +1 к уже существующему. То есть, если крайний файл был 3. log, то следующий будет 4. log

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

    - Увеличил мощность передатчиков и выделил для всех один определенный канал (будет полезным, когда рядом одновременно работает несколько таких котлов с контроллерами).

    - Доработал экранное отображение информации на домашнем контроллере.

    - Прописал все оповещения на домашнем контроллере cо звуковой и световой сигнализацией (загрузка, тревога).

    Экранчики сейчас выглядят вот так:
    photo_2018-01-13_13-02-24.jpg photo_2018-01-13_13-02-28.jpg
    В принципе, всё уже проверил в разных условиях, повычислял все глюки и несоответсвия в работе кодов, осталось в главном контроллере прописать алгоритмы для первички и вторички (пока просто скопирую со "старого" контроллера с небольшой адаптацией к архитектуре нового кода), и можно потихоньку переносить на котел в качестве рабочей системы.
     
  5. Perelesnik
    Регистрация:
    01.02.13
    Сообщения:
    991
    Благодарности:
    4.616

    Perelesnik

    Живу здесь

    Perelesnik

    Живу здесь

    Регистрация:
    01.02.13
    Сообщения:
    991
    Благодарности:
    4.616
    Адрес:
    Черкассы
    Остальные контроллеры (в один пост не уместилось по количеству символов):
    #include <SPI.h>
    #include <nRF24L01.h>
    #include <RF24.h>
    #include <Adafruit_SSD1306.h>
    #include <OneWire.h>

    RF24 radio (7, 8); / CE, CSN

    #define POWER_MODE 0 / режим питания, 0 - внешнее, 1 - паразитное
    OneWire sensDs (4); / датчик подключен к выводу 14

    #define OLED_RESET 4
    Adafruit_SSD1306 display (OLED_RESET);

    const byte address1[6] = "00001";
    const uint64_t pipe02 = 0xF0F1F2F3F1LL;

    unsigned long presentTime;
    unsigned long preMillisRadioWrite;
    long RadioWriteOFF = 900; / время приема радио
    long RadioWriteON = 100; / время передачи радио

    byte id = 3;
    float tadj = 3.19; / оффсет комнатной температуры

    char incomingBytes[7];
    int greenPin = 6;
    int yelloPin = 5;
    int soundPin = 9;
    byte bufData[9]; / буфер данных ds18b20
    float temperature; / измеренная температура ds18b20

    int alarm = 520; / частота звука тревоги
    int alarmtemp1 = 450; / тревога по температуре в райзере
    int alarmtemp2 = 300; / тревога по температуре в бункере
    int normtemp = 500; / приемлемая температура райзера
    int hightemp = 700; / высокая температура райзера
    int extratemp = 900; / повышенная температура райзера
    int loadtemp = 420; / температура бункера для загрузки
    int loadrizer = 450; / температура райзера для загрузки
    int servoprimlimalarm = 160; / положение сервы первички для тревоги

    void setup() {
    Serial. begin (9600);
    display. begin (SSD1306_SWITCHCAPVCC, 0x3C);
    radio. begin();
    radio. setChannel (9); / канал (0-127)
    radio. setDataRate (RF24_1MBPS);
    radio. setPALevel (RF24_PA_HIGH);
    radio. openWritingPipe (pipe02);
    radio. openReadingPipe (1, address1);

    display. clearDisplay();
    display. display();
    pinMode (greenPin, OUTPUT);
    pinMode (yelloPin, OUTPUT);
    pinMode (soundPin, OUTPUT);
    tone (soundPin, 440, 200);
    delay (500);
    }
    void loop() {

    presentTime = millis();

    sensDs. reset(); / сброс шины
    sensDs. write (0xCC, POWER_MODE); / пропуск ROM
    sensDs. write (0x44, POWER_MODE); / инициализация измерения

    struct HomeDevice {
    byte id;
    float temperature;
    int setthermfromhome;
    } text2;

    text2.id = id;
    text2.temperature = temperature;
    text2.setthermfromhome = 77;

    struct Datamain {
    byte id;
    long worktime;
    float riser;
    float bunker;
    int settherm;
    float forv_water;
    float rew_water;
    byte servoprim;
    byte servosec;

    } text;

    if (presentTime - preMillisRadioWrite >= RadioWriteOFF) {

    radio. stopListening();

    radio. write(&text2, sizeof (text2);
    }

    if (presentTime - preMillisRadioWrite >= RadioWriteOFF + RadioWriteON) {

    radio. startListening();
    if (radio.available() {

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

    }
    preMillisRadioWrite = presentTime;

    Serial. print (text.id);
    Serial. print("; ");

    Serial. print (text2.temperature);
    Serial. print("; ");

    if (text.worktime / 60 / 60 < 10) {
    Serial. print ("0");
    }
    Serial. print (text.worktime / 60 / 60);
    Serial. print (":");
    if (text.worktime / 60 % 60 < 10) {
    Serial. print ("0");
    }
    Serial. print (text.worktime / 60) % 60);
    Serial. print (":");
    if (text.worktime % 60 < 10) {
    Serial. print ("0");
    }
    Serial. print (text.worktime % 60);

    Serial. print("; ");
    Serial. print (text.riser);

    Serial. print("; ");
    if (text.bunker > 0 && text. bunker < 1030) {
    Serial. print (text.bunker);
    }
    else {
    Serial. print("0");
    }

    Serial. print("; ");
    Serial. print (text.settherm);

    Serial. print("; ");
    Serial. print (text.forv_water);

    Serial. print("; ");
    if (text.rew_water < 100 && text. rew_water > 0) {
    Serial. print (text.rew_water);
    }
    else {
    Serial. print("0");
    }

    Serial. print("; ");
    Serial. print (text.servoprim);

    Serial. print("; ");
    Serial. println (text.servosec);

    display. setTextSize (1);
    display. setTextColor (WHITE);
    display. setCursor (0, 0);
    display. println("R:");
    display. setCursor (15, 0);
    display. println (text.riser);
    display. setCursor (70, 0);
    display. println (text.worktime / 60 / 60);
    display. setCursor (85, 0);
    display. println (":");
    display. setCursor (90, 0);
    display. println (text.worktime / 60) % 60);
    display. setCursor (110, 0);
    display. println (":");
    display. setCursor (115, 0);
    display. println (text.worktime % 60);

    display. setCursor (61, 25);
    display. println ("1:");
    display. setCursor (74, 25);
    display. println (text.servoprim);

    display. setCursor (0, 12);
    display. println("B:");
    display. setCursor (15, 12);
    display. println (text.bunker);
    display. setCursor (70, 12);
    display. println("F:");
    display. setCursor (85, 12);
    display. println (text.forv_water);
    display. setCursor (0, 25);
    display. println("S:");
    display. setCursor (15, 25);
    display. println (text.settherm);

    display. setCursor (32, 23);
    display. println (text2.temperature, 1);
    display. drawRect (30, 21, 28, 11, 1);
    display. drawLine (0, 22, 30, 22, 1);
    display. drawLine (58, 22, 128, 22, 1);
    display. drawLine (66, 0, 66, 22, 1);
    display. drawLine (93, 22, 93, 33, 1);

    display. setCursor (97, 25);
    display. println("2:");
    display. setCursor (110, 25);
    display. println (text.servosec);
    display. display();
    display. clearDisplay();
    }

    sensDs. reset(); / сброс шины
    sensDs. write (0xCC, POWER_MODE); / пропуск ROM
    sensDs. write (0xBE, POWER_MODE); / команда чтения памяти датчика
    sensDs. read_bytes (bufData, 9); / чтение памяти датчика, 9 байтов

    if (OneWire: crc8 (bufData, 8) = bufData[8]) {

    temperature = (float)(int) bufData[0] | (int) bufData[1]) < 8) * 0.0625 + 0.03125 - tadj;
    }
    if (text.bunker < alarmtemp2 && text. riser < alarmtemp1 && text. worktime > 2400 && text. servoprim > servoprimlimalarm)

    {
    digitalWrite (yelloPin, HIGH);
    tone (soundPin, alarm);
    delay (400);
    digitalWrite (yelloPin, LOW);
    noTone (soundPin);
    delay (100);
    }

    if (text.riser > normtemp)
    {
    analogWrite (greenPin, 200);
    }
    else
    {
    digitalWrite (greenPin, LOW);
    }

    if (text.riser > hightemp)
    {
    analogWrite (yelloPin, 200);
    }
    else
    {
    digitalWrite (yelloPin, LOW);
    }

    if (text.riser < loadrizer && text. bunker < loadtemp && text. worktime > 1200 && text. servoprim > servoprimlimalarm)

    {
    digitalWrite (greenPin, HIGH);
    delay (200);
    digitalWrite (yelloPin, HIGH);
    delay (200);
    digitalWrite (greenPin, LOW);
    delay (200);
    digitalWrite (yelloPin, LOW);
    delay (200);

    }

    }

    #include "max6675.h"
    #include <SPI.h>
    #include <nRF24L01.h>
    #include <RF24.h>
    #include <Servo.h>

    RF24 radio (7, 8); / CE, CSN

    Servo servo1;
    Servo servo2;

    const byte address1[6] = "00001";
    const uint64_t pipe01 = 0xF0F1F2F3F4LL;
    byte id = 2;
    long worktime;
    float riser;
    float bunker;
    /int settherm;
    float forv_water;
    float rew_water;
    byte servoprim;
    byte servosec;

    unsigned long presentTime;
    unsigned long preMillisRadioWrite;
    long RadioWriteOFF = 500;
    long RadioWriteON = 200;

    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);

    byte presint1;
    byte presint2;
    byte angle1;
    byte angle2;
    byte dev1;
    byte dev2;
    byte flag1;
    byte flag2;
    unsigned long previousMillis = 0;
    unsigned long currentMillis = 0;
    unsigned long previousMillis2 = 0;
    unsigned long currentMillis2 = 0;
    int servoworktime = 2000;

    void setup() {
    /Serial.begin (9600);
    radio. begin();
    radio. setChannel (9); / канал (0-127)
    radio. setDataRate (RF24_1MBPS);
    radio. setPALevel (RF24_PA_MIN);
    radio. openWritingPipe (pipe01);
    radio. openReadingPipe (1, address1);

    presint1 = 200;
    presint2 = 200;
    delay (500);
    }
    void loop() {

    presentTime = millis();

    struct Datamain {
    byte id;
    long worktime;
    float riser;
    float bunker;
    int settherm;
    float forv_water;
    float rew_water;
    byte servoprim;
    byte servosec;

    } text;

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

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

    if (presentTime - preMillisRadioWrite >= RadioWriteOFF) {
    radio. stopListening();

    radio. write(&text1, sizeof (text1);
    riser = thermocouple1.readCelsius();
    bunker = thermocouple2.readCelsius();
    }

    if (presentTime - preMillisRadioWrite >= RadioWriteOFF + RadioWriteON) {

    radio. startListening();

    if (radio.available() {

    radio. read(&text, sizeof (text);
    angle1 = text. servoprim;
    angle2 = text. servosec;

    }
    preMillisRadioWrite = presentTime;
    }

    dev1 = (presint1 - angle1);
    dev2 = (presint2 - angle2);

    if (dev1 > 5)
    {
    flag1 = 1;
    previousMillis = millis();
    presint1 = angle1;
    }

    if (flag1 = 1)
    {

    servo1.attach (10);

    servo1.write (180 - angle1);
    currentMillis = millis();

    if (currentMillis - previousMillis > servoworktime)
    {

    flag1 = 0;
    servo1.detach();
    }

    }

    if (dev2 > 5)
    {
    flag2 = 1;
    previousMillis2 = millis();
    presint2 = angle2;
    }

    if (flag2 = 1)
    {

    servo2.attach (11);

    servo2.write (180 - angle2);
    currentMillis2 = millis();

    if (currentMillis2 - previousMillis2 > servoworktime)
    {

    flag2 = 0;
    servo2.detach();
    }

    }

    }
     
  6. Perelesnik
    Регистрация:
    01.02.13
    Сообщения:
    991
    Благодарности:
    4.616

    Perelesnik

    Живу здесь

    Perelesnik

    Живу здесь

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

    Для Уно другие скетчи! Если хотите строить именно на Уно (или Нано, без особой разницы), то там будут работать такие коды (они же сейчас у меня на работающем котле стоят):

    #include "max6675.h"
    #include <OneWire.h>
    #include <DHT.h>
    #include <Adafruit_SSD1306.h>
    #include <RCSwitch.h>
    #include <PID_v1.h>

    #define POWER_MODE 0
    #define DHTTYPE DHT11 / DHT 11

    #define OLED_RESET 4
    Adafruit_SSD1306 display (OLED_RESET);

    /Servo servo;

    RCSwitch mySwitch = RCSwitch(); /обзываем радиопередатчик

    OneWire sensDs (7); /куда подключен ds18b20
    const byte dht_pin = 4; /куда подключен датчик влажности

    DHT dht (dht_pin, DHTTYPE);
    int thermoDO1 = 2; /он же SO
    int thermoDO2 = 3; /он же SO
    int thermoCS = 5;
    int thermoCLK = 6; /он же SCK
    byte bufData[9]; / буфер данных
    float temperature; / измеренная температура ds18b20
    float therm1; /райзер
    float pretherm1; /предыдущая температура в райзере
    float therm2; /бункер
    int s1; /угол для сервы вторички
    int st2;
    int s2; /угол поворота сервы первички * 100
    int t1; /ограниченная температура датчика в райзере
    int pot; / данные с потенциометра
    int prepot; /предыдущие данные с потенциометра
    int devpot; /разница предыдущих и текущих данных потенциометра
    int s1flag;

    int potdeg; /градусы с потенциометра
    unsigned long currentTime; / таймер
    unsigned long loopTime; / таймер
    unsigned long currentTimeSend; / таймер
    unsigned long loopTimeSend; / таймер
    unsigned long radiotime; / таймер радио
    unsigned long pottime;
    boolean potflag = false;
    long worktime;
    int radioperiod = 1200; /время на отправку каждой из переменных по радиоканалу
    boolean transflag = false; / флаг целевого сервопривода для передачи данных
    double Setpoint, Input, Output; / PID переменные, дублируют уже существующие, но мне лень менять
    int spid; / готовый угол поворота сервы с ПИД регуляятора

    PID myPID(&Input, &Output, &Setpoint, 5, 0.5, 0.25, DIRECT); /создаем ПИД-регулятор
    / крайние 3 значения ПИД-регулятора содержат всю "магию" процесса -
    / их нужно настроить под себя, насколько быстро заслонка будет реагировать
    / на изменение температуры

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

    void setup() {
    Serial. begin (9600); / это для связи с контроллером сервоприводов
    currentTime = millis();
    loopTime = currentTime;
    pinMode (13, INPUT); / пин потенциометра
    display. begin (SSD1306_SWITCHCAPVCC, 0x3C);

    dht. begin();
    display. clearDisplay();

    mySwitch. enableTransmit (12); /включаем радио

    myPID. SetMode (AUTOMATIC);/включаем ПИД-регулятор
    myPID. SetOutputLimits (2, 180);
    pot = analogRead (A0);
    potdeg = map (pot, 0, 1023, 40, 95); / определяем границы устанавливаемой температуры
    prepot = pot;
    delay (100);
    }

    void loop() {

    radiotime = millis();

    if (digitalRead (13) = HIGH) /кнопка запуска таймера новой закладки топлива
    {
    currentTime = millis();
    loopTime = currentTime;
    display. setTextSize (5);
    display. setTextColor (WHITE);
    display. setCursor (0, 0);
    display. println("START");
    display. display();
    display. clearDisplay();
    }

    /работа с потенциометром

    pot = analogRead (A0); / потенциометр у нас на пине А0
    devpot = pot - prepot;

    if (devpot >= 10 && potflag = false) | (devpot <= -20 && potflag = false) / в смысле, если пользователь крутнул ручку настройки
    {
    potflag = true;
    pottime = radiotime;

    }

    if (potflag = true)
    {

    potdeg = map (pot, 0, 1023, 40, 95); / определяем границы устанавливаемой температуры
    display. setTextSize (5);
    display. setTextColor (WHITE);
    display. setCursor (40, 0);
    display. println (potdeg);
    display. display();
    display. clearDisplay();
    }

    if (radiotime - pottime >= 5000)/ даем 5 секунд ожидания действий пользователя
    {
    prepot = pot;
    potflag = false;

    }

    if (potflag = false) / весь этот остальной цикл программы запускается
    / только когда не меняются данные с потенциометра
    {

    / управление приводом заслонки вторичного воздуха
    therm1 = thermocouplea. readCelsius();
    t1 = constrain (therm1, 100, 1000);
    currentTimeSend = millis();

    if (currentTimeSend - loopTimeSend >= 5000) { / управляем каждым из сервоприводов раз в 5 секунд

    transflag = !transflag;
    loopTimeSend = currentTimeSend;
    s1flag = s1flag + 1;

    }

    if (s1flag >= 4)
    {
    pretherm1 = t1;
    s1flag = 0;

    }

    if (pretherm1 < t1)
    {
    st2 = st2 + (t1 - pretherm1);
    }
    if (pretherm1 > t1)
    {
    st2 = st2 - (pretherm1 - t1);
    }

    st2 = constrain (st2, 2, 180);

    if (t1 <= 400) {
    s1 = 2;
    }
    if (t1 > 400 && t1 <= 450) {
    s1 = (map (st2, 2, 180, 5, 180) + map (t1, 400, 450, 5, 80) / 2;
    }
    if (t1 > 450 && t1 <= 600) {
    s1 = (map (st2, 2, 180, 60, 180) + map (t1, 450, 600, 60, 120) / 2;
    }
    if (t1 > 600 && t1 <= 800) {
    s1 = (map (st2, 2, 180, 100, 180) + map (t1, 600, 800, 100, 160) / 2;
    }
    if (t1 > 800) {
    s1 = (map (st2, 2, 180, 160, 180) + map (t1, 800, 1020, 160, 180) / 2;
    }

    / управление приводом заслонки первичного воздуха

    if (OneWire: crc8 (bufData, 8) = bufData[8])
    {
    temperature = (float)(int) bufData[0] | (int) bufData[1]) < 8) * 0.0625 + 0.03125;

    }

    Input = temperature; /температура с датчика на выходе из теплообменника

    myPID. Compute();/считаем выходной сигнал ПИД-регулятора

    spid = Output;

    Setpoint = potdeg; / заданная температура

    if (temperature - potdeg > 1) {
    s2 = 2;
    }
    else {
    if (spid - (s1 / 2) >= 0 && potdeg - temperature < 3) {
    s2 = spid - (s1 / 2);
    }
    else {
    s2 = spid;
    }
    }
    / отправка данных на контроллер сервоприводов

    if (transflag = false)
    {
    Serial. print (String (s1, DEC); /данные для сервопривода вторички

    }

    if (transflag = true)
    {
    Serial. print (String (constrain (s2, 2, 180) * 100, DEC); /данные для сервопривода первички

    }

    worktime = (millis() - currentTime) / 1000; / таймер времени горения закладки топлива

    float h = dht. readHumidity();
    float t = dht. readTemperature();
    sensDs. reset(); / сброс шины
    sensDs. write (0xCC, POWER_MODE); / пропуск ROM
    sensDs. write (0x44, POWER_MODE); / инициализация измерения
    sensDs. reset(); / сброс шины
    sensDs. write (0xCC, POWER_MODE); / пропуск ROM
    sensDs. write (0xBE, POWER_MODE); / команда чтения памяти датчика
    sensDs. read_bytes (bufData, 9); / чтение памяти датчика, 9 байтов

    therm2 = thermocoupleb. readCelsius();

    / вывод данных на дисплей

    display. setTextSize (1);
    display. setTextColor (WHITE);
    display. setCursor (0, 0);
    display. println (therm1);

    display. setCursor (70, 0);
    display. println (worktime / 60 / 60);
    display. setCursor (85, 0);
    display. println (":");

    display. setCursor (90, 0);
    display. println (worktime / 60) % 60);
    display. setCursor (110, 0);
    display. println (":");

    display. setCursor (115, 0);
    display. println (worktime % 60);

    display. setCursor (110, 24);
    display. println (s1);

    display. setCursor (85, 24);
    display. println (s2);

    display. setCursor (0, 12);
    display. println (therm2);
    display. setCursor (90, 12);
    display. println (temperature);
    display. setCursor (0, 24);
    display. println (t);
    display. setTextSize (2);
    display. setCursor (50, 12);
    display. println (potdeg);
    display. display();
    display. clearDisplay();

    / отправка данных по радиоканалу
    mySwitch. send (s1, 13);
    myPID. Compute();
    delay (100);
    mySwitch. send (t * 100, 14);
    myPID. Compute();
    delay (100);
    mySwitch. send (constrain (s2, 2, 180) * 100, 15);
    myPID. Compute();
    delay (100);
    mySwitch. send (temperature * 100, 16);
    myPID. Compute();
    delay (100);
    mySwitch. send (therm2 * 100, 17);
    myPID. Compute();
    delay (100);
    mySwitch. send (therm1 * 100, 18);
    myPID. Compute();
    delay (100);
    mySwitch. send (worktime, 19);
    myPID. Compute();
    delay (100);
    mySwitch. send (potdeg, 20);
    myPID. Compute();
    delay (100);
    }

    }

    / скетч для Arduino, который принимает данные
    #include <Servo.h>

    Servo servo1;
    Servo servo2;

    String s1;
    int sighn;
    int sint1;
    int sint2;
    int presint1;
    int presint2;
    int angle1;
    int angle2;
    byte dev1;
    byte dev2;
    byte flag1;
    byte flag2;
    unsigned long previousMillis = 0;
    unsigned long currentMillis = 0;
    unsigned long previousMillis2 = 0;
    unsigned long currentMillis2 = 0;
    int worktime = 2000;

    void setup() {

    Serial. begin (9600);
    presint1 = 200;
    presint2 = 200;
    }

    void loop() {

    if (Serial.available() > 0) {

    s1 = Serial. readString();
    sighn = s1.toInt();

    if (sighn <= 180){
    sint1 = sighn;
    }
    else {
    sint2 = sighn/100;
    }

    angle1 = constrain (sint1, 0, 175);
    angle2 = constrain (sint2, 0, 175);

    }
    dev1 = (presint1 - sint1);
    dev2 = (presint2 - sint2);

    if (dev1 > 5)
    {
    flag1 = 1;
    previousMillis = millis();
    presint1 = sint1;
    }

    if (flag1 = 1)
    {

    servo1.attach (10);

    servo1.write (180 - angle1);
    currentMillis = millis();

    if (currentMillis - previousMillis > worktime)
    {

    flag1 = 0;
    servo1.detach();
    }

    }

    if (dev2 > 5)
    {
    flag2 = 1;
    previousMillis2 = millis();
    presint2 = sint2;
    }

    if (flag2 = 1)
    {

    servo2.attach (11);

    servo2.write (180 - angle2);
    currentMillis2 = millis();

    if (currentMillis2 - previousMillis2 > worktime)
    {

    flag2 = 0;
    servo2.detach();
    }

    }
    / Serial. println (sighn);
    }
    #include <RCSwitch.h>

    RCSwitch mySwitch = RCSwitch();

    float s2;
    float t;
    float temperature;
    float therm2;
    float therm1;
    float s1; /угол поворота сервы вторички
    float potdeg;

    long timing;

    int led1 = 4;
    int led2 = 5;
    int led3 = 6;
    int led4 = 7;

    int alarm = 520; / частота звука тревоги
    int alarmtemp1 = 450; / тревога по температуре в райзере
    int alarmtemp2 = 300; / тревога по температуре в бункере
    int normtemp = 500; / приемлемая температура райзера
    int hightemp = 700; / высокая температура райзера
    int extratemp = 900; / повышенная температура райзера
    int loadtemp = 420; / температура бункера для загрузки
    int loadrizer = 450; / температура райзера для загрузки

    unsigned long currentTime;
    unsigned long loopTime;

    const int Pin_tone = 3; / номер порта зуммера

    void setup() {
    Serial. begin (9600);

    currentTime = millis();
    loopTime = currentTime;

    pinMode (Pin_tone, OUTPUT);
    pinMode (led1, OUTPUT);
    pinMode (led2, OUTPUT);
    pinMode (led3, OUTPUT);
    pinMode (led4, OUTPUT);

    digitalWrite (led1, HIGH);
    delay (200);
    digitalWrite (led2, HIGH);
    delay (200);
    digitalWrite (led1, LOW);
    delay (200);
    digitalWrite (led3, HIGH);
    delay (200);
    digitalWrite (led2, LOW);
    delay (200);
    digitalWrite (led4, HIGH);
    delay (200);
    digitalWrite (led3, LOW);
    delay (200);
    digitalWrite (led4, LOW);
    delay (200);

    mySwitch. enableReceive (0); / Receiver on inerrupt 0 => that is pin #2

    }

    void loop() {

    digitalWrite (led4, LOW);

    if (mySwitch.available() {

    int value = mySwitch. getReceivedValue();

    if (mySwitch. getReceivedBitlength() = 13)
    {
    s1 = mySwitch. getReceivedValue();
    }

    if (mySwitch. getReceivedBitlength() = 14)
    {
    t = mySwitch. getReceivedValue() * 0.01;
    }

    if (mySwitch. getReceivedBitlength() = 15)
    {
    s2 = mySwitch. getReceivedValue() * 0.01;
    }

    if (mySwitch. getReceivedBitlength() = 16)
    {
    temperature = mySwitch. getReceivedValue() * 0.01;
    }

    if (mySwitch. getReceivedBitlength() = 17)
    {
    therm2 = mySwitch. getReceivedValue() * 0.01;
    if (therm2 < alarmtemp2 && therm1 < alarmtemp1 && timing > 2400 && s2 > 160)
    {
    digitalWrite (led3, HIGH);
    tone (Pin_tone, alarm);
    delay (400);
    digitalWrite (led3, LOW);
    noTone (Pin_tone);
    delay (100);
    }
    }

    if (mySwitch. getReceivedBitlength() = 18)
    {
    therm1 = mySwitch. getReceivedValue() * 0.01;
    analogWrite (led4, 140);

    if (therm1 > normtemp)
    {
    digitalWrite (led1, HIGH);
    }
    else
    {
    digitalWrite (led1, LOW);
    }

    if (therm1 > hightemp)
    {
    digitalWrite (led2, HIGH);
    }
    else
    {
    digitalWrite (led2, LOW);
    }

    if (therm1 > extratemp)
    {
    digitalWrite (led3, HIGH);
    }
    else
    {
    digitalWrite (led3, LOW);
    }
    if (therm1 < loadrizer && therm2 < loadtemp && timing > 1200 && s2 > 160)
    {
    digitalWrite (led1, HIGH);
    delay (200);
    digitalWrite (led2, HIGH);
    delay (200);
    digitalWrite (led1, LOW);
    delay (200);
    digitalWrite (led3, HIGH);
    delay (200);
    digitalWrite (led2, LOW);
    delay (200);
    digitalWrite (led3, LOW);
    }

    }

    if (mySwitch. getReceivedBitlength() = 19)
    {
    timing = mySwitch. getReceivedValue();
    }

    if (mySwitch. getReceivedBitlength() = 20)
    {
    potdeg = mySwitch. getReceivedValue();
    }

    currentTime = millis();
    if (currentTime >= (loopTime + 5000)
    {
    loopTime = currentTime;

    if (timing / 60 / 60 < 10) {
    Serial. print ("0");
    }
    Serial. print (timing / 60 / 60);
    Serial. print (":");
    if (timing / 60 % 60 < 10) {
    Serial. print ("0");
    }
    Serial. print (timing / 60) % 60);
    Serial. print (":");
    if (timing % 60 < 10) {
    Serial. print ("0");
    }
    Serial. print (timing % 60);

    Serial. print ("; ");
    Serial. print (therm1);
    Serial. print ("; ");
    Serial. print (therm2);
    Serial. print ("; ");
    Serial. print (temperature);
    Serial. print ("; ");
    Serial. print (potdeg);
    Serial. print ("; ");
    Serial. print (t);
    Serial. print ("; ");
    Serial. print (s2);
    Serial. print ("; ");
    Serial. print (s1);
    Serial. println ("; ");

    }

    mySwitch. resetAvailable();
    }

    }

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

    Да и, собственно, мой контроллер должен вскорости уехать в добрые руки, так что мне не на чем будет и испытывать - отлаживать этот код. У меня будет стоять Мега, на ней будет все теперь отлаживаться, под нее и продолжу писать дальше.
     
    Последнее редактирование: 13.01.18
  7. alarin
    Регистрация:
    29.07.16
    Сообщения:
    8.662
    Благодарности:
    3.751

    alarin

    Живу здесь

    alarin

    Живу здесь

    Регистрация:
    29.07.16
    Сообщения:
    8.662
    Благодарности:
    3.751
    Адрес:
    Казахстан, Алма-Ата
    Всех со Старым Новым годом Дорогие Товарищи!
     
  8. Сергей247
    Регистрация:
    30.04.12
    Сообщения:
    6.161
    Благодарности:
    1.867

    Сергей247

    Живу здесь

    Сергей247

    Живу здесь

    Регистрация:
    30.04.12
    Сообщения:
    6.161
    Благодарности:
    1.867
    Адрес:
    Минск
    Присоединяюсь. С наступающим СНГ! :)
     
  9. arsenty
    Регистрация:
    15.01.15
    Сообщения:
    3.097
    Благодарности:
    1.081

    arsenty

    Живу здесь

    arsenty

    Живу здесь

    Регистрация:
    15.01.15
    Сообщения:
    3.097
    Благодарности:
    1.081
    Всех с наступившим старым Новым Годом!...я тоже за МЕГУ, как и Руслан.
     
  10. Supervintiks
    Регистрация:
    20.09.12
    Сообщения:
    9.166
    Благодарности:
    10.365

    Supervintiks

    Живу здесь

    Supervintiks

    Живу здесь

    Регистрация:
    20.09.12
    Сообщения:
    9.166
    Благодарности:
    10.365
    Адрес:
    Русь
    :hello: Photo-0001.jpg тоже слегка :)принял на контакты...звезд в наступившем году
     
  11. V757V
    Регистрация:
    23.11.11
    Сообщения:
    1.683
    Благодарности:
    633

    V757V

    Живу здесь

    V757V

    Живу здесь

    Регистрация:
    23.11.11
    Сообщения:
    1.683
    Благодарности:
    633
    Адрес:
    Москва
    В расширенном режиме иконка "вставить" "код"
    Код:
    .....
    if (a==b) { ...} ; /////
    ....
     
  12. Perelesnik
    Регистрация:
    01.02.13
    Сообщения:
    991
    Благодарности:
    4.616

    Perelesnik

    Живу здесь

    Perelesnik

    Живу здесь

    Регистрация:
    01.02.13
    Сообщения:
    991
    Благодарности:
    4.616
    Адрес:
    Черкассы
    О! Сейчас попробую. Как раз чуть изменил алгоритм главного контроллера на Уно.

    Код:
    #include "max6675.h"
    #include <OneWire.h>
    #include <DHT.h>
    #include <Adafruit_SSD1306.h>
    #include <RCSwitch.h>
    #include <PID_v1.h>
    
    #define POWER_MODE  0
    #define DHTTYPE DHT11 // DHT 11
    
    #define OLED_RESET 4
    Adafruit_SSD1306 display(OLED_RESET);
    
    //Servo servo;
    
    RCSwitch mySwitch = RCSwitch(); //обзываем радиопередатчик
    
    OneWire sensDs (7); //куда подключен ds18b20
    const byte dht_pin = 4; //куда подключен датчик влажности
    
    DHT dht(dht_pin, DHTTYPE);
    int thermoDO1 = 2;  //он же SO
    int thermoDO2 = 3;  //он же SO
    int thermoCS = 5;
    int thermoCLK = 6;  //он же SCK
    byte bufData[9];  // буфер данных
    float temperature;  // измеренная температура ds18b20
    float therm1; //райзер
    float pretherm1; //предыдущая температура в райзере
    float therm2; //бункер
    int s1; //угол для сервы вторички
    int st2;
    int tempdeficite; // недостающие градусы по воде
    int s2; //угол поворота сервы первички * 100
    int t1 ; //ограниченная температура датчика в райзере
    int pot ; // данные с потенциометра
    int prepot ; //предыдущие данные с потенциометра
    int devpot; //разница предыдущих и текущих данных потенциометра
    int s1flag;
    
    int potdeg; //градусы с потенциометра
    unsigned long currentTime; // таймер
    unsigned long loopTime; // таймер
    unsigned long currentTimeSend; // таймер
    unsigned long loopTimeSend; // таймер
    unsigned long radiotime; // таймер радио
    unsigned long pottime;
    boolean potflag = false;
    long worktime;
    int radioperiod = 1200; //время на отправку каждой из переменных по радиоканалу
    boolean transflag = false; // флаг целевого сервопривода для передачи данных
    double Setpoint, Input, Output; // PID переменные, дублируют уже существующие, но мне лень менять
    int spid; // готовый угол поворота сервы с ПИД регуляятора
    
    PID myPID(&Input, &Output, &Setpoint, 5, 0.5, 0.25, DIRECT); //создаем ПИД-регулятор
    // крайние 3 значения ПИД-регулятора содержат всю "магию" процесса -
    // их нужно настроить под себя, насколько быстро заслонка будет реагировать
    // на изменение температуры
    
    MAX6675 thermocouplea(thermoCLK, thermoCS, thermoDO1);// это организовываем подключение термопар
    MAX6675 thermocoupleb(thermoCLK, thermoCS, thermoDO2);
    
    
    
    void setup() {
      Serial.begin(9600); // это для связи с контроллером сервоприводов
      currentTime = millis();
      loopTime = currentTime;
      pinMode(13, INPUT); // пин потенциометра
      display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
    
      dht.begin();
      display.clearDisplay();
    
      mySwitch.enableTransmit(12); //включаем радио
    
      myPID.SetMode(AUTOMATIC);//включаем ПИД-регулятор
      myPID.SetOutputLimits(2, 180);
      pot = analogRead(A0);
      potdeg = map(pot, 0, 1023, 40, 95); // определяем границы устанавливаемой температуры
      prepot = pot;
      delay(100);
    }
    
    void loop() {
    
      radiotime = millis();
    
    
      if (digitalRead (13) == HIGH) //кнопка запуска таймера новой закладки топлива
      {
        currentTime = millis();
        loopTime = currentTime;
        display. setTextSize (5);
        display. setTextColor (WHITE);
        display. setCursor (0, 0);
        display. println("START");
        display. display();
        display. clearDisplay();
      }
    
      //работа с потенциометром
    
      pot = analogRead(A0); // потенциометр у нас на пине А0
      devpot = pot - prepot;
    
    
      if ((devpot >= 10 && potflag == false) || (devpot <= -20 && potflag == false) ) // в смысле, если пользователь крутнул ручку настройки
      {
        potflag = true;
        pottime = radiotime;
    
      }
    
      if (potflag == true)
      {
    
        potdeg = map (pot, 0, 1023, 40, 95); // определяем границы устанавливаемой температуры
        display. setTextSize (5);
        display. setTextColor (WHITE);
        display. setCursor (40, 0);
        display. println (potdeg);
        display. display();
        display. clearDisplay();
      }
    
      if (radiotime - pottime >= 5000)// даем 5 секунд ожидания действий пользователя
      {
        prepot = pot;
        potflag = false;
    
      }
    
    
      if (potflag == false) // весь этот остальной цикл программы запускается
        // только когда не меняются данные с потенциометра
      {
    
    
    
    
    
    
        // управление приводом заслонки вторичного воздуха
        therm1 = thermocouplea.readCelsius();
        t1 = constrain(therm1, 100, 1000);
        currentTimeSend = millis();
    
        if (currentTimeSend - loopTimeSend >= 5000) { // управляем каждым из сервоприводов раз в 5 секунд
    
          transflag = !transflag;
          loopTimeSend = currentTimeSend;
          s1flag = s1flag + 1;
    
        }
    
        if (s1flag >= 4)
        {
          pretherm1 = t1;
          s1flag = 0;
    
        }
    
        if (pretherm1 < t1)
        {
          st2 = st2 + (t1 - pretherm1);
        }
        if (pretherm1 > t1)
        {
          st2 = st2 - (pretherm1 - t1);
        }
    
        st2 = constrain (st2, 2, 180);
    
    
    
        if (t1 <= 400) {
          s1 = 2;
        }
        if (t1 > 400 && t1 <= 450) {
          s1 = (map ( st2, 2, 180, 5, 180) + map ( t1, 400, 450, 5, 80)) / 2;
        }
        if (t1 > 450 && t1 <= 600) {
          s1 = (map ( st2, 2, 180, 60, 180) + map ( t1, 450, 600, 60, 120)) / 2;
        }
        if (t1 > 600 && t1 <= 800) {
          s1 = (map ( st2, 2, 180, 100, 180) + map ( t1, 600, 800, 100, 160)) / 2;
        }
        if (t1 > 800) {
          s1 = (map ( st2, 2, 180, 160, 180) + map ( t1, 800, 1020, 160, 180)) / 2;
        }
    
        // управление приводом заслонки первичного воздуха
    
    
        if ( OneWire::crc8(bufData, 8) == bufData[8] )
        {
          temperature =  (float)((int)bufData[0] | (((int)bufData[1]) << 8)) * 0.0625 + 0.03125;
    
        }
    
        Input = temperature; //температура с датчика на выходе из теплообменника
    
    
        myPID.Compute();//считаем выходной сигнал ПИД-регулятора
    
    
        spid = Output;
    
    
        Setpoint = potdeg; // заданная температура
    
        if ( temperature < potdeg ){
        tempdeficite = potdeg - temperature;
        }
    
        if ( temperature - potdeg > 1 ) {
          s2 = 2;
        }
        else {
          if (spid - (s1 / tempdeficite) >= 0 && (potdeg - temperature) < 4) {
            s2 = spid - (s1 / tempdeficite);
          }
          else {
            s2 = spid;
          }
        }
        // отправка данных на контроллер сервоприводов
    
    
    
    
    
        if (transflag == false)
        {
          Serial.print(String(s1, DEC)); //данные для сервопривода вторички
    
        }
    
        if (transflag == true)
        {
          Serial.print(String((constrain (s2, 2, 180)) * 100, DEC)); //данные для сервопривода первички
    
        }
    
    
    
    
        worktime = (millis() - currentTime) / 1000; // таймер времени горения закладки топлива
    
    
    
        float h = dht.readHumidity();
        float t = dht.readTemperature();
        sensDs.reset();  // сброс шины
        sensDs.write(0xCC, POWER_MODE); // пропуск ROM
        sensDs.write(0x44, POWER_MODE); // инициализация измерения
        sensDs.reset();  // сброс шины
        sensDs.write(0xCC, POWER_MODE); // пропуск ROM
        sensDs.write(0xBE, POWER_MODE); // команда чтения памяти датчика
        sensDs.read_bytes(bufData, 9);  // чтение памяти датчика, 9 байтов
    
    
    
        therm2 = thermocoupleb.readCelsius();
    
    
    
    
        // вывод данных на дисплей
    
        display.setTextSize(1);
        display.setTextColor(WHITE);
        display.setCursor(0, 0);
        display.println(therm1);
    
    
        display.setCursor(70, 0);
        display.println (worktime / 60 / 60);
        display.setCursor(85, 0);
        display.println (":");
    
        display.setCursor(90, 0);
        display.println ((worktime / 60) % 60);
        display.setCursor(110, 0);
        display.println (":");
    
        display.setCursor(115, 0);
        display.println (worktime % 60);
    
        display.setCursor(110, 24);
        display.println (s1);
    
        display.setCursor(85, 24);
        display.println (s2);
    
        display.setCursor(0, 12);
        display.println(therm2);
        display.setCursor(90, 12);
        display.println(temperature);
        display.setCursor(0, 24);
        display.println(t);
        display.setTextSize(2);
        display.setCursor(50, 12);
        display.println(potdeg);
        display.display();
        display.clearDisplay();
    
        // отправка данных по радиоканалу
        mySwitch.send(s1, 13);
        myPID.Compute();
        delay(100);
        mySwitch.send(t * 100, 14);
        myPID.Compute();
        delay(100);
        mySwitch.send((constrain (s2, 2, 180)) * 100, 15);
        myPID.Compute();
        delay(100);
        mySwitch.send(temperature * 100, 16);
        myPID.Compute();
        delay(100);
        mySwitch.send(therm2 * 100, 17);
        myPID.Compute();
        delay(100);
        mySwitch.send(therm1 * 100, 18);
        myPID.Compute();
        delay(100);
        mySwitch.send(worktime, 19);
        myPID.Compute();
        delay(100);
        mySwitch.send(potdeg, 20);
        myPID.Compute();
        delay(100);
      }
    
    }
    А с другой стороны, уже вчера вписал себе в "подпись" ссылку на архив со скетчами для Уно.

    ЗЫ: еще вчера нарыл годную среду под названием "Processing". В принципе, всё та же привычная "Сишка", очень похоже на Arduino IDE, но со своим "местным диалектом", конечно.
    Привлекла простота работы с СОМ - портами, изначально прекрасное взаимопонимание с Ардуинами и возможность простой компиляции созданной программы как в обычный "Экзешник", работоспособный на любом компьютере с "Виндой", так и для запуска на Линуксе.
    То есть, кроме обычного логирования в текстовый файл на компе и просмотра параметров в терминале, можно создать работающую на компьютере программулину, которая будет делать то же самое + строить динамические графики, + (что еще полезнее), позволит удаленно изменять параметры алгоритма работы котла: коэффициенты ПИД, реперные точки температур и так далее без необходимости вписывать изменения в код программы и перепрошивки и без необходимости иметь разветвленное меню настроек в самом контроллере. Просто эти изменения будут заноситься в EEPROM, а в самом коде в виде констант уже не будут присутствовать, как сейчас присутствуют.
    Чем это еще хорошо - раз настроенный котел при перепрошивке не "расстроится", а будет работать на основе все тех же индивидуальных настроек пользователя.
    Еще можно будет не иметь собственные "часы реального времени" на котле, а пользоваться часами на компьютере... в общем, неслабо так облегчит жизнь.

    Одно только " в минусе" - среда мне еще не очень знакома, придется потратить время на обучение.

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

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

    Замечаю, что тенденция получается почти такая же, как и в теме с беспилотниками на Ардупилоте (или Ардукоптере). Иду по проторенной дорожке, так сказать. Там тоже открытый проект на добровольных началах, вот только народу там немало трудится над кодами... а я пока вот в единственном лице. И потому медленновато получается.
     
  13. Оксфорд
    Регистрация:
    12.04.12
    Сообщения:
    9.428
    Благодарности:
    1.871

    Оксфорд

    Живу здесь

    Оксфорд

    Живу здесь

    Регистрация:
    12.04.12
    Сообщения:
    9.428
    Благодарности:
    1.871
    Адрес:
    Уфа
    Если действительно хотите, чтобы народ как-то принял участие, то выделили бы блок управления горением. А все сервисные функции убрали. Только самый минимум. Управлять настройками с компьютера - нонсенс. Какой-то ЦУП получается. Не та задача.
     
  14. alarin
    Регистрация:
    29.07.16
    Сообщения:
    8.662
    Благодарности:
    3.751

    alarin

    Живу здесь

    alarin

    Живу здесь

    Регистрация:
    29.07.16
    Сообщения:
    8.662
    Благодарности:
    3.751
    Адрес:
    Казахстан, Алма-Ата
    У меня все управление с компьютера и мне нравиться. Ставим задачу контроллеру и он будет ее выполнять уже самостоятельно. ЦУП это хорошо. Задача правильная и своевременная. Облачные сервисы все более популярны. А блок управления горением действительно может быть отдельным, самостоятельным и не обязательно "програмным", "железный" даже надежней будет, а вот управление сервисами, параметры работы должны быть в базе данных. Такая "многослойка " имеет хороший запас дуракоустойчивости, что в настоящее время крайне актуально. Даже сверхнавороченной железо в 90 процентах случаях выводят из строя чьи то ручки в 9 процентах энергетики, ну а оставшийся процент на все остальные "катаклизмы".:)
     
  15. Оксфорд
    Регистрация:
    12.04.12
    Сообщения:
    9.428
    Благодарности:
    1.871

    Оксфорд

    Живу здесь

    Оксфорд

    Живу здесь

    Регистрация:
    12.04.12
    Сообщения:
    9.428
    Благодарности:
    1.871
    Адрес:
    Уфа
    Дело конечно хозяйское. Но по мне пристегивать к котлу компьютер - это жесть. Причем собственно програмка достаточна примитивна. Там даже 328 мега с избытком. Не должен пользователь так далеко вникать. Максимум - настройка комнатной температуры. Если и ее не трогать- то можно год на экран не смотреть. Примерно так сейчас происходит эксплуатация- истопник только закидывает дрова и нажимает кнопку "пуск". Нечего настраивать.
     
Статус темы:
Закрыта.