[Przykład] Ustawiania sterownika za pomocą 2 przycisków

Zbiór tutoriali związanych z Arduino.
ODPOWIEDZ
andy-1970
Młodszy majsterkowicz
Posty: 2
Rejestracja: 11 mar 2015, 12:57

[Przykład] Ustawiania sterownika za pomocą 2 przycisków

Post autor: andy-1970 » 4 sie 2015, 12:55

Witam

Niejednokrotnie korzystałem z porad na różnych forach jak również z tego forum. Postanowiłem się więc podzielić kodem sterownika solarnego podgrzewania basenu. Sterownik nie został jeszcze przetestowany i pewnie wymaga kilku poprawek, lecz nie o sterowanie tu chodzi lecz o zmianę ustawień sterownika za pomocą dwóch przycisków.

W programie wykorzystałem bibliotekę do wielozadaniowości (timers). Przyzwyczajony do programowania w delphi nie mogłem pogodzić się z istnieniem jednej pętli loop i następnych pętli do obsługi np menu. Dzięki niej można podzielić program na procedury i nie bać się, że menu zablokuje nam np odczyt temperatury.

W sterowniku użyłem 3 termometrów DS18B20. Już wcześniej nauczyłem się oszczędzać piny arduino więc skorzystałem z biblioteki onewire.

Całość działa tak:
  • Co sekundę aktualizuję wyświetlacz i w razie potrzeby włączam lub wyłączam pompę lub elektrozawór. (1 linia obrony przed błędami odczytu temperatury)
  • Co 700 ms sprawdzam temperaturę i w przypadku wystąpienia sytuacji alarmowej odpowiednio włączam pompę i zamykam elektrozawór
  • Co 170 ms sprawdzam czy nie nacisnąłem przycisku i w zależności od tego jaki stan ustawiłem przyciskami wyświetlam to.
  • Dla zabawy dodałem zegarek, który jest potrzebny co cyklicznego załączania pompy. Dokładność nie jest wymagana, więc wystarczy mi taki mniej więcej. Gdy jest zegar to od razu zachciało się by w nocy pompa pracowała np rzadziej, więc ten zegarek trzeba by jakoś ustawić. A obudowa posiada tylko 2 przyciski. Dodałem więc procedurę inkrementator, która nie robi nic innego tylko liczy jak długo jest naciśnięty przycisk. Dzięki temu ustawienie godziny polega na ustawianiu minut. Jedno naciśnięcie - minuta, gdy dłużej przytrzymamy, to zwiększa o 10min a jeszcze dłużej o 30min.
[licz]Ostatnia procedura licz sekundy jest właściwym zegarkiem. Okazało się, że jednak dokładność jego jest żadna, więc w menu jest funkcja korygująca jego wskazania.[/list]

Ważne! w programie nadal są błędy, więc nie podłączajcie modułów wykonawczych.

#include <stdlib.h>
#include <DallasTemperature.h>
#include <EEPROM.h>

#include <LiquidCrystal.h>
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);

#include <Timers.h>
Timers <5> akcja;

#define BUTTON_MENU 7
#define BUTTON_SET  6

#define ONE_WIRE_BUS 10 // Wybieramy linię pod którą podepniemy termometry
#define PUMP 9
#define BAYPAS 8

//#include <Wire.h>  do SDA SCL
#include <OneWire.h>
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sensors(&oneWire);

byte sekundy;
byte minuty;
byte godziny;

byte delta_temp;
byte delta_temp_minus; //histereza
byte delta_temp_old;

byte cykl_filtr;
byte cykl_filtr_old;
byte ustawienie_filtr;
byte licznik_filtr;

byte alarm;
byte MENU;
byte PUMP_STATE; // tu przechowujemy stan pompy
byte BAYPAS_STATE; // tu przechowujemy stab elektrozaworu

byte Dodaj;
int czast;
int korekta_czas = 980;
int korekta_czas_old = korekta_czas;

float t1 = 19.2;
float t2 = 22.1;
float t3 = 77.2;
char *TT;

int mm; //to zmienna do symulacji - usunąć

void displayTemp(float T1, float T2, float T3) {
  String test = "";
  String linia1 = "";
  String linia2 = "";

  if ((T1>0) && (T1<100)) {
    test = dtostrf(T1,2,1,TT);
    test += " ";
  } else test = "---- ";

  if ((T2>0) && (T2<100)) {
    test += dtostrf(T2,2,1,TT);
    test += " ";
  } else test += "---- ";
 
  if ((T3>0) && (T3<100)) {
    test += dtostrf(T3,2,1,TT);
  } else test += "----";
  

  linia1 = test.substring(0,8);
  linia2 = test.substring(8,16);
  lcd.setCursor(0, 0);
  lcd.print(linia1);
  lcd.setCursor(0, 1);
  lcd.print(linia2);
}


