Arduino + Gyrator III + Ethernet shield e SD = Monitoraggio Sole

Salve a tutti, sono un neofita di programmazione e di Arduino ma vorrei realizzare un progetto scientifico per il monitoraggio della nostra stella… il sole. Ho già acquistato Arduino e stò cominciando a “giocare” con gli sketch che saranno la base del progetto appena descritto. In brevi parole il progetto è quello di costruire un datalogger (SD) che scrive ad intervalli regolari (5 min.) il valore letto su ingresso analogico. La data dovrà essere la più precisa possibile e per questo motivo ho pensato di utilizzare la sincronizzazione NTP utilizzando uno shield ethernet con SD. Fornirò ad Arduino anche un RTC (DS1307) in modo da mantenere la data ed ora corretta. Allora, la programmazione della sincronizzazione NTP è pronta e funzionante; la parte che riguarda la scrittura delle stringhe dati sulla SD è funzionante e stavo ora cercando di capire come realizzare dei timers per effettuare la lettura analogica ogni 5 min. e la sincronizzazione NTP ogni ora. Ho pensato di utilizzare la libreria TimeAlarm e lo sketch di prova funziona benissimo ma quando lo implemento nel mio sketch funziona solo un timers alla volta. A parte il fatto di includere il mio sketch con il problema per farvelo analizzare, avete qualche suggerimento in merito? Avete avuto anche voi esperienze negative con la libreria TimeAlarm? Considerate che ho già letto i suggerimenti in merito (TimeAlarm) a come dovrebbe essere implementato. Intanto vi mostro il codice… considerate che è in pieno debug. Grazie dei commenti.

SID_Datalogger.ino (10 KB)

di getto direi non usare la libreria TimeAlarm, ma usa direttamente la millis, o meglio ancora fai così:

tu hai 2 allarmi, uno Scrittura (ogni 5 min) e uno Aggiorna (ogni ora)

al primo avvio esegui Aggiorna, setti una variabile con il timestamp del prossimo aggiornamento Aggiorna.
Poi esegui Scrittura, e imposti un’altra variabile col timestamp del prossimo aggiornameto Scrittura.
Poi esegui una funzione Allarme, che prende il minore dei due timestamp e lo imposta come allarme dell’RTC.

A questo punto metti il micro in sleep, con risveglio dato da un interrupt in arrivo dall’RTC

Quanto scatta l’allarme dell’RTC, il micro viene svegliato, e controlla se il timestamp corrsiponde all’azione Aggiorna, se si la esegue, poi controlla se corrisponde a scrittura Scrittura, se si la esegue (nota come se per caso i 2 allarmi sono uguali vengono eseguite entramene le funzioni, ma prima l’aggiornamento di data e poi la lettura)
ovvio che entrambe la (o le ) funzione eseguita setta anche il timestamp del SUO prossimo aggiornamento.
viene rieseguita la funzione Allarme, che setta il prossimo allarme più vicino
l’arduino torna a nanna e la storia si ripete all’infinito.

edit: puoi sostituire all’allarme RTC la funzione millis(), però devi prevedere l’overflow della stessa, e non potrai mettere il micro “a nanna” ma dovrai fare una cosa del tipo:

while (allarmePiùVicino < millis() ){
   delay(1);//aspetta un millisecondo
}

Sono curioso... da astrofilo piccolo piccolo... che monitoraggi intendi eseguire sulla nostra stella?

Ciao ragazze/i e grazie per le risposte. Innanzi tutto rispondo alla più facile.. Leo72, Il Gyrator III è un ricevitore VLF (very low frequencies) che in prossimità di una eruzione solare riceve un impulso proporzionale alla durata ed all'entità dell'eruzione solare (flare). Arduino serve appunto per ricevere costantemente.. ogni 5 min. il valore di tensione dal ricevitore. Alla fine giornata si avrà un file CSV su cui si può costruire il grafico per vedere se ci sono state eruzioni solari e di che entità. In effetti qusta risposta va bene anche per Lesto, in quanto non voglio mettere Arduino in sleep perchè oltre a ricevere il segnale radio ogni 5 min. lo utilizzerò anche come orologio (dopotutto ha un display 4x20 ed è sincronizzato tramite NTP) e come termometro interno/esterno. Le capacità Arduino le ha.. basta sfruttarlo. Tornando al mio problema sul TimeAlarm. Si, grazie, la funzione "millis" può fare al mio caso. Sono comunque sconcertato perchè nel mio sketch il TimeAlarm non funziona. Eppure credo di aver rispettato tutto ciò che riguarda la funzione adottata. Lesto, tu non la utilizzi per qualche motivo specifico??? Sembrerebbe molto facile e comoda l'implementazione. Comunque sia, il tempo di studiare.. "come" e.. proverò il codice con millis. Debbo inoltre costruirmi prima un piccolo shield con l'RTC che ho appena acquistato.
Grazie ancora e ciao a tutti.

Carichi tante librerie, forse la TimeAlarm interferisce con qualcun'altra, bisognerebbe vedere come funziona.

