usare le matrici e contare tempo usando millis() invece di delay

Ciao,
pin piano imparo e sono nuovamente qui con il mio secondo programma, il codice è questo:

/*questo programma usa un encoder rotativo per selezionare una voce di menù, e alla pressione del pulsante
   invia ad un modulo DDS un set di frequenze a seconda del programma scelto*/
#include <PString.h>
#include <LiquidCrystal.h>
#include <DDS.h>           /* descrizione: http://m0xpd.blogspot.com/2014/03/dds-and-duedds-libraries.html
                              download:    https://github.com/m0xpd/DDS */

const int rs = 14, e = 15, d4 = 16, d5 = 17, d6 = 18, d7 = 19;   // costanti pin per display LCD

const int W_CLK = 8, FQ_UD = 9, DATA = 10, RESET = 11;           // costanti pin per modulo DDS

LiquidCrystal lcd(rs, e, d4, d5, d6, d7);                        // assegno i pin al display LCD

DDS dds(W_CLK, FQ_UD, DATA, RESET);                              // assegno i pin al modulo DDS

char FreqN[] = Freq;
char* Menu[] = {"", "Torino          ", "Genova          ", "Milano          ", "Reggio Emilia   ", "Perugia         ",
                "Campobasso      ", "Venezia         ", "Treviso         ", "Napoli          ", "Firenze         ", "Tortona       ",
                "Mantova         ", "Cervinia        ", "Vigevano        ", "Arezzo          ", "Avellino        ", "Bari            ",
                "Cuneo           ", "Imperia         ", "Bardonecchia    ", "Giussano        ", "Rimini          ", "Lugo di Ravenna ",
                "Pietra Ligure   ", "Bologna         ", "Reggio Calabria ", "Cosenza         ", "Matera          ", "Pescara         ",
                "Macerata        ", "Casteggio       ", "Domodossola     "
               };

unsigned int   Freq1[] = {732, 1633, 1834, 2222, 786, 768, 523, 333, 705, 2823, 0};
unsigned int   Freq2[] = {1522, 718, 717, 713, 972, 664, 643, 420, 8656, 773, 0};
unsigned int   Freq3[] = {7849, 1730, 1552, 1320, 1244, 957, 832, 776, 634, 327, 0};
unsigned long  Freq4[] = {287295, 16628, 18471, 18670, 19566, 1407, 827, 919, 929, 974, 0};
unsigned long  Freq5[] = {30, 250, 450, 950, 6150, 22500, 30280, 51330, 77500, 313350, 0};
unsigned int   Freq6[] = {621, 762, 769, 770, 1550, 802, 832, 966, 12312, 19421, 0};
unsigned long  Freq7[] = {387, 635, 673, 897, 11281, 18022, 107410, 176210, 361000, 394200, 0};
unsigned int   Freq8[] = {8697, 7270, 1050, 943, 824, 787, 745,  647, 555, 478, 0};
unsigned int   Freq9[] = {377, 471, 626, 628, 634, 714, 724, 744, 2162, 7867, 0};
unsigned long  Freq10[] = {794, 832, 1023, 16728, 20562, 55710, 85000, 187500, 442500, 696500, 0};
unsigned long  Freq11[] = {150, 5500, 12850, 35160, 93500, 269710, 426900, 822000, 766777, 937410, 0};
unsigned long  Freq12[] = {152, 442, 8146, 751, 1146, 797, 1011, 20313, 571000, 2596255, 0};
unsigned long  Freq13[] = {750, 800, 1006, 5170, 17500, 20213, 67500, 222530, 225910, 454370, 0};
unsigned int   Freq14[] = {422, 733, 827, 1043, 1048, 4412, 13154, 13218, 13290, 21059, 0};
unsigned int   Freq15[] = {332 , 380, 698, 722, 752, 776, 942, 1113, 3212, 4412, 0};
unsigned long  Freq16[] = {681, 900, 1061, 2500, 13930, 21308, 204510, 331300, 337300, 424280, 0};
unsigned long  Freq17[] = {370, 950, 2750, 3000, 72500, 96500, 375430, 175440, 375910, 598220, 0};
unsigned long  Freq18[] = {680, 900, 1063, 2500, 5500, 13930, 122500, 322600, 425750, 428750, 0};
unsigned int   Freq19[] = {523, 786, 854, 1093, 1144, 1360, 3032, 5122, 5522, 14421, 0};
unsigned long  Freq20[] = {680, 900, 2500, 5500, 13930, 93500, 126070, 210500, 447000, 519340, 0};
unsigned int   Freq21[] = {1044, 1059, 1067, 13163, 13243, 13281, 13343, 13456, 21159, 62500, 0};
unsigned long  Freq22[] = {680, 900, 2500, 5500, 13930, 93500, 386400, 437350, 442100, 526070, 0};
unsigned int   Freq23[] = {187, 453, 523, 662, 843, 854, 1223, 1360, 3032, 5522, 0};
unsigned int   Freq24[] = {453, 523, 623, 854, 1223, 1360, 3032, 5522, 13906, 15035, 0};
unsigned long  Freq25[] = {1122, 1170, 7500, 14153, 18210, 145500, 407500, 712500, 827500, 921060, 0};
unsigned int   Freq26[] = {633, 803, 808, 853, 16180, 16230, 20269, 20312, 20336, 20375, 0};
unsigned int   Freq27[] = {412, 543, 727, 1016, 1550, 2222, 8146, 11092, 11310, 11742, 0};
unsigned long  Freq28[] = {280, 750, 810, 980, 107410, 128310, 176210, 517100, 609420, 717210, 0};
unsigned int   Freq29[] = {343, 530, 686, 756, 761, 834, 530, 686, 756, 761, 0};
unsigned int   Freq30[] = {180, 190, 750, 9000, 11090, 22500, 47500, 115700, 377910, 47012, 0};
unsigned int   Freq31[] = {867, 1043, 1085, 21807, 867, 1043, 1085, 21807, 1043, 1085, 0};
unsigned int   Freq32[] = {424, 555, 647, 727, 745, 824, 999, 1050, 7270, 8697, 0};

