Eccomi di nuovo qui.
Ho letto il link indicato ed era proprio quello di cui avevo bisogno. Sono riuscito a impostare il testo, però vorrei fare in modo che lampeggi 3 volte (sostituendo un testo fisso) dopodiché ritorna al testo fisso impostato nel void setup.
Al momento non ho il codice sottomano, però ho creato una funzione void per il testo custom che all'occorrenza richiamo nel loop. Senza codice qualcuno riesce a darmi un idea di come farlo lampeggiare? Grazie
ciao
semplicemente puoi alternativamente stampare scrivere e poi cancellare il testo
Si ho pensato anche io a questa semplice soluzione. Però non sono riuscito a farla lampeggiare solo 3 volte ma lo fa di continuo...
Probabilmente avrò sbagliato io qualcosa
Devi contare fino a tre...
Nel senso che devo mettere un contatore e con un if se arriva a tre si ferma? Ho provato ma poiché il testo l'ho inserito in un voip che richiamo nel loop, non sono riuscito ad impostarlo nel contatore
Se non ci fai vedere il tuo codice diventa difficile aiutarti.
Si hai ragione, speravo in un aiuto teorico che poi sarei riuscito a tradurre in codice io purtroppo in questi giorni ho poco tempo per stare al PC e sto scrivendo dal telefono quindi mi è complicato scrivere il codice... Appena riesco riporto il codice... Intanto grazie a tutti
Ecco il codice
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#define I2C_ADDR 0x27
#define BACKLIGHT_PIN 3
#define En_pin 2
#define Rw_pin 1
#define Rs_pin 0
#define D4_pin 4
#define D5_pin 5
#define D6_pin 6
#define D7_pin 7
LiquidCrystal_I2C lcd(I2C_ADDR, En_pin, Rw_pin, Rs_pin, D4_pin, D5_pin, D6_pin, D7_pin);
int x = 0;
byte LT[8] = {
B00111,
B01111,
B11111,
B11111,
B11111,
B11111,
B11111,
B11111
};
byte UB[8] = {
B11111,
B11111,
B11111,
B00000,
B00000,
B00000,
B00000,
B00000
};
byte RT[8] = {
B11100,
B11110,
B11111,
B11111,
B11111,
B11111,
B11111,
B11111
};
byte LL[8] = {
B11111,
B11111,
B11111,
B11111,
B11111,
B11111,
B01111,
B00111
};
byte LB[8] = {
B00000,
B00000,
B00000,
B00000,
B00000,
B11111,
B11111,
B11111
};
byte LR[8] = {
B11111,
B11111,
B11111,
B11111,
B11111,
B11111,
B11110,
B11100
};
byte UMB[8] = {
B11111,
B11111,
B11111,
B00000,
B00000,
B00000,
B11111,
B11111
};
byte LMB[8] = {
B11111,
B00000,
B00000,
B00000,
B00000,
B11111,
B11111,
B11111
};
void setup() {
lcd.begin(16, 2);
lcd.setBacklightPin(BACKLIGHT_PIN, POSITIVE);
lcd.setBacklight(HIGH);
lcd.createChar(8, LT);
lcd.createChar(1, UB);
lcd.createChar(2, RT);
lcd.createChar(3, LL);
lcd.createChar(4, LB);
lcd.createChar(5, LR);
lcd.createChar(6, UMB);
lcd.createChar(7, LMB);
//qui è riportato il testo fisso che al momento ho commentato altrimenti si accavallano
/*lcd.setCursor(0, 0);
lcd.print("Squadra rossa ");
lcd.setCursor(0, 1);
lcd.print("Squadra blu");*/
}
void customG() {
lcd.setCursor(x, 0);
lcd.write(8);
lcd.write(1);
lcd.write(1);
lcd.setCursor(x, 1);
lcd.write(3);
lcd.write(4);
lcd.write(2);
}
void customO() { // uses segments to build the number 0
lcd.setCursor(x, 0);
lcd.write(8);
lcd.write(1);
lcd.write(2);
lcd.setCursor(x, 1);
lcd.write(3);
lcd.write(4);
lcd.write(5);
}
void customA() {
lcd.setCursor(x, 0);
lcd.write(8);
lcd.write(6);
lcd.write(2);
lcd.setCursor(x, 1);
lcd.write(255);
lcd.write(254);
lcd.write(255);
}
void customL() {
lcd.setCursor(x, 0);
lcd.write(255);
lcd.setCursor(x, 1);
lcd.write(255);
lcd.write(4);
lcd.write(4);
}
void loop() {
GOAL();
}
void GOAL() {
lcd.setCursor(x, 0);
lcd.write(8);
lcd.write(1);
lcd.write(1);
lcd.setCursor(x, 1);
lcd.write(3);
lcd.write(4);
lcd.write(2);
lcd.setCursor(4, 0);
lcd.write(8);
lcd.write(1);
lcd.write(2);
lcd.setCursor(4, 1);
lcd.write(3);
lcd.write(4);
lcd.write(5);
lcd.setCursor(8, 0);
lcd.write(8);
lcd.write(6);
lcd.write(2);
lcd.setCursor(8, 1);
lcd.write(255);
lcd.write(254);
lcd.write(255);
lcd.setCursor(12, 0);
lcd.write(255);
lcd.setCursor(12, 1);
lcd.write(255);
lcd.write(4);
lcd.write(4);
}
In pratica non riesco a trovare un modo per far lampeggiare la scritta GOAL dato che nel loop richiamo un void che ho inserito io
ho appena modificato il codice cosi:
void loop() {
GOAL();
}
void GOAL() {
lcd.setCursor(x, 0);
lcd.write(8);
lcd.write(1);
lcd.write(1);
lcd.setCursor(x, 1);
lcd.write(3);
lcd.write(4);
lcd.write(2);
lcd.setCursor(4, 0);
lcd.write(8);
lcd.write(1);
lcd.write(2);
lcd.setCursor(4, 1);
lcd.write(3);
lcd.write(4);
lcd.write(5);
lcd.setCursor(8, 0);
lcd.write(8);
lcd.write(6);
lcd.write(2);
lcd.setCursor(8, 1);
lcd.write(255);
lcd.write(254);
lcd.write(255);
lcd.setCursor(12, 0);
lcd.write(255);
lcd.setCursor(12, 1);
lcd.write(255);
lcd.write(4);
lcd.write(4);
delay (1000);
lcd.clear();
delay(1000);
}
ora lampeggia, ma non riesco a decidere il numero di volte in cui deve lampeggiare nel loop
Beh per prima cosa ho alcune perplessità leggendo il codice.
Intanto mi chiedo quale libreria LCD I2C tu stia usando, perché con l'interfaccia I2C non c'è bisogno di specificare tutti questi pin, visto che la comunicazione avviene tramite pin SDA/SCL (A4/A5):
LiquidCrystal_I2C lcd(I2C_ADDR, En_pin, Rw_pin, Rs_pin, D4_pin, D5_pin, D6_pin, D7_pin);
Purtroppo ci sono svariate librerie con lo stesso identico nome "LiquidCrystal_I2C", ma tu installa una libreria migliore e più aggiornata possibile, quantomeno quella di "fdebrabander" che trovi nelle librerie installabili (non è l'unica "buona" ma puoi iniziare usando questa), e rimuovi questa.
Poi non capisco l'uso della variabile "int x" che è fissa a zero e soprattutto viene usata solo per la prima lettera. Penso che tu voglia in futuro far "scorrere" la scritta, ma allora devi usarla per tutte le lettere (incrementandola e verificando quelle che "escono" dallo schermo che non vanno disegnate).
Poi se hai definito le funzioni "custom*()" per disegnare le lettere, perché non le usi nella funzione "GOAL()"?
Infine ti consiglierei di strutturare un poco il codice, ad esempio invece di una funzione per ogni lettera ne fai una sola, alla quale passi la lettera e lei al suo interno scriverà i caratteri necessari (alla posizione definita da "x" magari).
Vedi questa versione e dimmi se, oltre ad usare la libreria I2C "standard", capisci cosa ho fatto:
#include <LiquidCrystal_I2C.h>
#define I2C_ADDR 0x27
LiquidCrystal_I2C lcd(I2C_ADDR, 16, 2);
int x = 0;
byte LT[8] = {
B00111,
B01111,
B11111,
B11111,
B11111,
B11111,
B11111,
B11111
};
byte UB[8] = {
B11111,
B11111,
B11111,
B00000,
B00000,
B00000,
B00000,
B00000
};
byte RT[8] = {
B11100,
B11110,
B11111,
B11111,
B11111,
B11111,
B11111,
B11111
};
byte LL[8] = {
B11111,
B11111,
B11111,
B11111,
B11111,
B11111,
B01111,
B00111
};
byte LB[8] = {
B00000,
B00000,
B00000,
B00000,
B00000,
B11111,
B11111,
B11111
};
byte LR[8] = {
B11111,
B11111,
B11111,
B11111,
B11111,
B11111,
B11110,
B11100
};
byte UMB[8] = {
B11111,
B11111,
B11111,
B00000,
B00000,
B00000,
B11111,
B11111
};
byte LMB[8] = {
B11111,
B00000,
B00000,
B00000,
B00000,
B11111,
B11111,
B11111
};
void setup() {
lcd.init();
lcd.backlight();
lcd.createChar(8, LT);
lcd.createChar(1, UB);
lcd.createChar(2, RT);
lcd.createChar(3, LL);
lcd.createChar(4, LB);
lcd.createChar(5, LR);
lcd.createChar(6, UMB);
lcd.createChar(7, LMB);
//qui è riportato il testo fisso che al momento ho commentato altrimenti si accavallano
TestoFisso();
punteggio(0, 0);
}
// Simulo l'evento "goal", ma questa variabile verrà impostata
// all'interno del loop()
bool isGoal = true;
void loop() {
delay(1000); // Per ora lascio tempo per far vedere il testo fisso
if(isGoal)
{
for (int n=1; n<=3; ++n)
GOAL();
// Evito che continui a mostrare la scritta
isGoal = false;
// Ripristino il testo fisso
TestoFisso();
// Scrivo il punteggio attuale
punteggio(1, 0);
}
}
void TestoFisso() {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Squadra rossa ");
lcd.setCursor(0, 1);
lcd.print("Squadra blu ");
}
void punteggio(byte rossa, byte blu) {
lcd.setCursor(15, 0);
lcd.print(rossa);
lcd.setCursor(15, 1);
lcd.print(blu);
}
void GOAL() {
scrivi("GOAL");
delay (1000);
lcd.clear();
delay(500);
}
void scrivi(const char* stringa) {
x = 0; // Imposto la posizione iniziale
lcd.clear();
for (int i=0; i<strlen(stringa); ++i)
lettera(stringa[i]);
}
void lettera(char lettera) {
switch (lettera) {
case 'G':
lcd.setCursor(x, 0);
lcd.write(8);
lcd.write(1);
lcd.write(1);
lcd.setCursor(x, 1);
lcd.write(3);
lcd.write(4);
lcd.write(2);
break;
case 'O':
lcd.setCursor(x, 0);
lcd.write(8);
lcd.write(1);
lcd.write(2);
lcd.setCursor(x, 1);
lcd.write(3);
lcd.write(4);
lcd.write(5);
break;
case 'A':
lcd.setCursor(x, 0);
lcd.write(8);
lcd.write(6);
lcd.write(2);
lcd.setCursor(x, 1);
lcd.write(255);
lcd.write(254);
lcd.write(255);
break;
case 'L':
lcd.setCursor(x, 0);
lcd.write(255);
lcd.setCursor(x, 1);
lcd.write(255);
lcd.write(4);
lcd.write(4);
break;
}
x = x + 4;
}
PS: le funzioni chiamale "funzioni", non sono delle "void" perché prima del nome si indica semplicemente il tipo di valore che quella funzione restituisce, e "void" significa "non restituisce alcun valore"... Quindi non "la void loop" ma "la funzione loop()" o "la loop()"
Per finire, quando fai "esperimenti" ti consiglio di farlo usando un simulatore come Wokwi che uso molto anche io stesso, e infatti quel codice lo puoi vedere (e provare) qui:
La libreria LCD I2C che uso è quella per uno schermo LCD cinese che mi trovo a casa e sul quale sto testando il codice.
Per la variabile x, si in effetti mi occorre per altre parti del codice che ancora non ho riportato e ho dimenticato di commentarla.
Wokwi lo uso anche io infatti l'ho prima provato lì e poi riportato su Arduino.
Per quanto riguarda il tuo codice non ho dubbi che ci sia un modo migliore e più semplice per scrivere un codice, quindi appena riesco lo studio con calma e vedo come ottimizzare il tutto (che tra l'altro ancora non è finito in quanto poi dopo aver finito la parte del test dovrò aggiungere 2 sensori ultrasuoni e un cicalino).
Intanto grazie
Ho dato per ora uno sguardo molto rapido al tuo codice.
Per fare lampeggiare il testo "goal" hai usato una variabile booleana e smette di farlo quando diventa "false" (in questo caso 3 volte). Immaginavo che ci volesse qualcosa del genere ma non essendo molto pratico ho avuto qualche difficoltà sul modo in cui scriverla.
Per il resto hai creato funzioni personalizzati che richiami all'occorrenza. Sicuramente un buon metodo però non conosco bene la funzione "switch case" (dovrei studiarla un po') e anche con le stringhe per quanto riguarda la funzione "scrivi" non sono molto pratico.
Appena sto al PC lo provo su wokwi e cerco di capire meglio i dettagli.
Guardandolo bene però non capisco come funziona il punteggio...
Esatto, riuscire a creare funzioni che "fanno qualcosa" in modo autonomo, è un primo passo per una programmazione strutturata, che non riguarda solo la leggibilità (il codice di base risulta più corto e leggibile) ma anche la manutenibilità e debug (se qualcosa non fa quello che serve si può spesso identificare la funzione "responsabile" e quindi concentrarsi solo su quella). Il passo successivo sarebbe la programmazione ad oggetti ma è prematuro, ed in fondo per molte applicazioni di Arduino non sono realmente necessarie (a meno che non si parli di molto codice).
Comodissima quando hai una variabile che in base al suo valore devi fare cose diverse, delimitate dal "case" (che deve sempre finire con "break;").
Il codice:
switch (variabile) {
case '1':
...codice1
break;
case '2':
...codice2
break;
case '3':
...codice3
break;
...eccetera
}
equivale a fare:
if (variabile == '1') {
...codice1
}
else if (variabile == '2') {
...codice2
}
else if (variabile == '3') {
...codice3
}
...eccetera
Come vedi quando ci sono più opzioni diventa una sfilza di "else if(variabile == qualcosa)
" costringendo anche ad aggiungere varie parentesi graffe, per cui la switch risulta più leggibile e semplice.
Nel mio codice non c'è ovviamente alcune gestione del punteggio, ma mi limito a "simulare" un gol richiamando la funzione "punteggio()" per mostrare 1 a 0. Ovviamente nel tuo caso avrai forse delle variabili per memorizzare il punteggio per cui ti basta richiamare la funzione passando quelle variabili invece dei valori costanti 1 e 0 che ho messo io. Ma tutto questo dipende strettamente da com'è fatto (o come sarà fatto, visto che non mi è chiaro se tu abbia già iniziato a scriverlo) il codice "vero".
PS: comunque quando vuoi affrontare un problema completamente diverso da quello descritto dall'oggetto del topic, anche se riferito allo stesso progetto, meglio aprire una discussione separata.
Non so se qualche moderatore (Guglielmo @gpb01 lo puoi fare tu?) possa "dividere" questo thread per spostare tutti i post dal #13 in poi in un nuovo argomento, con nuovo oggetto...
FATTO !
Guglielmo
Per quanto riguarda le funzioni personalizzate da richiamare provo ad ottimizzare il codice in questo modo.
Per lo "switch case" lo hai spiegato molto bene ed effettivamente è molto piu pratico dell' "if- else if" (tendenzialmente uso sempre quest'ultimo) anche se però nel tuo codice non ho capito perfettamente come funziona visto che tu hai inserito 4 case (le 4 lettere) e vengono scritte tutte e 4 sul display.
Per il punteggio, ho solo cominciato a bozzare il codice e utilizzo un contatore che incrementa ad ogni attivazione del sensore ultrasuoni, e credo di riuscirci sentirà troppi intoppi...
In definitiva l'unica cosa si cui ho ancora qualcosa da capire del tuo codice sono le funzioni "scrivi" e "lettera", nel senso che ho capito come sono legate tra di loro ma mi sfugge ancora qualcosina nella sintassi o nella variabile (se è una variabile) "char".
Perché se vedi bene il codice, quella funzione viene richiamata 4 volte, una per ogni lettera da scrivere. Temo che ti manchino comunque alcune basi di programmazione, nonostante vedo che hai già scritto vari messaggi per vari argomenti. Ti consiglierei di leggere qualche libro introduttivo e/o seguire qualche videocorso su YouTube, perché cercare di "imparare sul campo" chiedendo o applicando "cose nuove" va bene, ma da un lato richiede molto più tempo per salire di livello, dall'altro rischi di avere sempre "visioni parziali" ossia non comprendere appieno il significato di certe cose perché ti limiti ad usarle.
In una definizione di funzione quelli indicati tra parentesi sono dei parametri da passare alla funzione, e sono preceduti dal tipo di dato.
Ad esempio in:
void punteggio(byte rossa, byte blu) {
il primo "void" indica che la funzione "punteggio" non restituisce alcun valore (per cui per tornare basta un "return;"), poi "byte" è il tipo di dato ossia un singolo byte con valori tra 0 e 255 seguito dal nome del parametro (che all'interno della funzione tu vedi come una variabile).
Invece in:
void scrivi(const char* stringa)
è sempre una funzione senza valori di ritorno ("void") ma "const" indica che quel valore è costante ossia la funzione non può modificarlo. Per il tipo di dato quella è una "stringa" o, per la precisione, un "puntatore a carattere" che in linguaggio C indichiamo appunto come "stringa C". Provo ora a spiegarti ma moolto brevemente, e, come dicevo, questi sono concetti abbastanza di base in linguaggio C ed è meglio se li approfondisci su qualche libro o tutorial, mi raccomando.
"char" significa generalmente che il dato è composto da un carattere, ma in questo caso "char*" con l'asterisco indica che si tratta di un "puntatore a caratteri" (poi ti spiego, sempre in breve, cos'è un "puntatore"), ossia quella che viene chiamata "stringa", una sequenza di caratteri terminata con un byte a zero.
Quindi ad esempio la stringa "CIAO" viene rappresentata in memoria da una sequenza di caratteri così (ogni riga qui indica un byte, per il quale ti indico sia il valore decimale sia il corrispondente carattere):
67 'C'
73 'I'
65 'A'
79 'O'
0 '\0'
Quando il programma deve leggere la stringa parte dal primo carattere e procede fino a che non trova il byte 0 (rappresentato come carattere '\0').
Come fa il programma a sapere quale sia il primo carattere? Ecco, qui usa il "puntatore" che è una variabile che contiene l'indirizzo in memoria della stringa "CIAO". A te quando programmi non interessa conoscere il valore del puntatore, ci pensa il compilatore. In realtà la variabile (parametro) "stringa", ossia "char* stringa", è un puntatore e contiene il valore numerico dell'indirizzo del primo carattere della stringa.
La gestione delle "stringhe C" è forse la cosa che più fa confondere chi inizia a programmare, ma ti assicuro che se non cerchi di studiare un poco questi aspetti invece di pretendere di usarli senza prima averli capiti diventa per te difficile e fonte di mal di testa.
Ok, facci sapere.
Ok grazie mille per la spiegazione...
Approfondirò questi argomenti per imparare sempre di più.
Dopo il discorso dell LCD sono passato alla parte dei sensori ad ultrasuoni. Anche se a me non occorre misurare la distanza ma solo attivare il sensore al passaggio della pallina, per testarli ho preso ad esempio uno dei tanti sketch che si trovano in rete. Il sensore pur tenendolo fermo su un piano rileva distanze diverse ad ogni misurazione. Pensando che possa essere un difetto del sensore ne ho provati altri e tutti fanno la stessa cosa... Premetto che ho preso sensori economici su AliExpress, anche se fino ad oggi tutto quello che ho preso ha sempre funzionato bene, ma è possibile che su 3 sensori diversi siano tutti difettosi? Non è che per caso per il primo utilizzo si deve calibrare in un qualche modo specifico?
Cambiando argomento conviene aprire una nuova discussione...
Che sensori hai preso? Se hai preso roba molto economica può essere che siano tutti farlocchi... se poi hai preso i classici hc-sr04 allora ti avvicini alla certezza...
Giusto per fare un tentativo puoi provare con una media di diverse letture, magari migliora qualcosa.