Leo72, si è vero.. mi sono accorto anche io che le librerie sono tante rispetto ad altri progetti/sketch ma.. servono tutte per le funzioni che debbo far svolgere ad Arduino. Mi sono dimenticato di dirvi che il TimeAlarm nel mio sketch in effetti funziona ma.. SOLO un alarm per volta.. se inserisco due Alarm NO!!! O funziona la sincronizzazione NTP ma non funziona la "read" ogni 5 min. oppure viceversa. Inoltre, mi aspettavo che se il compilatore (IDE) non mi da errori tutto dovrebbe funzionare correttamente.. evidentemente non è vero.
PS- Leo72, come astrofilo ti interessa il progetto?

Scusate se mi intrometto ma l'argomento mi interessa, non conoscevo la cosa ma è una figata :grin:

Bene, se vi interessa l'argomento.. della documentazione potete goglare con i seguenti riferimenti :
Sudden Ionospheric Disturbances (SID) e per quanto riguarda il ricevitore cercate il GYRATOR III.. L'associazione che vi fornisce molti dettagli in merito è l'Americana A.A.V.S.O.
Buona lettura e poi ne riparliamo.

Scusami Lesto ma... utilizzando millis e tenendo Arduino up and running per 6 mesi cosa succede alla variabile tirata in causa da millis? Mi spiego meglio cercando di utilizzare termini da "programmatore" quale io NON sono.. i millisecondi che passano dalla prima accensione di Arduino dopo 6 mesi raggiungeranno un numero che è compatibile con le capacità di Arduino oppure mi costringe a fare dei reset per azzerare questo numero che diventerà ENORME??? Il mio progetto dovrebbe essere slegato da questo eventuale problema e quindi forse sarebbe meglio tornare all'idea del TimeAlarm??!?!?!?!?! Una Vs opinione mi sarebbe d'aiuto.. grazie.

la millis() è un long, quindi può contenere al massimo qualche miliardo, quando arriva al massimo si resetta (overflow) e la variabile torna a 0. Se non erro succede circa una volta alla settimana, e devi prevedere questo caso speciale.

lesto:
la millis() è un long, quindi può contenere al massimo qualche miliardo, quando arriva al massimo si resetta (overflow) e la variabile torna a 0. Se non erro succede circa una volta alla settimana, e devi prevedere questo caso speciale.

Io ho letto 7 giorni, 20 giorni, 49 giorni, 50 giorni e 52 giorni....
Ho letto anche che quando arriva in overflow riparte da 0 ... MAH??!!

questa sarebbe una cosa da chiarire una volta per tutte perchè mi è poco chiara anche a me

http://arduino.cc/hu/Reference/Long mi attengo a info ufficiali
Long variables are extended size variables for number storage, and store 32 bits (4 bytes),
from -2,147,483,648 to 2,147,483,647.

se questa variabile indica i millisecondi 2,147,483,648 X 2 = 4.294.967.296 di millisecondi
4.294.967.296 / 1000 = 4.294.967,296 secondi

in un giorno ci sono 606024 secondi, = 86400 secondi

4.294.967,296 / 86400 = 49,71026962962962962962962962963 giorni

Ora l'overflow a quanto si legge dal reference non è 0, ma riparte da -2,147,483,648
Quindi quando in uno sketch ci troviamo al 49° giorno e si incontra
if(currentMillis - previousMillis > interval) va tutto in crisi ......

tradotto in esempio:
if(2147483647 - -2147483000 > 3600) che succede...?

E' così o no?

ciao

errore mio, non è un long ma un Unsigned Long, ovvero un long senza segno. Quindi 2^32

attento che la millis() non lavora in secondi, ma in MILLIsecondi, 1 secondo = 1000 millisecondi

ok errore, non l'avevo notato nemmeno io :slight_smile:

Uhmmm.. ancora però non mi avete detto il PERCHE' non volete che io utilizzi la libreria TimeAlarm!!! Teoricamente questa libreria mi permetterebbe di slegarmi dal problema del reset di millis ed inoltre offrirebbe una programmazione molto più semplice ad un neofita come me. Si tratterebbe, probabilmente, "SOLO" di capire dove ho commesso l'errore nell'implementazione della stessa. C'e' qualcuno che ha esperienza in merito e che potrebbe darmi dei consigli/suggerimenti o esempi di codice per far funzionare più allarmi contemporaneamente?
Grazie in ogni caso.

Allora, siccome sono “leggermente” testardo e per di più neofita, ho provato a prendere un semplice sketch che dimostra il funzionamento della libreria TimeAlarm, inserito due soli timers (come nel mio caso) e tutto funziona. In questo semplice sketch vengono caricate le SOLE librerie Time e TimeAlarms. Ho cercato quindi di capire se le mie tante librerie potessero interagire male tra di loro. Ho quindi ripreso il semplice sketch che funziona ed ho inserito “a vuoto” tutte le librerie che mi occorrono, compilato e caricato su arduino FUNZIONA anche in questo caso. Ora, mi sembra di capire (corregetemi se sbaglio) che:
A) La libreria TimeAlarms funziona correttamente.
B) Anche se io carico le molte librerie che mi servono per il codice finale NON interagiscono in maniera negativa sugli allarmi.
Da qui sono giunto alla conclusione che è il mio codice ad essere errato e non la libreria e neanche l’interazione delle molte che utilizzerò.
Credo quindi che partirò da questo semplice sketch ad aggiungere step by step il codice della sincronizzazione NTP e poi se funziona ancora tutto completandolo con la lettura del ricevitore VLF.

