326

Re: Автоматика на Arduino для ректификации и дистилляции (схема-прошивки)

Не понял восторгов по датчику DS18B20. Сегодня подключил два датчика к Ардуине, замерил.

Видна серьезная разница в температуре, хотя датчики лежат на столе совсем рядом. По паспорту сказано, что разброс +- полградуса. Как бы укладываемся в допустимую погрешность, но как быть с точной температурой для БК "добычи" продукта? Там ведь 78,15 для 760мм р.с. Т.е. не 78,3 или 77,8, а именно 79,15. Как в дайвинге и космосе - ставить минимум три датчика и брать среднее? Или смотреть по отбору жидкости и давать "поправки на ветер"?

327

Re: Автоматика на Arduino для ректификации и дистилляции (схема-прошивки)

zcom пишет:

как быть с точной температурой для БК

А зачем она нужна?

Бк 28/350 (750)
Рк 28/850 (1600)
Бк 54/750

328

Re: Автоматика на Arduino для ректификации и дистилляции (схема-прошивки)

zcom, проверь для начала установленное разрешение датчиков...

У вас в жизни всегда будет все, что вы хотите, если вы будете помогать другим людям получать то, чего хотят они.
Внимание! Через приват НЕ КОНСУЛЬТИРУЮ! Пишите в паблик.

329 (2017-01-04 14:11:08 отредактировано )

Re: Автоматика на Arduino для ректификации и дистилляции (схема-прошивки)

Artem.SHitov пишет:
zcom пишет:

как быть с точной температурой для БК

А зачем она нужна?

Ну, во-первых, это красиво. :)
А, во-вторых, как накапливать статистику, если показания скачут?

Иван пишет:

zcom, проверь для начала установленное разрешение датчиков...

Судя по скетчу-примеру стоят на 12-битное разрешение, но сейчас доизучаю даташит (datasheets.maximintegrated.com/en/ds/DS18B20.pdf), перепишу скетч, будет понятно.

330

Re: Автоматика на Arduino для ректификации и дистилляции (схема-прошивки)

zcom пишет:

Видна серьезная разница в температуре

Для начала - все датчики имеют свои погрешности. Но они не так важны для нас - для нас более важным является стабильность этой погрешности (что на самом деле имеет зависимость от температуры и питающего напряжения - http://alcodistillers.ru/forum/viewtopi … 309#p44309).
+ как сказал Иван - проверь что все датчики имеют одинаковую выставленную точность.

А вообще если хочется чтоб датчики показывали сравнимые температуры - их надо калибровать. По моему все программы позволяют ввести поправку для датчика (про ардуино не знаю). Но если есть желание калибровать - то делать это на воздухе - пустая трата времени (очень подвержен микро-флуктуациям).

Лучше всего взять термос, налить туда воды примерно равной температуры с 78С, закрыть, подождать несколько минут для стабилизации температуры, открыть снова и опкстить датчики, прикрыв при этом горловину термоса чтоб обеспечить герметичность.
В этом случае в домашних условиях мы обеспечиваем для важных условия при калибровке - 1) постоянство температуры во время измерения и 2) постоянство температуры в ограниченном пространстве нахождения датчиков.

РК: 42мм медь, 1.4м царга. Димрот 3м (8мм). Кубы 30л (кег, тэн 2квт) и 15л (тэн 2.8 квт).
Дистиллятор: на базе РК, поворот 42 в 22, доохладители 90см 1/2" в 3/4" и 4-х трубный 40см 8мм в 3/4". Куб 36л (индукция 3квт).

331

Re: Автоматика на Arduino для ректификации и дистилляции (схема-прошивки)

zcom пишет:

как накапливать статистику, если показания скачут?

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

Бк 28/350 (750)
Рк 28/850 (1600)
Бк 54/750

332

Re: Автоматика на Arduino для ректификации и дистилляции (схема-прошивки)

zcom, подключи для начала к компу, посмотри что там... да тебе уже дали совет.

У вас в жизни всегда будет все, что вы хотите, если вы будете помогать другим людям получать то, чего хотят они.
Внимание! Через приват НЕ КОНСУЛЬТИРУЮ! Пишите в паблик.

333 (2017-01-04 18:32:44 отредактировано zcom)

Re: Автоматика на Arduino для ректификации и дистилляции (схема-прошивки)

Написал я скетч для параллельного опроса произвольного количества датчиков температуры. Про калибровку понял. Точнее даже знал. :) Но была надежда, что этим занимаются на заводе.
Если нужны комментарии по скетчу, то отвечу на вопросы. Из "уникального". Параллельный опрос датчиков, отказ от использования программных задержек - работаем от готовности датчиков, возможность управлять периодом опроса (до 1 мс), возможность выгрузки массива температур (пока не реализовал, т.к. непонятно куда, но по коду видно, что для этого все готово). Работает пока через серийный порт, но это не принципиально, вывод можно куда угодно перенаправить.

#include <OneWire.h>

#define PIN_CONNECT 10          // on pin 10 (a 4.7K resistor is necessary)
#define SERIAL_BAUD 115200      //
#define PERIOD_MIN 1000         // 
#define RESOLUTION 12           // 9, 10, 11, 12 bit
#define SENSORS 2

struct tsdata {
  byte addr[8];
  byte answer[9];
  float tempC;
  float tempF;
  boolean enable = false;
  boolean readable = false;
};
tsdata ts[SENSORS];
unsigned long count = 0;
boolean readstate = false;

OneWire  ds(PIN_CONNECT);  

void print_hex(byte data[], byte l = 8, boolean ns = true) {
  byte i;
  for( i=0; i<l; i++) {
    if (data[i] < 16)
      Serial.print("0");
    Serial.print(data[i], HEX);
    if (i != (l-1))
      Serial.print(".");
  }
  if (ns)
    Serial.println();
}


