Oświetlenie Akwarium

co i jak zrobiłem...
Awatar użytkownika
Pyra
Site Admin
Posty: 8522
Rejestracja: niedziela 02 sie 2009, 20:35
Lokalizacja: Gądki

Re: Oświetlenie Akwarium

Post autor: Pyra »

Witam

Wczoraj popracowałem przy starym sterowniku, w celu zabudowy nowego transformatora, przesunąłem płytkę sterującą, przy okazji znalazłem uszkodzony przewód do sterowania przetwornicami LED.
Musiałem też wymienić 2 szt. białych XPG, bo padły po kilku miesiącach, jedna chyba po dwóch. Jeden szereg zmieniłem na 4 szt. SST-40 6500K, pozyskane sprawne poszły w miejsce uszkodzonych.
Wyświetlacz już się kończy, wyregulowałem kontrast, ale niewiele to dało, docelowo trzeba by go wymienić.

W nowym projekcie, żmudna dłubanina. Po całym dniu dzisiejszym, mam zrobione rozjaśnianie i ściemnianie oświetlenia i płynną zmianę temperatury (rano - wieczór). Tu napisałem kilka warunków rozróżniających stany. Jeśli trwa rozjaśnianie lub ściemnianie (lub zmiana temperatury) to mamy pół słoneczka, jeśli proces dobiegnie końca, to następuje zmiana na całe słoneczko (żółte) lub księżyc (biały).
Napisałem obsługę EEPromu, ustalanie adresów, konwersja liczb na bajty itp. Trochę było roboty.
Zmieniłem koncepcję obliczeń, zmienne float (zmiennoprzecinkowe) zamieniam na word (2 bajty) poprzez mnożenie przez 100. Dopiero na tych danych dokonuję obliczeń.
Czas też zmieniam, bajt godzin i minut łączę w jedną liczbę i tak porównuję w celu rozpoznania dnia i nocy.

PID niestety nie daje pełnej temperatury, lecz stabilizuje około 0,05 poniżej zadanej. Może się trochę poprawi, gdy wydłużę interwał pomiarowy co da możliwość zwiększenia dokładności regulacji. Teraz jest około 7s, docelowo chciałbym osiągnąć jakieś 5 - 10 minut, dostosowując do bezwładności ośrodka. Aktualnie mam 8 jednostek czasu, a celuję w 256 - 500.

Niestety nie do końca zrozumiałem zasadę wyświetlania znaków, i miałem kłopoty z zamazywaniem poprzedniej ikonki (słoneczko). Dodanie spacji nic nie dawało, bo zamazywała się np. połowa znaku. Docelowo najpierw zamazuję spacjami, potem dopiero drukuję. Nowy znak wyświetla się tylko jeśli nastąpiła zmiana. Ikonki wyświetlane są stabilniej, ale doszły kolejne warunki.
Zostało mi jeszcze 7kB na menu, jak mi zabraknie pamięci, to będę kombinował ze zmniejszeniem kodu.
Aktualnie:
"Szkic używa 23676 bajtów (77%) pamięci programu. Maksimum to 30720 bajtów.
Zmienne globalne używają 691 bajtów (33%) pamięci dynamicznej, pozostawiając 1357 bajtów dla zmiennych lokalnych. Maksimum to 2048 bajtów."

Pozdrawiam
Izali miecz godniejszy niżli topór w boju?
Piszmy po polsku, wszak jesteśmy Polakami.
Awatar użytkownika
Pyra
Site Admin
Posty: 8522
Rejestracja: niedziela 02 sie 2009, 20:35
Lokalizacja: Gądki

Re: Oświetlenie Akwarium

Post autor: Pyra »

Witam

