Go Down

Topic: Timer Programmabile (Read 7009 times) previous topic - next topic

Guidus93

Ormai è un po che lavoro a un progetto di un timer programmabile (utilizzo RTC) che gestisce due relè a stato solido. Il problema è che non riesco a fare passare la mezzanotte al mio timer, faccio un esempio che mi spiego meglio. Io vorrei tenere il timer OFF dalle 8.00 alle 14.00 . Se con il codice che ho provo a mettere l'orario che desidero non funziona correttemente. Ho bisogno che Arduino controlli nel Loop l'ora e lo stato dei relè perchè nel caso di mancamento di corrente il timer si deve riaccendere!

Questo il mio codice:
Code: [Select]
#include <Wire.h>
#include <RTClib.h>
#include <Time.h>
#include <TimeAlarms.h>
// Light states
#define STATE_OFF  0
#define STATE_ON   1

// Timer settings
#define START_TIME  0700
#define END_TIME    2300

RTC_DS1307 RTC;

int FanState;
int lightState;

// Define Relay
int lightRelay = 6;
int fanRelay = 7;
void setup() {  // Set the pinmode
  Serial.begin(9600);
  Wire.begin();
  RTC.begin();
  pinMode(lightRelay, OUTPUT);
  pinMode(fanRelay, OUTPUT);
  digitalWrite(lightRelay, LOW);
  lightState = STATE_OFF;
  digitalWrite(fanRelay, LOW); // put your setup code here, to run once:

}

void loop() {
 
DateTime now = RTC.now();
  int nowHourMinute = now.hour()*100 + now.minute();

  // FSM states
  switch(lightState) {

  case STATE_OFF:
    if(nowHourMinute > START_TIME && nowHourMinute < END_TIME) {
      Serial.print(now.hour(), DEC);
      Serial.print(':');
      Serial.print(now.minute(), DEC);
      digitalWrite(lightRelay, HIGH);
      digitalWrite(fanRelay, HIGH);
      Serial.println("\nFan On");
      Serial.println("\nLight On");
      FanState = STATE_ON;
      lightState = STATE_ON;

    }
    break;

  case STATE_ON:
    if(nowHourMinute > END_TIME) {
      Serial.print(now.hour(), DEC);
      Serial.print(':');
      Serial.print(now.minute(), DEC);       
      digitalWrite(lightRelay, LOW);
      lightState = STATE_OFF;

    }   
    break;
  }

leo72

Il problema è stato affrontato tantissime volte. Fai una ricerca che trovi la spiegazione del perché e del come risolvere.
Non puoi affrontare orari a cavallo di 2 giorni con un semplice if sulle variabili temporali. O usi un'altra variabile in cui salvi il cambio di giorno oppure usi, molto meglio, il tempo Unix (che è conteggiato in secondi da un punto fissato come "epoca", ossia inizio).

Guidus93

ho cercato molto ma non ho trovato nulla, se sei così gentile da linkarmi qualche discussione o qualche spiegazione mi fai un faovre!

leo72

Ho trovato questa, per ora. Ma ce ne sono un sacco:
http://forum.arduino.cc/index.php?topic=245354.0

Guidus93

Ok, ho capito che devo convertire il tutto a unixtime, ma non capisco come inserire questa cosa nel mio codice per il timer!

Guidus93

#5
Jul 02, 2014, 10:51 am Last Edit: Jul 02, 2014, 11:25 am by leo72 Reason: 1
Ho modificato la parte timer così
Code: [Select]
#include <Wire.h>
#include <RTClib.h>

RTC_DS1307 RTC;

int ledPin = 13;         // Set our LED pin

byte startHour = 8;    // Set our start and end times
byte startMinute = 45;  // Don't add leading zero to hour or minute - 7, not 07
byte endHour = 2;      // Use 24h format for the hour, without leading zero
byte endMinute = 45;

byte validStart = 0;    // Declare and set to 0 our start flag
byte poweredOn = 0;     // Declare and set to 0 our current power flag
byte validEnd = 0;      // Declare and set to 0 our end flag

void setup () {
 pinMode(ledPin, OUTPUT);   // Set our LED as an output pin
 digitalWrite(ledPin, LOW); // Set the LED to LOW (off)
 Serial.begin(9600);
 Wire.begin();              // Start our wire and real time clock
 RTC.begin();
 
 if (! RTC.isrunning()) {                       // Make sure RTC is running
   Serial.println("RTC is NOT running!");
   //RTC.adjust(DateTime(__DATE__, __TIME__));  // Uncomment to set the date and time
 }
}

void loop () {
 
 DateTime now = RTC.now(); // Read in what our current datestamp is from RTC
 
 if (now.second() == 0) { // Only process if we have ticked over to new minute
   if (poweredOn == 0) {  // Check if lights currently powered on
     checkStartTime();    // If they are not, check if it's time to turn them on
   } else {
     checkEndTime();      // Otherwise, check if it's time to turn them off
   }
 
   if (validStart == 1) { // If our timer is flagged to start, turn the lights on
     turnLightsOn();
   }
   if (validEnd == 1) {   // If our time is flagged to end, turn the lights off
     turnLightsOff();
   }
 }
 
 serialclockprint();
 delay(1000);  
}

byte checkStartTime() {
 DateTime now = RTC.now();  // Read in what our current datestamp is from RTC
 
 if (now.hour() >= startHour && now.minute() >= startMinute) {
   validStart = 1;  // If our start hour and minute match the current time, set 'on' flags
   poweredOn = 1;
 } else {
   validStart = 0;  // Otherwise we don't need to power up the lights yet
 }
 
 return validStart; // Return the status for powering up
}

byte checkEndTime() {
 DateTime now = RTC.now();  // Read in what our current datestamp is from RTC
 
 if (now.hour() == endHour && now.minute() == endMinute) {
   validEnd = 1;    // If our end hour and minute match the current time, set the 'off' flags
   poweredOn = 0;
 } else {
   validEnd = 0;    // Otherwise we don't need to power off the lights yet
 }
 
 return validEnd;   // Return the status for powering off
}

void turnLightsOn() {
 digitalWrite(ledPin, HIGH);  // Turn on the LED
 Serial.print("Light ON");
}

void turnLightsOff() {
 digitalWrite(ledPin, LOW);   // Turn off the LED
 Serial.print("Light OFF");
}
void serialclockprint() {
  DateTime now = RTC.now();

 
 Serial.print(now.hour(), DEC);
 Serial.print(':');
 Serial.print(now.minute(), DEC);
 Serial.print(':');
 Serial.print(now.second(), DEC);
 Serial.println();  
 Serial.println();
}


Dite che funziona?

leo72

"Dite che funziona?": la risposta è "boh", tu lo hai provato il codice (io non ho modo di montare su un DS1307 per i test)?  ;) ;)

