Olvasási idő: 8 perc

A program

Ha minden kész akkor már csak egy valami van hátra maga a program. A NANO esetében 32Kb hely áll rendelkezésre, ez a leforgatott programra vonatkozik. Én az Aduino IDE-t használtam erre a célra. A legtöbb Linux disztribúcióban benne van. De az oldalukról le is lehet tölteni bármilyen OS-re.

Akkor jöjjön a program. A kis memória miatt csak fix változókkal dolgoztam ,azaz minden egyes paraméter változtatás után le kellet fordítani a programot és rátölteni az Arduino-ra. Minden eszköz előtte egy teszt programmal kipróbáltam, és így építkeztem lépésről lépésre.

Lássuk a programot először is a változok bevezetése, és függvénykönyvtárak beemelése:


//2015.06.28  LCD rajzolási hibák megoldása + időzítés!!!
//2015.07.03  Watchdog bekapcsolása 4s idővel, min(), max() bevezetése
//2015.07.13 DS1307 library cseréje
#include 
#include 
#include 
#include "DHT.h"
#include 
#include 
#include 

LiquidCrystal_I2C lcd(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);  // Set the LCD I2C address

//RTC DS1307
//RTC_DS1307 rtc;
unsigned long oldSeconds = 0;
tmElements_t time; //DS1307
// SZENZOROK
#define DHTPIN 2  
#define DHTTYPE DHT22
DHT DHT22_Pin(DHTPIN, DHTTYPE);
byte DS18B20_Pin = 6; //digital 6 hőmérő 4K7Ohm <-> 5V
OneWire ds(DS18B20_Pin);  //MEGFELELŐ VÁLTOZONÉV!
unsigned long tempCheckTime = 0; //szenzor olvasás ideje

// KIMENETEK BEÁLLÍTÁSA
// LED PANEL
byte LED = 9; //PWM kivezetés
// RELAY 24V
byte relay = 12;
// PIR SENSOR
boolean pirStatus = false;
byte pirPin = 3;

// DÁTUM&IDŐ
byte fadeUpTime = 30; // másodpercben a led fel és le lufutásának ideje
long fadeStepTime = 1; //le-fel futás léptéke másodpercbe, mennyi időnként változtassa a led fényerejét
int fadeValue = 0; //PWM kezdő értéke 0-255 lehet
byte fadeValuePick = 255 / fadeUpTime; // a le és felfutás alatt ennyivel változik a kimenet értéke
// on time
byte onHour = 9;// bekapcsolás óra
byte onMinute = 0; // bekapcsolás perc
// off time
byte offHour = 20; // kikapcsolás óra
byte offMinute = 0; // kikapcsolás perc
//DateTime now;

// IDŐZITÉS
int backLightTime = 60 * 5; // háttérvilágítás kikapcsolási ideje másodpercben
boolean backLightStatus = false;
unsigned long backLightStop = 0; // LCD háttér világítás kikapcsolásának ideje
long ledIconTime = 0; // LEDicon villogtatás ideje ms
long pirIconTime = 0; // PIRicon villogtatás ideje ms
boolean pirLedStatus = false;
boolean ledStatus = false;
// KIÍRÓ STRINGEK
String ledTimeValue = "";

// DATA LOGGER DATAS
float maxminTemp[2] = {
  0.0, 100.0}; 
float maxminHum[2] = {
  0.0, 100.0};
unsigned long dataLoggerTime = 0; // adatLogger forgatás ideje
byte item = 2;


const char custom[][8] PROGMEM = {
  { 
    0x00,0x06,0x06,0x14,0x0f,0x04,0x0a,0x11               }
  , // pir
  { 
    0x00,0x0e,0x15,0x19,0x11,0x1f,0x0a,0x00               }
  , // LED OFF
  { 
    0x00,0x0e,0x1b,0x17,0x1f,0x1f,0x0a,0x00               }
  , // LED ON
  { 
    0x04,0x0a,0x0a,0x0a,0x0e,0x1f,0x1f,0x0e               }
  , // temp
  { 
    0x00,0x04,0x0a,0x04,0x00,0x00,0x00,0x00               }
  , // degree 
  { 
    0x04,0x04,0x0e,0x0e,0x1f,0x1f,0x1f,0x0e               }
  , // drop
  { 
    0x16,0x0f,0x16,0x00,0x00,0x0d,0x1e,0x0d               }
  , // fish 
  { 
    0x04,0x0a,0x11,0x15,0x11,0x15,0x11,0x1f               }  // hause
};

