Fuse Rescue: delay indispensabile?

Ciao a tutti

Dopo un'ora a fare tentativi assurdi con un codice che sembrava proprio dover funzionare, ho avuto l'ispirazione di mettere un delay e ha funzionato! Prima, rilevava la pressione del pulsante solo ogni tanto, nemmeno una volta su quattro. Qualcuno mi sa spiegare perché il delay risolve il problema? Non sapendo a che altro pensare, l'unica spiegazione era che stato==2 non fosse ancora vera un attimo dopo aver fatto l'assegnazione, perciò ho provato a mettere un delay a caso... E' sufficiente un delayMicroseconds(10). Come è possibile???...

Grazie
Gianluca

#include <LiquidCrystal.h>
LiquidCrystal lcd(17,15,13,12,11,10); 
// LiquidCrystal lcd(0,1,2,3,4,5); // RS,EN,D4,D5,D6,D7

uint32_t t_premuto; // millis() alla pressione del pulsante.
uint8_t prg=0; // Numero del programma selezionato.
uint8_t lfuse;
uint8_t hfuse;
uint8_t xfuse;
uint8_t stato=1;


void setup()  // run once, when the sketch starts
{
pinMode(0, OUTPUT); // LCD RS
pinMode(1, OUTPUT); // LCD EN
pinMode(2, OUTPUT); // LCD D4
pinMode(3, OUTPUT); // LCD D5
pinMode(4, OUTPUT); // LCD D6
pinMode(5, OUTPUT); // LCD D7
pinMode(A1, INPUT_PULLUP);

pinMode(6, INPUT_PULLUP);

lcd.begin(16,2);
lcd.print(F(" Fuse Rescue GG "));
lcd.setCursor(0,1); lcd.print("n.");
lcd.setCursor(5,1); lcd.print("LF");
lcd.setCursor(9,1); lcd.print("HF");
lcd.setCursor(13,1); lcd.print("Ext");
delay(2000);

lcd.clear();
lcd.setCursor(1,1); lcd.print('.');
}


   #define PREMUTO !(PIND&0b01000000) // Pulsante su PD6.

 
void loop()
{
t_premuto=millis(); // Prende il tempo.
while(PREMUTO) // Pressione lunga: programmazione.
  {
  if(millis()-t_premuto>3000)
    {
    lcd.setCursor(0,0); lcd.print(F("*PROGRAMMAZIONE*"));
    programma();
    delay(1000);
    lcd.setCursor(0,0); lcd.print(F(" *** FATTO! *** "));
    stato=0;
    return;
    }
  }

if(stato==1)
  {
  prg++; if(prg>4) prg=1;
  lcd.setCursor(0,1); lcd.print(prg); // Numero progressivo.
  lcd.setCursor(0,0); 
  switch(prg)
    {
    case 1:      
    lcd.print(F("328P 16MHz Bld  "));
    lfuse=0xFF; hfuse=0xFD; xfuse=0xDF;
    display_fuse();
    break;

    case 2:      
    lcd.print(F("328P 16MHz NoBld"));
    lfuse=0xFF; hfuse=0xFD; xfuse=0xDF;
    display_fuse();
    break;
    
    case 3:      
    lcd.print(F("328P  8MHz NoBld"));
    lfuse=0xFF; hfuse=0xFD; xfuse=0xDF;
    display_fuse();
    break;
    
    case 4:      
    lcd.print(F("328P  1MHz NoBld"));
    lfuse=0xFF; hfuse=0xFD; xfuse=0xDF;
    display_fuse();
    break;
    }
  stato=2;
  }
delay(10); // < < < < < < < < < < < DELAY! Qui sono 10ms, ma bastano 10us.
//                                  1us non basta; con 5us comincia a funzionare.
if(stato==2 && !PREMUTO) stato=3; 
if(stato==3 && PREMUTO) stato=1;
}

void display_fuse()
  {
  lcd.setCursor( 5,1); lcd.print(lfuse,HEX);
  lcd.setCursor( 9,1); lcd.print(hfuse,HEX);
  lcd.setCursor(13,1); lcd.print(xfuse,HEX);
  }


void sendcmd(byte command)  // Send command to target AVR.
  {
  }

void writefuse(byte fuse, boolean highbyte)  // write high or low fuse to AVR.
  {
  }

void programma()
  {
  } 

Ma trovi molto "fico" utilizzare sempre accessi diretti alle porte come fai fai tu invece che usare il "framework" Arduino ?

Per me è una grossa stupidaggine che NON ti offre, specie nella maggior parte dei casi, alcun vantaggio se non creare prodotti non "portabili" su altre MCU e rischiare problemi ... se nel "core", per le varie digitalRead(), digitalWrite(), analogRead(), analogWrite(), ecc. fanno una serie di altre operazioni ... spesso una ragione c'è ... :roll_eyes:

Poi, per me, continua a fare come ti pare ...

Guglielmo

1 Like

Ti stai riferendo all'unico uso che ne faccio nella macro della lettura del pulsante?
Non capisco, però, come possa produrre il difetto che ho riscontrato...

Comunque provo...

Confermo che così accade la stessa cosa:

// #define PREMUTO !(PIND&0b01000000) // Pulsante su PD6.
#define PREMUTO !(digitalRead(6)) // Pulsante su PD6.

Datman, scusa la domanda, ma non ti conveniva proseguire nel tuo precedente thread ossia QUI dove tra l'altro viene spiegato meglio il tutto?

Essendo un problema di esecuzione di un programma generico, in cui tra l'altro ho tolto tutta la parte della programmazione per evitare qualunque interferenza, ho preferito fare una discussione a parte sia per ritrovarla facilmente, sia perché ho modificato il programma per adattarlo all'hardware dello stroboscopio su cui lo sto provando.

Mi riferisco alla pessima abitudine che, in generale e senza un motivo specifico, hai di fare questa cosa, dato che ... non è la prima volta :wink:

Guglielmo

A volte lo faccio per scrivere un byte tutto insieme (cosa che in alcuni casi è addirittura risaputamente indispensabile per evitare condizioni logiche errate), altre volte lo faccio per impegare un decimo del tempo in azioni ripetute ("E' la somma che fa il totale!"), altre ancora perché trovo più comodo vedere tutti i bit di una porta.
Comunque mi sembra un'aggressione immotivata.

:joy: no, no, nessuna aggressione ...
... solo un'indicazione di una cattiva abitudine SE usata indiscriminatamente senza una VERA necessità ... ripeto, spesso le operazioni che fa il "framework" Arduino NON possono essere semplicemente eliminate perché poi possono provocare problemi ... ovvio che più operazioni vengono fatte e più il codice rallenta, ma a volte ... è necessario :roll_eyes:

Guglielmo

Come ho detto, però, con digitalRead fa la stessa cosa... :frowning:

Era un discorso in generale, non del caso specifico :wink:

Guglielmo

Ma quanto sei creativo, tanto. Quindi se tieni premuto il pulsante entri nel while se resta nel while per più di 3s fai delle cose tra cui un delay di 1s e poi restituisci il controllo alla funzione main() la quale chiama la funzione loop().

Io purtroppo con l'indentazione che usi non riesco a seguire il codice con facilità.

Poi se stato==1 stato=2 e poi un giro che come non ti confondi non lo so.
Oddio "non ti confondi", se non ti confondessi il codice si comporterebbe come desideri. Ora non lo so dovresti premere il pulsante in corrispondenza della esecuzione della ultime due if, perché se lo premi in ritardo rientra nel while.

Io preferisco usare la libreria JC_Button, ma ovviamente non devi usare delay e mantenere il tempo di ciclo sotto i 5ms.

Ciao.

Il delay di 1s serve solo per far leggere "PROGRAMMAZIONE", dato che la stessa dura un istante! Ora ho messo un delay anche dopo "FATTO!", dopo il quale torna pronto per programmare un altro microcontrollore nello stesso modo o, premendo il pulsante, in modo diverso.

In realtà il codice funziona benissimo, salvo la necessità di 1ms di delay che, evidentemente, non dipende da una logica errata...

Perché mi dovrei confondere?... Basta leggere il programma passo passo e vedere come si comporta con lo stato corrente: se lo stato è 2 e il pulsante non è premuto, lo stato passa a 3; lo stato ora è 3, ma il pulsante non è premuto, quindi ricomincia e torna lì attendendo la pressione del pulsante. Quando premo il pulsante, con lo stato ancora a 3, lo stato torna a 1 e ricomincia incrementando prg.

Ecco un video del funzionamento:

Si ma da cosa dipende allora, se non è errata la logica perché il delay sarebbe necessario?

Ciao.

Ecco: questo è l'oggetto di questa discussione! :joy:
Come ho scritto, bastano 10us!

Se togli il delay cosa accade?
Ad esempio lo commenti e nel while ci metti un Serial.print('.');

Ciao.

Con

//delay(1);
Serial.print(',');

a 38400 funziona benissimo ugualmente.
Funziona benissimo anche con un semplice Serial.print("");
Ciao.

P.s.: Non è nel while, ma tra l'assegnazione dello stato nell'if e, dopo l'if, lo if(stato==2):
if(stato==2 && !PREMUTO) stato=3;

Come prevedevo, scrivendo così va un po' meglio:

if(!PREMUTO && stato==2) stato=3; 
if(PREMUTO && stato==3) stato=1;

ma non è sufficiente per un funzionamento perfetto.

Incredibile a me rimbalza il pulsante al simulatore come è mai possibile che con l'hardware non noti questo rimbalzo.

Poi selezionato il programma devo comunque premere e avanza prog che adesso non è quello che avevo selezionato.

while (PREMUTO) // Pressione lunga: programmazione.
  {
    Serial.print('.');
    if (millis() - t_premuto > 3000)

Anche quando premo una sola volta, entra e rimane nel while e infatti stampa centinaio di .

Insomma dire che la logica è corretta è ottimistico. :smiley:

Io che sono ottimista vedo che fa acqua da tutte le parti. :laughing:

Ciao.

In parallelo al pulsante c'è un condensatore da 100nF! Prevenire è meglio che curare... :slight_smile:
"Garbage in, garbage out"!
Che con il condensatore funziona perfettamente si vede nel video al #13...

Ciao.