Guidus93

Ho preso montato la scheda ma non funziona, a ogni minuto che passa accende. Io ci sto diventando pazzo,
devo far accendere una luce alle 14.00 e farla spegnere alle 8.00 del giorno dopo, su internt e beò forum non ho trovato nulla che mi potesse aiutare

Guidus93

#8
Jul 02, 2014, 11:40 am Last Edit: Jul 02, 2014, 11:50 am by Guidus93 Reason: 1
Questo è il codice che ho scritto e sto usando da circa un paio di mesi. La modifica al timer mi sta facendo diventare pazzo!

Code: [Select]
#include <Wire.h>
#include <RTClib.h>
#include <Time.h>
#include <TimeAlarms.h>
#include "DHT.h"
#include <LiquidCrystal.h>
#define DHTPIN 8
#define DHTTYPE DHT21
DHT dht(DHTPIN, DHTTYPE);
#include <EEPROM.h>
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);

// Light states
#define STATE_OFF  0
#define STATE_ON   1

// Timer settings
#define START_TIME  0700
#define END_TIME    2300


RTC_DS1307 RTC;
// Var for Tmax e Tmin
byte tMIN;
byte tMAX;

// Var for Hmax e Hmin
byte hMIN;
byte hMAX;


int FanState;
int lightState;

// Define Relay
int lightRelay = 6;
int fanRelay = 7;

const int reset = 10;
int statoreset = 0;

void setup() {
 Serial.begin(9600);
 Wire.begin();
 RTC.begin();
 lcd.begin(20, 4);
 dht.begin();
 tMIN = EEPROM.read(1);
 tMAX = EEPROM.read(2);
 hMIN = EEPROM.read(3);
 hMAX = EEPROM.read(4);

 pinMode(reset, INPUT);
 digitalWrite(10, HIGH);
 // Set the pinmode
 pinMode(lightRelay, OUTPUT);
 pinMode(fanRelay, OUTPUT);
 digitalWrite(lightRelay, LOW);
 lightState = STATE_OFF;
 digitalWrite(fanRelay, LOW);
}

