18-09-2018, 22:35
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:
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ć:
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:
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:
- sterowanie PWM świt/zmierzch,
- pomiar temperatury plus chłodzenie,
- pomiar pH, plus obliczenie zawartości Co2 na podstawie wprowadzanego KH,
- obsługa dozownika nawozów na bazie pompy perstaltycznej,
- wyświetlanie danych na LCD 20x4.
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ć:
- sterowanie dwoma kanałami PWM świt/zmierzch, (ustawienia z LCD godzin włączania i wyłączania)
- pomiar temperatury - 2 kanały plus obsługa dwóch wiatraków do chłodzenia, (ustawienia z LCD histerezy oraz temperatur),
- pomiar pH (z możliwością kalibracji sondy),
- ustawianie wartości KH z pozycji LCD (bez konieczności aktualizacji sketcha jak to było do tej pory)
- wyliczanie zawartości Co2 na bazie pH i KH,
- obsługa dozownika nawozów (z możliwością zadawania jednorazowych porcji, czasu dozowania oraz monitorowania ilości nawozu w zasobniku),
- no i obowiązkowo: Data i Czas.
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:
- Jak zaprogramować zegar/datę aby można było z pozycji LCD ustawiać datę i godzinę (obecnie jest to aktualizowanie RTC DS1307 i start),
- 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),
- 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).
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;
}