Ho buttato giù due righe di codice creando la libreria per gestire la plafoniera che sto costruendo.
La libreria fornisce le funzioni "essenziali" che potrete facilmente estendere in base alle vostre necessità.
L'effetto alba e tramonto, qualora sia impostato, viene automaticamente regolato proporzionalmente ai secondi trascorsi in relazione all'ora di accensione e spegnimento del canale.
Per ogni canale basta impostare l'ora di accensione e spegnimento, eventuali minuti iniziali/finali di durata effetto alba/tramonto, il valore massimo pwm e il pin del canale.
Interfaccia (scheda denominata Plafo.h)
codice:
// Created by Niko Furioso on 15/07/13.
#ifndef __PLAFO_H__
#define __PLAFO_H__
#include <arduino.h>
enum Channels{
blue=0,
white=1,
uv=2,
moon=3
};
const byte channelsCount=4;
class Plafo {
public:
//Costruttore
Plafo();
void setChannel(const int channel,const byte startHour,const byte startMinute,const byte endHour,const byte endMinute,const unsigned int fadeLen,const byte maxPWM,const byte pin);
void perform(const byte nowHour,const byte nowMinute,const byte nowSecond);
private:
void performChannel(void* channel,const byte nowHour,const byte nowMinute,const byte nowSecond);
unsigned long elapsedTimeToSecond(const byte startHour,const byte startMinute,const byte startSecond,const byte endHour,const byte endMinute,const byte endSecond);
};
#endif
Implementazione (scheda denominata Plafo.cpp)
codice:
// Created by Niko Furioso on 15/07/13.
#include "Plafo.h"
struct Channel{
byte startHour,startMinute,maxPWM,lastPWM,pin;
unsigned long lightLen,fadeLen;
};
Channel *channels[channelsCount];
byte lastSecond;
//Costruttore
Plafo::Plafo(){
//Creazione canali
for (byte idx=0;idx<channelsCount;idx++){
channels[idx]= new Channel();
}
lastSecond=60;
}
//Metodi publici
void Plafo::setChannel(const int channel,const byte startHour,const byte startMinute,const byte endHour,const byte endMinute,const unsigned int fadeLen,const byte maxPWM,const byte pin){
//Configurazione canale
channels[channel]->startHour=startHour;
channels[channel]->startMinute=startMinute;
channels[channel]->lightLen=elapsedTimeToSecond(startHour,startMinute,0,endHour,endMinute,0);
channels[channel]->fadeLen=(unsigned long)fadeLen*60;
channels[channel]->maxPWM=maxPWM;
channels[channel]->pin=pin;
//Impostazione pin canale in uscita
pinMode(channels[channel]->pin,OUTPUT);
}
void Plafo::perform(const byte nowHour,const byte nowMinute,const byte nowSecond){
//Aggiornamento stato plafoniera
if (lastSecond!=nowSecond){
lastSecond=nowSecond;
for (byte idx=0;idx<channelsCount;idx++){
performChannel(channels[idx],nowHour,nowMinute,nowSecond);
}
}
}
//Metodi privati
void Plafo::performChannel(void* channel,const byte nowHour,const byte nowMinute,const byte nowSecond){
Channel *workCnl=(Channel*)channel;
//In base al valore massimo del canale determina se il pin è pwm o digitale
boolean isDigitalPin=workCnl->maxPWM==HIGH;
//Calcolo secondi trascorsi tra l'ora di accensione del canale e l'ora attuale
unsigned long elapsedSecond=elapsedTimeToSecond(workCnl->startHour,workCnl->startMinute,0,nowHour,nowMinute,nowSecond);
byte pwmValue=(isDigitalPin) ? LOW : 0;
//Verifica se il canale è acceso
if (elapsedSecond<=workCnl->lightLen){
//Verifica se alba
if (elapsedSecond<workCnl->fadeLen){
//Calcolo valore PWM in relazione ai secondi trascorsi dall'ora di inizio
pwmValue=(elapsedSecond*workCnl->maxPWM)/workCnl->fadeLen;
}//Verifica se tramonto
else if (elapsedSecond>workCnl->lightLen-workCnl->fadeLen){
//Calcolo valore PWM in relazione ai secondi mancanti all'ora di fine
pwmValue=((workCnl->lightLen-elapsedSecond)*workCnl->maxPWM)/workCnl->fadeLen;
}//Luce piena
else{
pwmValue=workCnl->maxPWM;
}
}
//Aggiorna lo stato del pin solo se il valore è effettivamente cambiato
if (workCnl->lastPWM!=pwmValue){
workCnl->lastPWM=pwmValue;
if (isDigitalPin){
digitalWrite(workCnl->pin,pwmValue);
}
else{
analogWrite(workCnl->pin,pwmValue);
}
}
}
unsigned long Plafo::elapsedTimeToSecond(const byte startHour,const byte startMinute,const byte startSecond,const byte endHour,const byte endMinute,const byte endSecond){
//Calcolo secondi tra ora di inizio e ora di fine
int elapsedHour;
elapsedHour=endHour-startHour;
if (elapsedHour<0)elapsedHour=24-startHour+endHour;
unsigned int elapsedMinute;
elapsedMinute=(unsigned int)elapsedHour*60 + endMinute-startMinute;
return (unsigned long)elapsedMinute*60 + endSecond-startSecond;
}
Per utilizzarla non resta che importarla nel vostro progetto, ad esempio:
codice:
#include "Plafo.h"
Plafo plafo;
void setup(void) {
//Channel,startHour,startMinute,endHour,endMinute,fadeLen,maxPWM,pin
plafo.setChannel(blue,18,0,4,0,30,180,7);//Dalle 18.00 alle 4.00, alba/tramonto 30 minuti, pwm massimo 180, pin 7
plafo.setChannel(white,18,15,3,45,75,180,5);//Dalle 18.15 alle 3.45, alba/tramonto 75 minuti
plafo.setChannel(uv,19,30,2,30,0,HIGH,22);//Dalle 19.30 alle 2.30, accensione immediata, pin 22 (digitale)
plafo.setChannel(moon,4,10,7,0,0,HIGH,23);//Dalle 4.10 alle 7.00
}
void loop(void) {
//Sostituire "hour","minute", "second" con le variabili dichiarate sul vostro progetto, che contengono rispettivamente l'ora, i minuti e i secondi correnti.
plafo.perform(hour,minute,second);
}
Per modificare, eliminare o aggiugere nuovi canali basta modificare "enum Channels" e la costante "channelsCount" presenti sull'interfaccia.
Spero che questa libreria vi possa essere di aiuto, naturalmente sono ben accetti consigli o segnalazioni di bug.
--------------AGGIORNAMENTI
19/07/2013 - i canali venivano ricreati ogni qualvolta venivano configurati