lcd che si blocca[Risolto]

Ciao a tutti,dopo tanto tempo finalmente torno a giocare ma ho incontrato subito un problema,l'LCD si blocca e non riesco a risolvere il problema.. ]:smiley:
Lo sketch in allegato l'ho preso in rete

#include <LiquidCrystal.h>
#include <TimerOne.h>

// buttons code 
#define btnRIGHT  0
#define btnUP     1
#define btnDOWN   2
#define btnLEFT   3
#define btnSELECT 4
#define btnNONE   5

// directions
#define FORWARD   HIGH
#define BACKWARD  LOW

// debounce time (milliseconds)
#define DEBOUNCE_TIME  200

// PINs for Pololu controller
#define PIN_STEP  2
#define PIN_DIR   3

// lookup table speed - ticks (interrupts)
const int speed_ticks[] = {-1, 600, 300, 200, 150, 120, 100, 86, 75, 67, 60, 55, 50, 46, 43};

// global variables
LiquidCrystal lcd(8, 9, 4, 5, 6, 7); //rs,enable,D4,D5,D6,D7

int actual_speed;
int actual_direction;

int ticks;
int tick_count;

int button;
boolean debounce;
int previous_time;

// custom LCD square symbol for progress bar
byte square_symbol[8] = {
  B11111,
  B11111,
  B11111,
  B11111,
  B11111,
  B11111,
  B11111,
};

// string constants
char forward_arrow[] = "-->";
char backward_arrow[] = "<--";

void setup() {

  // init the timer1, interrupt every 0.1ms
  Timer1.initialize(100);
  Timer1.attachInterrupt(timerIsr);
  
  // init LCD and custom symbol  
  lcd.begin(20, 4);
  lcd.setCursor(0,0);
  lcd.createChar(0, square_symbol);
  
  // pins direction
  pinMode(PIN_STEP, OUTPUT);
  pinMode(PIN_DIR, OUTPUT);
  
  // initial values
  actual_speed = 0;
  actual_direction = FORWARD;
  tick_count = 0;
  ticks = -1;
  debounce = false;

  digitalWrite(PIN_DIR, actual_direction);  
  updateLCD();
}
  
void loop() {
  
  // check if debounce active
  if(debounce) {
    button = btnNONE;
    if(millis() > previous_time + DEBOUNCE_TIME) debounce = false;
  } else button = read_buttons();
  
  // if a button is pressed, start debounce time
  if(button != btnNONE) {
    
    previous_time = millis();
    debounce = true;  
  }
    
  // check which button was pressed
  switch(button) {
    
    case btnUP:
      increase_speed();
      break;
    case btnDOWN:
      decrease_speed();
      break;
    case btnLEFT:
      change_direction(BACKWARD);
      break;
    case btnRIGHT:
      change_direction(FORWARD);
      break;
    case btnSELECT:
      emergency_stop();
      break;
  }
  
  // finally update the LCD
  updateLCD();
}

// increase speed if it's below the max (70)
void increase_speed() {
  
  if(actual_speed < 70) {
    actual_speed += 5;
    tick_count = 0;
    ticks = speed_ticks[actual_speed / 5];
  }
}

// decrease speed if it's above the min (0)
void decrease_speed() {
  
  if(actual_speed > 0) {
    actual_speed -= 5;
    tick_count = 0;
    ticks = speed_ticks[actual_speed / 5];
  }
}

// change direction if needed
void change_direction(int new_direction) {
  
  if(actual_direction != new_direction) {
    actual_direction = new_direction;
    digitalWrite(PIN_DIR, actual_direction);
  }
}

// emergency stop: speed 0
void emergency_stop() {
  actual_speed = 0;
  tick_count = 0;
  ticks = speed_ticks[actual_speed / 5];
}

// update LCD
void updateLCD() {
  
  // print first line:
  // Speed: xxxRPM --> (or <--)
  lcd.setCursor(0,0);
  lcd.print("Speed: ");
  lcd.print(actual_speed);
  lcd.print("RPM ");

  lcd.setCursor(13,0);
  if(actual_direction == FORWARD) lcd.print(forward_arrow);
  else lcd.print(backward_arrow);
  
  // print second line:
  // progress bar [#####         ]
  // 15 speed steps: 0 - 5 - 10 - ... - 70
  lcd.setCursor(0,1);
  lcd.print("[");
  
  for(int i = 1; i <= 14; i++) {
    
    if(actual_speed > (5 * i) - 1) lcd.write(byte(0));
    else lcd.print(" ");
  }
  
  lcd.print("]");
}

// timer1 interrupt function
void timerIsr() {

  if(actual_speed == 0) return;
  
  tick_count++;
  
  if(tick_count == ticks) {  
    
    // make a step
    digitalWrite(PIN_STEP, HIGH);
    digitalWrite(PIN_STEP, LOW);
    
    tick_count = 0;
  }
}