void setup(void) {
  byte i, j;

  Serial.begin(SERIAL_BAUD);

  ds.reset_search();
  i=0;
  while (ds.search(ts[i].addr)) {
    if (ds.crc8(ts[i].addr, 7) == ts[i].addr[7]) {
      if ((ts[i].addr[0] == 0x10) || (ts[i].addr[0] == 0x22) || (ts[i].addr[0] == 0x28)) {
        ts[i].enable = true;
        i++;
        if (i > SENSORS)
          break;
      }
    }
  }
  Serial.print("All sensor = ");
  Serial.println(i);
  for (i=0; i<SENSORS; i++) {
    if (ts[i].enable) {
      Serial.print("Device ");
      Serial.print(i);
      Serial.print(" = ");
      print_hex(ts[i].addr, 8, true);
      ds.reset();
      ds.select(ts[i].addr);
      ds.write(0x4E);
      ds.write(0);
      ds.write(0);
      switch (RESOLUTION) {
        case 9:
          ds.write(0x1F);
        case 10:
          ds.write(0x3F);
        case 11:
          ds.write(0x5F);
        default:
          ds.write(0x7F);
      }
      ds.write(0x48);
    }
  }
  count = millis();
}

void loop(void) {
  byte i, j;
  int16_t test;

  if ((millis() - count) <= PERIOD_MIN) {
    delay(1);
    return;
  }
  count = millis();
  if (!readstate) {
    for (i=0; i<SENSORS; i++) {
      if (ts[i].enable) {
        ts[i].readable = false;
        ds.reset();
        ds.select(ts[i].addr);
        ds.write(0x44);
      }
    }
    readstate = true;
    return;
  }
  if (!ds.read()) {
    return;
  }
  readstate = false;
  for (i=0; i<SENSORS; i++) {
    if (ts[i].enable) {
      ds.reset();
      ds.select(ts[i].addr);
      ds.write(0xBE);
      for (j=0; j<9; j++) {
        ts[i].answer[j] = ds.read();
      }
      ts[i].readable = (ds.crc8(ts[i].answer, 8) == ts[i].answer[8]);
    }
  }

  for (i=0; i<SENSORS; i++) {
    if (ts[i].enable) {
      Serial.print(i+1);
      Serial.print(": ");
      test = ts[i].answer[1] * 256 + ts[i].answer[0];
      if (ts[i].addr[0] == 0x10) {
        test = test << 3;
        if (ts[i].answer[7] == 0x10) {
          test = (test & 0xFFF0) + 12 - ts[i].answer[6];
        }
      }
      else {
        switch (ts[i].answer[4] & 0x60) {
          case 0x00:
            test = test & ~7;
          case 0x20:
            test = test & ~3;
          case 0x40:
            test = test & ~1;
        }
      }
      ts[i].tempC = (float)test / 16.0;
      ts[i].tempF = ts[i].tempC * 1.8 + 32.0; 
      Serial.print(ts[i].tempC);
      Serial.print("C, ");
      Serial.print(ts[i].tempF);
      Serial.println("F");
    }
  }
}

P.S. Да, еще предусмотрел в коде возможность "отключения/подключения" обнаруженных датчиков в ходе работы (поле enable структуры). Возможно, для чего-то и пригодится.

Artem.SHitov пишет:
zcom пишет:

как накапливать статистику, если показания скачут?

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

Барометрический датчик я взял. Это модуль от "Тройки", но что-то с Arduino Due не завелся. Заказал другой, который припаивается - GY-68, но пока непонятно, когда приедет. В наличии нет, после 9-ого скажут.
А так, да, тоже подключу его в этот скетч.

Куда данные выводить? Из реально накапливать и хранить в памяти Ардуинки. Но только там места мало. Можно скидывать из через серийный порт куда-нибудь сразу пакетом (формат?). Для этого, правда, надо команду передать соответствующую - через клавиатуру, например, или еще как.

В принципе, программировать на Ардуине легко. Так что заказы по доработке принимаются. :)

334

Re: Автоматика на Arduino для ректификации и дистилляции (схема-прошивки)

А может логичнее температурный лог на флэшку или SD карту скидывать? В простом текстовом формате, например, номер (расположение) датчика, время и температура через запятую и следующий замер с новой строки.

Jedem das Seine
БК 15\650 медь
РК 28\1300 медь
Учиться - никогда не поздно

335

Re: Автоматика на Arduino для ректификации и дистилляции (схема-прошивки)

zcom пишет:

Параллельный опрос датчиков

В каком месте интересно? Датчики опрашиваются последовательно в коде. И да - опрашивать их паралельно не получится - читай 1-Wire протокол.
Из коментариев - запрос на конверсию можно как раз параллельно всем послать - быстрее чем каждому по отдельности. Для этого - послать ресет, затем 0xСС (skip ROM), а затем 0x44. При этом конверсия будет произведена параллельно. При 2-х датчиках это не критично, а вот когда их 4-6 - тогда можно сэкономить.

Конверсия в датчике занимает какое-то время - то есть можно конечно выставить 1мс между посылкой конверсии и чтением - но что мы читаем при этом?

РК: 42мм медь, 1.4м царга. Димрот 3м (8мм). Кубы 30л (кег, тэн 2квт) и 15л (тэн 2.8 квт).
Дистиллятор: на базе РК, поворот 42 в 22, доохладители 90см 1/2" в 3/4" и 4-х трубный 40см 8мм в 3/4". Куб 36л (индукция 3квт).

336

Re: Автоматика на Arduino для ректификации и дистилляции (схема-прошивки)

zcom пишет:

Написал я скетч

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

zcom пишет:

Куда данные выводить?

Вот это вопрос меня в тупик ставит... да куда нравится, хоть в SQL писать... это зависит от поставленной самому себе задачи.

zcom пишет:

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

Легко... наверное, когда куча готовых примеров и можно их изменить.  Давай для начала в SQL в реальном времени... сможешь? Или на худой конец в CSV .

У вас в жизни всегда будет все, что вы хотите, если вы будете помогать другим людям получать то, чего хотят они.
Внимание! Через приват НЕ КОНСУЛЬТИРУЮ! Пишите в паблик.

337 (2017-01-04 22:50:32 отредактировано zcom)

Re: Автоматика на Arduino для ректификации и дистилляции (схема-прошивки)

