contaimpulsi x contakm parziale

Ciao a tutti,

dunque ragazzi devo aggiungere la funzione di contakm parziale su un lavoro già ultimato. Poichè le tematiche sono tante e i dubbi pure, ho pensato di aprire una discussione ad hoc. Spero di non aver sbagliato.
Entro nel merito: devo aggiungere questa funzione in uno sketch che richiama 4 funzioni tramite switch case. Questa implementazione di fatto diventerà, si spera, il quinto case. Ho pensato di non usare l’interrupt, ma bensì un digital read e qualche if e come hardware un contatto reed. A tal proposito ce la fa a rilevare il passaggio del magnete su uno scooter?
Inoltre poi ho la necessità di memorizzare il dato ogni km, in quanto lo scooter potrebbe essere spento in qualsiasi momento. Che ne pensate della parte di codice che riguarda lettura e memorizzazione?

la sequenza è questa:

accendo lo scooter → richiamo il valore memorizzato la volta precdente → comincio a contare e gli impulsi e a colcare i km percorsi → sommo questi dati a quello memorizzato e stampo il valore così ottenuto → ogni km salvo il dato in memoria

int contattoreed=6;
int contaimpulsi=0;
int contakm_now;
int contakm_prec;
int contakm_mem=0;          // variabile backup
int contakm_trip;      
int circonf_ruota=100;     //circonferenza ruota in cm
byte StatoPulsante=7;
byte StatoPulsantePrecedente;
unsigned long millis_p;

#define BUTTON 13 


void setup() {

Serial.begin(9600); 
pinMode(BUTTON, INPUT);
pinMode(contattoreed, INPUT);

}