int ciclo = 0;                         // setta a 0 la variabile del ciclo per eseguire i programmi del menu
int Freq;                              // variabile di settaggio frequenza
int encoder = 1;                       // posizione di start dell'encoder
bool letturaPrec = HIGH;               // Variabile lettura encoder
unsigned long startTime = millis();    // Variabile inizio conteggio
unsigned long contTempo = millis();    // Variabile tempo trascorso

void setup() {
  pinMode (4, INPUT_PULLUP);     // pin CLK encoder
  pinMode (5, INPUT_PULLUP);     // pin DT encoder
  pinMode (6, INPUT_PULLUP);     // pin pulsante encoder
  lcd.begin(16, 2);              // inizializza LCD
  dds.init();                    // inizializza modulo DDS
  dds.trim(125000000);           /* opzionale per la taratura fine della frequenza dell'oscillatore
                                    rispetto alla reale frequenza del quarzo. Esempio: (125000017) */

  Serial.begin(9600);
}

void loop() {
  if (digitalRead(6) == HIGH) {
    byte n = digitalRead(4);                  // assegna alla variabile "n" il livello letto dal pin CLK dell'encoder
    if ((letturaPrec == HIGH) && (n == LOW))  // rileva rotazione dell'encoder (fronte discesa CLK)
    {
      if (digitalRead(5) == HIGH) {           // se il pin DT è alto direzione decremento
        encoder--;                            // decrementa il valore di encoder
        if (encoder == 0) encoder = 32;       // decrementa circolarmente da 32 a 1

      } else {

        encoder = (encoder % 32) + 1;         // incrementa circolarmente da 1 a 32
      }

    }
    letturaPrec = n;

    if (digitalRead(6) == HIGH)               //se il pulsante non è premuto

      lcd.setCursor(0, 0);
    lcd.print(Menu[encoder]);

    while (digitalRead(4) == HIGH && digitalRead(5) == HIGH && digitalRead(6) == HIGH );
  }
  if (digitalRead(6) == LOW) {                 //se il pulsante viene premuto

    char buffer[7];
    PString str(buffer, sizeof(buffer));
    str = "Freq";                              // assegnazione del prefisso della variabile
    str += (encoder);                          // concatenamento con la variabile "encoder"


  }
}

grazie alle pazienti spiegazioni di Savoriano e Claudio_FF ho compreso e usato lo switch...Grazie Ragazzi! :slight_smile:
...ora il programma così com'è funziona, ma ho 4 problemi da risolvere:

  1. siccome questo è solo un test quindi le voci di menù saranno molte di più di 4 e le frequenze dei vari programmi molte di più di 2, mi chiedevo se ci fosse una maniera di creare una funzione che richiami la scrittura su lcd sia per la selezione dei programmi che per il cambio di frequenze, invece di ripetere i comandi una infinità di volte.
    2)Invece di scrivere una frequenza alla volta, dato che saranno diverse per ogni programma in numero ed in frequenze, se ci fosse un modo di scriverle in una matrice per ognuno dei programmi e richiamarle in sequenza.
  2. Invece di usare il delay fra una frequenza e l'altra vorrei usare il millis(), ma nonostante abbia provato in vari modi non riesco a farlo funzionare, e questo mi porta al 4 problema, vorrei se avessi sbagliato a selezionare o volessi cambiare il programma, poterlo interrompere attraverso la pressione del pulsante dell'encoder o un pulsante esterno, e il delay ovviamente non me lo permette.
    ringrazio in anticipo a chi vorrà darmi una mano

