PROBLEMI memorizzazione numero inserito con keypad

Salve a tutti sono Claudio e non ho molte esperienze con arduino, è la prima volta che utilizzo questo forum quindi spero di aver fatto le cose per bene.
Io sto cercando di far accendere lo schermo lcd tramite l'attivazione di un pulsante a scorrimento, per farlo ho utilizzato un relè, a quanto pare funziona quindi fin qui è ok.
Il problema stà nel fatto che arduino non fa stampare la scritta "Avviamento..." se i 5V passano per il relè, se viene collegato in modo diretto invece si, sapete aiutarmi?
Sto facendo questo prog. su Tinkercad perchè devo consegnarlo per un esame e non ho soldi da poter spendere. allego la foto dello schema elettrico e vi scrivo qui sotto il codice. Grazie ancora!

#include <LiquidCrystal.h>

LiquidCrystal lcd(12, 11, 5, 4, 3, 2);

void setup() {
  
  pinMode(1, INPUT);
  pinMode(0, OUTPUT);
  lcd.begin(16, 2);
  lcd.print("Avvio...");
  
}

void loop()
{
  if (digitalRead(1) == HIGH) {
    digitalWrite(0, HIGH);
  } else {
    digitalWrite(0, LOW);
  }
  lcd.setCursor(0, 1);
  lcd.print(millis() / 1000);
}
      
      

      

Buongiorno e benvenuto, :slight_smile:
essendo il tuo primo post, nel rispetto del regolamento della sezione Italiana del forum (… punto 13, primo capoverso), ti chiedo cortesemente di presentarti IN QUESTO THREAD (spiegando bene quali conoscenze hai di elettronica e di programmazione ... possibilmente evitando di scrivere solo una riga di saluto) e di leggere con molta attenzione tutto il succitato REGOLAMENTO ... Grazie. :slight_smile:

Guglielmo

P.S.: Ti ricordo che, purtroppo, fino a quando non sarà fatta la presentazione nell’apposito thread, nel rispetto del suddetto regolamento nessuno ti risponderà, quindi ti consiglio di farla al più presto. :wink:

Ho fatto la presentazione come da regolamento, grazie per avermi avvertito !

Scrivi "Avvio" nel setup() e accendi il display nel loop().
Puoi provare a spostare lcd.print("Avvio..."); dopo il digitalWrite() che accende.

Ci fai vedere lo schema che funziona? Quello pubblicato non è congruente
Il codice usato è quello che hai postato? Non dovresti usare i pin 0 e 1, mettine altri due (ad es. 6 e 7).

Ciao,
P.

va bene provvederò a cambiare i pin, grazie!

perfetto, ho fatto alcuni cambiamenti e ora funziona come deve, grazie mille!
avrei un’altra domanda, il compito che mi è stato assegnato, chiede di poter impostare una cifra minima e massima del livello d’acqua che poi andrà controllato tramite un sensore, come faccio a far usare come “impostazione” le cifre che scrivo sull’lcd? ho cercato su internet, ma ci sono risposte troppo vaghe e non precise :frowning:

Prima di usarle, dal momento con non le potrai scrivere con penna e/o matita, come pensi di 'scriverle' sul LCD? Puoi usare un tastierino a 3x4 o 4x4 tasti, puoi usare pulsanti UP, DOWN, PLUS, MINUS, puoi usare potenziometri... Hai un'idea?

Ciao,
P.

pensavo di utilizzare un tastierino 4x4 e di utilizzare l'asterisco come virgola, dato che devo poter impostare i livelli di altezza minima e massima con una precisione del decimo di metro.
La parte Hardware non mi preoccupa, bene o male so come funziona, ma per il Software sto a 0, mi sto arrangiando in questi giorni.

Nel tastierino devi prevedere, oltre all'asterisco (*) come virgola, il cancelletto (#) come terminatore e uno degli altri 4 tasti A, B, C o D per cancellare il numero appena immesso.

Per cominciare ti conviene usare la libreria 'keypad' che trovi qui e cominciare a impratichirti con gli esempi allegati.