d.styler пишет:
zcom пишет:

Параллельный опрос датчиков

В каком месте интересно? Датчики опрашиваются последовательно в коде. И да - опрашивать их паралельно не получится - читай 1-Wire протокол.

Рекомендую ознакомится. https://www.interfaceinnovations.org/on … ation.html

d.styler пишет:

Из коментариев - запрос на конверсию можно как раз параллельно всем послать - быстрее чем каждому по отдельности. Для этого - послать ресет, затем 0xСС (skip ROM), а затем 0x44. При этом конверсия будет произведена параллельно. При 2-х датчиках это не критично, а вот когда их 4-6 - тогда можно сэкономить.

Первое время делал именно так. Убил три часа времени - отладчика-то нет в Ардуине. Не работает. Датчики сигнал не воспринимают. Выдают непонятно что. Изучение импортных форумов (на наших все друг у друга перепечатывают или типовой пример правят) дало этот вариант решения. Это гарантировано работает, это раз, второе, для неиспользуемые датчики (enable = false) не напрягаются, третье, если есть еще устройства на OneWire, то они не получают "случайную" команду. А устройства я планирую добавлять.

d.styler пишет:

Конверсия в датчике занимает какое-то время - то есть можно конечно выставить 1мс между посылкой конверсии и чтением - но что мы читаем при этом?

Здесь ценность в том, что можно не ждать ответа от датчиков, а параллельно обрабатывать сигналы клавиатуры, управлять шаговыми двигателями, мощностью тэна и т.п. При использовании delay(1000), как во всех примерах, это невозможно. Здесь - легко. Даже на UNO.
Читаем после того, как датчики готовы. Кстати, здесь тоже подводный камень... Как оказалось. :(
Сейчас, как раз, правлю код.

Иван пишет:
zcom пишет:

Написал я скетч

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

Это написано, практически, "с нуля" по спецификациям. :) В пример поглядывал, но он реально однозадачный. А задача была - управление многими устройствами. Не только "умный градусник".

Иван пишет:
zcom пишет:

Куда данные выводить?

Вот это вопрос меня в тупик ставит... да куда нравится, хоть в SQL писать... это зависит от поставленной самому себе задачи.

zcom пишет:

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

Легко... наверное, когда куча готовых примеров и можно их изменить.  Давай для начала в SQL в реальном времени... сможешь? Или на худой конец в CSV .

Готовые примеры - это прекрасно, но они же уровня "обучалки". Очень плохо дружат между собой - проще новый код написать. В реальном вывод в SQL? Здесь вообще не проблема на стороне Arduino. Он-то в порт льет, успевай ловить. Проблема в софте на стороне компа. Там нужен "резидент", который в реальном времени снимает данные с порта и размещает их через ODBC в любой SQL-базе. С этим сложнее. :)
Проще в CSV выгружать по команде. Сделаю.

Kreg1969 пишет:

А может логичнее температурный лог на флэшку или SD карту скидывать? В простом текстовом формате, например, номер (расположение) датчика, время и температура через запятую и следующий замер с новой строки.

Да, думал об этом. С реальным временем сложно - нужен его источник. В Ардуине своих часов нет. Но можно использовать момент времени с начала запуска контроллера. Формат CSV. Его легко импортировать хоть в Excell, хоть в СУБД.


Вот новый вариант скетча. Код стал более читаем, избавился от проблем, связанных с использованием "паразитного питания" (по 2-м проводам, вместо трех). Теперь скетч будет корректно работать и с такой формой подключения. Код функций setup() и loop() существенно упростился. Теперь легко можно добавлять код для управления другими устройствами.
В начале кода есть идентификаторы.
TS_PERIOD - период опроса датчиков. В начале периода идет команда на конвертацию значений (подготовка показаний для считывания), по завершению периода - считывание и размещение куда укажем.
RESOLUTION - разрядность определения температуры. Чем точнее, тем дольше (для 12 бит надо 750мс).
SENSORS - количество датчиков на линии. У меня пока подключено два, планирую шесть.

#include <OneWire.h>

#define PIN_CONNECT 10          // on pin 10 (a 4.7K resistor is necessary)
#define SERIAL_BAUD 115200      //
#define TS_PERIOD   1000        // 
#define RESOLUTION  12          // 9, 10, 11, 12 bit
#define SENSORS     2           //

struct tsdata {
  byte addr[8];
  byte answer[9];
  float tempC;
  float tempF;
  boolean enable = false;
  boolean readable = false;
};
tsdata ts[SENSORS];
unsigned long count = 0;

OneWire  ds(PIN_CONNECT);  

void print_hex(byte data[], byte l = 8, boolean ns = true) {
  byte i;
  for( i=0; i<l; i++) {
    if (data[i] < 16)
      Serial.print("0");
    Serial.print(data[i], HEX);
    if (i != (l-1))
      Serial.print(".");
  }
  if (ns)
    Serial.println();
}

void ts_inin(void) {
  byte i=0, j;

  ds.reset_search();
  while (ds.search(ts[i].addr)) {
    if (ds.crc8(ts[i].addr, 7) == ts[i].addr[7]) {
      if ((ts[i].addr[0] == 0x10) || (ts[i].addr[0] == 0x22) || (ts[i].addr[0] == 0x28)) {
        ts[i].enable = true;
        i++;
        if (i > SENSORS)
          break;
      }
    }
  }
  Serial.print("All sensor = ");
  Serial.println(i);
  for (i=0; i<SENSORS; i++) {
    if (ts[i].enable) {
      Serial.print("Device ");
      Serial.print(i);
      Serial.print(" = ");
      print_hex(ts[i].addr, 8, true);
      ds.reset();
      ds.select(ts[i].addr);
      ds.write(0x4E);
      ds.write(0);
      ds.write(0);
      switch (RESOLUTION) {
        case 9:
          ds.write(0x1F);
        case 10:
          ds.write(0x3F);
        case 11:
          ds.write(0x5F);
        default:
          ds.write(0x7F);
      }
      ds.write(0x48);
    }
  }
}

