Архів позначки: Arduino

Arduino UNO. Чергове оновлення функціоналу

При використанні душу на дачі за рік сталася біда – забились якісь труби. Відповідно напір води став менший, а проточний нагрівач все ще гріє сильно як і рік тому назад. Тому вода стає дуже гаряча, і всередині нагрівача спрацьовує запобіжник від перегріву. Він приблизно стпрацьовує при 48-50 градусах Цельсія.

Потім нагрів відключається і йде прохолодна вода – “літньої” температури. Через 30 секунд нагрів включається і все повторюється.

Щоб побороти дане неподобство я вирішив ввести новий функціонал в Arduino UNO – максимальну температуру нагріву. Для цього впаяв іще один світлодіод і 3 саморобні “кпопки”. При перевищенні допустимого максимуму ткмператури нагрів відключається, вмикається червоне світло. Кнопками можна виставити бажану максимальну температуру.

Ось що роблять кнопки

  1. Збільшити t на 1 градус
  2. Показати t на моніторі
  3. Зменшити t на 1 градус

Максимальна температура зберігається в енергонезалежній пам’яті EEPROM. Тобто виставлена температура збережеться і після відключення всіх приладів. Щож, публікую код:

#include <EEPROM.h>

#define SERIAL_R 49000 // сопротивление последовательного резистора, 49 кОм
#define B 3950 // B-коэффициент
#define THERMISTOR_R 50000 // номинальное сопротивления термистора, 50 кОм
#define NOMINAL_T 25 // номинальная температура (при которой TR = 100 кОм)
#define MANUAL_CORRECTION 0 // РУЧНА КОРЕКЦІЯ температури на виході
const byte tempPin = A0;
int waterFlowNormal, minimumWaterFlow, TC2_OVF;
int afterReset = 0;
int heatOff = 7;
int heatOn = 4;
int transistor = 8;
int overHeat = 9;
int readVal;
bool settingsMaxTempMode = false;
int currentTemperature;

void setup() {
  // put your setup code here, to run once:
  pinMode(LED_BUILTIN, OUTPUT);
  pinMode(7, OUTPUT);
  pinMode(4, OUTPUT);
  pinMode(2, OUTPUT);
  pinMode(overHeat, OUTPUT);
  pinMode(transistor, OUTPUT);
  pinMode(5, INPUT_PULLUP);
  pinMode(10, INPUT_PULLUP);
  pinMode(11, INPUT_PULLUP);
  pinMode(12, INPUT_PULLUP);

  // set EEPROM cell for first time, or make it normal value
  byte val;
  val = EEPROM[0];
  if (val > 80) {
    EEPROM[0] = 43;
  }
  if (val < 10) {
    EEPROM[0] = 43;
  }
  
  // timer2 setup from https://www.teachmemicro.com/arduino-timer-interrupt-tutorial/
  TIMSK2 = (TIMSK2 & B11111110) | 0x01;
  TCCR2B = (TCCR2B & B11111000) | 0x07;
  // Timer/Counter 1 initialization
  // Clock source: T1 pin Rising Edge
  // Mode: Normal top=0xFFFF
  // OC1A output: Disconnected
  // OC1B output: Disconnected
  // Noise Canceler: On
  // Input Capture on Rising Edge
  // Timer1 Overflow Interrupt: Off
  // Input Capture Interrupt: Off
  // Compare A Match Interrupt: Off
  // Compare B Match Interrupt: Off
  TCCR1A = (0 << COM1A1) | (0 << COM1A0) | (0 << COM1B1) | (0 << COM1B0) | (0 << WGM11) | (0 << WGM10);
  TCCR1B = (1 << ICNC1) | (1 << ICES1) | (0 << WGM13) | (0 << WGM12) | (1 << CS12) | (1 << CS11) | (1 << CS10);
  TCNT1H = 0x00;
  TCNT1L = 0x00;
  ICR1H = 0x00;
  ICR1L = 0x00;
  OCR1AH = 0x00;
  OCR1AL = 0x00;
  OCR1BH = 0x00;
  OCR1BL = 0x00;
  minimumWaterFlow = 1;
  Serial.begin( 9600 );
  pinMode( tempPin, INPUT );
}