void loop() {

  // parte codice x read eeprom contakm_mem;
  contattoreed = digitalread(); 
  StatoPulsante = digitalRead(BUTTON)	 //leggi pulsante
   
  if(contattoreed = HIGH)             
    {
    contaimpulsi ++;                                   // incremento il contaimpulsi ad ogni giro di ruota
    contakm_now = (contaimpulsi x circonf_ruota)/1000; // ottengo la distanza in km
    contakm_trip = contakm_mem + contakm_now;          // il risultato finale è la somma del valore in memoria più quello istantaneo
    Serial.print(contakm_trip);
    contakm_trip = contakm_prec;
    }
  if(contakm_trip - contakm_prec = 1)                  // condizione da verificare per ri-memorizzazione dato in eprom      
    {
    contakm_trip = contakm_mem;
    // parte codice x write eeprom contakm_mem;                       // salvo il dato in quanto potrei spegnere lo scooter in qualsiasi momento
    }

 if ((StatoPulsante != StatoPulsantePrecedente) && (StatoPulsantePrecedente == 0))   // pulsante appena premuto
   {
      StatoPulsantePrecedente = StatoPulsante; 	//setta flag per pulsante premuto
      millis_p = millis();	//setta variabile controllo tempo
   }
   if ((StatoPulsante != StatoPulsantePrecedente) && (StatoPulsantePrecedente == 1))  //pulsante appena rilasciato
   {
      StatoPulsantePrecedente = StatoPulsante; 	//resetta flag per pulsante rilasciato
      if (millis() - millis_prec <= 2000) //pulsante premuto per meno di mezzo secondo
      {
      contakm_trip=0;                             // azzero il trip
      contakm_mem=0;                              // azzero anche la variabile backup                   
   // parte codice x write eeprom contakm_mem;                   // salvo il dato azzerato
      }
 millis_prec=millis;
 }

Ovviamente manca la parte delle eeprom che non so gestire. Avete qualche tutorial da passarmi?

Grazie

Ho pensato di non usare l'interrupt

E hai fatto male. Il sistema che hai adottato, può andare bene se Arduino non sta facendo altro, ma mi pare che tu lo usi anche come contagiri etc. E anche il contagiri è senza Interrupt, perchè mi pare che tu usassi la pulseIn(). Ora, metti che il sensore si attivi mentre il micro è in attesa del segnale dal contagiri ? Succede che ti perdi qualche lettura E' per questo che sia per il contakm che per il contagiri si dovrebbero usare degli interrupt. Oltretutto, per il contakm, visto che vuoi solo la distanza percorsa e non la velocità, la gestione è anche più semplice dato che devi solo memorizzare il numero degli inpulsi e non anche la frequenza degli stessi

Grazie x la risposta Brunello!

Comunque si, ricordi bene, uso la pulseIn per il contagiri. Tornando al contakm, ho escluso l'utilizzo dell'interrupt perchè e correggimi se sbaglio, quest'ultimo è prioritario su tutto. Quindi appena il micro sente una variazione sul pin relativo, anche se sto leggendo i giri del motore, l'esecuzione del programma si blocca. O no? La funzione contakm deve girare in background, e passatemi il termine.

Grazie

... si, è vero che l'interrupt è prioritario, ma considera pure che nel tuo caso TUTTO quello che deve fare è:

contaImpulsi++;

... e null'altro ... parliamo di μSec ;)

Guglielmo

Esatto quello che dice Guglielmo Oltretutto sei tu a dire che

La funzione contakm deve girare in background

const byte interruptPin = 2;
volatile unsigned long inpulsi = 0;

void setup() {
  pinMode(interruptPin, INPUT_PULLUP);
  attachInterrupt(digitalPinToInterrupt(interruptPin), conteggio, CHANGE); // CHANGE / LOW / FALLING
}

void loop() {
  if ( Display mostra km percorsi ) {
    // legge valore su Eeprom
    // lo somma a inpulsi attuali
    // visualizza km percorsi
  }
  // fai quello che vuoi
}

void conteggio() {
  inpulsi ++
}

gpb01: ... si, è vero che l'interrupt è prioritario, ma considera pure che nel tuo caso TUTTO quello che deve fare è:

contaImpulsi++;

... e null'altro ... parliamo di μSec ;)

Guglielmo

Scusa Guglielmo fammi capire bene, mentre al pin 2 o 3 ho il contatto reed che gira sulla ruota, e l'interrupt fa il suo lavoro di contaimpulsi++, lo switch case mi funzionerebbe bene? E nel case in cui staziono di volta in volta il funzionamento è regolare? L'invio di dati seriali all'oled tramite u8glib è garantito?

Grazie

Ricorda che l'interrupt equivale alla chiamata ad una subroutine, quindi ... ... il tuo programma sta facendo qualche cosa, si interrompe, entra nella routine di interrupt, la esegue, e torna esattamente a dove era rimasto ed il programma prosegue.

Per questo ,e ISR debbono essere il più veloci possibili, per interrompere per il tempo più breve possibile il programma che sta girando.

Mi raccomando, un bel "debouncing hardware" sul pin di ingresso dell'interrupt per evitare falsi conteggi ;)

Guglielmo

gpb01: Ricorda che l'interrupt equivale alla chiamata ad una subroutine, quindi ... ... il tuo programma sta facendo qualche cosa, si interrompe, entra nella routine di interrupt, la esegue, e torna esattamente a dove era rimasto ed il programma prosegue.

Per questo ,e ISR debbono essere il più veloci possibili, per interrompere per il tempo più breve possibile il programma che sta girando.

Mi raccomando, un bel "debouncing hardware" sul pin di ingresso dell'interrupt per evitare falsi conteggi ;)

Guglielmo

si blocca solo la prima volta, cioè quando accendo arduino e il reed comincia ad inviare i dati, o si blocca quando il contatore comincia a fare ++.

Inoltre avresti uno schema di come cablare bene il reed in ottica di interrupt?

NON si blocca nulla ! E come se tu, ad un certo punto, chiami una funzione che, nel tuo caso, tutto quello che fa è un incremento di una variabile e null’altro … ovvero poche decine di μSec.

Per il debouncing HW ti allego alcuni schemi …

Guglielmo

debouncing_hw.pdf (22.8 KB)

gpb01: NON si blocca nulla ! E come se tu, ad un certo punto, chiami una funzione che, nel tuo caso, tutto quello che fa è un incremento di una variabile e null'altro ... ovvero poche decine di μSec.

Per il debouncing HW ti allego alcuni schemi ...

Guglielmo

a perfetto, è come x il debouncing de pulsanti che mi ha spiegato Ete l'altro giorno. Ottimo, so farlo!

Guglielmo hai un buon link ad una faq, o altro dove posso imparare come salvare e richiamare un dato nella memoria eprom?

Grazie :)