void Wyswietlacz() {
  if (alarm==1) {
     lcd.setCursor(1,1); lcd.print(F("TEMPERAT"));
     lcd.setCursor(0,1); lcd.print(F("URA>70'"));
  } else {
   switch (MENU) {
    case 0: displayTemp(t1,t2,t3); break;
    case 1: lcd.clear(); lcd.setCursor(0,0); lcd.print(F("Filtr ")); lcd.setCursor(3,1); lcd.print(cykl_filtr); break;
    case 2: lcd.clear(); lcd.setCursor(0,0); lcd.print(F("Delta T.")); lcd.setCursor(3,1); lcd.print(delta_temp); break;
    case 3: lcd.setCursor(0,0); lcd.print(F("Godzina "));
       lcd.setCursor(0,1);
       if (godziny<10) lcd.print("0"); lcd.print(godziny); lcd.print(":");
       if (minuty<10) lcd.print("0"); lcd.print(minuty); lcd.print(":");
       if (sekundy<10) lcd.print("0"); lcd.print(sekundy);
       break;
    case 4: lcd.clear(); lcd.setCursor(0,0); lcd.print(F("KorCzas+")); lcd.setCursor(3,1); lcd.print(korekta_czas); break;
    case 5: lcd.clear(); lcd.setCursor(0,0); lcd.print(F("KorCzas-")); lcd.setCursor(3,1); lcd.print(korekta_czas); break;
   }
  }
}

void Stan() {
  t1 = t1 + mm;
  if (t1>100) mm = -1;
  if (t1<0) mm = 1;

  sensors.requestTemperatures();
  float temperature1 = sensors.getTempCByIndex(0); // basen
  float temperature2 = sensors.getTempCByIndex(1); // wej solar
  float temperature3 = sensors.getTempCByIndex(2); // wyj solar
  float avgtemp = ((temperature2+temperature3)/2); // generalnie jak pompa nie będzie pracować woda w solarze nagrzeje się równomiernie

  if ((temperature2>70) || (temperature3>70)) {
    PUMP_STATE=1;
    BAYPAS_STATE=0;
    digitalWrite(PUMP, HIGH); // uwaga - teraz jest ustawione dla npn - zmienić na PNP czyli LOW i HIGH
    digitalWrite(BAYPAS, LOW);
    alarm = 1; 
  }
  else
  {
    alarm = 0; 
    if ((avgtemp-temperature1) > delta_temp) {
       PUMP_STATE=1;
       BAYPAS_STATE=0;
       digitalWrite(PUMP, HIGH); // uwaga dopilnować negacji!
       digitalWrite(BAYPAS, LOW);
    } 
    // Jeśli temp jest mniejsza niz delta wylaczenia, to
    // jesli jest cykl filtrowania to wlaczamy tylko baypas
    // w przeciwnym wypadku wylaczamy pompe i baypas
    if ((avgtemp-temperature1) < (delta_temp-delta_temp_minus)) {
      if (licznik_filtr <= cykl_filtr) BAYPAS_STATE=1;
      else
      {
         PUMP_STATE=0;
         BAYPAS_STATE=0;
      }
    }
  }
}

void Czas() {
 Wyswietlacz();
 if (PUMP_STATE == 1) digitalWrite(PUMP, HIGH); else digitalWrite(PUMP, LOW);
 if (BAYPAS_STATE == 1) digitalWrite(BAYPAS, HIGH); else digitalWrite(BAYPAS, LOW);
}

void Inkrementator() {
 if (czast>10) Dodaj=10;
 if (czast>40) Dodaj=30;
 if (czast==0) Dodaj=1;
}

void EEPROMWriteInt(int p_address, int p_value)
     {
     byte lowByte = ((p_value >> 0) & 0xFF);
     byte highByte = ((p_value >> 8) & 0xFF);

     EEPROM.write(p_address, lowByte);
     EEPROM.write(p_address + 1, highByte);
     }

//This function will read a 2 byte integer from the eeprom at the specified address and address + 1
unsigned int EEPROMReadInt(int p_address)
     {
     byte lowByte = EEPROM.read(p_address);
     byte highByte = EEPROM.read(p_address + 1);

     return ((lowByte << 0) & 0xFF) + ((highByte << 8) & 0xFF00);
     }