ISR(TIMER2_OVF_vect) {
  TC2_OVF++;
  if (TC2_OVF > 30) { // 30 is 10 LED togles in 19 seconds
    TC2_OVF = 0;
    // Toggle LED
    digitalWrite( 2, digitalRead( 2 ) ^ 1 );
    // now thermistor logic
    int t = analogRead( tempPin );
    float tr = 1023.0 / t - 1;
    tr = SERIAL_R / tr;
    float steinhart;
    steinhart = tr / THERMISTOR_R; // (R/Ro)
    steinhart = log(steinhart); // ln(R/Ro)
    steinhart /= B; // 1/B * ln(R/Ro)
    steinhart += 1.0 / (NOMINAL_T + 273.15); // + (1/To)
    steinhart = 1.0 / steinhart; // Invert
    steinhart -= 273.15; 
    int rxresult = (int)steinhart + MANUAL_CORRECTION;
    currentTemperature = rxresult;
    if (settingsMaxTempMode) {
      byte val;
      val = EEPROM[0];
      Serial.println(val);
    } else {
      if (rxresult < -22) {
        Serial.println("ER");
      } else {
        Serial.println(rxresult);
      }
    }

    if (afterReset < 100) {
      afterReset++;
    }
    //code for timer counting impulses
    if ( TIFR1 & (1 << TOV1 )) { // if it has been overflow
      waterFlowNormal = 1;  // because overflow means in was more than 65535 tics (real test leads from ~5 to ~30)
      TIFR1 = (1 << TOV1 ); // clear the flag of overflow
    }
    else {
      if ((short int)TCNT1 > minimumWaterFlow) {
        waterFlowNormal = 1;
      }
      else {
        waterFlowNormal = 0;
      }
    }
    TCNT1 = 0;  // clear in any case
  }
}

void loop() {
  if (afterReset < 6) {
    digitalWrite(LED_BUILTIN, HIGH);   // turn the LED on (HIGH is the voltage level)
    delay(70);
    digitalWrite(LED_BUILTIN, LOW);    // turn the LED off by making the voltage LOW
    delay(60);
  } else {
    digitalWrite(LED_BUILTIN, LOW);
  }  
  
  byte maxTemperature = EEPROM[0];
  if ((waterFlowNormal == 1) and (currentTemperature <= maxTemperature)) {
    digitalWrite(heatOff, LOW);
    digitalWrite(heatOn, HIGH);
    digitalWrite(transistor, HIGH);
  }
  else {
    digitalWrite(heatOff, HIGH);
    digitalWrite(heatOn, LOW);
    digitalWrite(transistor, LOW);
  }
  if (currentTemperature > maxTemperature) {
    digitalWrite(overHeat, true);
  } else {
    digitalWrite(overHeat, false);
  }
  
  // Button Set Max Temp Minus 1
  readVal = digitalRead(10);
  if (readVal) {
    digitalWrite(overHeat, false);
  }
  else {
    // button pressed
    digitalWrite(overHeat, true);
    byte val;
    val = EEPROM[0];
    EEPROM[0] = val - 1;
    delay(400);
  }
    
  // Button Set Max Temp Plus 1
  readVal = digitalRead(12);
  if (readVal) {
    digitalWrite(overHeat, false);
  }
  else {
    // button pressed
    digitalWrite(overHeat, true);
    byte val;
    val = EEPROM[0];
    EEPROM[0] = val + 1;
    delay(400);
  }

   // Button Read Max Temp To UART
  readVal = digitalRead(11);
  if (readVal) {
    digitalWrite(overHeat, false);
    settingsMaxTempMode = false;
  }
  else {
    // button pressed
    digitalWrite(overHeat, true);
    settingsMaxTempMode = true;
    delay(400);
  }
}

Тести проводив “програмно”, так як код пишу в м. Полтава, а сама установка нагріву і душ знаходяться в будинку в селі Черкасівка. Надіюсь що я не помилився і зможу приймати душ, хоч із зменшеним напором води, але із стабільною температурою (реле буде швидко клацати і підтримувати температуру в межах +/- 1 C). До того ж – це економія електроенергії – зменшений потік води, нагрів включається і виключається. Сусідам не позаздриш – так як 5.5 кВт навантаження спричинятиме поблимування їх неекономних лампочок.

Arduino Uno – купив для проекту підігрівання води

Спочатку купив датчик протоки на АліЕкспресс, бронзовий такий з пропеллером всередині. Там датчик Холла. І ще термодатчик.

Зробив проєкт на Atmega8 – все працює, але рядом радянський холодильник, від перешкод якого программа реально збивається і двічі чуть не підшмалила ТЕНи (зазвичай просто зависає і не включає обігрів).

Тому вирішив я провести перевірку, на скільки Ордуїно протистоятиме таким потужним перешкодам. Програма мало чим відрізняється від коду на AVR-GCC, переваг мало в Ардуіно. А саме лише 2

  1. Не потрібен програматор
  2. USART працює на борту через той же СОМ-порт.
