Sono nuovo e avrei bisogno di una mano

buonasera a tutti sono nuovo in questo forum e avrei bisogno del vostro aiuto su di un progetto che sto portando avanti, si tratta di collegare arduino alla macchina, premetto che sono in primissima fase di progettazione, e in campo arduino ne so veramente poco. ho creato vari progetti in vb.net ma con arduino non mastico molto bene. allora, sto scrivendo vari sketch singolarmente e singolarmewnte funzionano, adesso vorrei unirli, ma trovo alcune difficolota, spero che qualcuno mi possa aiutare.
i 2 sketch sono il primo il riconoscimento della tessera con l rfid522 dove se il codice è corretto si accende un led verde e contemporaneamente dovrà lampeggiare il led del pulsante di avviamento motore auto, il secondo sketch è il blink non bloccante del led pulsante motore. Use code tags to format code for the forum. il problema che singolarmente funzionano ma se li unisco il led pulsante motore rimane acceso e non lampeggia.
grazie mille

primo sketch

#include <MFRC522.h>
#define GREEN_LED_PIN 2
#define RED_LED_PIN 3
#define LED_PULSANTE_PIN 4
#define INTERVALLO 1000

int stato = LOW;
unsigned long t0, dt;

MFRC522 rfid(10, 9);
 
String users[] = {"f3704273"};
int usersSize = sizeof(users)/sizeof(String);
 
void setup(){
  SPI.begin();
  rfid.PCD_Init();
  pinMode(GREEN_LED_PIN, OUTPUT);
  pinMode(RED_LED_PIN, OUTPUT);
  pinMode(LED_PULSANTE_PIN, OUTPUT);
  t0 = millis();
}
 
void loop(){
  if(rfid.PICC_IsNewCardPresent() && rfid.PICC_ReadCardSerial()){
    String uid = getUID();
    if(checkUID(uid)){
      led();
      blinkLed(GREEN_LED_PIN, 2000, 1);
     
    }else{
      blinkLed(RED_LED_PIN, 400, 2);
    }
  }
  delay(10);
}
 
String getUID(){
  String uid = "";
  for(int i = 0; i < rfid.uid.size; i++){
    uid += rfid.uid.uidByte[i] < 0x10 ? "0" : "";
    uid += String(rfid.uid.uidByte[i], HEX);
  }
  rfid.PICC_HaltA();
  return uid;
}
 
bool checkUID(String uid){
  for(int i = 0; i < usersSize; i++){
    if(users[i] == uid){
      return true;
    }
  }
  return false;
}


 void led(){
   dt = millis() - t0; 
   if ( dt >= INTERVALLO ) {
   t0 = millis();
   stato = !stato;
   digitalWrite(LED_PULSANTE_PIN, stato);
  }
 }
 

void blinkLed(int led, int duration, int repeat){
  for(int i = 0; i < repeat; i++){
    digitalWrite(led, HIGH);
    delay(duration/2);
    digitalWrite(led, LOW);
    delay(duration/2);
  }
}



secondo sketch

#define INTERVALLO 500
#define LED_PULSANTE_PIN 4

int stato = LOW;
unsigned long t0, dt;

void setup() {
  pinMode(LED_PULSANTE_PIN, OUTPUT);
  t0 = millis();
}

void loop() {
  led();
}
void led(){
dt = millis() - t0; 
  if ( dt >= INTERVALLO ) {
    t0 = millis();
    stato = !stato;
    digitalWrite(LED_PULSANTE_PIN, stato);
  }
}

Poiché separatamente funzionano, dovresti pubblicare il programma completo che non funziona!
In effetti, la funzione led, che puoi semplificare come segue, funziona:

#define INTERVALLO 500
#define LED_PULSANTE_PIN 4

unsigned long t0;
bool stato = true;

void setup() {
  pinMode(LED_PULSANTE_PIN, OUTPUT);
}

