Organizzare temporizzazioni di 40 porte

Buongiorno

Ho 40 porte output che dovrebbero possedere ciascuna 10 orari ON e 10 orari OFF giornalieri/settimanali strutturati così gg,mm,aa,hh,mm,ss, questi dati vengono presi da un file ini su SD e scritti sullo stesso file da una pagina html compilando dei campi, questo passaggio già lo faccio, mi resta da fare i controlli sullo sketch

Inizialmente pensavo di creare un array tipo "byte port_on[39][9][5];" e "byte port_off[39][9][5];"
Poi ho pensando che ci sono troppi cicli annidiati per leggere tutto, se registrassi dei long con un programma che converte data e ora in timestamp potrei avere solo un array "long port_time[39][9][9];" dove 10 sono i timestamp on e 10 i timestamp off.
Dovrei creare il programma per vedere quanto tempo impiega a fare tutti i controlli se ne vale o meno la pena, altrimenti quale altro metodo più veloce posso utilizzare prima di sbattermi ore e ore per nulla?
Pensavo anche di fare in modo che il programma si registrasse i timer più vicini ad essere eseguiti e che terminati quelli si andasse a prendere un altra serie (4-5) da esguire, non saprei .....
Come potrei strutturarlo per avere la massima efficienza, visto che arduino fa anche molte altre cose.

Questo in previsione di trasferire il programma su arduino due che ha un clock di quasi 6 volte più veloce
Qualsiasi suggerimento è gradito :slight_smile: grazie

Ti sevrvono veramente gli anni e i secondi?

Un array [39] ha 39 elementi e non 40. L' indice va da 0 a 38.

In tutti i casi non funziona. Gli array sono troppo grandi per essere memorizzati nella RAM di Arduino xx e in parte Arduiono MEGA xx.
"byte port_on[39][10][5];" e "byte port_off[39][10][5];" sono 2 volte 1950Byte ovvero 3900Byte
"long port_time[39][9][9];" sono 12636 Byte.

Non credo che hai bisogno della Arduino DUE a causa della veocitá di esecuzione ma piu per avere abbastanza RAM.
Sulla Arduino MEGA é possibile aggiungere RAM per avere 64K Byte di RAM interna.

Per favore spiegaci cosa vuoi fare per poterti consigliare la strada da intraprendere.

Ciao Uwe

40106*byte sono 2400 byte. 2 array di questo tipo sono 4800 byte, devi per forza usare un supporto esterno.

Anche 4010long sono 1600 byte, per 2 array sono 3200 byte.

Le alternative sono:

  1. usare un Atmega1284: ha 16 kB di SRAM e 4 kB di EEPROM, potresti memorizzare ad esempio gli array di unsigned long nella EEPROM del chip
  2. usare una memoria esterna, come ad esempio un chip EEPROM da 8 o 16 kB a cui accedi via I2C

Nel caso 1) però il tuo progetto poi non lo trasporti sulla DUE dato che hai un chip differente.
Nel caso 2) il passaggio è banale. Resta da capire la velocità che vuoi tu, ma se gli orari sono con risoluzione minima di 1 secondo immagino che fare la scansione di 80 dati da EEPROM non porti via più di 1 secondo di tempo. C'è però da tener conto del tempo di elaborazione del resto del codice: sommando i 2 valori, se ottieni più di 1 secondo di tempo di calcolo complessivo potresti saltare un allarme, sia esso ON che OFF

Quello che voglio fare e che sto facendo è una piattaforma arduino programmabile da file ini su sd, l'utente imposta la porta INPUT o OUTPUT, i timer e operazioni da eseguire in successione all'evento, tutto da pagina web, molte di queste cose già le fa, mi mancano i timer
Arduino mega ha a disposizione 54 porte tolte alcune necessarie al sistema, facciamo che solo 30 le metto programmabili a scelta dell'utente, togliamo i secondi che in effetti non servono, bhe forse anche l'anno posso eliminare.

Non credo che hai bisogno della Arduino DUE a causa della veocitá di esecuzione ma piu per avere abbastanza RAM.

bhe la differenza ce l'avrei eccome già adesso con un webserver noto una lentezza non indifferente.

ciao

@Leo
Ho 256Kb e ne sto usando 45k e non sto usando 4Kb di eeprom.
Per il passaggio alla DUE ovvio dovrò rivedere il programma, ma tutta la parte parsing dei file non credo cambierà, la parte ethernet sarà di rivedere, gestione scrittura lettura sd sarà da rivedere, ma buona parte sarà utilizzabile.
Mi auguro esca già con libreria ethernet e SD e alcune fondamentali. spero :astonished:

Vero, non mi ricordavo che avevi detto della MEGA, che ha 4 kB di EEPROM. Allora usa i timestamp e memorizza i dati lì dentro, mi pare la scelta più logica, anche in previsione del fatto che se va via l'alimentazione i tuoi dati restano.

Devi solo controllare se il tempo di scansione di tutti gli allarmi sommato a quello di esecuzione del codice nel caso di un allarme sfori il muro di 1 secondo, la risoluzione del timestamp. Altrimenti ti salta tutta la baracca.
Un'alternativa potrebbe essere quella di usare un buffer e

  1. usare un timer interno e fare la scansione degli allarmi in background
  2. attivare un flag ed inserire nel buffer il n° di allarme attivato (esempio: 1 solo byte, con 2 bit per indicare l'array nel formao binario 00-01-10 e gli altri 6 bit per indicare il numero di posizione dell'allarme stesso, dato che con 2^6=64 rientreresti nelle 30 o 40 porte gestibili.)
  3. da codice non dovresti far altro che controllare se si è attivato il flag dell'allarme e poi andare direttamente a leggere nel buffer se devi attivare o disattivare una porta e quale.