Jöhet az inicializálás és LCD-re ikonok kirajzolása:

void initialize(){
  float t;
  //SZENZOROK első lekérdezésének elvégézése...
  t = DHT22_Pin.readTemperature();
  delay(50);
  t = DHT22_Pin.readHumidity();
  delay(50);
  t = getTemp();
  delay(500);
  //SENZOR DHT22
  // haus, temp icon
  lcd.setCursor(0,1);
  lcd.write((uint8_t)0);
  lcd.setCursor(1,1);
  lcd.write((uint8_t)4);
  // humidity icon
  lcd.setCursor(12,1);
  lcd.write((uint8_t)6);
  //SENZOR DS18B20
  // fish&temp icon
  lcd.setCursor(0,2);
  lcd.write((uint8_t)7);
  lcd.write((uint8_t)4);
  lcd.setCursor(0,0);
  lcd.print("Init Ok");
  delay(500);
}

int freeRam () {
  extern int __heap_start, *__brkval; 
  int v; 
  return (int) &v - (__brkval == 0 ? (int) &__heap_start : (int) __brkval); 
}

A Setup() alaphelyzetbe állít mindent, és watchdog beállítás:

void setup(){
  //Serial.begin(9600);
  byte nb=0,bc=0;
  byte bb[8]; 

  //RTC DS1307
  Wire.begin();
  //rtc.begin();

  // LCD I2C
  lcd.begin(20,4);
  for (nb=0; nb<8; nb++ ) { // create 8 custom characters
    for (bc=0; bc<8; bc++) bb[bc]= pgm_read_byte( &custom[nb][bc] );
    lcd.createChar ( nb+1, bb );
  }  
  lcd.noBacklight();
  initialize();
  pinMode(relay, OUTPUT);
  digitalWrite(relay, LOW);
  pinMode(LED, OUTPUT);
  wdt_enable (WDTO_4S);//watchdog engedélyezése 4s-re
}

És a program fő része a loop():

void loop() {
  if(millis()/1000 > oldSeconds){
    oldSeconds = millis()/1000;

    if(RTC.read(time)){
      // DATE TIME
      doLCD();

      // CHECK TEMPS        
      if(millis()/1000 >  tempCheckTime ){
        tempCheckTime = millis()/1000 + 5;
        doTemp();
      }

      // DATA LOGGER
      if(millis()/1000 > dataLoggerTime){
        dataLoggerTime = millis()/1000 + 12;
        doDataLogger();
      }
    }
    else {
      if(RTC.chipPresent()){
        lcd.setCursor(0,0);
        lcd.print("DS1307 is stopped!");
      }
      else {
        lcd.setCursor(0,0);
        lcd.print("DS1307 read error!"); 
      }
    }
  }
  doPir();
  doLight();
  wdt_disable();  //watchdog tiltása
}

És a függvények:

void doDataLogger(){
  //now = rtc.now();
  String logData; 
  lcd.setCursor(0,3);
  switch(item){
  case 0:
    lcd.print(" Temp: ");
    lcd.print(maxminTemp[0], 1); // MAX
    lcd.print(" / ");
    lcd.print(maxminTemp[1], 1); // MIN
    lcd.print("  ");
    break;
  case 1:
    lcd.print(" Hum: ");
    lcd.print(maxminHum[0], 1); // MAX
    lcd.print(" / ");
    lcd.print(maxminHum[1], 1); // MIN
    lcd.print("  ");
    break;
  case 2:
    lcd.print(startUpTime("Run: "));
    break;
  case 3:
    lcd.print(setCenter("RAM: " + String(freeRam()) + " / 2048"));
    break;
  }
  item++;
  if(item == 4) item=0;

}