Ostatnie prace, posunęły projekt o kilka rzeczy.
Najważniejsze, to zostało zrobione sterowanie oświetleniem. Przyjąłem dwa warianty, które mogą być stosowane osobno lub łącznie
Przy przejściu porannym, oświetlenie zmienia się od minimum do pełnej jasności. Po osiągnięciu pełnej jasności, załącza się dodatkowy przekaźnik, którym można załączać dodatkowe oświetlenie w postaci żarówek czy świetlówek, lub zespołu lamp LED na 230V. Czas rozjaśniania (i ściemniania) to około 30 minut. Aktualnie jest ustawiona opcja "oświetlenia nocnego", jak poczuję potrzebę to jeszcze dołączę możliwość zmiany tego parametru w menu.
Przy przejściu wieczornym, najpierw gaśnie oświetlenie dodatkowe, a potem zaczyna się ściemnianie LED.
W obu przypadkach, wartość PWM jest zwiększana lub zmniejszana w zakresie od 2 do 128, pomiędzy 128 a 255, następuje jednorazowy przeskok.
Jeśli chodzi o regulację jasności PWM, to szczególnie przy minimum, następują przeskoki jasności, chcę to wyeliminować przez zastosowanie układu RC o bardzo długim czasie, który będzie łagodził przejścia. Szczególnie jest to widoczne na pierwszych 4-ch poziomach jasności. Tu jeszcze chyba dobuduję jedną opcję, wyjście Enable do ewentualnych przetwornic zasilających LED.
Pomiar i wyświetlenie temperatury następuje co minutę, natomiast cykl termostatu, został wydłużony do 5 minut, i dało mi to rozdzielczość czasów załączenia grzałki na poziomie 25, mam nadzieję, że to wystarczy. Zasadniczo, mogę cykl wydłużyć nawet do 10 minut, i wtedy rozdzielczość wzrośnie do 50.

Zrobiłem też menu, które umożliwia zmianę nastaw czasu rozpoczęcia cyklu dnia oraz nocy, niestety, nie zrobiłem sprawdzania, czy rano < wieczór, ale zostawiam to inteligencji obsługującego. Dalej mam możliwość zmiany temperatury dnia i nocy. Zmiany dokonywane są osobno dla godzin i minut (osobna pozycja menu) ale wyświetlam pełny czas w formacie hh:mm.
Zastanawiam się czy zrobić możliwość zmiany czasu, na razie z tego zrezygnowałem w związku z bardzo dużą precyzją zegara. Zasadniczą jego rolą jest ustalanie punktu przełączenia dnia i nocy, a nie wskazywanie dokładnego czasu. Przyroda w końcu też nie zna zmiany czasu z zimowego na letni itp.
Temperaturę mierzę i przeliczam z rozdzielczością 0,01°C, natomiast wyświetlam i ustawiam z precyzją 0,1°C. Temperaturę zmieniam "na raz" w zakresie od 18°C do 35°C
Proces zmian parametrów niestety zatrzymuje wyświetlanie zegara, jednak samo menu już nie. Dodatkowo zrobiłem zabezpieczenie, które przy braku reakcji w ciągu 10s, powoduje automatyczne opuszczenie menu.
Zostało mi jeszcze 4kB pamięci, więc ewentualne modyfikacje jeszcze są możliwe.

Pozdrawiam
Izali miecz godniejszy niżli topór w boju?
Piszmy po polsku, wszak jesteśmy Polakami.
Awatar użytkownika
Pyra
Site Admin
Posty: 8522
Rejestracja: niedziela 02 sie 2009, 20:35
Lokalizacja: Gądki

Re: Oświetlenie Akwarium

Post autor: Pyra »

Witam

Jako że ma być regulacja jasności LED, ale dużej mocy na oświetlenie nie przewiduję, będzie to niecały metr taśmy 12V zasilanej 11V, więc postanowiłem zrobić regulator analogowy. Jako element wykonawczy będzie pracował LM317 / LM350.
Obrazek
Jak widać układ jest bardzo prosty, a co za tym idzie, powinien być bardzo niezawodny.
Na wyjściu otrzymujemy napięcia z zakresu 7,5V - 11V, czyli światło księżyca, oraz słoneczko, chociaż bez szaleństw, dodatkowo przecież będzie światło dzienne. Dodatkowe światło, jednak przydaje się ze względu na obserwację wnętrza, oraz sam proces rozjaśniania i ściemniania.
Jeśli chodzi o wersję pełnego oświetlenia LED, będą to standardowe przetwornice sterowane napięciem, analogicznie jak w pierwotnym projekcie.
Wejście sygnału PWM z procesora, jest tu przedstawione jako napięcie V2. Kondensator jest tu w celu przefiltrowania sygnału PWM, i wygładzenia do napięcia stałego. Układ jest tak obliczony, że przy pełnym napięciu, w zasadzie działa na rezystorach, Napięcie uzyskane z PWM, jest zbliżone do normalnego napięcia panującego w punkcie przyłączenia, czyli u zbiegu rezystorów R2, R3 i R5.