usare un timer interno e fare la scansione degli allarmi in background

Lo intendi utilizzando la lib leOS? è fattibile così?

Con il leOS oppure direttamente manipolando un timer libero.
Il leOS ti occupa il timer 2, ricorda. Se hai una lib che lo adopera, avrai dei conflitti. Altrimenti potresti manipolare il timer 1.

Non so manipolare un timer di un mcu :fearful:

Usi librerie che utilizzano il timer 2?
Se la risposta è negativa, puoi usare il leOS. Crei una routine di check, falla però leggera, per non bloccare troppo il micro.
Potresti ad esempio schedulare un controllo ogni 10 ms e fare una sola lettura dalla EEPROM interna. Verifichi se c'è da attivare l'allarme e poi incrementi un contatore interno in modo che al successivo richiamo del task questo controlli l'elemento successivo. Con 80 check, impieghi 800 ms ad eseguire il controllo su tutti gli elementi dei 2 array, dovresti rientrarci agevolmente. Ho scelto 10 ms perché non so esattamente quanto tempo richieda una lettura dalla EEPROM ma senz'altro meno di una scrittura: una scrittura sulla EEPROM interna è data per 3,3 ms per cui io dico che sicuramente una lettura sta abbondantemente sotto al ms, forse anche di un fattore 10 o superiore.

Altra soluzione è il looper, il mio schedulatore che non usa timer. Metti una chiamata allo schedulatore software alla fine del ciclo principale del tuo codice che faccia ciò che ti ho appena descritto, così non sei costretto ad usare timer o preoccuparti per conflitti vari.

Usi librerie che utilizzano il timer 2?

Non lo so, non credo, se lo fanno a mia insaputa mi incaxxo :smiley: :smiley: :smiley:

Facciamo così, siccome non so di cosa parliamo e a me non piace lavorare su cose che non conosco, mi devo documentare, hai qualche link serio da suggerirmi per farmene almeno un idea

grazie ciao

Intanto il datasheet del microcontrollore, trovi di tutto e di più sui timer. Poi in rete si trovano tante cose, non ultimo puoi sempre leggerti i sorgenti delle mie lib, sono commentate passo passo nei punti che riguardano i timer così capisci come si instaura la gestione di un timer e di un interrupt.

In rete sui timer trovi tanta roba però principalmente riguarda la gestione PWM. Meglio di niente, per iniziare, fa anche quello.

ok grazie, se ho qualche dubbio ti stresserò un po' ]:smiley:

ciao

un chiarimento sulla dichiarazione dell' array non vorrei abusare di quella poca sram che ho

nel file port.ini ho messo queste variabili, in realtà il file sulla SD di arduino lo scrive un javascript

[digital PORT ON timer] 
(portimer_hi150) = 53,54,55,56,57,58 
(portimer_hi151) = 59,60,61,62,63,64
(portimer_hi152) = 65,66,67,68,69,80 
(portimer_hi153) = 81,82,83,84,85,86
(portimer_hi154) = 87,88,89,90,91,92 
(portimer_hi155) = 93,94,95,96,97,98
(portimer_hi156) = 03,04,05,06,07,08 

[digital PORT OFF timer] 
(portimer_lo120) = 11,12,13,14,15,16 
(portimer_lo121) = 17,18,19,20,21,22
(portimer_lo122) = 23,24,25,26,27,28 
(portimer_lo123) = 29,30,31,32,33,44
(portimer_lo124) = 35,36,37,38,39,40 
(portimer_lo125) = 41,42,43,44,45,46
(portimer_lo126) = 47,48,49,50,51,52

nello scketch dichiaro

byte port_on[40][7][6];
byte port_off[40][7][6];

ma poi le vado a leggere partendo negli indici da 0 ottenendo questa uscita

valori porta_on (in byte) 15-0 >> 53 54 55 56 57 58
valori porta_on (in byte) 15-1 >> 59 60 61 62 63 64
valori porta_on (in byte) 15-2 >> 65 66 67 68 69 80
valori porta_on (in byte) 15-3 >> 81 82 83 84 85 86
valori porta_on (in byte) 15-4 >> 87 88 89 90 91 92
valori porta_on (in byte) 15-5 >> 93 94 95 96 97 98
valori porta_on (in byte) 15-6 >> 3 4 5 6 7 8
valori porta_on (in byte) 16-0 >> 0 0 0 0 0 0
.........

valori porta_off (in byte) 12-0 >> 11 12 13 14 15 16
valori porta_off (in byte) 12-1 >> 17 18 19 20 21 22
valori porta_off (in byte) 12-2 >> 23 24 25 26 27 28
valori porta_off (in byte) 12-3 >> 29 30 31 32 33 44
valori porta_off (in byte) 12-4 >> 35 36 37 38 39 40
valori porta_off (in byte) 12-5 >> 41 42 43 44 45 46
valori porta_on (in byte) 12-6 >> 47 48 49 50 51 52
valori porta_off (in byte) 13-0 >> 0 0 0 0 0 0
.....

Non sto dichiarando più celle di quelle che mi servono?

saluti

Il compilatore non esegue controlli sugli indici per cui è tua cura evitare di usare indici al di fuori delle dimensioni del tuo array.
Quindi se tu dichiari a[6]a e poi leggi la cella a[6] in realtà non stai usando un array con 7 elementi ma stai semplicemente leggendo al di fuori dell'array stesso, quindi stai ottenendo dati inconsistenti letti chissà dove nella memoria
Attenzione perciò.

Ricorda sempre: gli indici vanno sempre da 0 a n-1, con n che rappresenta il numero di elementi dell'array come indicato nella dichiarazione dell'array stesso