void ts_conv(void) {
  byte i;
  
  for (i=0; i<SENSORS; i++) {
    if (ts[i].enable) {
      ts[i].readable = false;
      ds.reset();
      ds.select(ts[i].addr);
      ds.write(0x44);
    }
  }
}

void ts_read(void) {
  byte i, j;
  int16_t test;

  for (i=0; i<SENSORS; i++) {
    if (ts[i].enable) {
      ds.reset();
      ds.select(ts[i].addr);
      ds.write(0xBE);
      for (j=0; j<9; j++) {
        ts[i].answer[j] = ds.read();
      }
      ts[i].readable = (ds.crc8(ts[i].answer, 8) == ts[i].answer[8]);
      test = ts[i].answer[1] * 256 + ts[i].answer[0];
      if (ts[i].addr[0] == 0x10) {
        test = test << 3;
        if (ts[i].answer[7] == 0x10) {
          test = (test & 0xFFF0) + 12 - ts[i].answer[6];
        }
      }
      else {
        switch (ts[i].answer[4] & 0x60) {
          case 0x00:
            test = test & ~7;
          case 0x20:
            test = test & ~3;
          case 0x40:
            test = test & ~1;
        }
      }
      ts[i].tempC = (float)test / 16.0;
      ts[i].tempF = ts[i].tempC * 1.8 + 32.0; 
    }
  }
}

void ts_output_serial(void) {
  byte i;
  
  for (i=0; i<SENSORS; i++) {
    if (ts[i].enable) {
      Serial.print(i+1);
      Serial.print(": ");
      Serial.print(ts[i].tempC);
      Serial.print("C, ");
      Serial.print(ts[i].tempF);
      Serial.println("F");
    }
  }
}

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

  ts_inin();
  ts_conv();
  count = millis();
}

void loop(void) {
  if ((millis() - count) >= TS_PERIOD) {
    count = millis();
    ts_read();
    ts_output_serial();
    ts_conv();
  }
}

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

338 (2017-01-04 22:52:43 отредактировано )

Re: Автоматика на Arduino для ректификации и дистилляции (схема-прошивки)

zcom пишет:

Рекомендую ознакомится.

Почитал - ничего нового не увидел. Температура считывается последовательно.

zcom пишет:

Датчики сигнал не воспринимают.

Интересно - а у меня работают именно так (не ардуина - на компе). Более того - это согласно спецификации от MaxIntegrated...

zcom пишет:

При использовании delay(1000), как во всех примерах, это невозможно.

А в чем разница? Вместо цикла который посылает команду конверсии последовательно доступным устройствам - мы тупо шлем СС и 44 - и также выходим. Ждем как на скетче положенное время в мс и затем считываем. Т.е. между этими операциями делай что хочешь...

zcom пишет:

если есть еще устройства на OneWire, то они не получают "случайную" команду.

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

zcom пишет:

для 12 бит надо 750мс

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

РК: 42мм медь, 1.4м царга. Димрот 3м (8мм). Кубы 30л (кег, тэн 2квт) и 15л (тэн 2.8 квт).
Дистиллятор: на базе РК, поворот 42 в 22, доохладители 90см 1/2" в 3/4" и 4-х трубный 40см 8мм в 3/4". Куб 36л (индукция 3квт).

339 (2017-01-04 23:55:40 отредактировано )

Re: Автоматика на Arduino для ректификации и дистилляции (схема-прошивки)

zcom пишет:

Рекомендую ознакомится

Я ознакомился и ..

zcom пишет:

возможность управлять периодом опроса (до 1 мс), возможность выгрузки массива температур

А ты точно ознакомился со ссылкой?  Так там чёрным по белому про время написано.. ты как-то противоречишь логике датчика :)

Вот я процитирую...

How it works

A typical read operation of a 1Wire device consists of three steps:

Initialize conversion: Instructs 1Wire device to perform a conversion operation to copy the read value (e.g. temperature, humidity, voltage) into a non-volatile memory location for reading. Issuing this command typically takes 10-80ms.
Wait for conversion: Before the value can be read, the conversion must be completed. A typical conversion operation takes from 75-800ms, depending the precision of the read operation.
Read calculated value: Read the calculated value from the conversion operation. This process typically takes 10-80ms

zcom пишет:

Проблема "паразитного питания" для датчиков не позволяет сделать вариант считывания данные датчиков "по готовности".

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

У вас в жизни всегда будет все, что вы хотите, если вы будете помогать другим людям получать то, чего хотят они.
Внимание! Через приват НЕ КОНСУЛЬТИРУЮ! Пишите в паблик.

340 (2017-01-05 01:14:38 отредактировано )

Re: Автоматика на Arduino для ректификации и дистилляции (схема-прошивки)

Спасибо за комментарии. Питание изначально не паразитное. Финальная на сегодня доработка скетча. Добавил диагностику - поиск нужного датчика. Пока сегодня в колонну их втыкал запутался. Теперь все просто - зажигалкой секунду погрел и смотрим на экран, выводится номер датчика.
Сделал меню. Управляется отсылкой в порт цифры (один байт: 30Н..32Н). Вывод в CSV. Пока накапливание и скидывание лога не успел - колонну собирал. Завтра первый запуск.

#include <OneWire.h>

#define PIN_CONNECT 10          // on pin 10 (a 4.7K resistor is necessary)
#define SERIAL_BAUD 115200      //
#define TS_PERIOD   1000        // 
#define RESOLUTION  12          // 9, 10, 11, 12 bit
#define SENSORS     2           //

struct tsdata {
  byte addr[8];
  byte answer[9];
  float tempC = -273.15;
  float tempF = -273.15;
  boolean enable = false;
  boolean readable = false;
};
tsdata ts[SENSORS];
float tempC[SENSORS];
unsigned long count = 0;
byte operation = 0;

OneWire  ds(PIN_CONNECT);  

void print_hex(byte data[], byte l = 8, boolean ns = true) {
  byte i;
  for( i=0; i<l; i++) {
    if (data[i] < 16)
      Serial.print("0");
    Serial.print(data[i], HEX);
    if (i != (l-1))
      Serial.print(".");
  }
  if (ns)
    Serial.println();
}