Pozdrawiam
Izali miecz godniejszy niżli topór w boju?
Piszmy po polsku, wszak jesteśmy Polakami.
Awatar użytkownika
Pyra
Site Admin
Posty: 8522
Rejestracja: niedziela 02 sie 2009, 20:35
Lokalizacja: Gądki

Re: Oświetlenie Akwarium

Post autor: Pyra »

Witam

Po pewnym czasie eksploatacji oraz kilku poprawkach baboli, kod uzyskał już działającą postać.
Gdyby ktoś miał ochotę, to wklejam całość.

Kod: Zaznacz cały


//#define ILI9341_BLACK       0x0000      /*   0,   0,   0 */
//#define ILI9341_NAVY        0x000F      /*   0,   0, 128 */
//#define ILI9341_DARKGREEN   0x03E0      /*   0, 128,   0 */
//#define ILI9341_DARKCYAN    0x03EF      /*   0, 128, 128 */
//#define ILI9341_MAROON      0x7800      /* 128,   0,   0 */
//#define ILI9341_PURPLE      0x780F      /* 128,   0, 128 */
//#define ILI9341_OLIVE       0x7BE0      /* 128, 128,   0 */
//#define ILI9341_LIGHTGREY   0xC618      /* 192, 192, 192 */
//#define ILI9341_GREY        0x7BEF
//#define ILI9341_DARKGREY    0x7BEF      /* 128, 128, 128 */
//#define ILI9341_BLUE        0x001F      /*   0,   0, 255 */
//#define ILI9341_GREEN       0x07E0      /*   0, 255,   0 */
//#define ILI9341_CYAN        0x07FF      /*   0, 255, 255 */
//#define ILI9341_RED         0xF800      /* 255,   0,   0 */
//#define ILI9341_MAGENTA     0xF81F      /* 255,   0, 255 */
//#define ILI9341_YELLOW      0xFFE0      /* 255, 255,   0 */
//#define ILI9341_WHITE       0xFFFF      /* 255, 255, 255 */
//#define ILI9341_ORANGE      0xFD20      /* 255, 165,   0 */
//#define ILI9341_GREENYELLOW 0xAFE5      /* 173, 255,  47 */
//#define ILI9341_PINK        0xF81F


#include <Wire.h>
#include <EEPROM.h>
#include <SHT2x.h>
#include <DS3231.h>
#include "SPI.h"
#include "Adafruit_GFX_AS.h"
#include "Adafruit_ILI9341_AS.h"

DS3231 clock;
RTCDateTime dt;

#define sclk 13  // Nie zmieniać
#define miso 12  
#define mosi 11  // Nie zmieniać
#define cs   10
#define dc   9
#define rst  8                  // można podłączyć do resetu arduino
#define adrdzien 0              //adres eepromu z zawartością godziny rozpoczęcia dnia: 0 > hh, 1 > mm
#define adrnoc 2                //adres nocy 2 > hh, 3 > mm
#define adrtempdzien 4          //adres temperatury w dzień: 4 starszy bajt, 5 młodszy bajt
#define adrtempnoc 6            //adres temperatury w nocy
#define grzalka 7               //wyjście grzałki
#define UP 2                    // przycisk  UP na Pin 3
#define OK 3                    // przycisk  OK na pinie 4
#define DOWN 4                  // przycisk  DOWN na pinie 5
#define PWMLED 5                //wyjście na sterowanie oświetleniem PWM
#define zarowka 6               //wyjście na żarówkę


Adafruit_ILI9341_AS tft = Adafruit_ILI9341_AS(cs, dc, rst);       //Deklaracja biblioteki wyświetlacza

unsigned long start = micros(); //licznik czasu pętli
float temperature = 0;          //temperatura zmierzona
word temperatura = 0;           //przekonwertowana temeratura ze zmiennoprzecinkowej na całkowitą, float x 100
word termostat = 5;             //temperatura aktualna termostatu, po zmianie dąży do docelowej co 1
word termostata = 0;            //temperatura docelowa dnia lub nocy

