Go Down

Topic: Controllo e gestione carico casalingo con sistema di priorità ! (Read 8664 times) previous topic - next topic


5a2v0

I GOTO li ho usati per arrivare alla parte del codice che riguarda le azioni dei bottoni senza analizzare ulteriori "situazioni" dopo che il codice ha effettuato un distacco e cambiato alcune variabili che avrebbero quindi permesso l'esecuzione dell'istruzione successiva, ad esempio (riporto una parte abbreviata di codice):

Code: [Select]

//Distacco prima relè 1 ovvero sezione bagni
          if (rele1 == 0) {
digitalWrite(bagni, LOW);
rele1 = 1;
goto bottoni;
          }
//Se per relè 1 è già avvenuto il distacco, intervengo su relè 2
          if ((rele1 == 1) && (rele2 == 0)) {
.....ecc


Se ometto il goto, il codice mi esegue il primo distacco, cambiando la variabile e impostandola a 1, e mi esegue anche il secondo distacco.. che invece dovrà avvenire solo se le condizioni di consumo sussistono ancora..Quindi, con goto per questo loop ormai ho fatto un distacco e vado alla parte "finale" del codice, se i consumi saranno ancora alti in seguito, il codice andrà avanti staccando anche l'altro relè !

Per la domanda sugli IF usati come i WHILE non l'ho capita, puoi spiegarmi meglio cosa intendi ?

PaoloP

Per saltare parti del codice senza usare i goto devi legare gli IF con gli ELSE in modo che non vengano considerati se una condizione si è già verificata, oppure sostituire dove possibile con uno SWITCH CASE.
Riguardo i WHILE, guarda questo pezzo:
Code: [Select]
//Quando il consumo risulta maggiore anche del limite limiteMax per un tempo che va oltre intervalWattAlert, attiva il buzzer per segnalare l'esubero
    if (consumoTot > limitWattMax) {
      previousWattReset = millis();
      if (((millis() - previousWattAlert > intervalWattAlert) && (millis() - previousWattMaxAction < intervalWattMaxAction)) || (millis() - previousBuzzer > intervalMaxBuzzer)) {
        previousWattAlert = millis();
        while (consumoTot > limitWattMax) {
          //analogWrite(buzzer, 200);
          if (millis() - previousBuzzer > intervalMaxBuzzer) {
            previousBuzzer = millis();
            while (millis() - previousBuzzer <= timeBuzzer) {
              analogWrite(buzzer, 200);
            }
            while (millis() - previousBuzzer > timeBuzzer) {
              analogWrite(buzzer, 0);
              goto bottoni;
            }
          }
          goto bottoni;
        }
      }

L'unico WHILE che funziona da while, ovvera un ciclo con condizione è quello con l'analogWrite, gli altri sono degli IF mascherati in quanto inizia il ciclo e poi salta fuori con i GOTO.
Tra l'altro lasci appeso il ciclo while e, se il compilatore non ha ottimizzato il codice, ciclo dopo ciclo riempi lo stack e infine esaurisci la memoria.
Potresti, per debug, visualizzare ad ogni loop, nel diplay LCD, il quantitativo di memoria libera. La funzione FreeRam() la trovi nella libreria dell'IDE in SdFatUtil.h
Devi aggiungere
Code: [Select]
#include "SdfatUtil.h"
e
Code: [Select]
lcd.setCursor(x,y);
lcd.print((int)FreeRam());

dove con x e y indichi le coordinate del display dove stampare il numero.

5a2v0

quindi il tuo consiglio sarebbe quello di far diventare (dalla porzione di codice da te riportato):

Code: [Select]
  while (consumoTot > limitWattMax) {

in semplice if:

Code: [Select]
  if (consumoTot > limitWattMax) {

giusto ?
ovviamente lo correggerei nelle varie volte in cui ho commesso questo errore (credo si ripeta almeno 4 volte!!)

PaoloP

Si esatto, ma solo per i While che non sono cicli, ovvero che anno nel codice un goto o un break;.

5a2v0

OK tHANKS ;)

ma usare il GOTO può essere controproducente ? (al di la del mio uso errato/evitabile)

A breve (spero) di modificare la parte che gestisce gli esuberi e i distacchi integrando i controlli dei consumi dei nuovi sensori (speriamo arrivino...posta prioritaria dalla Cina...)

In ogni caso per il momento grazie dei tuoi preziosi consigli :)

PaoloP


ma usare il GOTO può essere controproducente ? (al di la del mio uso errato/evitabile)

--> http://www.hwupgrade.it/forum/showthread.php?t=2439046

5a2v0

riprendo il topic in mano visto che dopo un po di "gavetta" con arduino Yun, mi sono deciso ad utilizzarlo al posto di Uno per lo stesso progetto, ma con qualche modifica. Ecco le principali:

- Controllo consumi anche da remoto;

- Distacco e riallaccio da remoto;

- Possibilità futura di aggiungere la funzione per alzare ed abbassare le serrande già motorizzate da remoto;

- Le suddette operazioni saranno eseguibili comodamente da un app per Android che ho già realizzato e testato (e funziona :) )

- Segnalazioni acustiche tramite cassa audio (di quelle che si usano per i portatili o per ipod etc etc) collegata ad una scheda audio usb collegata alla porta usb gestita da linux, con riproduzione di file mp3 posti sulla scheda microSD (già funzionante);

Siccome ho deciso di risparmiare qualche pin prezioso che, con il primo progetto avevo un po trascurato, ho deciso di collegare il monitor (un nuovo 20x4 al posto del 16x2) tramite i2C.

I sensori di corrente (SCT-013-030) sono diventati 4:

pin A1 --- sensore linea BAGNI

pin A2 --- sensore linea STANZE

pin A3 --- sensore linea CUCINA

pin A4 --- sensore TOTALE

pin A5 --- offset (leggo la tensione in uscita da un partitore di tensione realizzato partendo dal VIN, che in particolare viene dall'alimentatore switching stabilizzato che alimenta il tutto (arduino + proto shield con partitore di tensione, 4 led, 1 scheda relè, 1 monitor 20x4);

I sensori sono tutti collegati al partitore di tensione come l'offset, ad ogni loop, come già nel progetto precedente con UNO, eseguo un tot (X) di letture in un dato tempo (20ms), ad ogni lettura sottraggo l'offset, ne considero i valori assoluti, sommo i valori e divido per il numero di letture ottenendo così la media. Da questo valore ottengo poi in modo (consapevolmente approssimato) gli ampere, quindi i watt!

Il mio attuale problema nasce dal fatto che nei 20ms (ho provato anche ad aumentare il tempo di campionamento) leggo X volte ben 5 porte analogiche che, in condizioni di carico quasi nullo in tutta la casa, dovrebbero avere letture uguali o quasi alla lettura del pin A5, portando la differenza uguale o quasi a 0, ottenendo quindi circa 0 watt di consumo dai calcoli.

Con Uno ed un solo sensore, era (quasi) così, in assenza di carico magari la media mi riportava 4 - 5 watt di consumo ma del tutto trascurabile (per me) visto la consapevolezza di una certa approssimazione alla base del progetto...

Con Yun e con 4 sensori, il fenomeno è diventato più evidente e volevo cercare di limitarlo!

In assenza di carico nei sensori, in genere ho 70 - 80 watt per ogni sezione !!! Fermo restando che se ad esempio accendo un utilizzatore in CUCINA, il valore riportato dal relativo sensore è molto attendibile e gli altri rimarrebbero intorno ai 70 - 80 watt..

Ho fatto fin ora davvero tante prove per cercare di capire dove potrebbe essere il problema, nell'ultimo disperato tentativo, ho deciso di togliere completamente i sensori, e collegare direttamente il partitore di tensione ai pin A1 - A2 - A3 - A4 - A5!

nel codice in particolare ho:
Code: [Select]

//Lettura dati dei sensori e calcolo della corrente assorbita e dei consumi in watt
  ampereTot = 0.00;
  ampereCucina = 0.00;
  ampereStanze = 0.00;
  ampereBagni = 0.00;
  numeroCampionamenti = 0;
  inizioCampionamenti = millis() ;
  do
  {
    numeroCampionamenti++;
    //offsetValue è la lettura senza carico quindi lo sottraiamo alle letture dei sensori
    offsetValue = analogRead(offsetPin);
    sensorTotValue = analogRead(sensorTotPin) - offsetValue;
    sensorCucinaValue = analogRead(sensorCucinaPin) - offsetValue;
    sensorStanzeValue = analogRead(sensorStanzePin) - offsetValue;
    sensorBagniValue = analogRead(sensorBagniPin) - offsetValue;
    //Alcune letture potrebbero avere valore negativo per cui noi consideriamo il valore assoluto
    sensorTotValue = abs(sensorTotValue);
    sensorCucinaValue = abs(sensorCucinaValue);
    sensorStanzeValue = abs(sensorStanzeValue);
    sensorBagniValue = abs(sensorBagniValue);
    ampereTot += sensorTotValue;
    ampereCucina += sensorCucinaValue;
    ampereStanze += sensorStanzeValue;
    ampereBagni += sensorBagniValue;
  }
  //20 sono i millisecondi che verranno campionati
  while ((millis() - inizioCampionamenti) < 20);
  //Per ottenere gli ampere reali moltiplichiamo la media di ampere letti nei 20ms per 0.166 che è il fattore di conversione calcolato con un carico noto
  ampereTot = (ampereTot / numeroCampionamenti) * fattoreConversione;
  ampereCucina = (ampereCucina / numeroCampionamenti) * fattoreConversione;
  ampereStanze = (ampereStanze / numeroCampionamenti) * fattoreConversione;
  ampereBagni = (ampereBagni / numeroCampionamenti) * fattoreConversione;
  //Infine moltiplichiamo gli ampere per la tensione stabilita per ottenere il consumo in Watt
  consumoTot = ampereTot * tensione;
  consumoCucina = ampereCucina * tensione;
  consumoStanze = ampereStanze * tensione;
  consumoBagni = ampereBagni * tensione;


Mi aspettavo (non dico degli 0 ma comunque dei valori molto vicini) e invece ho sempre quel maledetto "consumo fantasma" su ogni linea..

Ho letto su un altro topic del forum (si parlava di controllare la tensione di diverse batterie, ognuna collegata ad una porta analogica) qualcuno spiegava che a causa dell'alta impedenza delle porte analogiche, il sample-and-hold dell'ADC non permetteva una lettura corretta di valori possibilmente simili tra loro di diverse porte analogiche lette velocemente...

Ammesso che sia questo il mio problema, posso risolvere in qualche modo ???
In un altro topic ancora (si parlava di letture analogiche relative a sensori di temperatura) qualcuno consigliava di collegare ANCHE a massa la porta analogica (con una resistenza) in modo da avere letture più precise.. è fattibile/consigliabile nel mio caso ?

Allego per completezza, lo schema (seppur elementare) dell'attuale collegamento sperando possa aiutarVi ad aiutarMi :)

PaoloP


riallaccio da remoto;


Il riattacco da remoto non è un'operazione sicura poiché non puoi verificare le condizioni dell'impianto.

Brunello

l'Atmel ( pag 253-255 del datasheet ) suggerisce, quando si cambia canale, di effettuare una lettura a vuoto, visto che la lettura sequenziale dei vari canali potrebbe essere influenzata dalla lettura precedente.

La cosa piu' semplice e' fare due letture, in modo che venga scartata la prima

Code: [Select]
offsetValue = analogRead(offsetPin);
offsetValue = analogRead(offsetPin);
    sensorTotValue = analogRead(sensorTotPin) - offsetValue;
sensorTotValue = analogRead(sensorTotPin) - offsetValue;

5a2v0

Appena provato così:

Code: [Select]
    offsetValue = analogRead(offsetPin);
    offsetValue = analogRead(offsetPin);
    sensorTotValue = analogRead(sensorTotPin);
    sensorTotValue = analogRead(sensorTotPin) - offsetValue;
    sensorCucinaValue = analogRead(sensorCucinaPin);
    sensorCucinaValue = analogRead(sensorCucinaPin) - offsetValue;
    sensorStanzeValue = analogRead(sensorStanzePin);
    sensorStanzeValue = analogRead(sensorStanzePin) - offsetValue;
    sensorBagniValue = analogRead(sensorBagniPin);
    sensorBagniValue = analogRead(sensorBagniPin) - offsetValue;


ma purtroppo ho sempre il problema.. l'idea di mettere anche a massa con la resistenza la porta analogica è del tutto sbagliata ?

Brunello

non capisco una cosa.. vedo tutta l'alimentazione positiva collegata al Vin..

ma tu sul Vin che tensione  ci applichi ?

5a2v0

5,08v che prelevo da un alimentatore

Nello schema non é riportato... Sorry...

Brunello

ma hai misurato la tensione presente sul 5V di Arduino ?

5a2v0

Non uso il pin dei 5v x nulla per cui non ho controllato... Ho misurato alla uscita dell alimentatore, prima del partitore e subito dopo il partitore...

Go Up