• Witaj na Forum Arduino Polska! Zapraszamy do rejestracji!
  • Znajdziesz tutaj wiele informacji na temat hardware / software.
Witaj! Logowanie Rejestracja


Ocena wątku:
  • 0 głosów - średnia: 0
  • 1
  • 2
  • 3
  • 4
  • 5
Sterownik Akwarystyczny DIY
#1
Witajcie po ponad półrocznej przerwie.
Od moich ostatnich walk z arduino Nano i różnymi LCD  powstał projekcik który z powodzeniem pracuje (arduino Nano +

LCD 20x4) który obsługuje:
  1. sterowanie PWM świt/zmierzch,
  2. pomiar temperatury plus chłodzenie,
  3. pomiar pH, plus obliczenie zawartości Co2 na podstawie wprowadzanego KH,
  4. obsługa dozownika nawozów na bazie pompy perstaltycznej,
  5. wyświetlanie danych na LCD 20x4.
Projekt były OK ale brakuje mu np. możliwości ustawień bez konieczności ładowania sketcha ze zmianami.
Dlatego też jak to w życiu bywa potrzeba człowiekowi zmian :-). i postanowiłem udoskonalić sterownik.
W wyniku prób różnych wyświetlaczy i obsługi menu (temat widmo w zwykłych LCD) wybór padł na wyświetlacze NEXTION a dokładnie 2,4''.

Obecnie nowy sterownik będzie obsługiwać:
  1. sterowanie dwoma kanałami PWM świt/zmierzch, (ustawienia z LCD godzin włączania i wyłączania)
  2. pomiar temperatury - 2 kanały plus obsługa dwóch wiatraków do chłodzenia, (ustawienia z LCD histerezy oraz temperatur),
  3. pomiar pH (z możliwością kalibracji sondy),
  4. ustawianie wartości KH z pozycji LCD (bez konieczności aktualizacji sketcha jak to było do tej pory)
  5. wyliczanie zawartości Co2 na bazie pH i KH,
  6. obsługa dozownika nawozów (z możliwością zadawania jednorazowych porcji, czasu dozowania oraz monitorowania ilości nawozu w zasobniku),
  7. no i obowiązkowo: Data i Czas.
Jak widać zmiany spore :-) ale już pierwsze efekty są co można zobaczyć na krótkim filmiku:

i tu się kończy moje chwalenie :-( gdyż są tematy który nie mogę ogarnąć :-(

Mam gorącą prośbę  do Fachowców od arduino o pomoc!!!

Poniżej zamieszczam sketch sterownika. Całość pracuje na arduino MEGA 2560.

Na chwilę obecną co całości szczęścia brakuje:
  1. Jak zaprogramować zegar/datę aby można było z pozycji LCD ustawiać datę i godzinę (obecnie jest to aktualizowanie RTC DS1307 i start),
  2. Jak ustawić pętlę w części dozownika aby za każdym razem kiedy jest dozowana ustalona porcja wartość zasobnika zmniejszała się o ustaloną wartość (graficzne przedstawienie ilości w zasobniku jest skojarzone z pozycji LCD i działa na zmianę wartości zasobnika),
  3. Czy jest inny - prostszy sposób/metoda sterowania PWM gdyż w moim kodzie jest możliwość tylko zmiany godzin startu i końca natomiast ustalanie mocy świecenie wymaga ustawień ręcznych w kodzie (tabeli).
a teraz obiecany kod:

Kod:
#include "Arduino.h"
#include "Nextion.h"
#include <OneWire.h>
#include <DallasTemperature.h>
#include <TimeLib.h>
#include <Time.h>  
#include <Wire.h>
#include <DS1307RTC.h>

#define ONE_WIRE_BUS 13                               // pin 13 termomoetr
#define TEMPERATURE_RECISION 9
#define ODSTEP 1000
#define SensorPin A7                                  // wejście analogowe dla sensora pH - pin analogowy 7
#define LED A7                                        // nowy wpis do pH
#define samplingInterval 20                           // nowy wpis do pH
#define printInterval 800                             // nowy wpis do pH
#define ArrayLenth 40                                // times of collection
#define Offset 0.50                                   // kalibracja pH

//-----------------------PINY WE/WY ---------------------------------
int W1 = 5;                                           // pin 5 - wyjście do stycznika nr 1 - wentylator
int dozownik_1 = 6;                                           // pin 6 - wyjście do stycznika nr 2 - dozownik
int LED1 = 11;                                        // pin 11 - wyjście PWM do sterowania LED1
int LED2 = 10;                                        // pin 11 - wyjście PWM do sterowania LED2

int STEP = 1;                                         // długość trwania jednego kroku
int CZAS;                                             //czas do lampy led
int czas1;
int czas2;
int GODZ;                                             // godziny
int MIN;                                              // minuty
int maxD1 = 60;                                       // maksymalna moc kanału LED1
int maxD2 = 60;                                       // maksymalna moc kanału LED2
int ZMIANA = 60;  


int godzina_OFF;                                      // godzina wyłączenia dozownika
int minuta_OFF;                                       // minuty wyłączenia dozownika
int sekunda_ON = 00;                                  // sekunty włączenia dozownika

//int porcja;                                           // ilość wdozowywanego nawozu w ml

//int dzienG = 7;                                     // początek dnia - godziny
//int dzienM = 00;                                    // początek dnia - minuty
//int nocG = 20;                                      // początek nocy - godziny
//int nocM = 00;                                      // początek nocy - minuty
unsigned long czas_poprzedni = 0;
int licznik = 0;


int pH;
float b;
//float pH;                                            // dla sensora pH
                                   
int pHArray[ArrayLenth];                               //Store the average value of the sensor feedback  
int pHArrayIndex=0;                                    // nowy wpis do pH

//-----------------------ZMIENNE DLA TERMOMETRÓW -------------------------------
NexText t1 = NexText(1, 23, "t2");               //zmienna tekstowa dla termometra 1 (strona0)
NexText t2 = NexText(1, 24, "t3");               //zmienna tekstowa dla termometra 2 (strona0)


//-----------------------ZMIENNE DLA RTC -------------------------------

NexNumber g = NexNumber(1, 16, "page0.n1");     //zmienna numeryczna do zegara dla godzin (strona0)
NexNumber m = NexNumber(1, 17, "page0.n2");     //zmienna numeryczna do zegara dla minut (strona0)
NexNumber s = NexNumber(1, 18, "page0.n3");     //zmienna numeryczna do zegara dla sekund (strona0)
NexNumber d = NexNumber(1, 19, "page0.n4");     //zmienna numeryczna do kalendarza dla dni
NexNumber mie = NexNumber(1, 20, "page0.n5");   //zmienna numeryczna do kalendarza dla mieięcy
NexNumber r = NexNumber(1, 21, "page0.n6");     //zmienna numeryczna do kalendarza dla lat


//-----------------------ZMIENNE DLA TEMPERATURY - WIATRAK  -------------------------------

NexNumber limes = NexNumber(3, 4, "te0");           //zmienna numeryczna dla ustawień temperatury pobierana ze strony 3

//-----------------------ZMIENNE DLA SONDY PH  -------------------------------

NexNumber PHval = NexNumber(1, 12, "page0.n7");    //zmienna numeryczna dla wartosci pH wyswietlanej na stronie 0

//-----------------------ZMIENNE DLA TWARTOŚCI/co2  -------------------------------

NexNumber num1 = NexNumber(1, 31, "page0.n0");           //zmienna numeryczna dla twardości wyświetlanej na stronie 0
NexNumber co2 = NexNumber(1, 29, "page0.n8");            // obliczenie wartosci Co2 wyswietlanej na stronie 0

//-----------------------ZMIENNE DO STEROWANIA LAMPAMI   -------------------------------

NexNumber dG1 = NexNumber(3, 5, "page2.dg1");                     //zmienna numeryczna dla twardości wyświetlanej na stronie 0
NexNumber dM1 = NexNumber(3, 7, "page2.dm1");                     //zmienna numeryczna dla ustawień twardości pobierana ze strony 5
NexNumber nG1 = NexNumber(3, 4, "page2.ng1");                     //zmienna numeryczna dla twardości wyświetlanej na stronie 0
NexNumber nM1 = NexNumber(3, 6, "page2.nm1");                     //zmienna numeryczna dla ustawień twardości pobierana ze strony 5
NexNumber dzienG2 = NexNumber(7, 5, "page8.dzienG2");             //zmienna numeryczna dla twardości wyświetlanej na stronie 0
NexNumber dzienM2 = NexNumber(7, 7, "page8.dzienM2");             //zmienna numeryczna dla ustawień twardości pobierana ze strony 5
NexNumber nocG2 = NexNumber(7, 4, "page8.nocG2");                 //zmienna numeryczna dla twardości wyświetlanej na stronie 0
NexNumber nocM2 = NexNumber(7, 6, "page8.nocM2");                 //zmienna numeryczna dla ustawień twardości pobierana ze strony 5

NexText pora = NexText(0, 6, "po");                           // zmienna tekstowa dla pory dnia oświetlenia
NexNumber lamp1 = NexNumber(1, 23, "page0.l1");               // zmienna numeryczna dla statusu % lampy 1
NexNumber lamp2 = NexNumber(1, 24, "page0.l2");               // zmienna numeryczna dla statusu % lampy 2

//-----------------------ZMIENNE DO STEROWANIA DOZOWNIKIEM   -------------------------------

NexNumber zapas = NexNumber(8, 10, "zapas1");               // zmienna numeryczna dla ilości pełnego namiaru nawozu
NexNumber stan = NexNumber(1, 37, "zasobnik");                 // zmienna numeryczna dla wyswietlenia pozostalej ilosci nawozu
NexNumber porcja = NexNumber(8, 7, "doza1");                // zmienna numeryczna dla jednorazowej porcji nawozu
NexNumber porcja2 = NexNumber(1, 41, "n10");                 // zmienna numeryczna dla wyswietlenia ustalonej porcji nawozu
NexNumber nawozG = NexNumber(8, 17, "nawozG");              // zmienna numeryczna dla godziny podania nawozu
NexNumber nawozM = NexNumber(8, 16, "nawozM");              // zmienna numeryczna dla minuty  podania nawozu
NexProgressBar poziom = NexProgressBar(1, 35, "j1");          // wskaznik poziomu zasobnika z nawozem

NexTouch *nex_Listen_List[]=
{
  NULL
};


char buffer[10] = {0};


OneWire oneWire(ONE_WIRE_BUS);                        // termometr one wire
DallasTemperature sensors(&oneWire);                  // termometr
int numberOfDevices;
DeviceAddress tempDeviceAddress;

//--------------------------------------------------------------------------------------------------------
//-------------------SETUP-------------------------------
//--------------------------------------------------------------------------------------------------------
void setup() {

nexInit();
    sensors.begin();                                   // aktywacja termometr
    Serial.begin(9600);                                // aktywacja portu szeregowego
    Serial2.begin(9600);                               // aktwacja drugiego portu szeregowego
     while (!Serial) ;                                 // wait until Arduino Serial Monitor opens
 
   
   numberOfDevices = sensors.getDeviceCount();       // pobranie danych z sensora

//    pinMode(LED1, OUTPUT);                            // LED 1
//    pinMode(LED2, OUTPUT);                            // LED 2
//    pinMode(W1, OUTPUT);                              // wyjście wentylator
//    pinMode(W2, OUTPUT);                              // wyjście dozownik


   }                 // koniec void setup

   

//--------------------------------------------------------------------------------------------------------
//------------------- loop -------------------------------
//--------------------------------------------------------------------------------------------------------
void loop()
{


//------------------- ZEGAR -------------------------------  
tmElements_t tm;
 if (RTC.read(tm)) {                           // pobierz czas na wyświetlacz
   d.setValue(tm.Day);
 mie.setValue(tm.Month);
   r.setValue(tmYearToCalendar(tm.Year));
   g.setValue(tm.Hour);
   m.setValue(tm.Minute);
   s.setValue(tm.Second);
 }




unsigned long czas_aktualny = millis();
 if(czas_poprzedni - czas_aktualny> ODSTEP)

 czas_poprzedni = czas_aktualny;
 licznik = licznik + 1;


 Serial.println("swiatła start");
 LAMPY();                                                        // dane z bloku lampy
 Serial.println("temperatura start");
// printTemperature(DeviceAddress deviceAddress, int index);      // dane z bloku temperatury
 Serial.print("");
dozownik();                                                      // dane z bloku dozownika
 Serial.println("dozownik start");

PH_SONDA();                                                      // dane z bloku sondy pH
 Serial.println("sonda pH start");
   
}                                                                 // konice void loop


//-----------------------------------------------------------------------------------------

bool setSys0(uint32_t number)

{
 char buf[10] = {0};
 String cmd;

 utoa(number, buf, 10);
 cmd += "sys0=";
 cmd += buf;
 sendCommand(cmd.c_str());
 return recvRetCommandFinished();
}      // koniec funkcji bool

uint32_t numLimes;
//--------------------------------------------------------------------------------------------------------
//-------------------void ZEGAR-------------------------------
//--------------------------------------------------------------------------------------------------------
void zegar()
{



}





//--------------------------------------------------------------------------------------------------------
//-------------------void TEMPERATURY-------------------------------
//--------------------------------------------------------------------------------------------------------

void printTemperature(DeviceAddress deviceAddress, int index)
{
 float tempC = sensors.getTempC(deviceAddress);
 memset(buffer, 0, sizeof(buffer));
 String tempTXT = String(tempC, 2);
 tempTXT.toCharArray(buffer, 10);
 
 
   if(index == 0){
   t1.setText(buffer);
   Serial.print("temperatura 1=");
   Serial.print(buffer);

   limes.getValue(&numLimes);
   if(tempC > numLimes){
     setSys0(1);
   digitalWrite(W1,HIGH);
   Serial.println("wiatrak 1 - ON");
   }
   else{
     setSys0(0);
    digitalWrite(W1,LOW);  
    Serial.println("wiatrak 1 - OFF");
   }
 }
 if(index ==1){
   
    t2.setText(buffer);
    Serial.print("temperatura 2=");
    Serial.print(buffer);
   }
}




//--------------------------------------------------------------------------------------------------------
//-------------------VOID DOZOWNIK-------------------------------
//--------------------------------------------------------------------------------------------------------
void dozownik()
{
uint32_t d1;
uint32_t nG1;
uint32_t nM1;
uint32_t zasobnik;
tmElements_t tm;

//----------------------------pobieranie danych ---------------------------
porcja.getValue(&d1);           // pobranie wartosci ustawionej na wyswietlaczu ze strony page 10 - ilosc dozowana jednorazowo
nawozG.getValue(&nG1);          // pobranie wartosci ustawionej na wyswietlaczu ze strony page 10 - godzina dozowania
nawozM.getValue(&nM1);          // pobranie wartosci ustawionej na wyswietlaczu ze strony page 10 - minuta dozowania
zapas.getValue(&zasobnik);           // pobranie wartosci ustawionej na wyswietlaczu ze strony page 10 - stan zasobnika

//------------------------ wysłyłanie danych------------------------------
porcja2.setValue(d1);           // wyswietlenie na wyswietlaczu na stronie głównej wartosci - ilosc dozowana jednorazowo
stan.setValue(zasobnik);            // wysłanie wartosci do wyswietlenia na stronie 1
poziom.setValue(zasobnik);           // wysłanie wartosci na wskaznik poziomu na stronie 1

int sekunda_OFF = d1*60/100;                                                   // przeliczenie porcji w ml na czas dosowania w sekundach


if((nG1==tm.Hour)&&(nM1==tm.Minute)&&(sekunda_ON==tm.Second))    // warunek włączenia dozownika
{
 digitalWrite(dozownik_1,HIGH);                                                      //właczenie dozownika
 Serial.println("dozownik start");
 //a = a - d1;
 
}

if((nG1==tm.Hour)&&(nM1==tm.Minute)&&(sekunda_OFF==tm.Second)) // warunek wyłączenia dozownika
{
 digitalWrite(dozownik_1,LOW);                                                       //wyłaczenie dozownika
 Serial.println("dozownik stop");
}

}   //koniec void dozownik


//--------------------------------------------------------------------------------------------------------
//-------------------VOID  LAMPY-------------------------------
//--------------------------------------------------------------------------------------------------------
void LAMPY()
{
uint32_t num;
uint32_t dg1;
uint32_t dm1;
uint32_t ng1;
uint32_t nm1;

//uint32_t dG2;
//uint32_t dM2;
//uint32_t nG2;
//uint32_t nM2;
//------------------- ZEGAR -------------------------------  
tmElements_t tm;

 if (RTC.read(tm)) {                           // pobierz czas na wyświetlacz



//------------------- OŚWIETLENIE -------------------------------
 
   
  dG1.getValue(&dg1);
  dM1.getValue(&dm1);
  nG1.getValue(&ng1);
  nM1.getValue(&nm1);
   
//    dzienG2.getValue(&dG2);
//    dzienM2.getValue(&dM2);
//    nocG2.getValue(&nG2);
//    nocM2.getValue(&nM2);

    GODZ =  (tm.Hour);                                   // pobranie godziny z zegara
    MIN = (tm.Minute);                                      // pobranie minut z zegara
   
     int CZAS = (GODZ*60+MIN);                        // przejście na minuty - czas ogólny
     int czas1 = (dg1*60+dm1);                        // przeliczenie na minuty dla czasu gdy dzień
     int czas2 = (ng1*60+nm1);                        // przeliczenie na minuty dla czsu gdy noc

   // int czas1L2 = (dG2*60+dm2);                     // przeliczenie na minuty dla czasu gdy dzień
 //   int czas2L2 = (nG2*60+nm2);                   // przeliczenie na minuty dla czsu gdy noc

      static int D1;                                  //stopień rozjaśniania LED1, LED2
  //    static int D2;                                  //stopień rozjaśniania LED1, LED2

// -------------- LAMPA 1 --------------------------------------------

       int mocD1[61] =                                      //stopień rozjaśniania LED1
         {
            0,1,2,3,4,5,6,7,8,9,10,
            11,12,13,14,15,16,17,18,19,20,
            25,30,35,40,45,50,55,60,65,70,
            75,80,85,90,95,100,105,110,115,120,
            125,130,135,140,145,150,155,160,165,170,
            175,175,179,190,205,205,205,205,205,205                   // zasilanie na 100%
       };
         int mocD2[61] =                                      //stopień rozjaśniania LED1
         {
            0,1,2,3,4,5,6,7,8,9,10,
            11,12,13,14,15,16,17,18,19,20,
            25,30,35,40,45,50,55,60,65,70,
            75,80,85,90,95,100,105,110,115,120,
            125,130,135,140,145,150,155,160,165,170,
            175,175,179,195,210,215,225,235,245,255                   // zasilanie na 100%
         };

   if (CZAS < czas1)                                            // warunek gdy NOC
      {
       D1=0;                        //
 //    sendCommand("po.val=NOC");
       Serial.println("LED - NOC");
     pora.setText("NOC");
        }
    if ((czas1 <= CZAS)&&(CZAS <(czas1+ZMIANA)))                 // warunek gdy PORANEK
       {
        D1=((CZAS-czas1)/STEP);
      //  sendCommand("po.val=SWIT");
        Serial.println("LED - SWIT");
        pora.setText("SWIT");        

        }
    if (((czas1+ZMIANA) <= CZAS)&&(CZAS < (czas2-ZMIANA)))       // warunek gdy  DZIEŃ
        {
        D1=maxD1;
      //  sendCommand("po.val=DZIEN");
         Serial.println("LED - DZIEN");
     pora.setText("DZIEN");
         }
    if (((czas2-ZMIANA)<=CZAS)&&(CZAS<czas2))                     // warunek gdy ZMROK
         {
        D1=((czas2-CZAS)/STEP);
    //  sendCommand("po.val=ZMROK");
         Serial.println("LED - ZMROK");
  pora.setText("ZMROK");
         }
     if (czas2<=CZAS)                                            //NOC
         {
        D1=0; //
     
    pora.setText("NOC");
         Serial.println("LED - NOC");
        }
//      analogWrite(LED1, mocD1[D1]);
//      analogWrite(LED2, mocD2[D1]);
      lamp1.setValue((mocD1[D1]*100)/255);
      lamp2.setValue((mocD2[D1]*100)/255);
       Serial.println("stan lampy 1=");
       Serial.print(lamp1.setValue((mocD1[D1]*100)/255));
       Serial.println("stan lampy 2=");
       Serial.print(lamp2.setValue((mocD2[D1]*100)/255));
}
}


//--------------------------------------------------------------------------------------------------------
//-------------------void PH SONDA -------------------------------
//--------------------------------------------------------------------------------------------------------
void PH_SONDA()
{


 uint32_t num;                                  // pobrana wartosc
static unsigned long samplingTime = millis();
 static unsigned long printTime = millis();
 static float pHValue,voltage;
 if(millis()-samplingTime > samplingInterval)
 {
     pHArray[pHArrayIndex++]=analogRead(SensorPin);
     if(pHArrayIndex==ArrayLenth)pHArrayIndex=0;
     voltage = avergearray(pHArray, ArrayLenth)*5.0/1024;
     pHValue = 3.5*voltage+Offset;
     samplingTime=millis();
 }
 if(millis() - printTime > printInterval)   //Every 800 milliseconds, print a numerical, convert the state of the LED indicator
 {
       Serial.print("Voltage:");
       Serial.print(voltage,2);
       Serial.print("    pH value: ");
     
       Serial.print(pHValue,2);                     // wyswietlenie wartości pH na LCD wynik do dwóch miejsc po przecinku
                             
 PHval.setValue(pHValue);                         // wyswietlenie wartości pH na LCD
     
float CO2 = (3*num*pow(10,7-pHValue));


num1.getValue(&num);                                  //pobieranie wartości twardosci z wyswietlacza
 

 co2.setValue(3*num*pow(10,7-7));                    //wysłanie wartosci Co2 na wyswietlacz

 
}
}

double avergearray(int* arr, int number){
 int i;
 int max,min;
 double avg;
 long amount=0;
 if(number<=0){
   Serial.println("Error number for the array to avraging!/n");
   return 0;
 }
 if(number<5){   //less than 5, calculated directly statistics
   for(i=0;i<number;i++){
     amount+=arr[i];
   }
   avg = amount/number;
   return avg;
 }else{
   if(arr[0]<arr[1]){
     min = arr[0];max=arr[1];
   }
   else{
     min=arr[1];max=arr[0];
   }
   for(i=2;i<number;i++){
     if(arr[i]<min){
       amount+=min;        //arr<min
       min=arr[i];
     }else {
       if(arr[i]>max){
         amount+=max;    //arr>max
         max=arr[i];
       }else{
         amount+=arr[i]; //min<=arr<=max
       }
     }//if
   }//for
   avg = (double)amount/(number-2);
 }//if
 return avg;

}
 
Odpowiedź
#2
1. To jest ustawianie bardziej Nexion niż Arduino. Tak samo jak ustawiasz zmienną dM1 powinieneś mieć ekran, gdzie napełnisz zmienne czasu i dodatkową zmienną, która informuje, że czas został zmieniony na ekranie i należy go przesłać do RTC. Potem już w arduino gdzieś w pętli używasz tego co masz w swojej bibliotece RTC, np:
Kod:
        if(NXtimechange) //jeśli zmiana czasu==1
{
               Clock.setYear(NXYear);
        Clock.setMonth(NXMonth);
        Clock.setDate(NXDate);
        Clock.setDoW(NXDoW);
        Clock.setHour(NXHour);
        Clock.setMinute(NXMinute);
        Clock.setSecond(NXSecond);
timechange=0;//wyzeruj zmiane czasu
}
Clock oczywiście zamień na swój obiekt, a metody dostępne znajdziesz w przykładach i samej bibliotece, której używasz.
2. Masz już użyte millis to sobie zmień, że dozownik włączasz na np. 10s, warunek włączenia bez zmian, ale od razu ustawiaj przy jakiej wartości millis, czy tam sekund w oparciu o nie wyliczonych, wyłączasz. I zliczaj sobie te sekundy pracy dozownika w DozUzyte. Jak już ustalisz, że cały zbiornik to np. już ustalona zmienna stała DozMax=3245 sekund dozowania, to w drugiej zmiennej DozUzyte trzymaj aktualną ilość zużytą, na wyświetlaczu pokazuj DozMax-DozUzyte. 
3. Tu za bardzo nie rozumiem. Korzystanie z wartości w tabeli to ta prostsza metoda. Można wyliczać kolejne wartości w krokach rozjaśniania używając skomplikowanych obliczeń, tak by rozjaśnianie było zgodne z tym co nasze ludzkie oko odbiera. To ma dawać wizualnie ładny i płynny efekt. Nie wiem czy to tak działa na roślinki, czy dla niech po prostu nie można by zwiększać liniowo, bo im zależy tylko na tym ile energii dostają od światła. Poszukaj sobie o korekcji gamma, np. https://learn.adafruit.com/led-tricks-ga...-quick-fix . 
Jeśli natomiast zależy Ci tylko na ustawieniu max to co za problem ustawić sobie zmienną na ekranie, przesyłać do arduino i w funkcji analogWrite(pin,X); dodać sobie wcześniej ifa gdzie wartość X ustalasz z tabeli, a jeśli Max jest mniejsze od tej wartości to X=Max.
Miło być decenianym https://buycoffee.to/kaczakat
 
Odpowiedź
#3
Urządzenie jest niebezpieczne dla rybek. Nie lubisz ich?

- Zakładasz, że wszystko działa i będzie działać bezbłędnie.Czy to dobre założenia?
- Co się stanie gdy zostanie utracona komunikacja zegara po I2C? Czas dla sterownika zatrzyma się.Czy nie powinno być tak, że sterownik będzie nadal zliczał czas? Lepsze chyba to, ze godzina będzie nieaktualna, niż to że czas się zatrzymał, prawda? Poco zewnętrzyny RTC? Używasz Mega2560, więc nie problem użyć RTC, który on posiada. Co prawda płytka Arduino ma źle rozwiązane zasilanie ale pewnie dość łatwo to rozwiązać.
- Jaką temperaturę pokaże termometr 1-Wire gdy go nie będzie na magistrali? Jaką gdy magistrala ma zwarcie? Czy odczyt uwzględnia CRC? Chcesz sterować grzałką, jakie będą konsekwencje odczytania temperatury 0 lub -127 stopni?
- Czasy programów o wielkości 1kB na 8080 już się skończyły. Używasz bibliotek, na które nie możesz byc w 100% pewny, że działają bezbłędnie. TWI w AVR jest podatny na słynny status F8.Jak się zachowa sterownik w przypadku takiego błędu? Łatwo to sprawdzić, odłącz rezystory podciągające I2C do zasilania. Użyj więc watchdoga.W razie problemu z programem lub sprzętem lepiej chyba aby uC się zresetować niż ma np cały czas podawać karmę/nawóz czy grzać wodę.Dobrze radzę czy źle?

Co do wyświetlacza, wybrałeś NEXTION. Większe możliwości i niższą cenę oferują wyświetlacze ze sterownikiem FT8xx.Nie wymagają karty SD jak NEXTION co ułatwia pisanie softu, jego zmiany, zwiększa pewność działania. Same zalety.
Zrobiłeś malutkie symbole "+" i "-" do zmiany parametry a wielkie znaki wyświetlające nastawy. Wyświetlane wielkości wyglądają jak buttony a znaki "+" i "-" jak wyświetlana wielkość. Małe przyciski "+" i "-" wymuszają użycie rysika. Sterownik powinien być tak zrobiony aby chłop z ręką rolnika czy piekarza mógł go obsłużyć bez dodatkowych narzędzi. Przy okazji, czy obsłużysz ekran pojemnościowy rysikiem?

A aktualnym wykonaniu, na sterowniku powinien znaleźć się napis:
"Nie pozostawiać włączonego urządzenia bez nadzoru"
Po co więc taki sterownik, do którego trzeba posadzić człowieka aby nadzorował bez przerwy jego pracę?

Cytat:Jak zaprogramować zegar/datę aby można było z pozycji LCD ustawiać datę i godzinę (obecnie jest to aktualizowanie RTC DS1307 i start),
Zrób menu ustawiania czasu.
Ja jestem leniwy i wygodny. Dałbym DCF77, GPS lub Wi-Fi. Wi-Fi jest chyba najrozsądniejsze, czas pobierasz z NTP a dodatkowo sterownikiem możesz sterować zdalnie lub nadzorować jego prace czy obrazować wyniki pracy sterownika na serwerze.

Cytat:Czy jest inny - prostszy sposób/metoda sterowania PWM gdyż w moim kodzie jest możliwość tylko zmiany godzin startu i końca natomiast ustalanie mocy świecenie wymaga ustawień ręcznych w kodzie (tabeli).
PWM przechowuj w zmiennej w EEPROM. Tam też powinny znaleźć się inne nastawy. Nie wiedzę abyś cokolwiek przechowywał w eeprom. Do instrukcji można więc dopisać:
"Sterownik daje duże możliwości wyboru ustawień o ile są one zgodne z wyborem konstruktora". Coś jak z "Fordem T", "może być w dowolnym kolorze o ile jest to czarny".
Dane w EEPROM chroń przez CRC. Gdy CRC będzie błędne to albo przywracasz ustawienia domyślne i informujesz o tym na LCD albo sterownik podejmie prace gdy nastawy zostaną wprowadzone. Bezpieczniejsze jest aby przechowywać dwie kopie danych. W razie problemów odczytu jednej dane czytasz z drugiej, gdy się nie uda init EEPROM. Co zrobić gdy uda się odzyskać dane z drugiej kopi? Informować o tym użytkownika? Zależy od konstruktora, ja informuję, bo może to oznaczać, że ostatnie zmiany nastaw są stracone.
W EEPROM możesz też przechowywać liczniki wydanej karmy itp. Mega2560 ma 4kB EEPROM, więc można przechowywać tam logi (zmiany temperatury itp) byleby nie zajeździć pamięci.
 
Odpowiedź
#4
(19-09-2018, 02:51)kaczakat napisał(a): 1. To jest ustawianie bardziej Nexion niż Arduino. Tak samo jak ustawiasz zmienną dM1 powinieneś mieć ekran, gdzie napełnisz zmienne czasu i dodatkową zmienną, która informuje, że czas został zmieniony na ekranie i należy go przesłać do RTC. Potem już w arduino gdzieś w pętli używasz tego co masz w swojej bibliotece RTC, np: ...

Wielkie dzięki za podpowiedź z zegarem muszę to po testować, choć zakładam że i tak będę musiał nauczyć się programowania pamięci aby tam wszystko przechowywać i utrwalać.
Co do obsługi LED to byłem święcie przekonany że to metoda przekombinowana :-) Shy .
 
Odpowiedź
#5
(19-09-2018, 09:22)es2 napisał(a): Urządzenie jest niebezpieczne dla rybek. Nie lubisz ich?

- Zakładasz, że wszystko działa i będzie działać bezbłędnie.Czy to dobre założenia?
- Co się stanie gdy zostanie utracona komunikacja zegara po I2C? Czas dla sterownika zatrzyma się.Czy nie powinno być tak, że sterownik będzie nadal zliczał czas? Lepsze chyba to, ze godzina będzie nieaktualna, niż to że czas się zatrzymał, prawda? Poco zewnętrzyny RTC? Używasz Mega2560, więc nie problem użyć RTC, który on posiada. Co prawda płytka Arduino ma źle rozwiązane zasilanie ale pewnie dość łatwo to rozwiązać.
- Jaką temperaturę pokaże termometr 1-Wire gdy go nie będzie na magistrali? Jaką gdy magistrala ma zwarcie? Czy odczyt uwzględnia CRC? Chcesz sterować grzałką, jakie będą konsekwencje odczytania temperatury 0 lub -127 stopni?
...................
Co do wyświetlacza, wybrałeś NEXTION. Większe możliwości i niższą cenę oferują wyświetlacze ze sterownikiem FT8xx.Nie wymagają karty SD jak NEXTION co ułatwia pisanie softu, jego zmiany, zwiększa pewność działania. Same zalety.

Z wstępu odnoszę wrażenie, że nie jeździsz autem, nie latasz samolotami bo gdy zawiodą hamulce, albo padnie elektronika to katastrofa Wink  .
Nic nie pisałem że sterownik obsługuje np. grzałkę lecz wykonuje pomiar temperatury i obsługuje chłodzenie wiatrakiem.
W związku z moimi częstymi wyjazdami służbowymi zależy mi aby część operacji które mogą być "zautomatyzowane" takimi były. Nawozy rybą nie zaszkodzą, wiatraki wody nie wyziębią, światło też nic złego nie poczyni a pomiary jak temperatura czy pH są powszechnie stosowanymi praktykami nawet w medycynie i też są bezobsługowe.

Moja poprzednia wersja sprawuje się już prawie dwa lata wyśmienicie choć pracuje na arduino nano, niestabilnym DS 1307 i LCD 20x4 dlatego postanowiłem ją troszkę "unowocześnić" gdyż jakąkolwiek zmianę najpierw wprowadzałem do programu a następnie wczytywałem do arduino to jest bardzo nieporęczne. W tej wersji mogę/ chciałbym ustawiać z pozycji LCD co już częściowo działa.

Wyświetlacze Nextion nie potrzebują do pracy kart pamięci lecz tylko do wgrania oprogramowania, a jeżeli używasz np. arduino Mega który obsługuje więcej niż jeden port szeregowy to nawet nie potrzebujesz karty pamięci gdyż aktualizacja odbywa się z pozycji programu do Nextion i kabla USB.

Wielkie dzięki za sugestię z pamięcią EEPROM ale nie jestem na tyle mocny w programowaniu aby z niej na chwilę obecną korzystać dlatego piszę z prośbą o pomoc w tym dziale aby ktoś kto jest bieglejszy ode mnie pomógł w temacie.
Fajnie że wspomniałeś o zegarze w Mega 2560 bo widać na płytce kwarc ale nie trafiłem w sieci na rozwiązanie bazujące na jego zegarze stąd zostałem przy wspomnianym RTC DS 1307.
 
Odpowiedź
#6
(19-09-2018, 20:41)nebari napisał(a): Wielkie dzięki za sugestię z pamięcią EEPROM ale nie jestem na tyle mocny w programowaniu aby z niej na chwilę obecną korzystać dlatego piszę z prośbą o pomoc w tym dziale aby ktoś kto jest bieglejszy ode mnie pomógł w temacie.
https://www.arduino.cc/en/Reference/EEPROM
Zajęło to kilka sekund w Google https://www.google.com/search?q=arduinoe...=firefox-b

(19-09-2018, 20:41)nebari napisał(a): Fajnie że wspomniałeś o zegarze w Mega 2560 bo widać na płytce kwarc ale nie trafiłem w sieci na rozwiązanie bazujące na jego zegarze stąd zostałem przy wspomnianym RTC DS 1307.
Na stronie Mikrochip (Atmel) jest stosowny AN. Jak nie znajdziesz to mam gdzieś na komputerze.

(19-09-2018, 20:41)nebari napisał(a): Wyświetlacze Nextion nie potrzebują do pracy kart pamięci lecz tylko do wgrania oprogramowania, a jeżeli używasz np. arduino Mega który obsługuje więcej niż jeden port szeregowy to nawet nie potrzebujesz karty pamięci gdyż aktualizacja odbywa się z pozycji programu do Nextion i kabla USB.
Jak by nie było, trzeba coś tam zrobić, w jakiejś tam aplikacji na komputerze, czyli poświęcić czas na nauczenie się tego. Mając tylko uC i wyświetlacz nie da się nic zrobić. Jak zobaczyłem cenę, to stwierdziłem "szkoda czasu i pieniędzy".

Budując jakieś urządzenie, niekorzystne jest aby wgrywać program do uC i jeszcze do peryferii. Ewentualna zmiana softu może być kłopotliwa. Dlatego między innymi, nie używam mostków FTDI z USART, gdzie aby zmienić pamięć konfiguracji trzeba na komputerze uruchomić FT_PROG. Używam FT201,FT220 i podobnych (komunikacja po I2C/SPI) gdzie taką pamięć modyfikuję z poziomu uC. Dodatkowe zalety:
- Nie marnuję USART, których w AVR jest jak na lekarstwo. Szkoda, ze na to nie wpadli konstruktorzy Arduino :-(
- AVR nie wymaga kwarcu aby USART pracował z wymaganą dokładnością (nie dotyczy najnowszych uC Microchip-a).
- Transfer do mostka po SPI z prędkością 8 czy 10MB/s to nie problem (max dla FTDI to zdaje się 30MHz).
- Po I2C 400 lub 3,4Mb/s (FT200).
- Mam dodatkowy eeprom blisko 1kB nie związany z uC, więc np wymiana uC nie powoduje utraty ustawień.
- Do dodatkowego EEPROMdostęp ma także aplikacja na komputerze.
Co ciekawe, mostki I2C czy SPI kosztują tyle samo co większość UART. Dają większe możliwości, dlaczego więc nie sa używane w amatorskich konstrukcjach?
 
Odpowiedź
#7
Dodanie każdego rodzaju działań matematycznych na AVR to wzrost kodu na początek, a potem strata czasu przy obliczeniach. Przy MEGA2560 flash nie brakuje, jednak procek i tak jest marny, jednakoż możesz sobie to wyliczać jak i tak w Twoim kodzie wiele nie robi.
Jak nie chce Ci się wyciągać zestawu do aktualizacji to opisałem tu sposób na wgrywanie softu przez BT HC-05, to przypomnę: 
"... w niektórych HC-05 można wykorzystać pin state do resetu. Do modułu Arduino należy wgrać najlepiej bootloader od UNO, nawet jeśli to nie jest UNO, ale jest atmega 328, czyli UNO, PRO MINI, NANO. Potem te modułu identyfikują się jako UNO i taki moduł należy wybierać. W module HC-05 ustawić transmisję na 115200b komendą "AT+UART=115200,0,0" i tryb pracy PINSTATE "AT+POLAR=1,0".  Te ustawienia robi się raz i zostają w module BT. Od strony sprzętowej wtedy robimy "Autoreset Arduino", potrzebny kondensator elektrolityczny wpięty między reset i PINSTATE, 1u i co najmniej 16V. Minus kondensatora do pinu reset. Jak komenda polar zadziała, to powinno się udać z danym modułem. Teraz wystarczy dodać moduł BT do komputera, wybrać przypisany mu port COM w Arduino  i ładować. Testowałem, mi działa, robi się autoreset i programuje. Mój moduł nie wymaga konwertera poziomów 5V-3.3V (mam kilka z różnych źródeł i dotyczy to wszystkich moich), wprost podłączam pin TX/RX do Arduino, ale widziałem, że niektórzy kombinują z jakimiś dzielnikami.  Z tym bootloaderem chodzi w sumie o to by pasował do prędkości UART, w Nano i Promini jest większy i wolniejszy bootloder. Działa również  z płytkami z atmegą 168 i optibotem (nie wiem czemu tylko do UNO dają w Arduino od razu Optiboota, a w reszcie zostawili tego pokraka). Zaletą optiboota jest  większa prędkość, 4x mniej kodu, więcej zostaje na program, nie odwala mu po użyciu Watchdoga.
A tu jest opisany sposób z ESP link jako virtualCOM: https://www.youtube.com/watch?v=WEpMFmTU0iA .
Kondensator może być również ceramiczny bez polaryzacji, za to w każdym wypadku jednak 16V. Nawiązanie połączenia generuje impuls w dół, co ładnie robi reset (100n daje za słaby impuls, działa tylko raz) za to rozłączenie daje impuls w górę, dlatego te 16V będzie bardziej bezpieczne. Większe kondensatory, tzn. pojemność, generują większe szpilki."
MEGA 2560 ma transmisję 115200 przy wgrywaniu bootloaderem, także innego nie ma potrzeby wgrywać.
Można by wtedy realizować wiele dodatkowych rzeczy przy okazji - sam wspomniałeś o aktualizacji ustawień NEXTION'a, poza tym RTC można ustawić wysyłając jedną linijkę polecenia z parametrami czasu. Co do RTC Twój jest faktycznie nieszczególny. Ale  dorabianie akku do MEGA i jego wewnętrznego RTC jest wątpliwą korzyścią, gdy można mieć precyzyjniejszy RTC DS3231 już z baterią na parę lat za <1$ z ali, no w PL  ze 2$ link  , ale jak już i tak robisz zakupy przy okazji, bo poczta PL chętnie gania z przesyłkami z Chin za 5c, ale nie przyjmie listu w gabarycie A jak w środku koperty jest za dużo powietrza, stąd takie ceny przesyłek na Allegro.
Miło być decenianym https://buycoffee.to/kaczakat
 
Odpowiedź
#8
(20-09-2018, 07:29)kaczakat napisał(a): można mieć precyzyjniejszy RTC DS3231 już z baterią na parę lat za <1$ z ali, no w PL  ze 2$ link
I super "precyzję" 50ppm. Układ DS3231 w detalu kosztuje ok 20zł. Chińskie badziewie, z kawałkiem PCB,baterią i eeprom 24C64 można kupi za ok 6zł. Jaka cena, taka jakość. Pobawić się można a precyzję ma co któraś tam sztuka, bo DS3231 pochodzą z odrzutu. Na forach można poczytać posty w rodzaju "Zegar DS3231 ma odchyłke kilka minut na dobę". A ile powinien miec przy deklarowanych 2ppm?
Jaka cena taka jakość.

Trzeba mieć świadomość, że tanie dodatki do Arduino to chłam. Pozwala poznać układ ale NIE NADAJE SIĘ,do stosowania w urządzeniach, które maja pracować niezawodnie. Owszem, można mieć szczęście i kupić coś dobrego z tego chłamu.
Pytanie, ile pieniędzy trzeba przeznaczyć aby zweryfikować czy np taki DS3231 zachowuje swoje parametry gwarantowane przez producenta?

Wykorzystanie Aurduino poszło w złym kierunku. To miała być tania platforma do nauki a jest używana do urządzeń użytkowych. To ZŁY WYBÓR!
Czy pchanie się w DS3231  ma sens w sterowaniu akwarium? Nie zapominajmy też o konieczności (jak na razie) zmiany czasu dwa razy do roku.
Użycie wewnętrznego RTC w tym przypadku ma wiele zalet:
- niższy koszt (brak zewnętrznych elementów)
- większa niezawodność (wszystko w jednym układzie)
- krótszy kod łatwiejszy do napisania (nie trzeba pisać obsługi błędów, gdy brakuje RTC, obsługi błędów I2C, reanimacji I2C gdy slave ją zablokuje)

Naturalnie problemem jest używać wewnętrznego RTC na większości płytek Arduino, bo zostały one stworzone do NAUKI, ZABAWY. Najsensowniejszym rozwiązaniem jest własna PCB ze wszystkimi wymaganymi elementami a nie kilka płytek połączonych plątaniną przewodów.
 
Odpowiedź
#9
No my już na tym forum wszyscy chyba wiemy, że Arduino do niczego się nie nadaje. Misja spełniona, pora ruszyć na podbój reszty świata. Elektroda z tego co czytałem też już zaliczona, może jakieś zagraniczne fora potrzebują ewangelizacji?
No jak można z Panem dyskutować, daję link do polskiego sklepu, z FV, z VATem cena 7pln, a Pan mi tu krzyczy NEIN, NEIN, NEIN!, że 20 w detalu. Może u Mirka tak. Pewnie i za 60 się znajdzie. Mam garść takich płytek i wszystkie działają OK. Na pewno te droższe to takie wybrane z taśmy, te najlepsze.
Co rybkom do zmiany czasu? One potrzebują jedynie stałych interwałów, one nic o UE i KE nie wiedzą.
Nebari ma tą płytkę Arduino Mega i nie będzie dorabiał kwarcu na wsuwki by dało się zastosować Pana teorie, ani tym bardziej tam lutował na laminacie. Ma wystarczająco dobry zegar do tego celu. Jak będzie chciał rzadziej korygować czas to sobie zmieni na jakiś lepszy.
Tak swoją drogą @Nebari to nie ma kwarcu do RTC na oryginalnej płytce Arduino MEGA ten malutki jest do napędzania procka. W klonach nawet jest normalny duży.
Przecież Nebari nie produkuje sterowników, bawi się i uczy monitorując parametry akwarium.
Możemy robić coś poza migającymi ledami na Arduino? Pozwoli Pan???, proszę, tak ślicznie proszę...
Miło być decenianym https://buycoffee.to/kaczakat
 
Odpowiedź
#10
(20-09-2018, 15:44)kaczakat napisał(a): No my już na tym forum wszyscy chyba wiemy, że Arduino do niczego się nie nadaje
Nadaje. Jak już pisałem, do nauki, do zabawy, do testowania, ale NIE do budowania urządzeń użytkowych.
TO SĄ FAKTY a z faktami się NIE DYSKUTUJE!

(20-09-2018, 15:44)kaczakat napisał(a): Co rybkom do zmiany czasu? One potrzebują jedynie stałych interwałów, one nic o UE i KE nie wiedzą.
Kto zaproponował super precyzyjny zegar do akwarium? Amnezja?
A co do zmiany czasu, to chyba kolega nie wie o co chodzi. Zmiana czasu "wymusza" skorygowanie ustawień zegara. Wystarczy, że zegar ma 20ppm i będzie ok.

(20-09-2018, 15:44)kaczakat napisał(a): Możemy robić coś poza migającymi ledami na Arduino?
Można by zrobić poważny projekt ale to się nie opłaca. Będzie drogi (długi czas realizacji) i pewnie zanim zostanie wdrożony będzie przestarzały i nikt rozsądny go nie kupi. NIE DA się za zabawki, zrobić POWAŻNEGO URZĄDZENIA w sensownym czasie za sensowne pieniądze.
Nie widziałem seryjnie produkowanego sterownika do kawy wykonanego na Arduino a tym bardziej sterownika pralki lub systemu alarmowego itp, itd.
TO SĄ FAKTY a z faktami się NIE DYSKUTUJE!

Skwituję to tak, jak to widzą przyszli pracodawcy czy zleceniodawcy "Arduino lepiej sobie do CV NIE WPISYWAĆ!!!".
TO SĄ FAKTY a z faktami się NIE DYSKUTUJE!

PS
Gdybym projekty realizował na Arduino, już dawno poszedłbym z torbami, a nie zrealizowałem 5 czy 10 projektów w życiu. Tyle to w ciągu roku. I nie są to projekty jednostkowe ale produkowane w setkach czy tysiącach szt.
 
Odpowiedź
  


Skocz do:


Przeglądający: 1 gości