byte hhdzien = 8;               //godzina rozpoczęcia dnia
byte mmdzien = 0;               //minuta rozpoczęcia dnia
byte hhnoc = 20;                //godzina rozpoczęcia końca dnia
byte mmnoc = 0;                 //minuta rozpoczecia nocy
byte poradoby = 0;              //pora doby dzień = 1, rano lub wieczór =2, noc = 3
word licznik = 0;               //liczenie czasu w pętli pomiarów
byte licznikLED = 0;            //liczenie czasu rozjaśniania LEDów
byte liczniktemp = 0;           //licznik czasu zmiany temperatury
word tsr = 0;                   //zmienna zawierająca sumę 10 pomiarów
byte oldss = 0;                 //poprzednie sekundy
byte LEDDN = 0;                 //jasność docelowa LED
byte LED = 0;                   //jasność światła LED
int ep;                         //uchyb poprzedni
int en;                         //uchyb następny
int U;                          //sygnał sterujący
int C;                          //część całkująca

byte menu = 0;
byte submenu = 0;


void setup() {

licznik = 500;                //500 = 5 minut
licznikLED = 25;              //25 = 15s 
liczniktemp = 100;            //200 = 1 minuty

  Wire.begin();  
  clock.begin();
  Serial.begin(9600);
  pinMode(grzalka, OUTPUT);       //grzałka
  pinMode(PWMLED, OUTPUT);        //wyjście LED
  pinMode(zarowka, OUTPUT);       //wyjście na sterowanie oświetleniem klasycznym
  pinMode(DOWN,INPUT_PULLUP);     // konfiguracja pinów dla przycisków
  pinMode(UP,INPUT_PULLUP);       // konfiguracja pinów dla przycisków
  pinMode(OK,INPUT_PULLUP);       // konfiguracja pinów dla przycisków
       
  tft.init();

  tft.setRotation(3);
  tft.fillScreen(ILI9341_BLACK);

      tft.setTextColor(ILI9341_YELLOW, ILI9341_BLACK); 
      tft.setTextSize(1);
      tft.drawString("Termostat - akwarium",40,0,4);      
  tft.setTextColor(ILI9341_GREEN);
      tft.drawString("Temp.                        Wilg.",40,30,4);
      tft.drawString("Czas",20,170,4);
      tft.drawString("Menu",20,210,4);
    tft.setTextSize(2);       

  tft.setTextColor(ILI9341_BLUE, ILI9341_BLACK);  
    tft.drawString("|",280,60,4);      
    tft.drawString("*",125,60,4);                    //st. C

        
pomiartemp();
tsr = temperature * 900;
temperature = temperature *10;
termostat = temperature;                            //przyjęcie zmierzonej temperatury, jako aktualną termostatu by dążyć do docelowej
termostat = termostat *10;
termostat = termostat + 5;                          //zaokrąglenie ostatniej cyfry do 5
//EEPROM.update(adrdzien,hhdzien); 
//EEPROM.update((adrdzien+1),mmdzien); 
//EEPROM.update(adrnoc,hhnoc); 
//EEPROM.update((adrnoc+1),mmnoc);   
// byte pomocnicza = 0;
// pomocnicza = termostat;
//EEPROM.update((adrtempdzien +1),pomocnicza); 
//pomocnicza = termostat>>8;
//EEPROM.update(adrtempdzien,pomocnicza);
// pomocnicza = termostat;
//EEPROM.update((adrtempnoc +1),pomocnicza); 
//pomocnicza = termostat>>8;
//EEPROM.update(adrtempnoc,pomocnicza);  
  //clock.setDateTime(__DATE__, __TIME__);                    //ustaw czas pobrany z serwaera
  // Manual (Year, Month, Day, Hour, Minute, Second)          //ustawienia zegara
  //clock.setDateTime(2014, 4, 25, 0, 0, 0);

//termostata = (odczyteeprom(adrtempdzien)<<8) + odczyteeprom (adrtempdzien +1);
hhdzien = odczyteeprom(adrdzien);
mmdzien = odczyteeprom(adrdzien + 1);
hhnoc = odczyteeprom(adrnoc);
mmnoc = odczyteeprom(adrnoc + 1);

}