void ts_inin(void) {
  byte i, j, n=0;

  ds.reset_search();
  while (ds.search(ts[n].addr)) {
    if (ds.crc8(ts[n].addr, 7) == ts[n].addr[7]) {
      if ((ts[n].addr[0] == 0x10) || (ts[n].addr[0] == 0x22) || (ts[n].addr[0] == 0x28)) {
        ts[n].enable = true;
        n++;
        if (n > SENSORS)
          break;
      }
    }
  }
  Serial.print("Number of sensors = ");
  Serial.println(n);
  for (i=0; i<SENSORS; i++) {
    if (ts[i].enable) {
      Serial.print("Device ");
      Serial.print(i);
      Serial.print(" = ");
      print_hex(ts[i].addr, 8, true);
      ds.reset();
      ds.select(ts[i].addr);
      ds.write(0x4E);
      ds.write(0);
      ds.write(0);
      switch (RESOLUTION) {
        case 9:
          ds.write(0x1F);
        case 10:
          ds.write(0x3F);
        case 11:
          ds.write(0x5F);
        default:
          ds.write(0x7F);
      }
      ds.write(0x48);
    }
  }
  if (n != 0)
    Serial.println("Menu:");
    Serial.println("1 - Starts measurement");
    Serial.println("2 - Starts diagnostics");
    Serial.println("0 - To stop all operations");
    Serial.println("Choice?");
}

void ts_conv(void) {
  byte i;
  
  for (i=0; i<SENSORS; i++) {
    if (ts[i].enable) {
      ts[i].readable = false;
      ds.reset();
      ds.select(ts[i].addr);
      ds.write(0x44);
    }
  }
}

void ts_read(void) {
  byte i, j;
  int16_t test;

  for (i=0; i<SENSORS; i++) {
    if (ts[i].enable) {
      ds.reset();
      ds.select(ts[i].addr);
      ds.write(0xBE);
      for (j=0; j<9; j++) {
        ts[i].answer[j] = ds.read();
      }
      ts[i].readable = (ds.crc8(ts[i].answer, 8) == ts[i].answer[8]);
      test = ts[i].answer[1] * 256 + ts[i].answer[0];
      if (ts[i].addr[0] == 0x10) {
        test = test << 3;
        if (ts[i].answer[7] == 0x10) {
          test = (test & 0xFFF0) + 12 - ts[i].answer[6];
        }
      }
      else {
        switch (ts[i].answer[4] & 0x60) {
          case 0x00:
            test = test & ~7;
          case 0x20:
            test = test & ~3;
          case 0x40:
            test = test & ~1;
        }
      }
      ts[i].tempC = (float)test / 16.0;
      ts[i].tempF = ts[i].tempC * 1.8 + 32.0; 
    }
  }
}

void ts_diag(void) {
  byte i;

  for (i=0; i<SENSORS; i++)
    if (abs(ts[i].tempC - tempC[i]) >= 5) {
      Serial.print("ts");
      Serial.print(i);
      Serial.print(", resting temperature = ");
      Serial.print(tempC[i]);
      Serial.print("C, current temperature = ");
      Serial.print(ts[i].tempC);
      Serial.println("C");
    }
}

void ts_output_serial(void) {
  byte i;
  
  Serial.print("ts_data,");
  Serial.print(millis());
  for (i=0; i<SENSORS; i++) {
    if (ts[i].enable) {
      Serial.print(",");
      Serial.print(ts[i].tempC);
    }
  }
  Serial.println();
}

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

  ts_inin();
  ts_conv();
  count = millis();
}

void loop(void) {
  byte i, data;

  data = Serial.read();
  if (data == 0x30) {
    operation = 0;
    Serial.println("Break of operation");
  }
  if (data == 0x31) {
    operation = 1;
    Serial.println("Running measurement");
  }
  if (data == 0x32) {
    operation = 2;
    Serial.println("Running diagnostics");
    ts_read();
    for (i=0; i<SENSORS; i++)
      tempC[i] = ts[i].tempC;
  }

  switch (operation) {
    case 1:
      if ((millis() - count) >= TS_PERIOD) {
        count = millis();
        ts_read();
        ts_output_serial();
        ts_conv();
      }
    case 2:
      if ((millis() - count) >= TS_PERIOD) {
        count = millis();
        ts_read();
        ts_diag();
        ts_conv();
      }
  }
}
d.styler пишет:
zcom пишет:

Рекомендую ознакомится.

Почитал - ничего нового не увидел. Температура считывается последовательно.

:) Все примеры в Инете для Ардуин (или почти все) используют референсный код из примеров к библиотеке. А там последовательный опрос каждого датчика с использование функции delay, что требует использования прерываний для создания видимости многозадачности. Ну, не комп Ардуина, а однозадачный микроконтроллер. :) Эта статья показывает, как можно ускорить работу с датчиками. Можно, конечно, даташит прочитать, шину изучить и самому написать (в принципе, это правильный путь, но долгий в данном случае). Рад, что у вас изначально правильно сделано.

341 (2017-01-16 00:21:06 отредактировано zcom)

Re: Автоматика на Arduino для ректификации и дистилляции (схема-прошивки)

Все попытки сохранить лог работы внутри Ардуины не увенчались успехом. У Ардуины мало памяти, так что актуален только вариант с выгрузкой данных в режиме реального времени. Программы протоколлирования сом-порта необходимы. Я снимаю лог (формат csv) Arduino IDE, затем все копирую, сохраняю в текстовый файл, загужаю в Excell. Там уже и графики можно строить, и анализировать.

342

Re: Автоматика на Arduino для ректификации и дистилляции (схема-прошивки)

zcom пишет:

....Финальная на сегодня доработка скетча.....

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

Справедливость проявляется в воздаянии каждому по его заслугам.
Цицерон

343

Re: Автоматика на Arduino для ректификации и дистилляции (схема-прошивки)

Толян пишет:
zcom пишет:

....Финальная на сегодня доработка скетча.....

