21

Re: Настраиваемый термометр на Arduino

valera ©:

Как автор сделает в своем термометре управление реле по температуре любого датчика, то это будет самая простая штука, для автоматизации ректификации.

Автор специально по моей нижайшей просьбе сделал скетч без автоматизации для работы в ручном режиме на газу :). И у автора есть мощнейшая версия для работы с управлением и даже отрисовыванием графиков - но уже в другой теме.

22 (2017-06-23 12:13:07 отредактировано )

Re: Настраиваемый термометр на Arduino

valera ©:

Как автор сделает в своем термометре управление реле по температуре любого датчика, то это будет самая простая штука, для автоматизации ректификации.

Еще два транзистора, биппер и... все :)

SLOG ©:

И у автора есть мощнейшая версия для работы с управлением и даже отрисовыванием графиков - но уже в другой теме.

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

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

23 (2017-06-23 12:46:46 отредактировано valera)

Re: Настраиваемый термометр на Arduino

Мне данный термометр в самый раз, но нужен биппер, чтоб при росте температуры в царге на 0.1 прискакать к колонне. Клапанов у меня нет и не будет... Сейчас работаю на перешитых w1209 на нижнем звуковой повторитель поворотов за 50 рублей. Но хочется компактности ардуины.

24

Re: Настраиваемый термометр на Arduino

valera ©:

Клапанов у меня нет и не будет...

крайне удобная вещь.

Алкоголь не помогает найти ответ,
он помогает забыть вопрос!

25

Re: Настраиваемый термометр на Arduino

al, дабы не офф, пошли ко мне в тему Стабильная РК из нержи с наклонным дефлегматором. Своими руками.

26

Re: Настраиваемый термометр на Arduino