void loop(void) {

  if(digitalRead(OK)==LOW){delay(40); if(digitalRead(OK)==LOW){delay(200); if (menu == 0) menu = 1;}}                       // jeśli OK  
  ustaw();                         
    
  tft.setTextSize(2);
//  tft.setTextColor(ILI9341_BLUE, ILI9341_BLACK); 
  word dzien;             
  word noc;
  word czas;  
  byte nowadoba = 0;

  dt = clock.getDateTime();                       //pobranie czasu z zegara
  byte hh = dt.hour;            
  byte mm = dt.minute;
  byte ss = dt.second;
  czas = (hh << 8) + mm;                          //przeliczanie godzin i minut na jedną liczbę
  dzien = (hhdzien << 8) + mmdzien;
  noc = (hhnoc << 8) + mmnoc;

  if (czas >= dzien && czas <= noc) {             //rozpoznanie pory doby dla wyświetlenia ikony
     nowadoba = 1;
     termostata = (odczyteeprom(adrtempdzien)<<8) + odczyteeprom (adrtempdzien +1);    
     LEDDN = 255; 
  }
  else {
     nowadoba = 3;
     termostata = (odczyteeprom(adrtempnoc)<<8) + odczyteeprom (adrtempnoc +1);
     LEDDN = 2;
    }

  if (termostat != termostata) nowadoba = 2;      //Jeśli temperatura aktualna i docelowa są różne to jest wieczór lub poranek 
  if (nowadoba != poradoby){                      //Jeśli nastąpiła zmiana pory doby to wyświetl nowy symbol
    poradnia(nowadoba);
    poradoby = nowadoba;    
  }
  
  if (oldss != ss){                               //Nowa sekunda to wyświetl czas
    oldss = ss;
    zegar(hh,mm,ss);            
  }

   if (liczniktemp == 200){                                   //cykl zmian temperatury 0,1C na 2 minuty
    liczniktemp = 0;
    if (termostata > termostat) termostat = termostat + 10;
    if (termostata < termostat) termostat = termostat - 10;    
  }
   
  if (licznik == 500){                                        //cykl grzania 5 minut
     licznik = 0;
     pomiartemp();
     grzanie();                                               //Termostat obliczanie PID
  }

  if (licznikLED == 25){                                      //cykl zmiany jasności 15s
    licznikLED = 0;
     if (LED < LEDDN) {LED++; if (LED > 127) LED = LEDDN;}    //rozjaśnianie LED
     if (LED > LEDDN) {LED--; if (LED > 129) LED = 129;}      //ściemnianie LED
     if (LED == 255) digitalWrite(zarowka,HIGH);              //załączenie żarówki     
     if (nowadoba == 3)digitalWrite(zarowka,LOW);             //wyłaczenie żarówki
     analogWrite(PWMLED,LED);                                 //ustawienie jasności LED    
     pomiartemp();
     temp(mm,ss);                                             //wyświetlanie temperatury i wilgotności      
  }

  if (licznik < U) {                                          //Obsługa grzałki
     tft.setTextColor(ILI9341_RED, ILI9341_BLACK);         
     tft.drawString(")",70,110,4);                            //grzałka włączona  
     digitalWrite(grzalka,HIGH);
  }
  else {
    tft.setTextColor(ILI9341_BLUE, ILI9341_BLACK);         
    tft.drawString(")",70,110,4);                             //grzałka wyłączona 
    digitalWrite(grzalka,LOW);    
  }
if ((millis() - start) > 600){                                 //600 to 0,6s
licznik ++;    
licznikLED++;
liczniktemp++;
start = millis();
}
      
}

void nastawaczasu(byte adres, byte zakres){
  byte dane;
  byte godz;
  byte minuty;
  byte nowe = 255;
  unsigned long czas;
  czas = millis();
  godz = odczyteeprom(adres); 
  minuty = odczyteeprom(adres + 1);
     
  while (true){
  byte xpos = 180;   
  byte ypos = 210;
  if (zakres == 23) {dane = godz;}
  else {dane = minuty;}
  tft.setTextSize(1);  
  tft.setTextColor(ILI9341_GREEN,ILI9341_BLACK);
  
  if (nowe != dane){ 
      if (godz < 10) xpos+= tft.drawChar('0',xpos,ypos,4);
      xpos+= tft.drawNumber(godz,xpos,ypos,4);  
      xpos+= tft.drawChar(':',xpos,ypos,4);
      if (minuty<10) xpos+= tft.drawChar('0',xpos,ypos,4);
      xpos+=tft.drawNumber(minuty,xpos,ypos,4);
      
      nowe = dane;
  }
     if(digitalRead(UP)==LOW){delay(40);if(digitalRead(UP)==LOW) {delay(200); dane++; czas = millis(); if (dane > zakres) {dane = 0;}}}          // jeśli UP   
     if(digitalRead(DOWN)==LOW){delay(40);if(digitalRead(DOWN)==LOW) {delay(200); czas = millis(); if (dane == 0) {dane = zakres + 1;}dane--;}}   // jeśli DOWN   
     if(digitalRead(OK)==LOW){delay(40); if(digitalRead(OK)==LOW){delay(200); zapiszczas(adres,godz,minuty); break;}}      // wejście  submenu      
     if (zakres == 23) {godz = dane;}
     else {minuty = dane;}  
     if (millis() - czas > 10000) {tft.drawString("            ",180,210,4); submenu = 0; break;}  

     dt = clock.getDateTime();                     //pobranie czasu z zegara
  byte hh = dt.hour;            
  byte mm = dt.minute;
  byte ss = dt.second;
    if (oldss != ss){
    oldss = ss;
    zegar(hh,mm,ss);
    }
 }
}