void loop() {
  led();

void led(){
  if (millis()-t0 >= INTERVALLO) {
    t0 = millis();
    digitalWrite(LED_PULSANTE_PIN, stato);
    stato = !stato;
  }
}

Il mancato funzionamento nell'insieme dipende da qualche funzione del resto del programma che lo tiene bloccato per un po' di tempo in attesa di qualcosa.

Il secondo sketch funziona benissimo, ma quando vado ad implementarlo alla funzione rfid la funzione led si blocca. Nel primo sketch ho implementato la funzione led prima della funzione blinkLed(GREEN_LED_PIN, 2000, 1)
ma si blocca

C'è una qualche regola da seguire x unire 2 sketch? Perché ho altri sketch da inserire, come l orologio con il setting e altre funzioni per far funzionare l auto.

1 Like

In genere no c'è alcuna regola, poiché non è previsto lo sviluppo separato di più sketch per poi unirli. Diciamo che è quello che molti vorrebbero fare e tentano di fare senza risultato.

Questo è incoraggiante, poiché hai già capito quando si viene a creare il problema, cioè quando una chiamata a funzione monopolizza la CPU per un tempo considerato troppo alto per fare funzionare l'applicazione. Ad esempio il responsabile potrebbe essere una chiamata bloccante per la lettura del rfid.
Ora io non conosco la libreria, nel senso che non sono andato a studiare se ci sono funzioni "bloccanti" ecc.

Una semplificazione è quella di considerare "bloccante" qualunque funzione poiché richiede un certo numero di cicli di clock per essere eseguita. Però un conto è attendere 10us che la funzione restituisca il controllo al chiamante, un altro è attendere 1 secondo. Ecco uno dei motivi per cui delay() è bandito, come pure while e for, in sostanza tutti i cicli innestati dentro la funzione loop che è già un ciclo infinito, ciclo che possiamo chiamare main loop.

Ora tu sei abituato con vb.net su un pc con sistema operativo multi task. Ma su arduino non ci sono sufficienti risorse hardware per un sistema operativo.

Un altra semplificazione può essere quella di fare eseguire delle istruzioni per ogni ciclo di loop che impegnano la CPU per un tempo massimo di supponiamo 1ms, il che vorrebbe dire che hai una reattività di poco più 1ms. Che è già buono per la maggior parte delle applicazioni pratiche. Con la esperienza si riesce a fare anche meglio di 1ms sempre che serva.

Spero di averti dato degli spunti utili su cui ragionare.

Ciao.

Beh! Più o meno. In questi giorni provero a fare qualche altra prova e vediamo, cmq grazie mille

@nightwolf:

:warning:
Ti segnalo che, nella sezione in lingua Inglese, si può scrivere SOLO in Inglese ... quindi, per favore, la prossima volta presta più attenzione in quale sezione metti i tuoi post; questa volta esso è stato spostato, da un moderatore della sezione di lingua Inglese, nella sezione di lingua Italiana ... la prossima volta potrebbe venire direttamente eliminato. Grazie.

Dunque, io vado che chiami la funzione led sotto due condizione:

if(rfid.PICC_IsNewCardPresent() && rfid.PICC_ReadCardSerial()){
    String uid = getUID();
    if(checkUID(uid)){
      led();
      blinkLed(GREEN_LED_PIN, 2000, 1);

Chiami anche la funzione blinkLed() che usa delay e che quindi è "bloccante"

Ora scrivo quasi lo stesso codice, anzi copio e modifico:

bool blinkEnable = false;  // prima del setup()


void loop(){
  led();   // la chiama sempre ad ogni ciclo di loop
  if(rfid.PICC_IsNewCardPresent() && rfid.PICC_ReadCardSerial()){
    String uid = getUID();
    if(checkUID(uid)){
      // led(); // spostata nel main loop
      // blinkLed(GREEN_LED_PIN, 2000, 1); rimosso è bloccante
      blinkEnable = true; // abilita lampeggio
     
    }else{
      // blinkLed(RED_LED_PIN, 400, 2); // rimosso è bloccante
      blinkEnable = false; disabilita lampeggio
    }
  }
  // delay(10); // delay rimosso è bloccante
}

void led(){
    if (blinkEnable == true) {
       dt = millis() - t0; 
       if ( dt >= INTERVALLO ) {
           t0 = millis();
           stato = !stato;
           digitalWrite(LED_PULSANTE_PIN, stato);
      }
   } else {
           digitalWrite(LED_PULSANTE_PIN, LOW);
           t0 = 0;  // azzero il timer
   }
}

Di seguito un link ad applicazione non bloccante:

Ciao.

Ah! C'è anche la blinkLed nel codice pubblicato! Non l'avevo vista, ero convinto che non l'avesse pubblicata! Proprio non l'avevo vista... :frowning: D'altra parte, non credevo che dopo aver fatto lampeggiare un LED usando millis() ne avesse fatto lampeggiare un altro usando delay...

La soluzione è semplice: rinominare t0 con t_led_puls e t_led_blink e poi fare per il secondo led la stessa cosa del primo o addirittura parametrizzare ulteriormente la funzione led e usarla anche per l'altro con t[0] e t[1] per i tempi.

grazie mille, adesso funziona il tutto, ho solo aggiunto un piccolo blink per il led rosso e il led verde, perchè in quel modo non si accendevano più.

void loop(){
  led();
  if(rfid.PICC_IsNewCardPresent() && rfid.PICC_ReadCardSerial()){
    String uid = getUID();
    if(checkUID(uid)){
      blinkEnable = true;
      digitalWrite(GREEN_LED_PIN, HIGH);
      delay(300);
      digitalWrite(GREEN_LED_PIN, LOW);
    }else{
      blinkEnable = false;
      digitalWrite(RED_LED_PIN, HIGH);
      delay(300);
      digitalWrite(RED_LED_PIN, LOW);
    }
  }

questo solo x dirmi se la tessera avvicinata è esatta oppure no, non so se è nel modo corretto, ma funziona.

questo è il risultato finito, grazie mille


#include <MFRC522.h>
#define GREEN_LED_PIN 2
#define RED_LED_PIN 3
#define INTERVALLO 500
#define LED_PULSANTE_PIN 4

int stato = LOW;
unsigned long t0, dt;

MFRC522 rfid(10, 9);
 
String users[] = {"f3704273"};
int usersSize = sizeof(users)/sizeof(String);

bool blinkEnable = false;

 
void setup(){
  SPI.begin();
  rfid.PCD_Init();
  pinMode(GREEN_LED_PIN, OUTPUT);
  pinMode(RED_LED_PIN, OUTPUT);
  pinMode(LED_PULSANTE_PIN, OUTPUT);
  t0 = millis();

}
 
void loop(){
  led();
  if(rfid.PICC_IsNewCardPresent() && rfid.PICC_ReadCardSerial()){
    String uid = getUID();
    if(checkUID(uid)){
      blinkEnable = true;
      digitalWrite(GREEN_LED_PIN, HIGH);
      delay(300);
      digitalWrite(GREEN_LED_PIN, LOW);
    }else{
      blinkEnable = false;
      digitalWrite(RED_LED_PIN, HIGH);
      delay(300);
      digitalWrite(RED_LED_PIN, LOW);
    }
  }
  
}
 
String getUID(){
  String uid = "";
  for(int i = 0; i < rfid.uid.size; i++){
    uid += rfid.uid.uidByte[i] < 0x10 ? "0" : "";
    uid += String(rfid.uid.uidByte[i], HEX);
  }
  rfid.PICC_HaltA();
  return uid;
}
 
bool checkUID(String uid){
  for(int i = 0; i < usersSize; i++){
    if(users[i] == uid){
      return true;
    }
  }
  return false;
}
 
void led(){
    if (blinkEnable == true) {
       dt = millis() - t0; 
       if ( dt >= INTERVALLO ) {
           t0 = millis();
           stato = !stato;
           digitalWrite(LED_PULSANTE_PIN, stato);
      }
   } else {
           digitalWrite(LED_PULSANTE_PIN, LOW);
           t0 = 0;  // azzero il timer
   }
}

adesso, se a questo codice vorrei aggiungere l orologio che ho gia in un altro sketch e che funziona perfettamente( è da un paio di giorni che è acceso), in teoria basta aggiungerlo, non dovrebbe andare in blocco sono soltanto "void" e richiami, ma non è vero va tutto in blocco, il codice di sopra si blocca. aggiungo il cod dell orologio.

#include <LiquidCrystal_I2C.h>
#include <Wire.h>
 
LiquidCrystal_I2C lcd(0x27,16,2);  

 
void setup() {
  pinMode(8, INPUT_PULLUP);                      // pulsante1 connesso al pin 8
  pinMode(9, INPUT_PULLUP);                      // pulsante2 connesso al pin 9
 
  lcd.backlight();
  lcd.init();
  Wire.begin();                                  // Inizializzazzione bus I2C
}
 
char Time[]     = "ORA:   :  :  ";
char Calendar[] = "DATA:  /  /20  ";
byte i, second, minute, hour, date, month, year;
 
void DS3231_display(){
  // Converto BCD in decimale
  second = (second >> 4) * 10 + (second & 0x0F);
  minute = (minute >> 4) * 10 + (minute & 0x0F);
  hour   = (hour >> 4)   * 10 + (hour & 0x0F);
  date   = (date >> 4)   * 10 + (date & 0x0F);
  month  = (month >> 4)  * 10 + (month & 0x0F);
  year   = (year >> 4)   * 10 + (year & 0x0F);
  // Fine conversione
  Time[12]     = second % 10 + 48;
  Time[11]     = second / 10 + 48;
  Time[9]      = minute % 10 + 48;
  Time[8]      = minute / 10 + 48;
  Time[6]      = hour   % 10 + 48;
  Time[5]      = hour   / 10 + 48;
  Calendar[14] = year   % 10 + 48;
  Calendar[13] = year   / 10 + 48;
  Calendar[9]  = month  % 10 + 48;
  Calendar[8]  = month  / 10 + 48;
  Calendar[6]  = date   % 10 + 48;
  Calendar[5]  = date   / 10 + 48;
  lcd.setCursor(0, 0);
  lcd.print(Time);                               // Scrivi sul display l'ora
  lcd.setCursor(0, 1);
  lcd.print(Calendar);                           // Scrivi sul display la data
}
void blink_parameter(){
  byte j = 0;
  while(j < 10 && digitalRead(8) && digitalRead(9)){
    j++;
    delay(25);
  }
}
byte edit(byte x, byte y, byte parameter){
  char text[3];
  while(!digitalRead(8));                        // Aspetta fin quando il (pin #8) è rilasciato
  while(true){
    while(!digitalRead(9)){                      // Se il pulsante (pin #9) è premuto
      parameter++;
      if(i == 0 && parameter > 23)               // Se l'ora > 23 ==> ora = 0
        parameter = 0;
      if(i == 1 && parameter > 59)               // Se i minuti > 59 ==> minuti = 0
        parameter = 0;
      if(i == 2 && parameter > 31)               // Se la data > 31 ==> data = 1
        parameter = 1;
      if(i == 3 && parameter > 12)               // Se il mese > 12 ==> mese = 1
        parameter = 1;
      if(i == 4 && parameter > 99)               // Se l'anno > 99 ==> anno = 0
        parameter = 0;
      sprintf(text,"%02u", parameter);
      lcd.setCursor(x, y);
      lcd.print(text);
      delay(200);                                // Attendi 200ms
    }
    lcd.setCursor(x, y);
    lcd.print("  ");                             // Inserisci due spazi
    blink_parameter();
    sprintf(text,"%02u", parameter);
    lcd.setCursor(x, y);
    lcd.print(text);
    blink_parameter();
    if(!digitalRead(8)){                         // Se il pulsante sul (pin #8) è premuto
      i++;                                       // Incrementa 'i' di un parametro
      return parameter;                          // Restituisce il valore del parametro e esce
    }
  }
}
 void Ora(){
  if(!digitalRead(8)){                           // Se il pulsante1 (pin #8) è premuto
      i = 0;
      hour   = edit(5, 0, hour);
      minute = edit(8, 0, minute);
      date   = edit(5, 1, date);
      month  = edit(8, 1, month);
      year   = edit(13, 1, year);
      // Converti da decimal in BCD
      minute = ((minute / 10) << 4) + (minute % 10);
      hour = ((hour / 10) << 4) + (hour % 10);
      date = ((date / 10) << 4) + (date % 10);
      month = ((month / 10) << 4) + (month % 10);
      year = ((year / 10) << 4) + (year % 10);
      // Fine conversione
      // Scrivi data sul modulo DS3231 RTC
      Wire.beginTransmission(0x68);               // Inizia il protocollo I2C sul'indirizzo del DS3231 
      Wire.write(0);                              // Invia registrazione indirizzo
      Wire.write(0);                              // Reimposta e avvia l'oscillatore
      Wire.write(minute);                         // Scrivi i minuti
      Wire.write(hour);                           // Scrivi l'ora
      Wire.write(1);                              // Scrivi giorno (non usato)
      Wire.write(date);                           // Scrivi data
      Wire.write(month);                          // Scrivi mese
      Wire.write(year);                           // Scrivi anno
      Wire.endTransmission();                     // Interrompere la trasmissione e rilasciare il bus I2C
      delay(200);                                 // Attendi 200ms
    }
    Wire.beginTransmission(0x68);                 // Inizia il protocollo I2C sul'indirizzo del DS3231 
    Wire.write(0);                                // Invia registrazione indirizzo
    Wire.endTransmission(false);                  // I2C restart
    Wire.requestFrom(0x68, 7);                    // Richiedi 7 byte da DS3231 e rilascia il bus I2C alla fine della lettura
    second = Wire.read();                         // Leggi i secondi dal registro 0
    minute = Wire.read();                         // Leggi i minuti dal registro 1
    hour   = Wire.read();                         // Leggi ora dal registro 2
    Wire.read();                                  // Leggi il giorno dal registro 3 (non utilizzato)
    date   = Wire.read();                         // Leggi la data dal registro 4
    month  = Wire.read();                         // Leggi il mese dal registro 5
    year   = Wire.read();                         // Leggi l'anno dal registro 6
    DS3231_display();                             // Visualizza ora e calendario
    delay(50);                        
}
void loop() {
    Ora();
}

ho semplicente aggiunto al loop Ora(); per far si che quando accendo arduino mi compaia l ora ma la lettura della tessera si blocca.
Ps. non so se si vede l ora perche sto usando per le prove un arduino uno e per l orologio e il tutto definitivo un arduino mega, ma se con l arduino uno caricando lo sketch si blocca la lettura delle tesserer è inutile caricare il tuìtto sul mega o sbaglio!!

No sembra non sia corretto. Io ho potuto modificare il codice perché vi era poco da modificare. Il mio intento non è quello di risolverti il problema ma mostrarti come scrivere codice non "bloccante" poiché è l'unico modo per avere reattività. Superato questo scoglio non si hanno più grandi problemi.

Quindi secondo me devi insistere con quella porzione di codice che dici funzionare anche se contiene codice "bloccante".

Inoltre se hai veramente letto quell'articolo sai già che aggiungendo altre funzionalità si finisce presto per non capirci più nulla. A scanso di equivoco, non è che io o tu non ci capiamo più nulla ma chiunque pure il più bravo dei programmatori su questa terra.

Ciao.

Grazie mille, proverò a fare tentativi, ho visto che per errore il pin 9 è in comune, adesso cambio il pin 9 di pullup e vediamo

Se continui ad aggiungere delay qua e là, andrà sempre peggio!
Inoltre, non ho mai visto tanti calcoli per visualizzare ora e data... :frowning_with_open_mouth:

Leggendo il codice del loop qui sopra ed eliminando i delay, mi chiedo: Ma è proprio necessario verificare continuamente la presenza della carta RFid?
Non sarebbe già sufficiente verificare la presenza ogni 1 secondi?

In alcune applicazioni non serve neanche fare ciò ogni secondo poiché una volta autenticati non serve più la presenza della carta, dopo l'autenticazione inizia a contare il tempo di timeout che una volta scaduto richiede una nuova autenticazione.

Ho gia modificato il loop qui sopra con la sola accensione del led verde fisso, perché mi servirà più avanti come condizione. Mentre il blink del led mi serve per il pulsante di avviamento. Ho anche modificato l intero sketch dell orologio rendendolo non bloccante, devo soltanto provarlo sulla bradboard. Per quello che devo fare con l auto ho bisogno che il led verde rimanga acceso.

Ok, grazie per la risposta. Io non riesco ad immaginare per cosa usi rfid in auto. In realtà una idea tutta mia me la sono fatta ma da come scrivi la mia idea non corrisponde all'uso che ne fai.

Io ad esempio penso così:
Se inserisco la carta in tempo massimo di 1 secondo viene riconosciuta (se è quella registrata), adesso accendo il led.
Se il led è acceso abilito il pulsante che sarà in grado di fare qualcosa se lo premo, questo qualcosa potrebbe pure essere avviare il motore dell'auto. Ora se rimuovo la carta entro 1 secondo al massimo il led si spegne e si spegne anche quello che avevo acceso premendo il pulsante. Io verificherei quanto tempo impiega la cpu per verificare la carta se corretta o meno, potrei scoprire così la verifica impiega ad esempio 10 millesimi di secondo, se nel loop non ci sono delay o cicli bloccanti anche se il loop fosse pieno di codice che impegna la cpu per 100ms potrei arrivare alla conclusione che non mi serve leggere la carta ogni 110 millesimi di secondo, se così fosse potrei decidere di usare millis per interrogare il lettore ogni 500ms o 1000ms ecc.

Ecco, questo è un risultato da festeggiare, ma come dici tu è meglio provare il tutto su breadbord.

No no rileggendo sembra proprio che deve funzionare come me lo sono immaginato. Il led lampeggiante indica all'utente che il pulsante di avviamento è abilitato?

Ciao.

Esatto, il tutto dovrà funzionare come se fosse un sistema di antifurto, se la carta non è valida il led verde non si accende e di conseguenza quando andrò a schiacciare il pulsante che saro sotto schemi a stato non si accenderà il quadro e non andrà allo stato 2. Un po come le chiavi di oggi, che se non si legge il transponder non si avviano. È giusto per fare una sicurezza in più, visto che toglierò il blocchetto di accensione e il tutto si attiverà tramite codice. Ah, dimenticavo sarà anche gestito tramite app.