Господа винокуры, а каким образом можно скопировать текст скетча из 3-го поста???
Копируется мягко говоря коряво, а набирать по строчке с экрана это какой-то аццкий трэш :(. В теме с ардуино же каким то образом копировали???

27

Re: Настраиваемый термометр на Arduino

SLOG,  выдели, нажми ctrl+с вставь в любой текстовик ctrl+v
Подотри снизу строчку с копирайтом, если в IDE скетч копируешь.

У вас в жизни всегда будет все, что вы хотите, если вы будете помогать другим людям получать то, чего хотят они.
Регистрация на форуме отключает почти всю рекламу.

28

Re: Настраиваемый термометр на Arduino

Иван ©:

SLOG,  выдели, нажми ctrl+с вставь в любой текстовик ctrl+v
Подотри снизу строчку с копирайтом, если в IDE скетч копируешь.

Ну да, казалось бы... Так не копируется, сбивается всё форматирование вдребезги напополам: все слова начинающиеся с шарпа копируется столбиком (но без продолжения фразы после пробела) :(. Всё что после пробела копируется ниже но без форматирования одной строкой. Залез в код страницы, скопировал с форматированием, но символы <> копируются неправильно. Поправил руками - всё-таки не весь текст набивать :). Но поймал в итоге вот такую ошибку - и как это исправить у меня идей нет:

Arduino: 1.8.3 (Windows 7), Плата:"Arduino/Genuino Uno"

K:\arduino-1.8.3-windows\sketch\sketch.ino:66:0: warning: "abs" redefined

#define abs(a) (a&gt;0?a:-a)

^

In file included from sketch\sketch.ino.cpp:1:0:

K:\arduino-1.8.3-windows\hardware\arduino\avr\cores\arduino/Arduino.h:94:0: note: this is the location of the previous definition

#define abs(x) ((x)>0?(x):-(x))

^

K:\arduino-1.8.3-windows\sketch\sketch.ino: In function 'int scanDs18()':

K:\arduino-1.8.3-windows\sketch\sketch.ino:173:40: warning: invalid conversion from 'void*' to 'uint8_t* {aka unsigned char*}' [-fpermissive]

   while ( ds->search((void*)&addr.bytes)) {

                                        ^

In file included from K:\arduino-1.8.3-windows\sketch\sketch.ino:3:0:

C:\Users\Admin\Documents\Arduino\libraries\OneWire/OneWire.h:181:13: note: initializing argument 1 of 'uint8_t OneWire::search(uint8_t*)'

     uint8_t search(uint8_t *newAddr);

             ^

K:\arduino-1.8.3-windows\sketch\sketch.ino: In function 'void setup()':

sketch:216: error: 'class LiquidCrystal_I2C' has no member named 'init'

   lcd.init();

       ^

K:\arduino-1.8.3-windows\sketch\sketch.ino: In function 'int readTemp()':

sketch:287: error: 'lt' was not declared in this scope

   for (dsCnt = 0; dsCnt &lt; MAX_DS18; dsCnt++) {

                          ^

sketch:287: error: expected ')' before ';' token

   for (dsCnt = 0; dsCnt &lt; MAX_DS18; dsCnt++) {

                                      ^

sketch:287: error: expected ';' before ')' token

   for (dsCnt = 0; dsCnt &lt; MAX_DS18; dsCnt++) {

                                               ^

sketch:441: error: expected '}' at end of input

}

^

sketch:441: error: expected '}' at end of input

exit status 1
'class LiquidCrystal_I2C' has no member named 'init'

29 (2017-06-25 22:09:43 отредактировано )

Re: Настраиваемый термометр на Arduino

SLOG, Так процитируй пост с кодом, потом выдели и вырежи, потом вставь себе в текстовик.
Надо будет сделать автокопирование  *WRITE*

SLOG ©:

exit status 1
'class LiquidCrystal_I2C' has no member named 'init'

SLOG ©:

 lcd.init();

Замени на lcd.begin ();

У вас в жизни всегда будет все, что вы хотите, если вы будете помогать другим людям получать то, чего хотят они.
Регистрация на форуме отключает почти всю рекламу.

30

Re: Настраиваемый термометр на Arduino

Иван ©:

Так процитируй пост с кодом

Шутка в том, что тогда копируется без пробелов вообще т.е. в одну строку :(.

Иван ©:

Замени на lcd.begin ();

Попробую завтра. Сегодня уже не до того..

31

Re: Настраиваемый термометр на Arduino

SLOG,  у меня все нормально копируется без бубнов просто с поста

#include <LiquidCrystal_I2C.h>
#include <EEPROM.h>
#include <OneWire.h>
#include <SFE_BMP180.h>
#include <Wire.h>

//#define SOLID_GRAPH // если нравятся "залитые" графики, раскоментируйте

#define MAGIC "alcodistillers.ru"
#define MAX_DS18 3
#define AVERAGING_COUNT 3

#define PIN_DS18 10
#define PIN_BUTTON 2
#define PIN_SDA 5   // useless on *duino
#define PIN_SCL 4

OneWire  *ds;  // on pin 10 (a 4.7K resistor is necessary)
SFE_BMP180 pressure;
LiquidCrystal_I2C lcd(0x27, 20, 4);

#define VAL_COUNT 5*8
float t[VAL_COUNT];
uint16_t tpos = 0;
#define P(x)   Serial.print(x)
#define PL(x)   Serial.println(x)

struct ds18ScratchPad_struct {
  union {
    uint8_t bytes[9];
    struct {
      uint8_t tempLsb, tempMsb, alarmHiTemp, alarmLoTemp, config,
              internalByte, countRemain, countPerC, crc;
    } regs;
  };
};
typedef struct ds18ScratchPad_struct ds18ScratchPad_t;

struct ds18DeviceRom_struct {
  union {
    uint8_t bytes[8];
    struct {
      uint8_t family, serial[6], crc;
    } regs;
    uint64_t dword;
    uint32_t u32[2];
  };
};
typedef struct ds18DeviceRom_struct ds18DeviceRom_t;

typedef struct {
  ds18DeviceRom_t addr;
  float aTemp[AVERAGING_COUNT];
  float cTemp;
  uint8_t aCount;
  uint8_t errorCount;
} ds18;

ds18 ds18s[MAX_DS18];
double bmp180Temp = 0, bmp180Pressure = 0;
uint8_t hasBmp180 = 0;

uint32_t nextLcdUpdate = 0;
//

#define abs(a) (a>0?a:-a)
void graph( float temp) {
  int16_t i;
  float tmin, tmax, tmin0;
  t[tpos++] = tmin = tmax = temp;
  tpos %= VAL_COUNT;
  for (i = 0; i < VAL_COUNT; i++) {
    if (t[i] == INT16_MAX) continue;
    if (tmin > t[i]) tmin = t[i];
    if (tmax < t[i]) tmax = t[i];
  }
  float tdiv = (tmax - tmin) / 8;
  if (tdiv < 0.0625) { //1/16 temp step && 8 steps per line
    tdiv = 0.0625;
    tmin0 = (tmax + tmin) / 2 - 0.0625 * 3;
  } else {
    tmin0 = tmin;
  }

  uint8_t c[8];
  uint8_t y, x, py = 100;
  P("+++++ Temp:"); P(temp); P(" tpos="); P(tpos); P(" min="); P(tmin); P(" max="); P(tmax); P(" div="); PL(tdiv);
  int p;
  for (i = 0; i < VAL_COUNT; i++) {
    p = (i + (int)tpos);// % VAL_COUNT;
    p %= VAL_COUNT;
    if (i % 5 == 0) {
      memset(c, 0, sizeof(c));
    }
    if (t[p] < INT16_MAX) {
      x = 1 << (4 - i % 5);
      y = (uint8_t)((t[p] - tmin0) / tdiv) + 1;
      if (y > 8) y = 8;
#ifdef SOLID_GRAPH
      for (int y1 = 8 - y; y1 < 8; y1++)
        c[y1] |= x;
#else
      //      P(p); P(" "); P(t[p]); P(" "); P(x); P(" "); P(y); P(" "); P(py); PL(";");
      if (py > 8  || py == y) {
        if (y) c[8 - y] |= x;
      } else if (py > y) {
        for (int y1 = y; y1 < py; y1++)
          c[8 - y1] |= x;
      } else {
        for (int y1 = py + 1; y1 <= y; y1++)
          c[8 - y1] |= x;
      }
      py = y;
#endif
    }
    if (i % 5 == 4)
      lcd.createChar(i / 5, c);
  }

  char str[21];
  snprintf(str, 21, "%2d.%02d \010\011\012\013\014\015\016\017 %2d.%02d", (int)tmin , (int)(tmin * 100) % 100,
           (int) tmax , (int)(tmax * 100) % 100);
  lcd.setCursor(0, 3);
  lcd.print(str);
}

//
int readConfig() {
  char t[sizeof(MAGIC)];
  EEPROM.get(0, t);
  Serial.println("Read config");
  if (memcmp(MAGIC, t, sizeof(MAGIC))) {
    Serial.println("no magic");
    resetConfig();
    return 0;
  }
  for (int i = 0; i < MAX_DS18; i++)
    EEPROM.get(sizeof(MAGIC) + i * sizeof(ds18DeviceRom_t),  ds18s[i].addr.bytes);
}

int saveConfig() {
  Serial.println("Save Config");
  EEPROM.put(0, MAGIC);
  for (int i = 0; i < MAX_DS18; i++) {
    EEPROM.put(sizeof(MAGIC) + i * sizeof(ds18DeviceRom_t), ds18s[i].addr.bytes);
  }
}

int resetConfig() {
  Serial.println("Reset config");
  memset (ds18s, 0, sizeof(ds18s));
  saveConfig();
}

int dumpConfig() {
  int i, i1;
  for (i1 = 0; i1 < MAX_DS18; i1++) {
    Serial.print("ROM =");
    Serial.print(i1 + 1);
    for ( i = 0; i < 8; i++) {
      Serial.write(' ');
      Serial.print(ds18s[i1].addr.bytes[i], HEX);
    }
    Serial.println();
  }
}

int scanDs18() {
  int i, empty, saveFlag = 0;
  ds18DeviceRom_t addr, addr_zero;
  memset(&addr_zero, 0, sizeof(ds18DeviceRom_t));
  ds->reset_search();
  while ( ds->search((void*)&addr.bytes)) {
    empty = -1;
    for (i = 0; i < MAX_DS18; i++) {
      if (!memcmp(&ds18s[i].addr, &addr, sizeof(ds18DeviceRom_t))) {
        break;
      }
      if (empty == -1 && !memcmp(&ds18s[i].addr, &addr_zero, sizeof(ds18DeviceRom_t))) {
        empty = i;
      }
    }
    if (i == MAX_DS18) {
      if (empty >= 0) {
        memcpy(&ds18s[empty].addr, &addr, sizeof(ds18DeviceRom_t));
        saveFlag = 1;
      } else {
        Serial.println("Unable to save new ds18, manual reset needed");
      }
    }
  }
  if (saveFlag) {
    saveConfig();
  }
}

uint8_t bak[] = {219, 191, 165, 143, 122, 102, 85, 69, 53, 39, 25, 12};
uint16_t par[] = {689, 667, 641, 613, 579, 536, 490, 436, 368, 295, 207, 108};

float getParVolPercent(int temp) {
  if (temp >= 100 || temp < 88) return 0;
  temp -= 88;
  return ((float)par[temp]) / 10;
}

float getBakVolPercent(int temp) {
  if (temp >= 100 || temp < 88) return 0;
  temp -= 88;
  return ((float)bak[temp]) / 10;
}

void setup(void) {
  Serial.begin(115200);
  Serial.println(MAGIC);

  lcd.init();
  lcd.backlight();
  lcd.setCursor(0, 0);
  lcd.print(">>>>>>>>>  <<<<<<<<<");
  lcd.setCursor(2, 1);
  lcd.print(MAGIC);
  lcd.setCursor(3, 2);
  lcd.print("samogon powered!");

  pinMode(PIN_BUTTON, INPUT_PULLUP); //подтягиваем входы кнопок к плюсу встроенными резисторами
  pinMode(PIN_DS18, INPUT_PULLUP); //подтягиваем входы кнопок к плюсу встроенными резисторами
  ds = new OneWire(PIN_DS18);
  if (!digitalRead(PIN_BUTTON)) {
    if (!digitalRead(PIN_BUTTON))
    {
      lcd.clear();
      lcd.setCursor(0, 3);
      lcd.print("reset ds18b20 config");

      Serial.println("Reset");
      resetConfig();
    }
  }

  readConfig();
  scanDs18();
  dumpConfig();

  // Wire.pins(PIN_SDA, PIN_SCL);
  if (pressure.begin()) {
    Serial.println("BMP180 init success");
    hasBmp180 = 1;
  } else  {
    Serial.println("BMP180 init fail\n\n");
  }
  for (int i = 0; i < VAL_COUNT; i++) {
    t[i] = INT16_MAX;
  }
  float q = 77;
  for (int i = 0; i < 50; i++) {
    q += 0.125 * (1 - random(0, 3));
    graph(q);
    delay(50);
  }
  lcd.clear();
  for (int i = 0; i < VAL_COUNT; i++) {
    t[i] = INT16_MAX;
  }
}

// coRoutines
#define crBegin switch(crStaticVar) { case 0:
#define crReturn(x) do { crStaticVar=__LINE__; return x ; case __LINE__:; } while (0)
#define crFinish }

#define MIN_POLL_DELAY 40 //ms

#ifdef crStaticVar
#undef crStaticVar
#endif

#define crStaticVar _dsStatus
int _dsStatus = 0;
int dsCnt;
int readTemp() {
  ds18ScratchPad_t scp;
  crBegin;
  ds->reset();
  ds->skip();
  ds->write(0x44, 0);
  crReturn(750);        // time to calculate temp
  for (dsCnt = 0; dsCnt < MAX_DS18; dsCnt++) {
    ds->reset();
    ds->select((void*)&ds18s[dsCnt].addr.bytes);
    ds->write(0xBE);         // Read Scratchpad
    for (int i = 0; i < 9; i++) {           // we need 9 bytes
      scp.bytes[i] = ds->read();
    }
    if (OneWire::crc8((void*)&scp.bytes, 8) != scp.regs.crc) {
      if (ds18s[dsCnt].errorCount < 10)
        ds18s[dsCnt].errorCount++;
      else
        ds18s[dsCnt].cTemp = 0;
      Serial.print("Error!!!!");
    } else {
      ds18s[dsCnt].errorCount = 0;
      int TReading, SignBit;
      float temp = 11.11;

      TReading = (scp.regs.tempMsb << 8) + scp.regs.tempLsb;
      SignBit = TReading & 0x8000;  // test most sig bit

      if (SignBit) // negative
        TReading = (TReading ^ 0xffff) + 1; // 2's comp
      temp = 1.0 * (SignBit ? (-TReading) : TReading) / 16;
      ds18s[dsCnt].aTemp[ds18s[dsCnt].aCount++] = temp;
      if (ds18s[dsCnt].aCount == AVERAGING_COUNT) {
        ds18s[dsCnt].aCount = 0;
        temp = 0;

        for (int i = 0; i < AVERAGING_COUNT; i++) {
          temp += ds18s[dsCnt].aTemp[i];
        }
        ds18s[dsCnt].cTemp = temp / AVERAGING_COUNT;
      }
    }
    crReturn(MIN_POLL_DELAY);
  }
  crFinish;
  crStaticVar = 0;
  nextLcdUpdate = 0;
  return MIN_POLL_DELAY;
}
#ifdef crStaticVar
#undef crStaticVar
#endif

#define crStaticVar _bmp180Status
int _bmp180Status = 0;

int readPressure() {
  if (!hasBmp180)
    return 5000;
  crBegin
  pressure.startTemperature();
  crReturn(MIN_POLL_DELAY);
  pressure.getTemperature(bmp180Temp);
  crReturn(MIN_POLL_DELAY);
  pressure.startPressure(3);
  crReturn(MIN_POLL_DELAY);
  pressure.getPressure(bmp180Pressure, bmp180Temp);
  bmp180Pressure /= 1.333;

  crFinish;
  crStaticVar = 0;
  nextLcdUpdate = 0;
  return 2000;
}

int dumpTemp() {
  if (ds18s[0].cTemp > 0)
    graph(ds18s[0].cTemp);
  return 5000;
}
int pos = 0;
int updateLcd() {
  char str[21];//,f1[6],f2[6],f3[6];
  if (nextLcdUpdate < millis()) {
    Serial.println("----------");

    // строка 1
    snprintf(str, 21, "n:%02d.%02d o:%2d   ", (int)ds18s[0].cTemp, (int)(ds18s[0].cTemp * 100) % 100,
             (int)ds18s[2].cTemp);
    lcd.setCursor(0, 0);
    lcd.print(str);
    Serial.println(str);

    // строка 2
    float   pt = (78.91 - (780 - bmp180Pressure ) * 0.038);
    //    strcpy(str,"To=55 P=777.7 Tc=77.7f");
    if (hasBmp180) {
      snprintf(str, 21, "k:%02d.%02d c:%2d.%1d/%3d.%1d      ", (int)ds18s[1].cTemp, (int)(ds18s[1].cTemp * 100) % 100,
               (int)pt, (int)(pt * 10) % 10, (int)bmp180Pressure, (int)(bmp180Pressure * 10) % 10);
    } else {
      snprintf(str, 21, "o:%2d                        ", (int)ds18s[2].cTemp);
    }
    lcd.setCursor(0, 1);
    lcd.print(str);
    Serial.println(str);

    // строка 3
    if (ds18s[0].cTemp > 88 || ds18s[1].cTemp > 88) { // дистилляция
      int vpp = getParVolPercent(ds18s[0].cTemp) * 10;
      int vpb = getBakVolPercent(ds18s[1].cTemp) * 10;
      snprintf(str, 20, "%par=%2d.%1d %bak=%2d.%1d          ", vpp / 10, vpp % 10, vpb / 10, vpb % 10);
    } else {
      memset(str, ' ', 20);
      str[20] = '\0';
    }
    lcd.setCursor(0, 2);
    lcd.print(str);
    Serial.println(str);

    // строка 4 - графики
    nextLcdUpdate = millis() + 2000;
  }
  return 200;
}

uint32_t prev_time = 0;

enum {POLL_DS, POLL_BMP, POLL_DUMP, POLL_LCD, POLL_END};
#define MAX_POLL_MS 10000
uint32_t polls[POLL_END] = {0};
void loop(void) {
  uint32_t timems = millis();
  uint32_t minms = timems + MAX_POLL_MS;
  uint32_t x;
  for (int i = 0; i < POLL_END; i++) {
    if (polls[i] < timems) {
      switch (i) {
        case POLL_DS:
          x = readTemp();
          break;
        case POLL_DUMP:
          x = dumpTemp();
          break;
        case POLL_BMP:
          x = readPressure();
          break;
        case POLL_LCD:
          //          x = dumpTemp();
          x = updateLcd();
          break;

      }
      polls[i] = timems + x;
    } else {
    }
    if (minms > polls[i] ) {
      minms = polls[i];
    }

  }
  delay(minms - timems);
}
У вас в жизни всегда будет все, что вы хотите, если вы будете помогать другим людям получать то, чего хотят они.
Регистрация на форуме отключает почти всю рекламу.

32

Re: Настраиваемый термометр на Arduino

Иван ©:

SLOG,  у меня все нормально копируется без бубнов просто с поста

Чудеса, попробую завтра поставить другой браузер.

33 (2017-06-26 12:48:38 отредактировано Андрей М)

Re: Настраиваемый термометр на Arduino

Иван ©:

SLOG, Так процитируй пост с кодом, потом выдели и вырежи, потом вставь себе в текстовик.
Надо будет сделать автокопирование  *WRITE*

SLOG ©:

exit status 1
'class LiquidCrystal_I2C' has no member named 'init'

SLOG ©:

 lcd.init();

Замени на lcd.begin ();

1. Не нужно менять.
2. С библиотеками из верхнего поста темы собирается без проблем
3. Скетч выложил на яндекс

https://yadi.sk/d/15EcaRbJ3KTHjR
1.8.3 собирается без ошибок.

SLOG ©:

#define abs(a) (a&gt;0?a:-a)

Это от неправильного копирования - браузер не заменил спецсимволы на соответствующие им знаки. Поменяй браузер :)

34

Re: Настраиваемый термометр на Arduino

Андрей М ©:

Поменяй браузер

Видимо придётся :). Подложила "огненная лисичка" банальную свинью ;)

35

Re: Настраиваемый термометр на Arduino

SLOG ©:

Видимо придётся

Не торопись. У меня такая же хрень. И на хроме тоже.
Тут чет с настройками надо пошевилить.

36 (2017-06-27 00:01:12 отредактировано SLOG)

Re: Настраиваемый термометр на Arduino

Андрей М ©:

1.8.3 собирается без ошибок.

Ура! Заработало!!! Анимация во время загрузки - отличная находка! СПА-СИ-БО! Чувствуется рука профессионала :).

37

Re: Настраиваемый термометр на Arduino

Важное дополнение про внешнее питание!!!!!
На Vin нужно подавать не менее 7 вольт!!!!!!!

38

Re: Настраиваемый термометр на Arduino

Андрей М ©:

На Vin нужно подавать не менее 7 вольт!!!!!!!

??? А если меньше - чем чревато? Я уже зарядку 5-ти вольтовую прикрутил.

39

Re: Настраиваемый термометр на Arduino

SLOG ©:
Андрей М ©:

На Vin нужно подавать не менее 7 вольт!!!!!!!

??? А если меньше - чем чревато? Я уже зарядку 5-ти вольтовую прикрутил.

на выходе 5V будет 4,1в. Если ничего не греется и не проседает (по подсветке экрана видно), оставь 5.

40

Re: Настраиваемый термометр на Arduino

SLOG ©:

Я уже зарядку 5-ти вольтовую прикрутил.

Если блок питания на 2 ампера, то вряд ли просядет.

РК медь 35/1000&1500, 2КВт/ Arduino от d.styler (собираю БК 28мм на клампах)
Volkswagen T5 Caravella 2006