void zapiszczas(byte adres, byte godz, byte minuty){
  tft.drawString("OK           ",180,210,4);   
  EEPROM.update(adres,godz); 
  EEPROM.update((adres+1),minuty); 
  if (adres == adrdzien){hhdzien = godz; mmdzien = minuty;}
  else {hhnoc = godz; mmnoc = minuty;}
  
  delay(1000);
  tft.drawString("         ",180,210,4); 
  submenu = 0;  
}

void nastawatemp(byte adres){
  word dane;
  word nowe = 0;
  float temp = 0;
  unsigned long czas;
  czas = millis();  
  dane = (odczyteeprom(adres)<<8) + odczyteeprom (adres +1);        //odczyt temperatury do ustawienia
//  dane = 2555;
  while (true){
    temp = dane;
    temp = temp / 100;                                                            //przeliczenie temperatury na liczbę zmiennoprzecinkową do wyświetlenia
    tft.setTextSize(1);  
    tft.setTextColor(ILI9341_GREEN,ILI9341_BLACK);

    if (nowe != dane) {tft.drawFloat(temp,2,180,210,4);  tft.drawString("*",250,210,4);  nowe = dane;}
     if(digitalRead(UP)==LOW){delay(40);if(digitalRead(UP)==LOW) {delay(200); if (dane < 3495) dane = dane + 10;czas = millis();}}          // jeśli UP   
     if(digitalRead(DOWN)==LOW){delay(40);if(digitalRead(DOWN)==LOW) {delay(200); if (dane > 1815) dane = dane - 10;czas = millis();}}      // jeśli DOWN   
     if(digitalRead(OK)==LOW){delay(40); if(digitalRead(OK)==LOW){delay(200);zapisztemp(adres,dane); break;}}                               // wejście  submenu   
     if (millis() - czas > 10000) {tft.drawString("            ",180,210,4); submenu = 0; break;}    

       dt = clock.getDateTime();                     //pobranie czasu z zegara
  byte hh = dt.hour;            
  byte mm = dt.minute;
  byte ss = dt.second;
    if (oldss != ss){
    oldss = ss;
    zegar(hh,mm,ss); 
    }        
  }
}

void zapisztemp(byte adres, word dane){
  tft.drawString("OK           ",180,210,4); 
  byte pomocnicza = 0;
  pomocnicza = dane;
  EEPROM.update((adres +1),pomocnicza); 
  pomocnicza = dane>>8;
  EEPROM.update(adres,pomocnicza);
  delay(1000);
  tft.drawString("         ",180,210,4); 
  submenu = 0;
}