Скетч из сообщения копируется с ошибками

С ошибками? Странно, конечно. Может не все копируете? Или, наоборот, что-то лишнее прихватывается? Вот, проверенный вариант. На днях появится обновленный вариант для измененной БК с черновым расчетом поглощаемого димротом тепла в реальном времени. Не знаю, на сколько этот расчет будет соответствовать действительности, но хотя бы в первом приближении будет интересно посмотреть.

#include <OneWire.h>
#include <memorysaver.h>
#include <UTFT.h>

#define PIN_CONNECT     10          // on pin 10 (a 4.7K resistor is necessary)
#define SERIAL_BAUD     115200      //
#define TS_PERIOD       1000        // 
#define TS_RESOLUTION   12          // 9, 10, 11, 12 bit
#define SENSORS         6           //

#define TOP_COLUMN      "28.F6.29.01.00.00.80.D6"
#define MIDDLE_COLUMN   "28.F5.33.01.00.00.80.4E"
#define IN_WATER        "28.B2.34.01.00.00.80.EF"
#define IN_DIMROT       "28.13.29.01.00.00.80.14"
#define OUT_DIMROT      "28.F4.DF.00.00.00.80.0D"
#define FREE_TS         "28.12.29.01.00.00.80.23"

extern uint8_t SmallFont[];
extern uint8_t BigFont[];
extern uint8_t SevenSegNumFont[];

struct tsdata {
  byte addr[8];
  byte answer[9];
  float tempC = -273.15;
  float tempF = -273.15;
  boolean enable = false;
  boolean readable = false;
};
tsdata ts[SENSORS];
float tempC[SENSORS];
unsigned long count = 0;
byte operation = 1;

OneWire ds(PIN_CONNECT);  
UTFT    LCD(CTE32HR, 38, 39, 40, 41);

// from http://forum.arduino.cc/index.php?topic=37391.0 #9
char * floatToString(char * outstr, double val, byte precision, byte widthp){
 char temp[16]; //increase this if you need more digits than 15
 byte i;

 temp[0]='\0';
 outstr[0]='\0';

 if(val < 0.0){
   strcpy(outstr,"-\0");  //print "-" sign
   val *= -1;
 }

 if( precision == 0) {
   strcat(outstr, ltoa(round(val),temp,10));  //prints the int part
 }
 else {
   unsigned long frac, mult = 1;
   byte padding = precision-1;
   
   while (precision--)
     mult *= 10;

   val += 0.5/(float)mult;      // compute rounding factor
   
   strcat(outstr, ltoa(floor(val),temp,10));  //prints the integer part without rounding
   strcat(outstr, ".\0"); // print the decimal point

   frac = (val - floor(val)) * mult;

   unsigned long frac1 = frac;

   while(frac1 /= 10) 
     padding--;

   while(padding--) 
     strcat(outstr,"0\0");    // print padding zeros

   strcat(outstr,ltoa(frac,temp,10));  // print fraction part
 }

 // generate width space padding 
 if ((widthp != 0)&&(widthp >= strlen(outstr))){
   byte J=0;
   J = widthp - strlen(outstr);

   for (i=0; i< J; i++) {
     temp[i] = ' ';
   }

   temp[i++] = '\0';
   strcat(temp,outstr);
   strcpy(outstr,temp);
 }

 return outstr;
}

char * ts_addr(char * outstr, byte i) {
  sprintf(outstr, "%02X.%02X.%02X.%02X.%02X.%02X.%02X.%02X", ts[i].addr[0], ts[i].addr[1],  ts[i].addr[2], ts[i].addr[3], ts[i].addr[4], ts[i].addr[5], ts[i].addr[6], ts[i].addr[7]);
  return outstr;
}

char * ts_name(byte i, boolean shortName=false) {
  char temp[22];

  ts_addr(temp, i);
  if (strcmp(temp, TOP_COLUMN)==0) {
    if (shortName)
      return "TOP";
    else
      return "top column";
  }
  if (strcmp(temp, MIDDLE_COLUMN)==0) {
    if (shortName)
      return "2/3";
    else
      return "2/3 column";
  }
  if (strcmp(temp, IN_WATER)==0) {
    if (shortName)
      return "WATER";
    else
      return "input water";
  }
  if (strcmp(temp, IN_DIMROT)==0) {
    if (shortName)
      return "DIMROT";
    else
      return "input dimrot";
  }
  if (strcmp(temp, OUT_DIMROT)==0) {
    if (shortName)
      return "outWATER";
    else
      return "output dimrot";
  }
  if (strcmp(temp, FREE_TS)==0) {
    if (shortName)
      return "FREE";
    else
      return "free sensor";
  }
  return '\0';
}

void ts_output_all_address(boolean s=true) {
  byte i;
  char temp[22];
   
  for (i=0; i<SENSORS; i++) {
    if (ts[i].enable) {
      Serial.print("Device ");
      Serial.print(i);
      Serial.print(" = ");
      Serial.println(ts_addr(temp, i));
    }
  }
}

void ts_init(boolean showMenu=true) {
  byte i, j, n=0;
  char temp[22];

  ds.reset_search();
  while (ds.search(ts[n].addr)) {
    if (ds.crc8(ts[n].addr, 7) == ts[n].addr[7]) {
      if ((ts[n].addr[0] == 0x10) || (ts[n].addr[0] == 0x22) || (ts[n].addr[0] == 0x28)) {
        ts[n].enable = true;
        ds.reset();
        ds.select(ts[n].addr);
        ds.write(0x4E);
        ds.write(0);
        ds.write(0);
        switch (TS_RESOLUTION) {
          case 9:
            ds.write(0x1F);
          case 10:
            ds.write(0x3F);
          case 11:
            ds.write(0x5F);
          default:
            ds.write(0x7F);
        }
        ds.write(0x48);
        n++;
        if (n > SENSORS)
          break;
      }
    }
  }
  if (showMenu) {
    Serial.print("Number of sensors = ");
    Serial.println(n);
    for (i=0; i<SENSORS; i++) {
      if (ts[i].enable) {
        Serial.print("Device ");
        Serial.print(i);
        Serial.print(" = ");
        Serial.println(ts_addr(temp, i));
      }
    }
    if (n != 0) {
      Serial.println("Menu:");
      Serial.println("1 - Starts measurement");
      Serial.println("2 - Starts diagnostics");
      Serial.println("3 - Show sensors address");
      Serial.println("0 - To stop all operations");
      Serial.println("Choice?");
    }
  }
}