Ciao,
P.

Aggiorno la situazione, ho provato il programma da me fatto a parte, e funziona, riesco a scrivere, diciamo che c'ho preso un pochino la mano, però quando lo inserisco nel programma intero non funziona, non mi fa scrivere, è come se ignorasse totalmente l'ultima parte del loop.
Un altro problema che ho riscontrato, è che una volta che io accendo l'lcd con il pulsante, ma una volta che parte il loop, (ovviamente) il programma non controlla piu' lo stato del pulsante, quindi se volessi spengere il tutto a metà loop non sarebbe possibile dato che non lo controlla, consigli su come risolvere anche questo problema?

Comunque vi ringrazio tantissimo per l'aiuto che mi state dando, i professori non vogliono aiutarci e io (come tutta la classe) sto cercando aiuto disperato ovunque, quindi oltre che aiutare me aiutate anche la classe ahaha.

Prova a postare il nuovo codice.

pensavo di averlo già messo ahahaha... eccolo qui `

#include <Keypad.h>
#include <LiquidCrystal.h>

LiquidCrystal lcd(5, 4, 3, 2, A4, A5);


const byte ROWS = 4; 
const byte COLS = 4; 
char keys[ROWS][COLS] = {
  {'1','2','3','A'},
  {'4','5','6','B'},
  {'7','8','9','C'},
  {'*','0','#','D'}
};
byte rowPins[ROWS] = {A0, A1, 11, 10}; 
byte colPins[COLS] = {9, 8, 7, 6}; 
int LCDRow = 0;


Keypad keypad = Keypad( makeKeymap(keys), rowPins, colPins, ROWS, COLS );

void setup() {
  
  pinMode(13, INPUT);
  pinMode(12, OUTPUT);
  Serial.begin(9600);
}

void loop()
  {
  if (digitalRead(13) == HIGH) {
    digitalWrite(12, HIGH);
  } else {
    digitalWrite(12, LOW);
  }
  
                 // fase di avvio programma
                 // avvio lcd
  {
    lcd.begin(16, 2);
    delay(2000);
                //scrivo "avvio..."
    {
      lcd.print("Avvio...");
      delay(5000);
      lcd.clear();

             //scrivo "inserire altezza"
      {
        delay(4000);
        lcd.print("Inserire altezza");
      }
           //sposto il cursore e scrivo "Hmin:"
      {
        lcd.setCursor(0, 1);
        lcd.print("Hmin:");
        delay(3000);
      }      
      {
        char key = keypad.getKey();        
        
        if (key){
          Serial.println(key);
          lcd.setCursor (6, 0);
          lcd.print(key);          
          delay(9000);
        }
      }
    }
  }
}

 

Ho cercato di modificare il tuo codice per acquisire un numero scritto sul display. Il codice compila, ma NON SO SE FUNZIONA. Quindi devi provarlo tu e vedere se fa al caso tuo. Questo è il codice

#include <Keypad.h>
#include <LiquidCrystal.h>
//QUESTE DEFINIZIONI SONO NECESSARIE PER LA LOOP CONSIGLIATA DI ACQUISIZIONE
//NUMERO SU LCD
#define VIRGOLA 0x0A //<CARATTERE_SPECIALE>  ABCD*#
#define FINE_NUMERO 0x0B //<CARATTERE_SPECIALE> ABCD*#

LiquidCrystal lcd(5, 4, 3, 2, A4, A5);


const byte ROWS = 4; 
const byte COLS = 4; 
char keys[ROWS][COLS] = {
  {'1','2','3','A'},
  {'4','5','6','B'},
  {'7','8','9','C'},
  {'*','0','#','D'}
};
byte rowPins[ROWS] = {A0, A1, 11, 10}; 
byte colPins[COLS] = {9, 8, 7, 6}; 
int LCDRow = 0;


Keypad keypad = Keypad( makeKeymap(keys), rowPins, colPins, ROWS, COLS );

void setup() {
  
  pinMode(13, INPUT);
  pinMode(12, OUTPUT);
  Serial.begin(9600);
                 // fase di avvio programma
                 // avvio lcd
  lcd.begin(16, 2);
}

void loop() {
  if (digitalRead(13) == HIGH) {
    digitalWrite(12, HIGH);
  }
  else {
    digitalWrite(12, LOW);
  }
                //scrivo "avvio..."
  lcd.print("Avvio...");
  delay(5000);
  lcd.clear();
                 //scrivo "inserire altezza"
  lcd.print("Inserire altezza");
                 //sposto il cursore e scrivo "Hmin:"
  lcd.setCursor(0, 1);
  lcd.print("Hmin:");
                 //scrivo altezza minima
  //QUI DEVI INSERIRE UNA LOOP DA CUI ESCI QUANDO HAI FINITO DI SCRIVERE IL VALORE DI Hmin
  //PER CAPIRE QUANDO HAI FINITO DEVI PREVEDERE UN CARATTERE (key) SPECIALE (ABCD*#)
  //DI 'FINE_NUMERO'
  //DEVI PREVEDERE UN MODO PER 'CONVERTIRE' UN INTERO COME QUELLO CHE OTTERRAI DALLA
  //TASTIERA IN UN ALTRO FLOAT CON DUE CIFRE DECIMALI. iL MODO PIÙ SEMPLICE È DIVIDERE
  //L'INTERO PER 100 TRASFORMANDOLO IN UN FLOAT.
  //PER FAR QUESTO DEVI IGNORARE IL CARATTERE 'VIRGOLA'
  int hMin = 0;
  char key;
  while (true) {
    key = keypad.waitForKey();
    if (key == VIRGOLA) {
      Serial.println(key);
      lcd.print(key);          
      continue;
    }
    if (key == FINE_NUMERO) break;
    else {
      Serial.println(key);
      lcd.print(key);          
      //QUI DEVI INCREMENTARE UNA VARIABILE hMin INTERA PER IL RESTO DEL PROGRAMMA
      hMin = hMin * 10 + key;
    }
  }
  //QUI SI ESCE CON HmIN CONTENENTE IL VALORE DA DIVIDERE PER 100 E PORRE IN UN FLOAT
  //.  .  . RESTO DEL PROGRAMMA
}

Alcune spiegazioni sono nei commenti.

Ciao,
P.

OK perfetto, ho fatto alcuni controlli e direi che funziona, unica cosa, ho impostato la lettera A e la B come pulsanti per uscire dal loop e confermare ma devo ancora sistemare bene, per il resto va tutto, grazie mille

Sono andato avanti, ho escluso per il momento la parte della tastiera, per poter inserire le 3 elettrovalvole (simulate nella foto da 3 relè) e 1 sensore per misurare il livello del liquido (simulato nella foto dal potenziometro),
facendo questa cosa mi sono ritrovato senza pin, quindi ho cercato di aggiungere un registro a scorrimento (74HC595), ho visto alcuni prog. che lo utilizzavano però facevano tutti accendere una fila di led in una certa sequenza definita da " for(int i = 0; i< 8; i++)",
è da un paio d'ore che cerco di modificare questa cosa ma mi ritrovo sempre con un programma pieno di problemi, sicuramente voi riuscirete ad aiutarmi nuovamente.
Lo scopo del programma è quello di leggere l'input del sensore (potenziometro) e di confrontarlo con un minimo = 30 e massimo=200

-se il sensore rileva il livello dell'acqua sotto il valore 30 allora deve accendersi il relè di
sinistra (uscita 8 del registro)
-se è al di sopra di 200 deve accendersi il relè centrale
-deve accendersi il relè di destra solo se interviene una richiesta esterna (magari un pulsante).

Spero voi possiate farci qualcosa, so di aver chiesto già tanto, ma penso che questo possa essere l'ultimo passo per la conclusione del mio progetto, grazie ancora.

#include <Keypad.h>
#include <LiquidCrystal.h>
#define A 0x0A
#define B 0x0B

LiquidCrystal lcd(5, 4, 3, 2, A4, A5);


const byte ROWS = 4; 
const byte COLS = 4; 
char keys[ROWS][COLS] = {
  {'1','2','3','A'},
  {'4','5','6','B'},
  {'7','8','9','C'},
  {'*','0','#','D'}
};

byte rowPins[ROWS] = {A0, A1, 8, A2}; 
byte colPins[COLS] = {A3, 10, 7, 6}; 
byte leds = 0;


Keypad keypad = Keypad( makeKeymap(keys), rowPins, colPins, ROWS, COLS );

int LCDRow = 0;
int valoremin = 30;
int valroemax = 200;
int tDelay = 500;
int latchPin = 11;      // (11) ST_CP [RCK] on 74HC595
int clockPin = 9;      // (9) SH_CP [SCK] on 74HC595
int dataPin = 12;     // (12) DS [S1] on 74HC595


void updateShiftRegister()
{
   digitalWrite(latchPin, LOW);
   shiftOut(dataPin, clockPin, LSBFIRST, leds); //LSBFIRST starts from the least significant Byte, that corresponds to 8th pinout 
   digitalWrite(latchPin, HIGH);
}
// this second function is to turn them off
void updateShiftRegister2() 
{ 
   digitalWrite(latchPin, HIGH);
   shiftOut(dataPin, clockPin, LSBFIRST, leds); //if we start with MSBFIRST in this function, then it would start from the most significant, that is the 1st pinout.
   digitalWrite(latchPin, LOW);
}


void setup() {
  
  pinMode(clockPin, OUTPUT);
  pinMode(latchPin, OUTPUT);
  pinMode(dataPin, OUTPUT);
 Serial.begin(9600);
}

void loop()
{
  lcd.begin(16, 2);
  delay(2000);
  {
    lcd.print("Avvio...");
    delay(5000);
    lcd.clear();
    {
      delay(4000);
      lcd.print("Inserire altezza");
    }
    {
      lcd.setCursor(0, 1);
      lcd.print("Hmin:");
      delay(3000);
    }
    {
  pinMode(latchPin, OUTPUT);
  pinMode(dataPin, OUTPUT);  
  pinMode(clockPin, OUTPUT);
   Serial.begin(9600);
}
    /*
    void loop() 
    {
    leds = 0;
    updateShiftRegister2(1);
    delay(500);
    for (int i = 0; i < 8; i++)
    {
    bitSet(leds, i);
    updateShiftRegister2(1);
    delay(500);
    }
    leds = 0;
    updateShiftRegister2(0);
    delay(500);
    for (int i = 0; i < 8; i++)
    {
    bitSet(leds, i);
    updateShiftRegister2(0);
    delay(500);
    }
    
    for (int i = 0; i < 8; i++)
    {
    bitSet(leds, i);
    updateShiftRegister2();
    delay(500);
    }
    */
    {
      leds = 0;
      updateShiftRegister();
      for (int i = 0; i < 8; i++)
      {
        delay(tDelay);
        bitSet(leds, i); //bitset sets the byte of each led to on
        updateShiftRegister();   
      } 
      for (int i = 0; i < 8; i++)
      {
        
        bitClear(leds, i); //bitclear sets the byte of each led to off
        updateShiftRegister2();  
        delay(700);
      }
    }
  }
}

//{
//      char key;
//      while (true){
//        key = keypad.waitForKey();
//        if (key == A) {
//          Serial.println(key);
//          lcd.print(key);
//          continue;
//        }
//        if (key == B) break;
//        else {
//          Serial.println(key);
//          lcd.print(key);
//          Hmin = Hmin * 10 + key;
//        }
//      }
//    }
//  }
//}


Non credo che copiando pezzi di codice alla cieca senza sapere cosa stai facendo possa portarti molto lontano.

L'introduzione di un componente come il 74HC595 implica averne capito il funzionamento. Lo so che è difficile, ma è necessario studiarsi il tutorial limitandosi a 'Example 1: One Shift Register' e cercando di capire come funziona il codice associato.
Poi magari anche il datasheet cercando di capire il Timing Diagram di pag 8.

Se non si compiono questi passi, o si trova un esempio ESATTAMENTE calibrato sulle nostre esigenze, oppure farlo funzionare è una botta di...

Vedi cosa non capisci, descrivilo ESATTAMENTE e ti diamo una mano.

Ciao,
P.

va bene ora me lo guardo per bene

ho fatto alcune prove e penso di aver capito il suo funzionamento, cosa più importante, ho capito che non mi serve, infatti mi è bastato rimuovere il pulsante pilotato da arduino e farlo funzionare in modo " diretto"( senza if e altre cose) e spostare il cavo del pin Digitale 11 al pin Analogico A2 che a quanto pare riesce comunque a fare il lavoro del pin 11.
Con questo cambiamento sono riuscito ad avere 3 pin digitali liberi (quelli che cercavo di avere in più dal 74CH595), per poter pilotare i 3 relè che simulano le elettrovalvole.
Dopo aver visto che funziona, quindi, sono tornato a sistemare la parte della tastiera, infatti vorrei fare alcune domande,

in :

#define VIRGOLA 0x0A 
#define FINE_NUMERO 0X0B

"0x0A" e "0x0B" cosa stanno a significare?

in più:

{
      int Hmin = 0;
      char key;
      while (true){
        key = keypad.waitForKey();
        if (key == VIRGOLA) {
          Serial.println(key);
          lcd.print(key);
          continue;
        }
        if (key == FINE_NUMERO) break;
        else {
          Serial.println(key);
          lcd.print(key);
          Hmin = Hmin * 10 + key;
        }

non ho capito la parte del key == VIRGOLA o key == FINE_NUMERO, cioè, key è il tasto e ok, ma essendo VIRGOLA definito come 0x0A ossia 10, a cosa si riferisce?

Rivedendo il codice quelle definizioni sono sbagliate.

Nella gestione della tastiera, quando tu scrivi un numero sul display lcd, questo numero è composto da una serie di cifre. Di più, se il numero è con decimali c'è anche la virgola.
Il pezzo di programma che 'scrive' le cifre le scrive una per volta. La tua tastiera ha le cifre da 0 a 9 più una serie di caratteri speciali: * # A B C D. Quando tu scrivi

  char key;
  key = keypad.waitForKey();

nella variabile key finisce un CARATTERE ASCII che può essere da '0' a '9' o '*' '#' 'A' 'B' 'C' 'D'. Ora tu devi usare uno dei caratteri speciali per far scrivere il CARATTERE ASCII corrispondente alla virgola ',' sul display lcd. Io te ne avevo scelto uno (sbagliando). È il carattere 'A'. Quando dalla tastiera arriva 'A' sul lcd devi scrivere ','. E anche qui avevo sbagliato il programma.
Ma tu devi utilizzare un altro carattere speciale per indicare al programma che hai finito di scrivere il numero, altrimenti come ne esci? Io te ne avevo scelto un altro (sbagliando ancora), È il carattere 'B'. Quando dalla tastiera arriva 'B' significa che l'utente ha finito di scrivere il numero, il programma esce dal ciclo di scrittura e continua.
Ma a mio avviso devi utilizzare un altro carattere speciale per cancellare il carattere che hai inserito e devi scrivere il pezzo di codice che cancella il carattere sul lcd, sposta il cursore indietro di una posizione, controlla che la cancellazione sia lecita, cioè che non ci siano più numeri da cancellare. Contestualmente alla ricezione di ciascun carattere, ed eventualmente alla sua cancellazione, devi prevedere come calcolare il valore in decimale, perché quelli forniti dalla tastiera sono caratteri ASCII.

Sembrava facile scrivere un input da tastiera per scriverlo su un lcd, eh? Anche il codice che ho scritto io nel post #15 è sbagliato.

Per semplicità puoi usare il carattere 'C' per cancellare TUTTO il numero e riscriverlo daccapo.

Questo DOVREBBE ESSERE un codice corretto.

#include <Keypad.h>
#include <LiquidCrystal.h>
//QUESTE DEFINIZIONI SONO NECESSARIE PER LA LOOP CONSIGLIATA DI ACQUISIZIONE
//NUMERO SU LCD
#define VIRGOLA 'A'     //<CARATTERE_SPECIALE> A
#define FINE_NUMERO 'B' //<CARATTERE_SPECIALE> B
#define CANCELLA 'C'    //<CARATTERE_SPECIALE> C

LiquidCrystal lcd(5, 4, 3, 2, A4, A5);


const byte ROWS = 4; 
const byte COLS = 4; 
char keys[ROWS][COLS] = {
  {'1','2','3','A'},
  {'4','5','6','B'},
  {'7','8','9','C'},
  {'*','0','#','D'}
};
byte rowPins[ROWS] = {A0, A1, 11, 10}; 
byte colPins[COLS] = {9, 8, 7, 6}; 
int LCDRow = 0;


Keypad keypad = Keypad( makeKeymap(keys), rowPins, colPins, ROWS, COLS );

void setup() {
  
  pinMode(13, INPUT);
  pinMode(12, OUTPUT);
  Serial.begin(9600);
                 // fase di avvio programma
                 // avvio lcd
  lcd.begin(16, 2);
                 //scrivo "avvio..."
  lcd.print("Avvio...");
  delay(5000);
  lcd.clear();
}

void loop() {
  if (digitalRead(13) == HIGH) {
    digitalWrite(12, HIGH);
  }
  else {
    digitalWrite(12, LOW);
  }
                //scrivo "avvio..."
  lcd.print("Avvio...");
  delay(5000);
  lcd.clear();
                 //scrivo "inserire altezza"
  lcd.print("Inserire altezza");
                 //sposto il cursore e scrivo "Hmin:"
  lcd.setCursor(0, 1);
  lcd.print("Hmin:");
                 //scrivo altezza minima
  //QUI DEVI INSERIRE UNA LOOP DA CUI ESCI QUANDO HAI FINITO DI SCRIVERE IL VALORE DI Hmin
  //PER CAPIRE QUANDO HAI FINITO DEVI PREVEDERE UN CARATTERE (key) SPECIALE (ABCD*#)
  //DI 'FINE_NUMERO'
  //DEVI PREVEDERE UN MODO PER 'CONVERTIRE' UN INTERO COME QUELLO CHE OTTERRAI DALLA
  //TASTIERA IN UN ALTRO FLOAT CON DUE CIFRE DECIMALI. iL MODO PIÙ SEMPLICE È DIVIDERE
  //L'INTERO PER 100 TRASFORMANDOLO IN UN FLOAT.
  //PER FAR QUESTO DEVI IGNORARE IL CARATTERE 'VIRGOLA'
  int hMin = 0;
  char key;
  while (true) {
    key = keypad.waitForKey();
    if (key == VIRGOLA) {
      Serial.println(',');
      lcd.print(',');          
      continue;
    }
    if (key == CANCELLA) {
      Serial.println("Cancellato");
      lcd.setCursor(5, 1);      //POSIZIONA IL CURSORE ALL'INIZIO DEL NUMERO
      lcd.print("           "); //SCRIVI UN NUMERO DI SPAZI PER CANCELLARE
      lcd.setCursor(5, 1);      //RIPOSIZIONA IL CURSORE ALL'INIZIO DEL NUMERO
      continue;
    }
    if (key == FINE_NUMERO) {
      break;
    }
    //key-48 TRASFORMA IL CARATTERE ASCII IN NUMERO DECIMALE
    if (key-48 >= 0 && key-48 <=9) {   //SE È UN NUMERO
      Serial.println(key);
      lcd.print(key);          
      //QUI DEVI INCREMENTARE UNA VARIABILE hMin INTERA PER IL RESTO DEL PROGRAMMA
      hMin = hMin * 10 + (key-48);
    }
  }
  //QUI SI ESCE CON HmIN CONTENENTE IL VALORE DA DIVIDERE PER 100 E PORRE IN UN FLOAT
  //.  .  . RESTO DEL PROGRAMMA
}

Alla fine in hMin tu hai un numero INTERO da trasformare in float con le due ultime cifre come decimali.

Ciao,
P.