void ustaw(){
   tft.setTextSize(1);  
  tft.setTextColor(ILI9341_GREEN,ILI9341_BLACK);
  if (menu >0){
    if(digitalRead(UP)==LOW){delay(40);if(digitalRead(UP)==LOW) {delay(200); menu++; submenu = 0; if (menu > 7) menu = 1;}}               // jeśli UP   
    if(digitalRead(DOWN)==LOW){delay(40);if(digitalRead(DOWN)==LOW) {delay(200); menu--; submenu = 0; if (menu < 1) menu = 7;}}           // jeśli DOWN   
    if(digitalRead(OK)==LOW){delay(40); if(digitalRead(OK)==LOW){delay(200);if (submenu == 1) {submenu = 2;}}}      // wejście  submenu     
  } 
    
  switch(menu){    
    case 0:

    break;
    
    case 1:
    if (submenu == 0) {tft.drawString("<<<  ",100,210,4); submenu = 1;}   
    if(digitalRead(OK)==LOW){delay(40); if(digitalRead(OK)==LOW){menu = 0; submenu = 0; tft.drawString("                  ",100,210,4);delay(200); }}                 // Powrót z menu          
    break;

    case 2:
    if (submenu == 0) {tft.drawString("D-h  ",100,210,4); submenu = 1;}   
    if(submenu == 2){delay(200);nastawaczasu(adrdzien, 23);}      // wejście  submenu         
    break;

    case 3:
    if (submenu == 0) {tft.drawString("D-m ",100,210,4); submenu = 1;}   
    if(submenu == 2){delay(200);nastawaczasu(adrdzien, 59);}      // wejście  submenu           
    break;

    case 4:
    if (submenu == 0) {tft.drawString("N-h  ",100,210,4); submenu = 1;}   
    if(submenu == 2){delay(200);nastawaczasu(adrnoc, 23);}      // wejście  submenu         
    break;

    case 5:
    if (submenu == 0) {tft.drawString("N-m ",100,210,4); submenu = 1;}   
    if(submenu == 2){delay(200);nastawaczasu(adrnoc, 59);}      // wejście  submenu       
    break;

    case 6:
    if (submenu == 0) {tft.drawString("TeD   ",100,210,4);  submenu = 1;}   
    if(submenu == 2){delay(200);nastawatemp(adrtempdzien);}      // wejście  submenu        
    break;

    case 7:
    if (submenu == 0) {tft.drawString("TeN   ",100,210,4);  submenu = 1;}   
    if(submenu == 2){delay(200);nastawatemp(adrtempnoc);}      // wejście  submenu       
    break;
       
  }
  tft.drawString("         ",170,210,4);      
 }

void poradnia(byte symbol){

    tft.drawString("    ",200,110,4);  
  switch (symbol){
    case 1:              //słońce
    tft.setTextColor(ILI9341_YELLOW, ILI9341_BLACK);  
    tft.drawString("!",190,110,4);              //pół słońca - ' 39; słońce - ! 33; księżyc - ( 40   
    break;

    case 2:              //pół słońca
    tft.setTextColor(ILI9341_YELLOW, ILI9341_BLACK);   
    tft.drawString("'",190,110,4);      
    break;

    case 3:              //księżyc
    tft.setTextColor(ILI9341_WHITE, ILI9341_BLACK); 
    tft.drawString("(",190,110,4);    
    break;
       
  }
  
}

byte odczyteeprom(byte adres){
 return EEPROM.read(adres);
}

void zapiseeprom(byte adres,byte dane){
  EEPROM.update(adres,dane);
}

void pomiartemp(){
    temperature = SHT2x.GetTemperature(); 
    temperatura = temperature * 100;
}

void temp(byte mm, byte ss){
    tsr = tsr + temperatura;
    temperatura = tsr /10;
    tsr = tsr - temperatura;    
    temperature = temperatura;
    temperature = temperature / 100;
    tft.setTextSize(2);
    tft.setTextColor(ILI9341_BLUE, ILI9341_BLACK); 
    tft.drawFloat(temperature,1,20,60,4);    
    tft.drawFloat(SHT2x.GetHumidity(),0,220,60,4);  

   
}

void grzanie(){              //procedura termostatu
byte dt = 30; //co ile pobiera się próbkę  
byte Kp = 20; //wzmocnienie
byte Ti = 30; //stała całkowania
byte Td = 40; //stała różniczkowania

 en = (termostat - temperatura);
 C += ((ep + en)/2)*dt;
 U = Kp*(en + (1/Ti)*C + Td*(en - ep)/dt);
 ep = en; 

 
 if (U < 0) U = 0;
 if (U > 500) U = 500;

     Serial.print("  LED ");
    Serial.print(LED);     
    Serial.print("  termostat " );
    Serial.print(termostat);   
    Serial.print("  temperatura " );
    Serial.print(temperatura);       
    Serial.print("  temp = ");
    Serial.print(temperature);
    Serial.print("  en = ");
    Serial.print(en);
    Serial.print("  ep = ");
    Serial.print(ep);
        Serial.print("  C = ");
    Serial.print(C);
    Serial.print("  U =" );
    Serial.println(U); 
 }