void loop() {

 int h = dht.readHumidity();
 int t = dht.readTemperature();
 float h1 = dht.readHumidity();
 float t1 = dht.readTemperature();
 if (isnan(t) || isnan(h)) {
   Serial.println("FALIED to read from DHT");
 }
 else {
   lcd.setCursor(0, 1);
   lcd.print("T:");
   lcd.print(t);
   lcd.print("C");
   lcd.setCursor(0, 2);
   lcd.print("H:");
   lcd.print(h);
   lcd.print("%");

   Serial.print("T:");
   Serial.print(t1);
   Serial.println("");
   Serial.print("H:");
   Serial.print(h1);

   delay(100);
 }

 if (t > tMAX)
 {
   tMAX = t;
   EEPROM.write(2, t);
 }
 // se la temperatura supera il dato MAX allora modifico il dato MAX
 // scrivo questo dato anche nella eeprom
 if (t < tMIN && t > 0)
 {
   tMIN = t;
   EEPROM.write(1, t);
 }
 // se la temperatura è minore del dato MIN allora modifico il dato MIN
 // scrivo questo dato anche nella eeprom


 if (h > hMAX)
 {
   hMAX = h;
   EEPROM.write(4, h);
 }
 // se la temperatura supera il dato MAX allora modifico il dato MAX
 // scrivo questo dato anche nella eeprom
 if (h < hMIN && h > 0)
 {
   hMIN = h;
   EEPROM.write(3, h);
 }
 // se la temperatura è minore del dato MIN allora modifico il dato MIN
 // scrivo questo dato anche nella eeprom
 statoreset = digitalRead (reset);
 if ( statoreset == LOW) {
   tMIN = t;
   tMAX = t;
   hMAX = h;
   hMIN = h;
 }

 lcd.setCursor(6, 1);
 lcd.print("T+:");
 lcd.print(tMAX);
 lcd.print("C");
 lcd.setCursor(13, 1);
 lcd.print("T-:");
 lcd.print(tMIN);
 lcd.print("C");
 lcd.setCursor(6, 2);
 lcd.print("H+:");
 lcd.print(hMAX);
 lcd.print("%");
 lcd.setCursor(13, 2);
 lcd.print("H-:");
 lcd.print(hMIN);
 lcd.print("%");

 int h2 = dht.readHumidity();

 if (lightState == STATE_OFF && h2 >= 60) {
   digitalWrite(fanRelay, HIGH);
   Serial.println("\nFan On");
   lcd.setCursor(10, 3);
   lcd.print("Fan ON");
 }
 if (lightState == STATE_OFF && h2 <= 50) {
   digitalWrite(fanRelay, LOW);
   Serial.println("\nFan OFF");
   lcd.setCursor(10, 3);
   lcd.print("      ");

 }
 DateTime now = RTC.now();
 int nowHourMinute = now.hour() * 100 + now.minute();

 // FSM states
 switch (lightState) {

   case STATE_OFF:
     if (nowHourMinute > START_TIME && nowHourMinute < END_TIME) {
       Serial.print(now.hour(), DEC);
       Serial.print(':');
       Serial.print(now.minute(), DEC);
       digitalWrite(lightRelay, HIGH);
       digitalWrite(fanRelay, HIGH);
       Serial.println("\nFan On");
       Serial.println("\nLight On");
       FanState = STATE_ON;
       lcd.setCursor(10, 3);
       lcd.print("Fan ON");
       lcd.setCursor(0, 3);
       lcd.print("Light ON");
       lightState = STATE_ON;

     }
     break;

   case STATE_ON:
     if (nowHourMinute > END_TIME) {
       Serial.print(now.hour(), DEC);
       Serial.print(':');
       Serial.print(now.minute(), DEC);
       digitalWrite(lightRelay, LOW);
       lcd.setCursor(0, 3);
       lcd.print("        ");
       lightState = STATE_OFF;

     }
     break;
 }


 lcd.setCursor(0, 0);
 if (now.day() < 10)
 {
   lcd.print("0");
 }
 lcd.print(now.day(), DEC);
 lcd.print('/');
 if (now.month() < 10)
 {
   lcd.print("0");
 }
 lcd.print(now.month(), DEC);
 lcd.print('/');
 lcd.print(now.year(), DEC);
 lcd.print(' ');
 if (now.hour() < 10)
 {
   lcd.print("0");
 }
 lcd.print(now.hour(), DEC);
 lcd.print(":");
 if (now.minute() < 10)
 {
   lcd.print("0");
 }
 lcd.print(now.minute(), DEC);
 lcd.print(":");
 if (now.second() < 10)
 {
   lcd.print("0");
 }
 lcd.print(now.second(), DEC);

 Serial.println("");
 Serial.print(now.day(), DEC);
 Serial.print('/');
 Serial.print(now.month(), DEC);
 Serial.print('/');
 Serial.print(now.year(), DEC);
 Serial.print(' ');
 Serial.print(now.hour(), DEC);
 Serial.print(':');
 Serial.print(now.minute(), DEC);
 Serial.print(':');
 Serial.print(now.second(), DEC);
 Serial.println();
 Serial.println();
 Alarm.delay(100);

}