String startUpTime(String textData){
  String newData = ""; 
  long startSeconds = millis()/1000;
  int startMinutes = (startSeconds % 3600) / 60;
  int startHours = (startSeconds % 86400) / 3600;
  int startDays = (startSeconds % (86400 * 30)) / 86400;
  newData = setCenter(textData + startDays + "d " + startHours + "h " + startMinutes + "m");
  return newData;
}

String setFillLine(String text){
  int length = text.length();
  String space = " ";
  String tmpText = "";
  if(length < 20){
    for(int i=length; i <= 19; i++){
      tmpText += space;
    }
  }
  return text + tmpText; 
}

String setCenter( String text ){
  int firstPos = (20 - text.length()) / 2;
  String space = " ";
  String tmpText = "";
  for(int i=1; i <= firstPos; i++){
    tmpText +=  space;  
  }
  return setFillLine(tmpText + text);
}

void doLCD(){ //DÁTUM IDŐ KIÍRÁSA
  lcd.setCursor(0,0);
  lcd.print(tmYearToCalendar(time.Year));
  lcd.print(".");
  zero(time.Month);
  lcd.print(".");
  zero(time.Day);
  lcd.setCursor(12,0);
  zero(time.Hour);
  lcd.print(":");
  zero(time.Minute);
  lcd.print(":");
  zero(time.Second);
}

void zero(int dat){
  if( dat < 10 ) lcd.print("0");
  lcd.print(dat, DEC);  
}



//  doTemp()
// hőmérséklet, páratartalom, vízálló hőmérő adatok kiírása LCD-re
void doTemp() {
  //now = rtc.now();
  float h,c,temp;

  //SENZOR DHT22
  c = DHT22_Pin.readTemperature();
  h = DHT22_Pin.readHumidity();
  lcd.setCursor(3,1);
  lcd.print(c, 1);
  lcd.write((uint8_t)5);
  lcd.print("c");
  lcd.setCursor(14,1);
  lcd.print(h, 1);
  lcd.print("%");

  // DATA LOGGER
  // minMax(c, 0);//2015.07.02
  // minMax(h, 1);
  maxminTemp[0] = max(maxminTemp[0], c);
  maxminTemp[1] = min(maxminTemp[1], c);
  maxminHum[0] = max(maxminHum[0] ,h);
  maxminHum[1] = min(maxminHum[1] ,h);

  //SENSOR DS18B20
  temp = getTemp();
  lcd.setCursor(3,2);
  if(temp == -1000) {
    lcd.print("-none");
    return;  
  }
  lcd.print(temp, 1); // kiírás az LCD-re 1 tizedes értékkel
  lcd.write((uint8_t)5);
  lcd.print("c");
}

void minMax(float number, byte nr){
  switch(nr){
  case 0:
    if(maxminTemp[0] < number ) maxminTemp[0] = number;//MAX
    if(maxminTemp[1] > number ) maxminTemp[1] = number;//MIN
    break;
  case 1:
    if(maxminHum[0] < number ) maxminHum[0] = number;//MAX
    if(maxminHum[1] > number ) maxminHum[1] = number;//MIN
    break;    
  }
}