2)Invece di scrivere una frequenza alla volta, dato che saranno diverse per ogni programma in numero ed in frequenze, se ci fosse un modo di scriverle in una matrice per ognuno dei programmi e richiamarle in sequenza.

Si, una matrice a 2 dimensioni

int cicli[nrCicli] [nrFrequenze]

Se in un ciclo ci sono meno frequenze lo riempi di 0 e agirai di conseguenza nel tuo programma.

  1. Invece di usare il delay fra una frequenza e l'altra vorrei usare il millis(),

La frequenza deve cambiare sempre dopo 10sc?

Ho fatto questo in 5mn senza testarlo, quindi avrà sicuramente dei problemi ma l'idea potrebbe essere questa:

 bool bStart = false;
  int frequenza;
  if (digitalRead(6) == LOW)               //se il pulsante viene premuto
  {
    bStart = true;
    lcd.setCursor(0, 1);
    lcd.print("RUN         Hz");
    frequenza = 0;
    startTime = millis();
  }
  
  bool bPrintLCD = true;
  while(bStart)
  {
    if (bPrintLCD)
    {
      lcd.setCursor(5, 1);
      lcd.print(cicli[ciclo][frequenza]);
      dds.setFrequency(cicli[ciclo][frequenza]);              //invio la prima frequenza al DDS
      bPrintLCD = false;
    }
    if (digitalRead(6) == LOW) bStart = false;
    if (millis() - 10000 > startTime)
    {
      frequenza++;
      startTime = millis();
      bPrintLCD = true;
      if (cicli[ciclo][frequenza] == 0)    // un ciclo deve finire con una frequenza 0
        bStart = false;
    }    
  }
    
}

Grazie mille Savoriano, per la risposta, ho capito quello che hai scritto eccetto

lcd.print(cicli[ciclo][frequenza]);

Ho guardato e letto decine di tutorial sulle matrici, ma nessuno mi ha chiarito le idee,
su come dovrei fare.

Nel frattempo ho editato il codice iniziale con le modifiche che ho effettuato,
ho scritto per bene le 32 (fittizie) voci di menù e i relativi array con 10 frequenze ognuno,
che terminano con una undicesima frequenza pari a 0 come intelligentemente hai suggerito.

Ho fatto a meno della tiritera dello switch per stampare la prima riga e scorrere il menù.

...ora... per la seconda parte, come faccio, visto che gli array hanno tutti lo stesso prefisso "Freq" e un numero crescente che corrisponde alla variabile "encoder", a combinare i due elementi per ottenere Freq1..... Freq32 per richiamare gli array? [RISOLTO] con la libreria PString

#include <PString.h>

int encoder = 25;

void setup() {
  
Serial.begin(9600);
}
void loop() {
  
char buffer[7];
PString str(buffer, sizeof(buffer));
str = "Freq"; // assignment
str +=(encoder); // concatenation
{
  Serial.println(str);
}
}

Come risultato stampa Freq25.....

Una volta selezionato l'array corrispondente come li estraggo e li stampo?
E qui ritorno al fatto che non ho capito la riga di codice sopra perché il resto tu mi hai scritto come farlo.
Perdonami, ho 63 anni e ci metto un po' a digerire le cose ;D in particolare gli esempi standard con mille parentesi, invece con un piccolo esempio pratico mi è molto più facile.

+1 per la precisione e la correttezza con cui scrivi. Non bisogna sforzarsi per cercare di capire. Grazie! :slight_smile:

unsigned int   cicli[] [] = {732, 1633, 1834, 2222, 786, 768, 523, 333, 705, 2823, 0};
                                {1522, 718, 717, 713, 972, 664, 643, 420, 8656, 773, 0};
                                {7849, 1730, 1552, 1320, 1244, 957, 832, 776, 634, 327, 0};
                                {287295, 16628, 18471, 18670, 19566, 1407, 827, 919, 929, 974, 0};
..............

Ho guardato e letto decine di tutorial sulle matrici,

Questo mi sembra buono

+1 per la precisione e la correttezza con cui scrivi. Non bisogna sforzarsi per cercare di capire. Grazie!

Vero!
Beato lui, io faccio sempre una fatica!!! :confused:

oxyjo:
come faccio, visto che gli array hanno tutti lo stesso prefisso "Freq" e un numero crescente che corrisponde alla variabile "encoder", a combinare i due elementi per ottenere Freq1..... Freq32 per richiamare gli array?[RISOLTO] con la libreria PString