leo72

Usa il timestamp, altrimenti diventi matto.

La mia libreria swRTC (link in calce) li gestisce. Devi solo fissare una "epoca", ossia una data di riferimento, ad esempio il 1° gennaio 2000 che diventa l'istante 0. Da quel momento in poi parte il conteggio dei secondi e tutti gli orari possono essere rappresentati in base ad un tot numero di secondi dopo quell'epoca. Ad esempio, ipotizziamo che il 2 luglio 2014 alle 15:00 (cioè adesso) siano trascorsi 1.000.000 di secondi dall'epoca (non lo so quanti sono, ho tirato a caso), domani a quest'ora sarà l'istante 1.086.400 (un giorno contiene 86.400 secondi), tra 1 ora sarà l'istante 1.003.600 (1 ora sono 3600 secondi). Quando perciò fissi un orario non dovrai far altro che calcolare il timestamp di quel momento.
Similarmente, se vuoi mettere un allarme che si ripete, non dovrai far altro che contare il numero di secondi.

Guidus93

Ho provato a guardare la tua libreria ma continuo a non capire.
Ho provato a convertire l'orario tutto in secondi, ma continua a non andare? Qualcun o che mi può buttare giù due linee guida ?
Code: [Select]

#include <Wire.h>
#include "RTClib.h"

RTC_DS1307 rtc;

long Tc , Ton, Toff;

int ledPin = 13;
int TonH = 16;
int TonM = 39;
int TonS = 0;
int ToffH = 16;
int ToffM = 35;
int ToffS= 0;

void setup () {
  Serial.begin(9600);
  Wire.begin();
  rtc.begin();

  DateTime now = rtc.now();
  Tc = (now.hour()*3600)+(now.minute()*60)+(now.second());
  Ton = (TonH*3600)+(TonM*60)+(TonS);
  Toff = (ToffH*3600)+(ToffM*60)+(ToffS);
 
}

void loop () {
   
  if (Tc >= Ton) {
    if (Tc < Toff) {
      digitalWrite(ledPin, HIGH);
      Serial.println("Light ON");
    }
    else {
      digitalWrite(ledPin, LOW);
      Serial.println("Light OFF");
    }
  }
     
 
 
  DateTime now = rtc.now();
   
    Serial.print(now.year(), DEC);
    Serial.print('/');
    Serial.print(now.month(), DEC);
    Serial.print('/');
    Serial.print(now.day(), DEC);
    Serial.print(' ');
    Serial.print(now.hour(), DEC);
    Serial.print(':');
    Serial.print(now.minute(), DEC);
    Serial.print(':');
    Serial.print(now.second(), DEC);
    Serial.println();
   
   
    Serial.println();
    delay(1000);
}

GalaxyHD96

ma non fai prima a farti tu stesso un timer? fai moolto prima e con qualche variabile di piu te ne esci...

leo72

Ricordati però di 2 cose:
1) devi usare UNSIGNED long, altrimenti potresti trovarti con numeri negativi;
2) devi comunque usare un flag per segnare lo stato dell'illuminazione perché in un secondo, con la velocità di elaborazione dell'Arduino, tu farai decine (o centinaia di controlli), per cui devi trasformare tuto in una cosa come questa:

Code: [Select]
IF (timestamp_ora_attuale >= timestamp_ora_attivazione) AND (stato = off) THEN
  stato = on
  attivazione luci
END IF

IF (timestamp_ora_attuale >= timestamp_ora_disattivazione) AND (stato = on) THEN
  stato = off
  disattivazione luci
END IF


leo72

PS:
la mia lib accetta una coppia di data/ora con un'epoca e ti restituisce un timestamp. Devi convertire quindi tutto in un orario con data.
Se vuoi usare solo l'orario, devi semplificare i calcoli.

Go Up