droidprova:
Guglielmo hai un buon link ad una faq, o altro dove posso imparare come salvare e richiamare un dato nella memoria eprom?

Ti allego un pdf :wink:

Ricorda che ogni cella della EEPROM ha una vita massima garantita di 100’000 scritture, quindi … non scrivere troppo spesso :smiley: :smiley: :smiley:

Guglielmo

EEPROM.pdf (181 KB)

Guglielmo perdonami ma rileggevo ed ho dei dubbi: ma se io sono in un altro case, senza che io abbia mai richiamato la subroutine dell'interrupt attraverso il suo case dedicato, in background il contatore legge ed incrementa lo stesso o è fermo?

Grazie ma vorrei capire bene questo discorso.

Nicola

Tu puoi essere dove ti pare nel tuo programma, quando scatta l'interrupt è la MCU che provvede a salvare il punto in cui eri, eseguire ciò che è nella ISR e tornare a dove stava.

Guglielmo

gpb01: Tu puoi essere dove ti pare nel tuo programma, quando scatta l'interrupt è la MCU che provvede a salvare il punto in cui eri, eseguire ciò che è nella ISR e tornare a dove stava.

Guglielmo

Ok, metto tutto su breadboard e provo il codice per vedere come va. Grazie come sempre!

Usa il PullUp esterno ( non il PullDown ) e metti il reed al GND

Brunello: Usa il PullUp esterno ( non il PullDown ) e metti il reed al GND

l'esempio centrale del pdf che ha allegato Guglielmo, vero?

Ragazzi ho un dubbio: sulla pcb che sto perfezionando, devo effettuare due debouncing, uno per un pulsante e uno per contatto reed. Bene, per entrambi i casi va bene scegliere quello con pull-up esterno verso gnd ( l'esempio centrale del pdf allegato da guglielmo) o c'è un criterio da seguire? In rete e su varie doc. Trovo esempi a random e discordanti.

X Guglielmo: ho consultato il pdf sulle eeprom con lib avr, essendo totalmente in inglese ho dei dubbi. Conosci degli esempi pratici in italiano?

Inoltre con l'avr riesco a memorizzare variabili float maggiori di 1024?

Grazie mille

droidprova: Conosci degli esempi pratici in italiano?

... scherzi a parte, la vedo dura ::)

droidprova: Inoltre con l'avr riesco a memorizzare variabili float maggiori di 1024?

Dove hai letto che i "float" vanno fino a 1024 ? ? ? :o :o :o O per quale arcano motivo ti viene questo dubbio ? ::)

Un float occupa 4 bytes e va da -3.4028235E+38 a 3.4028235E+38.

Guglielmo

È che so che la singola cella di memoria ha appunto quel limite...

Per il debouncing puoi dirmi qualcosa?

Grazie

La singola cella di memoria ? ? ? ... è un byte e va da 0 a 255 ...

Non è il caso che ti dai una ripassata ai "tipi" di dato nel reference ? ;)

I preferisco sempre usare quello con pull-up esterno (quindi verso il +Vcc) e chiudere con i contatti verso GND ... ... e mi sembra che anche Brunello ti suggersica quello.

Guglielmo