// read buttons connected to a single analog pin
int read_buttons() {
  
 int adc_key_in = analogRead(0);
 
 if (adc_key_in > 1000) return btnNONE;
 if (adc_key_in < 50)   return btnRIGHT;  
 if (adc_key_in < 195)  return btnUP; 
 if (adc_key_in < 380)  return btnDOWN; 
 if (adc_key_in < 555)  return btnLEFT; 
 if (adc_key_in < 790)  return btnSELECT;   
}

E' un comando per motori stepper e dovrebbe visualizzare velocità in RPM ,senso di rotazione ed inoltre la velocità è espressa anche da una barra progressiva.........Funziona tutto ma ,se pigio i pulsanti ripetutamente,dopo un numero preciso di pressioni, si inchioda l'LCD.
Credo sia un problema di memoria del display ma non mi è mai capitato................
Sapete darmi qualche consiglio??
Ciao a tutti.

edit
Non è solo l'LCD che si blocca ma anche il micro

Allora nel frattempo ho decommentato tutto ciò che riguarda l'utilizzo dell'LCD perchè pensavo potesse dipendere da esso ma non ho risolto. Continua ad andare in blocco dopo un tot di pressioni dei pulsanti...
Dando per scontato che il problema sia l'esaurimento della RAM dell'Atmega sto cercando di capire da dove deriva

const int speed_ticks[] = {-1, 600, 300, 200, 150, 120, 100, 86, 75, 67, 60, 55, 50, 46, 43};

e mi domando quanto occupa questa ???

allora il tuo problema è relativo al debounce e ti spiego in modo che tu possa capire
ogni tipo di dato allora un massimo di tot nella ram.
io posso scommettere che il tuo arduino non andrà in blocco dopo un tot di pressioni ma dopo un tot di tempo, per la precisione 33 secondi questo perchè la variabile che hai definito per salvare l'ultima operazione (previous_time) è una int.
in arduino uno le int vengono salvate a 16bit ovvero possono salvare valori da 0 a 65,535. ora millis fa un incremento ogni millisecondo quindi tu avrai che 16bit andranno in overflow (sforano la memoria e si azzerano) dopo 33 secondi ovvero un valore di 33000 che è la metà questo perchè tu non gli hai specificato che quell'int conterrà solo valori positivi (estendendo il tuo blocco quindi a 65 secondi e mezzo).

fortunatamente arduino ci permette di salvare variabili a 32bit, i nomi sono long.
siccome però a noi il solo long non basta gli diciamo che avrà solo valore positivo aggiungendo prima la parolina unsigned.

quindi con una variabile a 32bit "solo positiva" il nostro contatore andrà in overflow a 4,294,967,295 ovvero a 4,294,967 secondi ovvero 1193 ore ovvero ogni 49,7 giorni.
per la precisione 49 giorni, 17 ore, 2 minuti, 47 secondi e 295 millesimi di secondo.

dopodichè non potrai andare oltre perchè anche la funzione millis() ha questo limite, tuttavia potrai implementare un controllo per l'overflow (controlli se il valore precedente di millis era più grande di quello nuovo, condizione possibile solo nell'overflow e conti questo problema)

ricapitolando sostituisci

int previous_time;

con

unsigned long previous_time;

poi implementa un sistema di controllo per l'overflow

P.S.:
hai mai sentito parlare di millennium bug? cerca in google
il millennium bug è dato proprio da questo problema perchè il tempo ad oggi è contanto come i secondi trascorsi dalla mezzanotte di capodanno del 1970

Grazie superlol,mentre mi hai scritto stavo facendo delle prove con il serial monitor e la memory free ed effettivamente non c'erano problemi di ram........
Il discorso della variabile "int previous_time" mi era proprio sfuggito........questo è il copia e incolla :roll_eyes:
Solitamente quando uso la millis uso sempre una unsigned long e se prevedo che il dispositivo debba restare acceso per più di 49 giorni faccio un controllo del valore e se superiore a un tot con una if riazzero il contatore.
Comunque mentre scrivevo sono passati più di 30 secondi circa e tutto ora funziona,GRAZIE :wink:

edit
Grazie dell'ottima spiegazione

@tonid : Ti consiglio di dare una letta a QUESTO articolo di Leo che spiega come usare la millis() e ... un trucco per evitare proprio l'overflow :wink:

Guglielmo

@tonid : Ti consiglio di dare una letta a QUESTO articolo di Leo che spiega come usare la millis() e ... un trucco per evitare proprio l'overflow

Grazie anche a te Guglielmo,conosco bene l'articolo di Leo,non essendo una cima a programmare faccio molta fatica ad interpretare gli sketch scritti da altri,diverso è se li devo scrivere io,faccio molta attenzione alle variabili da scegliere in funzione di ciò che devono contenere proprio perchè molte volte i problemi si possono nascondere dietro queste piccole cose e diventano difficili da individuare per chi non mastica bene :D.
Ciao