//  doLight()
// LEDPanel vezérlése
// FEL-LE-húzás, ki be kapcsolt állapotok 
void doLight(){
  long m = time.Minute;
  long h = time.Hour;
  long oM = onMinute;
  long oH = onHour;
  long offM = offMinute;
  long offH = offHour;
  unsigned long tSeconds, onSeconds, offSeconds;
  String text = "";

  h *= 3600;
  m *= 60;
  oM *= 60;
  oH *= 3600;
  tSeconds = h+m+time.Second;
  onSeconds = oH+oM;
  offM *= 60;
  offH *= 3600;
  offSeconds = offH+offM;

  if(tSeconds >= onSeconds && offSeconds >= tSeconds){ // LIGHT ON
    // ide jön amit még be kell kapcsolni
    digitalWrite(relay, HIGH);
    analogWrite(LED, fadeValue);
    if( tSeconds >= onSeconds &&  tSeconds <= onSeconds + fadeUpTime ){ // LED UP
      blinkLedIcon();
      if(millis()/1000 >= fadeStepTime ) {
        fadeStepTime = millis()/1000 + 1;
        fadeValue += fadeValuePick;
        if(fadeValue >= 255) fadeValue = 255;
      }
    }
    if( tSeconds > onSeconds + fadeUpTime &&  tSeconds < offSeconds - fadeUpTime ){ // ON
      fadeValue = 255;
      analogWrite(LED, fadeValue); // max kimenet PWM
      text = expandZero(offHour) + ":" + expandZero(offMinute);
      if(text != ledTimeValue) {
        drawTimer(1, 12,2, text);
        ledTimeValue = text;
      }
    }
    if( offSeconds - fadeUpTime <= tSeconds  ){ // LED DOWN
      blinkLedIcon();
      if(millis()/1000 >= fadeStepTime ) {
        fadeStepTime = millis()/1000 + 1;
        fadeValue -= fadeValuePick;
        if(fadeValue <= 0) fadeValue = 0;
      }
    }
  }
  else{ // LIGHT OFF
    text = expandZero(onHour) + ":" + expandZero(onMinute);
    if(text != ledTimeValue) {
      drawTimer(0, 12,2, text);
      ledTimeValue = text;
    }
    // ide jön amit még ki kell kapcsolni
    //lightStatus = false;
    digitalWrite(LED, LOW);
    digitalWrite(relay, LOW);
  }
}

//  blinkLedIcon
// 500ms idönként váltogat(villogtat) 2 ikont az LCD-n
void blinkLedIcon(){
  if(millis() > ledIconTime) {
    ledIconTime = millis() + 350;
    ledStatus = !ledStatus;
    lcd.setCursor(12,2);
    if(ledStatus) lcd.write((uint8_t)3);
    else lcd.write((uint8_t)2); 
  }
}


//  drawTimer()
// időzitő ikon állapt kirajzokása LCD-re
void drawTimer(boolean statusInfo, int row, int column, String data){
  lcd.setCursor(row,column);
  if(statusInfo) lcd.write((uint8_t)3);
  else lcd.write((uint8_t)2);
  lcd.print( " ");
  lcd.print(data);
}

//  doPir()
// pir szenzor magas jel esetén beállítja a háttér világitás kikapcsolási idejét
// JELENLEG MÁSODPERC ALAPON
void doPir(){
  pirStatus = digitalRead(pirPin);
  if(pirStatus){
    backLightStatus = true;
    backLightStop = millis()/1000 + backLightTime;
    if(millis() > pirIconTime) {
      pirIconTime = millis() + 350;
      pirLedStatus = !pirLedStatus;
      lcd.setCursor(10,1);
      if(pirLedStatus) lcd.write((uint8_t)1);
      else lcd.print(" ");
    } 
  }
  if(!pirStatus && pirLedStatus) {
    lcd.setCursor(10,1);
    lcd.print(" "); // icon törlése inaktivitáskor
    pirLedStatus = !pirLedStatus;
  }
  if(backLightStatus && !pirStatus) {
    if(millis()/1000 >= backLightStop) backLightStatus = false;
  }
  if(backLightStatus) lcd.backlight();
  else lcd.noBacklight();
}

//  expandZero()
// kibővití 0-val az elején a kapott integert
// visszatérési érték String
// expandZero(125); => "0125"
String expandZero( int nr){
  if(nr < 10 ) return "0" + String( nr );
  else return String(nr);
}

float minValue( float tomb[]){
  float min = 100;
  for(int nr=0; nr<12; nr++){
    if(tomb[nr] < min){
      min = tomb[nr];
    }
  }
  return min;
}