void zegar(byte hh, byte mm, byte ss){

    byte xpos = 85;
    byte ypos = 155; 
    
    tft.setTextSize(2);
    tft.setTextColor(ILI9341_BLUE, ILI9341_BLACK);     
     
      if (hh<10) xpos+= tft.drawChar('0',xpos,ypos,4);
      xpos+= tft.drawNumber(hh,xpos,ypos,4);

      xpos+= tft.drawChar(':',xpos,ypos,4);
      if (mm<10) xpos+= tft.drawChar('0',xpos,ypos,4);
      xpos+=tft.drawNumber(mm,xpos,ypos,4);
      
      xpos+= tft.drawChar(':',xpos,ypos,4);
      if (ss<10) xpos+= tft.drawChar('0',xpos,ypos,4);
      tft.drawNumber(ss,xpos,ypos,4);    
}
Przy pierwszym uruchomieniu programu, należy zająć się poniższym fragmentem:

Kod: Zaznacz cały

//EEPROM.update(adrdzien,hhdzien); 
//EEPROM.update((adrdzien+1),mmdzien); 
//EEPROM.update(adrnoc,hhnoc); 
//EEPROM.update((adrnoc+1),mmnoc);   
// byte pomocnicza = 0;
// pomocnicza = termostat;
//EEPROM.update((adrtempdzien +1),pomocnicza); 
//pomocnicza = termostat>>8;
//EEPROM.update(adrtempdzien,pomocnicza);
// pomocnicza = termostat;
//EEPROM.update((adrtempnoc +1),pomocnicza); 
//pomocnicza = termostat>>8;
//EEPROM.update(adrtempnoc,pomocnicza);  
  //clock.setDateTime(__DATE__, __TIME__);                    //ustaw czas pobrany z serwaera
  // Manual (Year, Month, Day, Hour, Minute, Second)          //ustawienia zegara
  //clock.setDateTime(2014, 4, 25, 0, 0, 0);
Tutaj należy "odkomentować" wszystkie linie, a następnie przy deklaracji zmiennych, wpisać wartości starowe. Po zapisaniu w eepromie, trzeba przywrócić pierwotny stan programu, gdyż wszystkie dane już będą zapamiętane.

Wyjaśnienia wymagają ostatnie trzy linijki:
//clock.setDateTime(__DATE__, __TIME__); //ustaw czas pobrany z serwaera
Ustawia czas ściągnięty z komputera. Niestety, dostajemy wtedy opóźnienie zegara o czas wgrywania programu.
// Manual (Year, Month, Day, Hour, Minute, Second) //ustawienia zegara
//clock.setDateTime(2014, 4, 25, 0, 0, 0);[/code]
Natomiast ten fragment, umożliwia ręczne ustawienie czasu, te dwa sposoby, należy traktować alternatywnie.
Nie zrobiłem ustawiania czasu, gdyż wyszedłem z założenia, że zwierząt nie obowiązują zmiany zima/lato, a niedokładność zegara wynosząca kilka minut w skali roku, jest w tym zstaosowaniu do pominięcia. Jeśli ktoś chce mieć możliwość ręcznego ustawienia czasu, może sobie dopisać odpowiedni fragment w menu.

Mała poprawka dostyczy też układu regulacji jasności taśmy LED, rezystor R2 ma teraz wartość 2k2, co dało zakłądany zakres regulacji jasności.

Pozdrawiam
Izali miecz godniejszy niżli topór w boju?
Piszmy po polsku, wszak jesteśmy Polakami.
Awatar użytkownika
Pyra
Site Admin
Posty: 8522
Rejestracja: niedziela 02 sie 2009, 20:35
Lokalizacja: Gądki

Re: Oświetlenie Akwarium

Post autor: Pyra »

Witam

Po małej zmianie oświetlenia, (4 x XPG i 4 x XML2 65000k + 4 x deep red i 4 x royal blue) Dołożeniu CO2, roślinki rosną całkiem przyjemnie, puszczając tlen strumieniami bąbelków.
obrazek
Kliknij obrazek, aby powiększyć

Aktualnie pracuję nad nowymi przetwornicami, z których będę mógł wyciągnąć jakieś 2A. Najprawdopodobniej będzie to przeróbka popularnych modułów za pomocą dodatkowego wzmacniaczy operacyjnych.

Pozdrawiam
Izali miecz godniejszy niżli topór w boju?
Piszmy po polsku, wszak jesteśmy Polakami.
ODPOWIEDZ