void Przyciski () {
  if (digitalRead(BUTTON_MENU) == LOW) {
      MENU++;
      if (MENU>5) MENU=0;
      delay(50);
  }

  if (MENU !=3) {
  if (digitalRead(BUTTON_SET) == LOW) {
      switch (MENU) {
       case 1: cykl_filtr ++; if (cykl_filtr>4) cykl_filtr=1; break;
       case 2: delta_temp = delta_temp+2; if (delta_temp>12) delta_temp=4; break;
       case 4: korekta_czas++; break;
       case 5: korekta_czas--; break;
       
     }    
     delay(50);
  }
  } else {
    if (digitalRead(BUTTON_SET) == LOW) {
     minuty = minuty + Dodaj;
     if (minuty > 59) {
       minuty=0;
       godziny++;
       if (godziny > 23) godziny=0;
       }
     czast++;  
     delay(2);
    }
  } 
  if (digitalRead(BUTTON_SET) == HIGH) czast=0;

  Wyswietlacz();
  // zapis ustawień
  switch (MENU) {
    case 0:
       displayTemp(t1,t2,t3); 
       if (cykl_filtr != cykl_filtr_old) { EEPROM.write(1, cykl_filtr); cykl_filtr_old = cykl_filtr; }
       if (delta_temp != delta_temp_old) { EEPROM.write(0, delta_temp); delta_temp_old = delta_temp; }
       if (korekta_czas != korekta_czas_old) { EEPROMWriteInt(2,korekta_czas); korekta_czas_old = korekta_czas; }
       break;
  }
}


void LiczSekundy() {
  static unsigned long lastTick = 0;
 if (millis() - lastTick >= korekta_czas) { // korekta spóźniania - wygląda na to że 1000 milis trwa dłużej, więc zmniejszymy tą wartość 990 nadal za dużo
  lastTick = millis();
  sekundy++;
  //if (sekundy == 2) sekundy++; // korekta spóźniania
 }
 if (sekundy > 59) {
     sekundy=0;
     minuty++;
     if (minuty > 59) {
       minuty=0;
       godziny++;
       if (cykl_filtr>0) { // normalny program
         licznik_filtr++;
       }
       // Tutaj program
       if (cykl_filtr<4) {
         if (licznik_filtr > cykl_filtr*2) {
           licznik_filtr=1;
       }
       if (licznik_filtr <= cykl_filtr) {
         PUMP_STATE=1;
       } else {
         PUMP_STATE=0;
       }
     }
     if (godziny > 23) {
       godziny=0;
     }
   }
 }
}

void setup() {
  TT = new char[4];
  lcd.begin(8, 2);
  pinMode(BUTTON_MENU, INPUT);
  digitalWrite(BUTTON_MENU, HIGH);
  
  pinMode(BUTTON_SET, INPUT);
  digitalWrite(BUTTON_SET, HIGH);

  pinMode(PUMP, OUTPUT);
  digitalWrite(PUMP, HIGH); // negacja z powodu tranzystorów PNP

  pinMode(BAYPAS, OUTPUT);
  digitalWrite(BAYPAS, HIGH);

  
  mm=1;
  Dodaj = 1;
  //Wire.begin();
  sensors.begin();

  sekundy=0;
  minuty=0;
  godziny=0;
  delta_temp_minus=2;
  licznik_filtr=1;
  alarm = 0;
  MENU=0;
  PUMP_STATE=0;
  BAYPAS_STATE=0;

  delta_temp = EEPROM.read(0);
  cykl_filtr = EEPROM.read(1);
  korekta_czas = EEPROMReadInt(2);
  if (korekta_czas == 0) korekta_czas = 980;
  delta_temp_old = delta_temp;
  cykl_filtr_old = cykl_filtr;  
  korekta_czas_old = korekta_czas;
  if ((delta_temp<4) || (delta_temp>12)) delta_temp=4;
  if ((cykl_filtr<1) || (cykl_filtr>4)) cykl_filtr=1;

  akcja.attach(0, 1000, Czas);
  akcja.attach(1, 700, Stan);
  akcja.attach(2, 170, Przyciski);
  akcja.attach(3, 300, Inkrementator);
  akcja.attach(4, 50, LiczSekundy);
}

void loop() {
  akcja.process();
}

Co miesiąc do wygrania nagrody o wartości ponad 1600 zł!


ODPOWIEDZ

Strony partnerskie: