[risolto] Contamarce per moto

Salve a tutti,
In questo lungo periodo di corona virus ho continuato a studiare ed esercitarmi sul mio progettino di contamarce per moto.
Direi che è quasi completo sembra funzionare correttamente almeno su un software di simulazione Proteus8.9 ma ce un piccolo intoppo che non riesco a risolvere.
vi descrivo l'intoppo:

All'accensione della moto il selettore delle marce si trova in posizione Neutral e fin qui tutto bene il circuito indica la N poi inserendo la prima marcia non succede nulla il circuito rimane ad indicare la N.
Se invece di inserire la 1ma marcia inserico la 2nda marcia il circuito incìdica 2, poi se inserisco la 1m marcia il circuito indica la 1.
Ora se dalla 1ma passo alla seconda il conteggio avviene regolarmente e se continuo arriva fino alla 6sta marcia e viceversa fino alla 1ma, e questo passaggio dalla 2nda alla 1ma e viceversa mi va anche bene perche uno dei mie obiettivi era proprio di non mostrare la lettera N tra 1 e 2 e tra 2 e 1.

Ora supponiamo che arivo ad un semaforo ed avevo la 1ma innesstata quindi passo al Neutral e la lettera N viene indicata attendo che scatti il semaforo verde e innesto la 1ma marcia però il circuito rimane ad indicare la lettera N e questo è il problemino che non riesco a risolvere.

Grazie in anticipo a chi mi aiuta o frnisce suggerimenti.

qui di segiuto che lo sketch,

// uso degli ing digitali 
// siano definiti i pin 9,10,11, come N, mar_su, mar_giu
// Contamarce, o meglio definito, indicatore di marcia inserita.
// Arduino UNO R3 made in cina
// Due finecorsa effetto Hall a tre poli NO nomalmente aperto
// resitenze da 330 per pilotare il display 16seg.
// definizione ingressi sensori  usando la manipolazione porte DDRX non serve più definire i pin 9,10,11,
#define N 9 // NEUTRAL pin
#define su 10 // pin intterruttore di marcia su
#define giu 11 // pin interruttore di marcia giu
 //ultimo incoveniente da risolvere: all'accensione il Neutral è attivato High e N viene indicato.
 // innestando la 1ma non viene mostrato nr 1. Innestando al 2nda il nr 2 viene mostrato.
 // dalla 2nda passo all 1ma il nr 1 viene mostrato. Se adesso passo dalla 1ma in neutral la N viene mostrata ma se ripasso
 //in 1ma rimane su N.  
 
 
  //int val_n = 0;   //   attuale lettura input pin
  int old_val_n = 1; 
  int val_giu = 0;
  int old_val_giu = 0;
  int val_su = 0;
  int old_val_su = 0;
 //int state = 0;
  int gear = 0;
 int buttonState; 
 
unsigned long lastDebounceTime = 0;// the last time the output pin was toggled
unsigned long debounceDelay = 250;
  
void setup() {
  DDRD = 0b11111111; //imposta pin 0-7 come output
  DDRB = 0b000001;   // imposta pin 8 come output e 9-13 input
  //check funzionamento display
 digitalWrite(0, 1);
 digitalWrite(1, 1);
 digitalWrite(2, 1);
 digitalWrite(3, 1);
 digitalWrite(4, 1);
 digitalWrite(5, 1);
 digitalWrite(6, 1);
 digitalWrite(7, 1);
 digitalWrite(8, 1);
 digitalWrite(9, 1);
 delay(500);
  digitalWrite(0, 0);
  digitalWrite(1, 0);
  digitalWrite(2, 0);
  digitalWrite(3, 0);
  digitalWrite(4, 0);
  digitalWrite(5, 0);
  digitalWrite(6, 0);
  digitalWrite(7, 0);
  digitalWrite(8, 0);
  digitalWrite(9, 0);
  delay(200);
  
  //Serial.begin(9600); 
 
}
// è stato inserito un tempo di controllo sul pin Neutral per attivare ilneutral solo 
//se è il tempo è maggiore di deboundDealy ricavandolo dall'esempio debounddelay.
void loop() {
 int val_n = digitalRead(9);   // check to see if you just pressed the button
  // (i.e. the input val_n went from LOW to HiGH), and you've waited long enough
  // since the last press to ignore any noise:
  // If the switch changed, due to noise or pressing: 
  if (val_n != old_val_n ) { // lettura stato pin val_n se è cambiato fail il reset del tempo
    // reset the debouncing timer
    lastDebounceTime = millis();
  }
  if ((millis() - lastDebounceTime) > debounceDelay) {
    // whatever the val_n is at, it's been there for longer than the debounce
    // delay, so take it as the actual current state:
    // if the button state has changed:
    if (val_n != buttonState) {
      buttonState = val_n;

    if (val_n = HIGH) { //  se la condizione val_n è vera la lettera N viena mostrata
    PORTD=0b10110110;
    PORTB=0b000001;
   delay(10);
    }
    }
  }
 
  old_val_n= val_n;
  val_giu = digitalRead(11);
   if ((val_giu == HIGH) && (old_val_giu==LOW) && (val_n ==LOW)) {
     gear -= 1;
     setnum(gear);
    delay(50);
   }
  old_val_giu = val_giu;
      
 val_su = digitalRead(10);
   if ((val_su == HIGH)&& (old_val_su == LOW)&& (val_n ==LOW)) { // && (old_val_su == LOW))
     gear += 1;
     setnum(gear);
     delay(50);
   }
 old_val_su = val_su;
    
  if (gear >6) {gear=6;}
   if (gear <1) {gear=1;}

}
 void setnum (int gear){
  
  switch (gear){
    case 1:
    PORTD=0b00000110;
    PORTB=0b000000;
  break;
 
  case 2:
  PORTD=0b01011011;
  PORTB=0b000000;
  
  break;
   
  case 3:
  PORTD=0b01001111;
  PORTB=0b000000;
  break;
 
  case 4:
  PORTD=0b01100110;
  PORTB=0b000000;
  break;
 
  case 5:
  PORTD=0b01101101;
  PORTB=0b000000;
  break;
 
  case 6:
  PORTD=0b01111101;
  PORTB=0b000000;
  break;
  }
} // FINE loop

Distinti Saluti,

Ps ricordiamoci di osservare le misure di sivurezza in questo periodo.

Ammetto che non mi sono msso a seguire granché la logica, ma posso fornirti qualche indicazion minima.
Questa riga:

if (val_n = HIGH) { //  se la condizione val_n è vera la lettera N viena mostrata

è errata il controllo di uguagianza va fatto con == e non con = perché in tal caso assegni il valore e il risultato è sempre vero.
Tu inizializzi old_val_n con 1 che, quando il sistema parte se val_n vale HIGH (ch corrisponde a uno) non entri in questo if

if (val_n != old_val_n )

Non so se è voluto, essendo un "valore precedente" al primo giro dovresti ignorarlo o inizializzarlo con un valore differente rispetto al valore attuale assegnato a val_n.
Non mi è chiaro come mai solo per la N hai gestito il debounce software e per su e giù no, suppongo è gestito via hardware, allora mi chiedo perché complicarsi la vita via software quando è molto più semplice e meglio farlo via hardware, ma magari ignoro qualcosa del progetto.

Altra cosa

DDRB = 0b000001; // imposta pin 8 come output e 9-13 input

Quando si manipolano i registi in tal modo è meglio esplicitare sempre tutti i singoli bit, qui ne mancano un paio, funziona solo perché tu stai settando solo il primo pin come output

Altra cosa che ho visto solo ora, questo pezzo di codice

if (gear >6) {gear=6;}
   if (gear <1) {gear=1;}

Lo fai dopo aver richiamato la funzione che visualizza la marcia inserita (setnum) il che potrebbe portare a visualizzazioni errate, io ti consiglio di fare anzi così:

gear += 1;
if (gear >6) {gear=6;}

e stessa cosa per la parte in discesa

Ciao Fabpolli, prima di tutto grazie per la risposta, e sicuramente mi sono perso nei meandri delle if quando ho inserito il debounddelay. ho dimenticato di dire che non sono un esperto di programmazione C++ ma sono alle prime armi.
Andiamo passo per passo.

Parto dalla manipolazione delle porte, guardando la piedinatura dell ATmega 328 i bit sulla porta B sono 6 da PB0 a PB5 quindi credo che non manchi nessun bit mentre sono 8 per la porta D.

La impostazione di old_va_n: All'accensione della moto il selettore delle marce si trova in posizione Neutral
quindi l'ingresso pin 9 val_n è alto e ho pensato, forse erroneamente, che old_val_n dovesse essere ad 1.
ho fatto una prova impostando int old_val_n a 0 ma nulla è cambiato.
il problemino iniziale rimane.

L'impostazione di Debound su N la ho voluta perché quando sei in moto e scali le marce e arrivi dalla seconda alla prima marcia e viceversa passi dalla prima all seconda per un brevissimo istante si accende la luce neutral e io volevo evitare che la stessa cosa succedesse sull'arduino.
Cosa questa che accadeva prima che inserissii il debound sul N.
per le altre marce non mi serve il debound.

Per qunato riguarda la comparazione ho aggiustato l'espressione in

if (val_n == HIGH)

poi ho fatto una prova con simulatore ma nulla è ancora cambiato.

L'ultimo tuo suggerimento invece ha risolto il mio problemino mettendo

if (gear >6) {gear=6;}
   if (gear <1) {gear=1;}

subito dopo (gear+=1 e prima del (setnum)) anche per le marce giu prima dei (gear -=1).

Ora il contamarce funziona perfettament; dalla posizione N va in prima marcia e viceversa.

:smiley: :smiley: :smiley: :smiley: :smiley: :smiley: :smiley: :smiley: :smiley: :smiley: :smiley: :smiley: :smiley:
Grazie Grazie Grazie Grazie Grazie Grazie Grazie Grazie Grazie Grazie Grazie Grazie Grazie Grazie Grazie Grazie Grazie Grazie Grazie Grazie Grazie Grazie Grazie Grazie Grazie Grazie Grazie Grazie Grazie Grazie

Perdonami Fabpolli
rileggendo bene l'indicazione della manipolazione delle porte mi sono reso conto che intendevi i due bit non utilizzati della portaB.

Domanda cosa intendi per meglio esplicitare tutti i Bit?

Ciao Grazie ancora.

Saluti Lorenzo

Ancora una domanda, come si fa a mettere [risolto] nella visuallizzazione del post?

LOLLO65:
Ancora una domanda, come si fa a mettere [risolto] nella visuallizzazione del post?

Si va in edit sul PRIMO post del thread e si cambia il titolo aggiungendo, all'inizio, [RISOLTO]. :slight_smile:

Guglielmo

ok grazie Gulielmo.

Esplicitare: credo che intenda dire che tu stai scrivendo solo i primi 6 bit, da B0 a B5:

DDRB = 0b000001; // imposta pin 8 come output e 9-13 input

Di fatto, però, stai impostando:

DDRB = 0b00000001;

cioè stai forzando a 0 (ingressi) anche B6 e B7. Non sapendo se esistono e, nel caso siano registri presenti, che cosa facciano, è opportuno fare in modo di non interferire con essi. Considera che, all'accensione, tutti i pin sono impostati come ingressi, perciò devi definire solo le uscite:

DDRB |= 1;

In questo modo tu sommi 1 allo stato della porta, impostando B0 come uscita.

Nota: così come nel sistema decimale, anche nel sistema binario le cifre sono allineate a destra: se in decimale scrivo 5, sono 5 unità; se scrivo 35, sono 3 decine e 5 unità: la cifra a destra è sempre quella delle unità. Allo stesso modo, se in binario scrivo 1 è uguale a 0001 e a 000000001; se scrivo 101 è uguale a 0101 e a 00000101.

Ciao Gianluca,
grazie della spiegazione, ho compreso che e sufficiente scrivere i bit che mi interessa gestire.
pero ancora non comprendo quanti bit ( piedini ci sono sulla portaB) 6 o 8?
Guardandno la piedinatura dell'AT mega 328 sono riportate le descrizioni da PB0 a PB5 gli altri due bit PB6 e PB7 dove sono?

Guardando invece la board di Arduino digital UNO che ho in effetti ci sono altri 4 pin di cui uno è il GND,
gli altri tre sono Vref, SDA, SCL, non ho idea a cosa servono e andro a rivedere la scheda tecnica.

allego immagine della board.

Grazie ancora.

PB6 e PB7 sono condivisi con il quarzo. Per liberarli bisogna usare l'oscillatore interno.
Vref è la tensione di riferimento dell'ADC.
SDA e SCL sono il bus I2C.

Detto che tutte le spiegazioni sopra sono perfette, guardando sul DS del 328 dal paragrafo 15.4.5 in poi PORTB e DDRB vengno indicati come a 8 bit, quindi esplicitando la notazione binaria credo sia più corretto (sebbene equivalente) indicare tutti i bit. Poi come detto manipolare porte e registri in modo diretto occorre sapere cosa si stia facendo perché agire con leggerezza e non documentandosi a fondo si rischia di incappare in malfunzionamenti o comportamenti non desiderati

Visto che si sei, tutto questo blocco:

  //check funzionamento display
 digitalWrite(0, 1);
 digitalWrite(1, 1);
 digitalWrite(2, 1);
 digitalWrite(3, 1);
 digitalWrite(4, 1);
 digitalWrite(5, 1);
 digitalWrite(6, 1);
 digitalWrite(7, 1);
 digitalWrite(8, 1);
 digitalWrite(9, 1);
 delay(500);
  digitalWrite(0, 0);
  digitalWrite(1, 0);
  digitalWrite(2, 0);
  digitalWrite(3, 0);
  digitalWrite(4, 0);
  digitalWrite(5, 0);
  digitalWrite(6, 0);
  digitalWrite(7, 0);
  digitalWrite(8, 0);
  digitalWrite(9, 0);
  delay(200);

si può concentrare in:

PORTD=0xFF; // Accende tutta la porta D
PORTB|=0x03; // Accende i primi due bit della porta B
delay(500);
PORTD=0; // Spegne tutta la porta D
PORTB&=0b11111100; // Spegne i primi due bit della porta B (oppure PORTB&=~0x03)
delay(200);

Nota il miscuglio di notazioni esadecimale, decimale e binaria secondo come più comodo per il valore da impostare: 0xFF significa tutto acceso; 0x03 significa 1+2, quindi i due bit a destra accesi; 0 possiamo scriverlo come vogliamo; 0b11111100 significa i due bit a destra spenti.

Ciao Fabpolli,
grazie ancora per la risposta e le informazioni che mi fornisci.
Hai ragione sul fatto di sapere cosa sista facendo e qui pago venia perché le mie conoscenze di C++ e del mondo arduino sono pressoché nulle; mondo questo a cui mi sono affacciato solo da qualche mese; quindi ne ho ancora di strada da fare per imparare questo mondo però io non vado di corsa; in effetti scopiazzo qua la da altri esempi e cerco di adattarli al mio proggettino. però l'inserimento del DeboundDelay me lo sono studiato tutto da solo.
In ogni caso grazie ancora x mille volte.

Ciao GianLuca,
Interessante la tua descrizione sulle impostazioni delle porte anzi su come scrivere in modo diverso una stessa cosa, Poi sono andato a rileggere i tuoi suggerimenti del 25 febbraio nel precedente post e ho apportato alcun aggiustamenti allo sketch modificando questo

  //check funzionamento display
 digitalWrite(0, 1);
 digitalWrite(1, 1);
 digitalWrite(2, 1);
 digitalWrite(3, 1);
 digitalWrite(4, 1);
 digitalWrite(5, 1);
 digitalWrite(6, 1);
 digitalWrite(7, 1);
 digitalWrite(8, 1);
 digitalWrite(9, 1);
 delay(500);
  digitalWrite(0, 0);
  digitalWrite(1, 0);
  digitalWrite(2, 0);
  digitalWrite(3, 0);
  digitalWrite(4, 0);
  digitalWrite(5, 0);
  digitalWrite(6, 0);
  digitalWrite(7, 0);
  digitalWrite(8, 0);
  digitalWrite(9, 0);
  delay(200);

In questo, che è anche piu bello da vedersi,

 DDRD = 0b11111111; //imposta pin 0-7 come output
// test funzionale display
  PORTD=0b10110110;
  delay(200);
  PORTD=0b00000110;
  delay(200);
  PORTD=0b01011011;
  delay(200);
  PORTD=0b01001111;
  delay(200);
  PORTD=0b01100110;
  delay(200);
  PORTD=0b01101101;
  delay(200);
  PORTD=0b01111101;
  delay(200);
  PORTD=0b00000000;

Sicuramente posso riscriverlo secondo le tue indicazioni.

Ho poi accorpato l'accensione dei led e ho eliminato l'uso della porta B alleggerendo lo sketch,
senza definire i pin di ingresso con il define lo sketch funziona lo stesso come tu hai detto all'accensione tutti i pin sono impostati come input.

Gianluca ,Grazie della spiegazione.

Saluti Lorenzo,
a proposito sono tornato in italia e attualmente sono in regime di quarantena, terminata la quarantena andrò a dedicarmi alla mia attivita principale "esplorazioni Geomarine". per 6 settimane.