Нижче скидаю код фінальної прошивки, яку скоро буду тестувати “на залізі”
int waterFlowNormal, minimumWaterFlow, TC2_OVF;
int afterReset = 0;
int heatOff = 7;
int heatOn = 4;
int transistor = 8;

void setup() {
// put your setup code here, to run once:
pinMode(LED_BUILTIN, OUTPUT);
pinMode(7, OUTPUT);
pinMode(4, OUTPUT);
pinMode(2, OUTPUT);
pinMode(transistor, OUTPUT);
pinMode(5, INPUT_PULLUP);
// timer2 setup from https://www.teachmemicro.com/arduino-timer-interrupt-tutorial/
TIMSK2 = (TIMSK2 & B11111110) | 0x01;
TCCR2B = (TCCR2B & B11111000) | 0x07;
// Timer/Counter 1 initialization
// Clock source: T1 pin Rising Edge
// Mode: Normal top=0xFFFF
// OC1A output: Disconnected
// OC1B output: Disconnected
// Noise Canceler: On
// Input Capture on Rising Edge
// Timer1 Overflow Interrupt: Off
// Input Capture Interrupt: Off
// Compare A Match Interrupt: Off
// Compare B Match Interrupt: Off
TCCR1A = (0 << COM1A1) | (0 << COM1A0) | (0 << COM1B1) | (0 << COM1B0) | (0 << WGM11) | (0 << WGM10);
TCCR1B = (1 << ICNC1) | (1 << ICES1) | (0 << WGM13) | (0 << WGM12) | (1 << CS12) | (1 << CS11) | (1 << CS10);
TCNT1H = 0x00;
TCNT1L = 0x00;
ICR1H = 0x00;
ICR1L = 0x00;
OCR1AH = 0x00;
OCR1AL = 0x00;
OCR1BH = 0x00;
OCR1BL = 0x00;

//Serial.begin(9600);
minimumWaterFlow = 1;
}

ISR(TIMER2_OVF_vect) {
TC2_OVF++;
if (TC2_OVF > 30) { // 30 is 10 LED ttogles in 19 seconds
TC2_OVF = 0;
// Toggle LED
digitalWrite( 2, digitalRead( 2 ) ^ 1 );

//

if (afterReset < 100) {
afterReset++;
}
//code for timer counting impulses
if ( TIFR1 & (1 << TOV1 )) { // if it has been overflow
waterFlowNormal = 1; // because overflow means in was more than 65535 tics (real test leads from ~5 to ~30)
TIFR1 = (1 << TOV1 ); // clear the flag of overflow
}
else {
if ((short int)TCNT1 > minimumWaterFlow) {
waterFlowNormal = 1;
}
else {
waterFlowNormal = 0;
}
}
//Serial.println(TCNT1);
TCNT1 = 0; // clear in any case
}
}

void loop() {
if (afterReset < 6) {
digitalWrite(LED_BUILTIN, HIGH); // turn the LED on (HIGH is the voltage level)
delay(70);
digitalWrite(LED_BUILTIN, LOW); // turn the LED off by making the voltage LOW
delay(60);
} else {
digitalWrite(LED_BUILTIN, LOW);
}
if (waterFlowNormal == 1) {
digitalWrite(heatOff, LOW);
digitalWrite(heatOn, HIGH);
digitalWrite(transistor, HIGH);
}
else {
digitalWrite(heatOff, HIGH);
digitalWrite(heatOn, LOW);
digitalWrite(transistor, LOW);
}

}

В майбутньому хочу зробити індикацію температури води в градусах і винести показання до душу на 10 метрів від датчика протоки. Це дозволило б регулювати температуру з точністю до 1 градуса.

Власники газових котлів, в яких то виключається обігрів, то кип’яток ошпарює – стоять с стороні і смокчуть морозиво

UPDATE

Тести, проведені на дачі з працюючим холодильником довели, що Ардуіно ні разу не зависло. В основному коли включається холодильник, Ардуїно сприймає це як одиночний сигнал з датчика протоки і включає підігрів на 1 секунду. Також таке відбувається іноді коли спрацьовує накачування насоса (управляється механічним реле тиску, накачує до 2х атмостер).

Але виявлено, що іноді, коли включається реле підігріву, самі ТЕНи нагрівача не включаються. Можливо це стається у зв’язку з наявністю в обігрівачі захисту від перевищення температури. В любому випадку це вже не має відношення до Ардуіно.

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