float maxValue(float tomb[]){
  float max = 0;
  for(int nr=0; nr<12; nr++){
    if(tomb[nr] > max){
      max = tomb[nr];
    }
  }
  return max;
}

//  getTemp()
// vissza adja a szenzor által mért értéket
// DS18B20 senzor type
float getTemp(){
  byte data[12];
  byte addr[8];
  if ( !ds.search(addr)) {
    ds.reset_search();
    return -1000; // nincs eszköz
  }
  if ( OneWire::crc8( addr, 7) != addr[7]) return -2000; // CRC hiba
  if ( addr[0] != 0x10 && addr[0] != 0x28) return -3000; // eszköz nem válaszol
  ds.reset();
  ds.select(addr);
  ds.write(0x44,1); // start conversion, with parasite power on at the end
  byte present = ds.reset();
  ds.select(addr);  
  ds.write(0xBE); // Read Scratchpad
  for (int i = 0; i < 9; i++) { // we need 9 bytes
    data[i] = ds.read();
  }
  ds.reset_search();
  byte MSB = data[1];
  byte LSB = data[0];
  float tempRead = ((MSB << 8) | LSB); //using two's compliment
  float TemperatureSum = tempRead / 16;
  return TemperatureSum;
}

A akvarium_V0_7.ino sketch letöltése

Két forrásból lehet letölteni, első helyi zip fájl, és Google Drive-rol akvarium_V0_7.ino névvel.

akvarium_V0_7.zip

Letöltés

akvarium_V0_7.ino

Letöltés

Működik, de lehetne jobb is

Az Arduino NANO megfelelő választás egy ilyen vezérléshez, kis fogyasztás elegendő programozható port, kis méret. Viszont ami nekem van az egy kínai replika, nem eredeti. Ettől függetlenül működik a vezérlés, az adatok kijelzése. 2015 első negyedéve óta használom ezt a hardver az akvárium világítás vezérlésére, még nem kellet benne semmit kicserélni. Pár alkalommal fagyott meg az egész rendszer, de mindig lekapcsolt fázisban. Így sohasem maradt felkapcsolva egész éjjel a LED panel, még nyaralások alkalmával sem.

Ami hátrány jelenleg, hogy a kis memória miatt nem megoldott a teljes külső paraméter állítás, és az adatok eltárolása, bár egy SD kártyás illesztéssel kibővítve még talán elférne a program a memóriában. És bármilyen változtatás a programban, újabb feltöltést igényel. Ennek gyorsítására én több NAN-ot használok, és egyre feltöltöm a programot áramtalanítás után csere és mehet újra az egész.

Arduino kategória további bejegyzései:

  • Arduino multitasking
    Olvasási idő: 3 perc Multitasking avagy párhuzamos vezérlés. Jobb kifejezés rá a párhuzamos feladat végrehajtás. Miért is van erre szükség? Nem minden esetben, de…
  • Arduino Nano BMP180 teszt
    Olvasási idő: 4 perc BMP180 egy alap szenzor egy időjárás állomás elkészítéséhez. Megkapjuk tőle a légnyomást, hőmérsékletet, és még a tengerszint feletti magasságot is….
  • Arduino pro IDE telepítése Linux-ra
    Olvasási idő: 4 perc Arduino programozására eddig a sima Arduino IDE-t használtam. Viszont rátaláltam egy egy alfa kiadásra ami már 2019 októberében megjelent. Jelenleg…
  • Arduino Nano fotodióda teszt
    Olvasási idő: 2 perc Fotodióda tesztelése Arduino Nano-val. Az általam használt dióda egy éjszakai fényt adó egységből való, így nem tudom a típusát, sem…
  • Arduino DS1307-RTC dátum, idő beállítás
    Olvasási idő: 3 perc Ezt az eszköz már elég régóta használom, de most volt vele csak gondom. És így megosztom, azt a pár egyszerű…
  • Arduino – Akvárium világítás vezérlés
    Olvasási idő: 8 perc A program Ha minden kész akkor már csak egy valami van hátra maga a program. A NANO esetében 32Kb hely…