void ts_conv(void) {
  byte i;
  
  for (i=0; i<SENSORS; i++) {
    if (ts[i].enable) {
      ts[i].readable = false;
      ds.reset();
      ds.select(ts[i].addr);
      ds.write(0x44);
    }
  }
}

void ts_read(void) {
  byte i, j;
  int16_t test;
  float tC;

  for (i=0; i<SENSORS; i++) {
    if (ts[i].enable) {
      ds.reset();
      ds.select(ts[i].addr);
      ds.write(0xBE);
      for (j=0; j<9; j++) {
        ts[i].answer[j] = ds.read();
      }
      ts[i].readable = (ds.crc8(ts[i].answer, 8) == ts[i].answer[8]);
      test = ts[i].answer[1] * 256 + ts[i].answer[0];
      if (ts[i].addr[0] == 0x10) {
        test = test << 3;
        if (ts[i].answer[7] == 0x10) {
          test = (test & 0xFFF0) + 12 - ts[i].answer[6];
        }
      }
      else {
        switch (ts[i].answer[4] & 0x60) {
          case 0x00:
            test = test & ~7;
          case 0x20:
            test = test & ~3;
          case 0x40:
            test = test & ~1;
        }
      }
      ts[i].tempC = (float)test / 16.0;
      ts[i].tempF = ts[i].tempC * 1.8 + 32.0;
    }
  }
}

void ts_diag(void) {
  byte i;
  char temp[22];

  for (i=0; i<SENSORS; i++)
    if (abs(ts[i].tempC - tempC[i]) >= 5) {
      Serial.print("Device ");
      Serial.print(i);
      Serial.print(" = ");
      Serial.println(ts_addr(temp, i));
      Serial.print(", resting temperature = ");
      Serial.print(tempC[i]);
      Serial.print("C, current temperature = ");
      Serial.print(ts[i].tempC);
      Serial.println("C");
    }
}

void ts_output_serial(void) {
  byte i;
  
  Serial.print("ts_data,");
  Serial.print(millis());
  for (i=0; i<SENSORS; i++) {
    if (ts[i].enable) {
      Serial.print(",");
      Serial.print(ts[i].tempC);
    }
  }
  Serial.println();
}

void lcd_init(void) {
  LCD.InitLCD(0);
  LCD.clrScr();
}

void ts_output_lcd(void) {
  byte i, b;
  char text[7], buf[4], temp[22];;
  int y;

  LCD.setFont(BigFont);
  LCD.print("Temperature", LEFT, 20);
  for (i=0; i<SENSORS; i++) {
    if (ts[i].enable) {
      ts_addr(temp, i);
      if (strcmp(temp, TOP_COLUMN)==0)
        y = 50;
      else if (strcmp(temp, MIDDLE_COLUMN)==0)
        y = 105;
      else if (strcmp(temp, IN_WATER)==0)
        y = 170;
      else if (strcmp(temp, IN_DIMROT)==0)
        y = 225;
      else if (strcmp(temp, OUT_DIMROT)==0)
        y = 280;
      else if (strcmp(temp, FREE_TS)==0)
        y = 335;
      else
        y = 390;
      LCD.setFont(SevenSegNumFont);
      floatToString(text, ts[i].tempC, 2, 6);
      if (text[0] = 32) {
        buf[0] = text[1];
        buf[1] = text[2];
        buf[2] = '\0';
        LCD.print(buf, 32, y);
      }
      else if (text[0] = '-') {
          buf[0] = text[1];
          buf[1] = text[2];
          buf[2] = '\0';
          LCD.print(buf, 32, y);
      }
      else {
          buf[0] = text[0];
          buf[1] = text[1];
          buf[2] = text[2];
          buf[3] = '\0';
          LCD.print(buf, 0, y);
      }
      LCD.fillRect(102, y + 43, 106, y + 48);
      buf[0] = text[4];
      buf[1] = text[5];
      buf[2] = '\0';
      LCD.print(buf, 112, y);
      LCD.setFont(BigFont);
      LCD.print("ts", 184, y);
      text[0] = char(49 + i);
      text[1] = '\0';
      LCD.print(text, 216, y);
      LCD.print(ts_name(i, true), 184, y + 34);
    }
  }
}

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

  lcd_init();
  ts_init(false);
  ts_conv();
  count = millis();
}

void loop(void) {
  byte i, data;
  char temp[22], text[7];

  data = Serial.read();
  if (data == 0x30) {
    operation = 0;
    Serial.println("Break of operation");
    ts_init();
  } 
  else if (data == 0x31) {
    operation = 1;
    lcd_init();
    Serial.println("Running measurement");
  }
  else if (data == 0x32) {
    operation = 2;
    lcd_init();
    Serial.println("Running diagnostics");
    ts_read();
    for (i=0; i<SENSORS; i++)
      tempC[i] = ts[i].tempC;
  }
  else if (data == 0x33) {
    operation = 3;
    // Output serial
    Serial.println("Show sensors address");
    for (i=0; i<SENSORS; i++) {
      if (ts[i].enable) {
        Serial.print("Device ");
        Serial.print(i);
        Serial.print(" = ");
        Serial.print(ts_addr(temp, i));
        Serial.print(", ");
        Serial.println(ts_name(i));
      }
    }
    // Output lcd
    lcd_init();
    for (i=0; i<SENSORS; i++) {
      if (ts[i].enable) {
        LCD.setFont(BigFont);
        LCD.print("ts =", 0, 30 + i*20);
        text[0] = char(49 + i);
        text[1] = '\0';
        LCD.print(text, 32, 30 + i*20);
        LCD.print(ts_addr(temp, i), 70, 30 + i*20);
      }
    }
  }

  if (operation == 1) 
    if ((millis() - count) >= TS_PERIOD) {
      count = millis();
      ts_read();
      ts_output_serial();
      ts_output_lcd();
      ts_conv();
    }
  if (operation == 2) 
    if ((millis() - count) >= TS_PERIOD) {
      count = millis();
      ts_read();
      ts_diag();
      ts_conv();
    }
}