Hai usato PString solo per concatenare due stringhe da stampare sulla seriale passando attraverso un buffer? Si otteneva lo stesso risultato con due semplici Serial.print

Serial.print("Freq");
Serial.println(encoder);

Che comunque non c'entra con il richiamo degli array (le righe della matrice), e qui veniamo al dubbio successivo che non ho ben compreso qual è:

cicli[riga][colonna]

'cicli' è la matrice (che tecnicamente è un array di array tutti lunghi uguali)
La riga (il singolo array) lo scegli col primo indice.
La colonna (l'elemento all'interno dell'array) lo scegli col secondo indice.

@Datman, Grazie :slight_smile: cerco di fare il possibile, visto che sto chiedendo aiuto e non mi pare bello che qualcuno debba perdere del tempo per cercare di capire cosa scrivo. Inoltre serve molto a me perché programmando da poco tempo, da una volta all'altra devo andare a vedere e capire cosa ho scritto.

@Savoriano, grazie per la risposta, alla fine avevo scritto diversi array, perché alcune righe di frequenze superavano il valore di" unsigned int" e quindi diventavano "unsigned long", proverò a farne una unica
tutta con "unsigned long".

@Claudio_FF, la stampa sulla seriale mi è servita solo di esempio, lo scopo era di creare una variabile unendo il prefisso Freq con il valore dell'encoder, per andare a richiamare la riga di frequenze corrispondente al menù visto che il suffisso è la variabile "encoder", non certo per stamparla sulla seriale. :slight_smile:

La cosa che mi riesce difficile, è capire, una volta che so quale riga devo andare a leggere, come tirare fuori i valori intervallati di tre minuti per passarli tutti e 10 al DDS fino a fine riga, che finisce con uno 0 (come suggerito da Savoriano), per avere il modo di uscire dal ciclo.

Comunque ora cercherò di comprendere bene quello che mi avete scritto, per capire come fare.
Grazie molte. :slight_smile:

lo scopo era di creare una variabile unendo il prefisso Freq con il valore dell'encoder, per andare a richiamare la riga di frequenze corrispondente al menù

Purtroppo questo non è possibile.

Purtroppo questo non è possibile.

ma l'esempio che ho scritto fa esattamente questa cosa....
vuoi dire che non è valida oppure non è utilizzabile?

Vuol dire che probabilmente stiamo parlando/pensando a cose diverse :grin:

La cosa che mi riesce difficile, è capire, una volta che so quale riga devo andare a leggere, come tirare fuori i valori intervallati di tre minuti per passarli tutti e 10 al DDS fino a fine riga, che finisce con uno 0 (come suggerito da Savoriano), per avere il modo di uscire dal ciclo

C'è una via maestra che risolve tutti questi problemi, è un modo di ragionare e impostare le cose: la programmazione a stati.

Si riassume nello strutturare tutto il programma sotto forma di domande (quindi if), queste domande sono molto simili al ragionamento umano, si tratta solo di formalizzare ogni funzionamento desiderato in questa forma:

  • in che stato sono?
  • in questo stato che eventi mi interessa riconoscere?
  • quando riconosco un evento cosa devo fare (compreso entrare in un nuovo stato)?

Lo stato corrente può essere rappresentato dal valore di una semplice variabile.

Uno stato di attesa temporale diventa un semplice if che controlla rapidamente se è trascorso un certo tempo, e se non lo è prosegue oltre senza bloccare niente. Quindi con questa struttura un ritardo non è un arresto dell'esecuzione per un certo tempo, ma la permanenza in un certo stato per un certo numero di cicli di loop.

In uno stato di attesa come questo, ad ogni ciclo di loop si possono controllare N possibili eventi oltre lo scadere del tempo, comprese azioni su pulsanti ecc.

La forma più comoda per scrivere gli stati è una struttura switch controllata dalla variabile di stato (mi sembra di ricordare che ne avevamo già parlato... avevo anche allegato dei disegni), è un discorso che non riguarda lo specifico problema da risolvere, ma un modo/metodo generale per risolvere nel modo più semplice qualsiasi problema.

C'è una via maestra che risolve tutti questi problemi, è un modo di ragionare e impostare le cose: programmazione a stati.

Mi sembra di capire che il suo problema è leggere un array chiamandolo per mezzo del contenuto di una stringa.
Si è creato una stringa che contiene "Freq25" e vuole quindi andare a leggere l'array "Freq25".
Questa cosa non è possibile in modo "diretto" ma bisogna utilizzare una serie di if per confrontare questa string

if (str == "Freq25")
{
dds.setFrequency(Freq25[x]);

In questo modo ritorni al punto di partenza, anzi, peggiori la situazione.

Vuol dire che probabilmente stiamo parlando/pensando a cose diverse

Ho paura che sia questo il problema!