Di seguito il codice che funziona per Vs curiosità:

/*
 * TimeAlarmsExample sketch
 */
 
#include <SPI.h>
#include <Ethernet.h>
#include <EthernetUdp.h>
#include <LiquidCrystal.h>
#include <Wire.h>
#include <DS1307.h>
#include <SD.h>
#include <Time.h>
#include <TimeAlarms.h>

void setup()
{
  Serial.begin(9600);
  
  setTime(8,29,40,1,1,10);                       // set time to 8:29:40am Jan 1 2010

  Alarm.timerRepeat(15, RepeatTask1);            // timer for every 15 seconds
  Alarm.timerRepeat(10, RepeatTask2);            // timer for every 10 seconds
}

void RepeatTask1()
{
  Serial.println("15 second timer");
}

void RepeatTask2()
{
  Serial.println("10 second timer");
}

void  loop()
{
  digitalClockDisplay();
  Alarm.delay(1000); // wait one second between clock display
}

void digitalClockDisplay()
{
  // digital clock display of the time
  Serial.print(hour());
  printDigits(minute());
  printDigits(second());
  Serial.println();
}

// utility function for digital clock display: prints preceding colon and
// leading 0.
//
void printDigits(int digits)
{
  Serial.print(":");
  if(digits < 10)
    Serial.print('0');
  Serial.print(digits);
}

marsel60:
Uhmmm.. ancora però non mi avete detto il PERCHE' non volete che io utilizzi la libreria TimeAlarm!!! Teoricamente questa libreria mi permetterebbe di slegarmi dal problema del reset di millis ed inoltre offrirebbe una programmazione molto più semplice ad un neofita come me. Si tratterebbe, probabilmente, "SOLO" di capire dove ho commesso l'errore nell'implementazione della stessa. C'e' qualcuno che ha esperienza in merito e che potrebbe darmi dei consigli/suggerimenti o esempi di codice per far funzionare più allarmi contemporaneamente?
Grazie in ogni caso.

perchè NON sappiamo cosa fa la libreria. Gestisce gli overflow? sicuro? e usa dei timer? e se usa dei timer li modifica in modo che altre librerie che usano quei timer non vanno? se no, altre liberire modificano il timer in modo che la tua libreria non funzioni?

con la millis vai molto più sul sicuro :slight_smile:

ps. il fatto di includere e basta le altre librerie NON è un test, perchè di fatto il compilatore si accorge che non le usi e non le compila, quindi non le inizializza, quindi non vengono eseguiti gli strani giochi dei timer

Ma se hai un orologio preciso, su variabili che siano hh,mm,ss oppure un ntp timestamp, perchè non usi quelle variabili per impostare i timer?

ciao

@marsel:
ormai il tempo libero è poco e la voglia di fare ancora meno. Ho venduto il newtoniano 114/1000 che avevo e mi sono tenuto solo un rifrattorino cinese per qualche osservazione dal balcone. Magari quando i figli saranno più grandicelli, vedrò di coinvolgerli :wink:

@pablos:
millis è unsigned long, e come tale conta da 0 a (2^32)-1, ossia 4294967295. Quando supera questo valore, semplicemente riparte da 0 (non da -2147483648). Ricordati che l’Arduino non è un computer dove abbiamo l’applicazione che gira in una zona di memoria ben definita, con un sistema che controlla che la stessa non faccia casini o un terminale in cui rientrare se va in errore il programma.
Se fai un confronto (4294967200+100)>4294967290, ad esempio, il confronto risulta falso perché 4294967200+100, essendo maggiore di 4294967295, fa resettare la variabile, che assume il valore di 4, e siccome 4<4294967290, il test fallisce. Quindi, semplicemente salti una esecuzione del codice scadenzato.

@pablos2:
effettivamente, avendo accesso ad un RTC, basta farsi un array con 2/3/4 ecc… orari ed eseguire le operazioni agli orari prefissati

Si Leo mi era sfuggita come a Lesto la questione del unsigned, per il resto volevo matematicamente dimostrare che i giorni sono 49.7 sia che parta da -xxxxx che da 0, la questione dell'overflow l'ho già incontrata ed è per me stato un problema, ecco perchè ho voluto implementare la tua libreria e aggiornarlo ogni tanto con NTP, mi serviva un timestamp da usare come array, ho eliminato la questione millis, funziona egregiamente e sono contento :).
ciao

Leo, dovrai perdonare ora la mia ENORME ignoranza in materia (ricordate con ho acquistato Arduino una settimana fa!) ma.. cosa significa far eseguire le operazioni agli orari prefissati nell'array dell'RTC? Un esempiuccio di codice mi farebbe molto comodo a questo punto se hai la BONTA' e PAZIENZA di farmi capire. Grazie anticipate della comprensione e del tempo "perso" per me.