Вопросы по коду задавайте, отвечу.

Толян пишет:

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

Схему надо нарисовать. Тут вы правы. Но ее пока нет. :) Словесное описание.  Я использую Arduino Due, схема и скетч подойдет и для Arduino Mega2560. Используется сама тушка, на нее одевается TFT-дисплей 480х320 точек (покупал в Амперке, он там один такой). Далее на 10 контакт PWM одевается проводник, соединяются сигнальные линии всех датчиков температуры в одну линию, подключаются к этому проводнику. Далее с платы Ардуины забираю "землю" (GND) и питание (+3,3В для Due и +5 для Mega2560). Также соответствующие провода датчиков в одну шину и к ним питание и землю. Между сигнальным проводом и питанием припаиваем резистор на 4,7кОм. Вроде как все.
Недостающие библиотеки для скетча скачиваем с github. Ищем через google, например.

Это общий вид сборки без датчиков. Датчики подключаются через разъемы.

Вот монтажная плата с разъемами и резистором.

Это уже готовый к работе вариант. Тоже без датчиков (просто они на колонне закреплены, не снять просто так).

344

Re: Автоматика на Arduino для ректификации и дистилляции (схема-прошивки)

zcom пишет:

С ошибками? Странно, конечно. Может не все копируете?...

Копирую все, но для примера, после копирования, вместо кавычек, автоматом ставит буквы с символами.

Справедливость проявляется в воздаянии каждому по его заслугам.
Цицерон

345 (2017-01-24 02:26:38 отредактировано zcom)

Re: Автоматика на Arduino для ректификации и дистилляции (схема-прошивки)

Толян пишет:
zcom пишет:

С ошибками? Странно, конечно. Может не все копируете?...

Копирую все, но для примера, после копирования, вместо кавычек, автоматом ставит буквы с символами.

Понял. Проблема именно в копировании.... https://yadi.sk/d/zhFjOAM-3AYEMY
Я сейчас в процессе понимания как Ардуиной еще мощностью нагрева тэна управлять. Так, чтобы не Ардуина постоянно по прерываниям симистор открывала, а, например, при помощи цифрового потенциометра, встроенного в цепь вместо ручного. Она его значение раз в секунду изменяла и не отвлекалась более на это. Но точность оставляет желать лучшего из-за разброса параметров других компонент, хотя... калибровка... Пока в железе еще не повторил. Прототипы с ручным управлением есть.

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

346 (2017-01-24 03:51:43 отредактировано Kreg1969)

Re: Автоматика на Arduino для ректификации и дистилляции (схема-прошивки)

zcom пишет:

Да, думал об этом. С реальным временем сложно - нужен его источник. В Ардуине своих часов нет. Но можно использовать момент времени с начала запуска контроллера. Формат CSV. Его легко импортировать хоть в Excell, хоть в СУБД.

Так существуют же модули часов реального времени для ардуинки...

zcom пишет:

Так, чтобы не Ардуина постоянно по прерываниям симистор открывала, а, например, при помощи цифрового потенциометра, встроенного в цепь вместо ручного.

Если строить управление мощностью на твердотельном реле, то может проще взять реле с управлением не по сопротивлению а по напряжению? Там правда придется какой то преобразователь управляющего сигнала городить, если мне память не изменяет, то диапазон управляющего напряжения для реле от 3 до 32 вольт.

Jedem das Seine
БК 15\650 медь
РК 28\1300 медь
Учиться - никогда не поздно

347

Re: Автоматика на Arduino для ректификации и дистилляции (схема-прошивки)

Я пробовал. ТТ по напряжению не работает как симистор. Только вкл- выкл. Нужно что то другое, чтобы например ШИМ управлялось. Чисто теоретически (сам не пробовал) можно поставить мост и управлять мощным транзистором мосфетом. Он может плавно открываться.
Как вариант использовать ПИД регулятор. На ардуинке он тоже реализуется.

Ленивые всё делают быстро, что бы скорее отделаться от работы и делают хорошо, чтобы не переделывать.
С уважением, Николай.
Моё оборудование : → Винокурня Николя

348

Re: Автоматика на Arduino для ректификации и дистилляции (схема-прошивки)

Очередное продолжение версии что в начале темы на дисплее  0.96" IIC/I2C 128x64 OLED
Автоматика на Arduino для ректификации и дистилляции (схема-прошивки)

На дисплей выводятся показания 4х датчиков ds18b20 и давления BMP 180
Код по ссылке  https://drive.google.com/file/d/0B5BI-x … sp=sharing

Ленивые всё делают быстро, что бы скорее отделаться от работы и делают хорошо, чтобы не переделывать.
С уважением, Николай.
Моё оборудование : → Винокурня Николя

349

Re: Автоматика на Arduino для ректификации и дистилляции (схема-прошивки)

Надоело мне постоянно вытаскивать из корпуса потроха блока, переделываю постоянно, экспериментирую.
Сделал просто на платформе, что бы все доступно.
Здесь еще дисплей Nextion прикручен.
Так как все мое хозяйство в подвале, очень не удобно постоянно туда нырять. Вывел я на него показания с колонны и заодно управление котлом отопления. Сейчас все тестируется, интерфейс простенький написал. Как все отлажу можно и украшательством заняться.

   

Ленивые всё делают быстро, что бы скорее отделаться от работы и делают хорошо, чтобы не переделывать.
С уважением, Николай.
Моё оборудование : → Винокурня Николя

350

Re: Автоматика на Arduino для ректификации и дистилляции (схема-прошивки)

Николя, ну... руки-то золотые!
Вот и нет покоя!!  *THUMBSUP*
Завидую!!!  :rolleyes: