[code] // Rispetto alla versione 9.1 si utilizza il contatore del Timer T2 invece che la funzione micros() // per leggere il tempo, dopo aver accelerato il Timer T2 portandolo ad un click ogni mezzo microsecondo. // riducendo a UN microsecondo l'errore introdotto dalla misura del tempo con micros() che e' di 4 us // Al pin 2 corrisponde il valore del secondo bit nel registro PIND // Al Pin 3 corrisponde il valore del terzo bit nel registro PIND // Al Pin 12 corrisponde il valore del quarto bit nel registro PINB // LA CONDIZIONE NORMALE E' UNO e diventa ZERO quando passa l'ombra. // Il tubo originale si e' rotto e nel nuovo e'cambiata anche la distanza tra i fotodiodi // che adesso si trovano a 523 millimetri l'uno dall'altro. // // Invece che due pin analogici leggo i pin digitali 3 e 12 comandati da un trigger esterno // controllando solo se stanno ad uno o a zero // quando passa un'ombra e NON FACENDO ALTRO se non il controllo del pin 2 per il reset // Il display DFRobot porta in uscita solo i pin D0,D1,D2,D3,D11,D12 // e gli analogici A1,A2,A3,A4.A5 usa A0 per leggere quale pulsante // è stato premuto // ************ FUNZIONA **************** /*-----( Importa le librerie necessarie)-----*/ #include "LiquidCrystal.h" // e' la libreria per gestire il display #include "DHT.h" // libreria per gestire il sensore temperatura e Umidita' #define DHTPIN 11 // Il pin 11 è quello che usa il sensore #define DHTTYPE DHT22 //definisce il tipo di sensore (gestisce anche il fratello minore DHT11) /*-----( Dichiarazioni Variabili )-----*/ int Diodo_Uno = 0; int Diodo_Due = 0; int pin2 = 1; int pin3 = 1; int pin12 = 1; int pinA1 = 0; volatile unsigned long Contatore_degli_overflow = 0; //definisco e azzero la variabile che conta gli overflow volatile unsigned long Conteggi_totali_T2 = 0; //definisco e azzero la variabile che ospiterà il numero totale dei conteggi del Timer T2 unsigned long Tempo = 0; unsigned long Tempo_T2 = 0; unsigned long Tempo_Start = 0; unsigned long Tempo_Stop = 0; float V2; float Errore_Metri; float Volt; float Letture[10]; float Somma=0; float Media=0; float Metri_Secondo_T2 = 0; int h=0; int t=0; int n=0; int x=0; int i=0; DHT dht(DHTPIN, DHTTYPE); LiquidCrystal lcd(8, 9, 4, 5, 6, 7); //Sono i piedini usati dal display LCD void setup() /*----( SETUP: Viene letto solo alla partenza )----*/ { lcd.begin(16, 2); // Fa partire l'oggetto lcd che gestisce il display lcd dht.begin(); // Fa partire l'oggetto dht che gestisce i sensori temp e umid // Modifiche al Timer T2 TCCR2B = TCCR2B & 0b11111000 | 0x02; //mettendo a zero i primi tre bit e poi mettendo un 1 in seconda posizione // indico al prescaler di dividere il clock di base per otto ottenendo un clik ogni mezzo microsecondo TIMSK2 |= 0b00000001; //abilito la generazione di interrupt di overflow mettendo un 1 nella prima posizione del registro TCCR2A &= 0b11111100; //metto a zero (normale) i bit WGM21 e WGM20 che si trovano nel registro TCCR2A in prima e seconda posizione TCCR2B &= 0b11110111; //metto a zero (normale) il bit WGM22 che si trova nel registro TCCR2B in quarta posizione pinMode(2, INPUT); // Pin a cui e' connesso il pulsante di calcolo della media e reset pinMode(3, INPUT); // Pin a cui e' connesso il primo fotodiodo triggherato pinMode(12, INPUT); // Pin a cui e' connesso il secondo fotodiodo triggherato pinMode(A1,INPUT); // ci leggo la tensione di batteria //Serial.begin(9600); // Inizializzo la porta seriale lcd.clear(); lcd.setCursor(0, 0); lcd.print("CRONOGRAFO V.9.2 "); //Scrivo versione ed autore lcd.setCursor(0, 1); lcd.print("di Pino Grasso"); delay(2000); lcd.clear(); // ripulisco lo schermo e ci scrivo lcd.setCursor(0, 0); // i campi fissi normali sul display lcd.print("m/s= "); lcd.setCursor(0, 1); lcd.print("Temp= "); lcd.setCursor(8, 1); lcd.print("Umid= "); }/*--(Fine setup )---*/ void loop() /*----( LOOP: Gira costantemente)----*/ { Diodo_Uno = 0; // Azzero gli indicatori di evento Diodo_Due = 0; do { if (((B00000001 & (PIND >> 2))) == 0) // Controllo se e'stato pigiato il pulsante di RESET, se è stato premuto calcolo la media e appena ripremuto azzero e mostro la tensione di batteria // il piedino due si trova nel secondo bit del registro PIND // allora sposto o destra di due posizioni tutti i bit del registro, cosi' il primo a destra e'lui // poi faccio un AND logico in binario col il byte 00000001 // e dato che l'AND torna UNO solo se entrambi i bit sono a UNO // leggo lo stato di quel bit. Questa istruzione sostituisce la digitalRead() che impiega troppo tempo { calcola_media(); } } while ((B00000001 & (PIND >> 3)) == 1); // continua a girare fino a quando il pin 3 a cui è collegato il primo fotodiodo sta alto // il piedino tre si trova nel terzo bit del registro PIND // allora sposto o destra di tre posizioni tutti i bit del registro, cosi'il primo a destra e' lui // poi faccio un AND logico in binario col il byte 00000001 // e dato che l'AND torna UNO solo se entrambi i bit sono a UNO // leggo lo stato di quel bit.Questa istruzione sostituisce la digitalRead() che impiega troppo tempo azzera_timer_T2(); // chiamo la funzione che azzera il contatore, questo è il contatore su cui poi si faranno i calcoli Tempo_Start = micros(); // dato che e' uscito dal loop mi segno il tempo dell'evento ed alzo il flag del diodo uno Diodo_Uno = 1; do { // passo ad osservare il secondo fotodiodo // if ((micros() - Tempo_Start ) > 1000000) // Controllo il tempo che passa aspettando un segnale if (leggi_contatoreT2() > 2000000) { break; // se e'passato troppo tempo dal primo evento esco dal ciclo while } // perche' e' una falsa partenza } while ((B00000001 & (PINB >> 4)) == 1); // altrimenti continua il giro fino a quando succede qualcosa anche al diodo due sul pin12 // il piedino dodici si trova nel quarto bit del registro PINB // allora sposto o destra di quattro posizioni tutti i bit del registro, cosi' il primo a destra e' lui // poi faccio un AND logico in binario col il byte 00000001 // e dato che l'AND torna UNO solo se entrambi i bit sono a UNO // leggo lo stato di quel bit.Questa istruzione sostituisce la digitalRead() che impiega troppo tempo Tempo_T2=leggi_contatoreT2(); // E' uscito dal loop perche' ha sentito qualcosa o perche' e' passato troppo tempo e mi segno il tempo Tempo_Stop = micros(); // Lascio il calcolo in micros() per comodita' Tempo = (Tempo_Stop - Tempo_Start); // mi calcolo l'intervallo tra i due eventi if (Tempo < 1000000 && Tempo > 100) // Se il tempo e' maggiore di 100 microsecondi e minore di un secondo { Diodo_Due = 1; // alzo il flag del diodo due perche' qualcosa e' passato davvero } else { Diodo_Due = 0; // altrimenti lo abbasso per un falso allarme } if ((Diodo_Uno == 1) && (Diodo_Due == 1)) // se entrambi i diodi hanno sentito un evento faccio i conti { Metri_Secondo_T2 = ((0.523 * 1000000) / (Tempo_T2/2)); // Calcolo del tempo in base ai click del contatore T2 //che bisogna dividere per due per ottenere i microsecondi // 0.523 e' la distanza tra i fotodiodi V2 = (0.523 * 1000000) / ((Tempo_T2+2)/2); // Calcolo la velocita'  con l'incertezza di 2 click da mezzo microsecondo // se il proiettile, nei microsecondi indicati da Tempo, // ha percorso mezzo metro, quanti metri percorrera'  in un milione di microsecondi ? // Tempo sta a 0.523 come 1000000 sta ad x quindi x=0.523*1000000/(Tempo_T2/2) perche' ogni click vale mezzo us Errore_Metri = Metri_Secondo_T2 - V2; // Errore in metri della misura della velocita'  n=n+1; // n è il contatori dei colpi sparati e parte da zero if (n>10) { // controllo che non siano più di dieci for(x=0; x<=10; x++) { Letture[x]=0; // altrimenti azzero il vettore } n=1; // pongo a 1 il contatore } Letture[n]=Metri_Secondo_T2; // e registro nel vettore la nuova misura come primo colpo di una nuova serie leggi_temperatura(); // Leggo temperatura e umidita' scrivi_sul_display(); // scrivo sul display i valori calcolati e rilevati } } // Chiude il LOOP principale /*-----( Dichiarazioni di funzioni)-----*/ // FUNZIONE CHE SCRIVE SUL DIPLAY void scrivi_sul_display() { lcd.setCursor(0, 0); // Scrivo i campi fissi sul display lcd.print("m/s= "); lcd.setCursor(4, 0); // Cursore alla posizione 4 della prima riga lcd.print(Metri_Secondo_T2); // Scrive la velocita'  rilevata in m/s lcd.setCursor(9, 0); lcd.print("+o-"); lcd.setCursor(13, 0); lcd.print(Errore_Metri); lcd.setCursor(0, 1); // Cursore alla posizione 0 della seconda riga lcd.print(" "); lcd.setCursor(0, 1); lcd.print(n); // scrivo sul display il numero dei colpi lcd.setCursor(2, 1); // Cursore alla posizione 2 della seconda riga lcd.print("T= "); lcd.setCursor(5, 1); // Cursore alla posizione 5 della seconda riga lcd.print(t); // Scrive la temperatura rilevata lcd.setCursor(8, 1); // Cursore alla posizione 8 della seconda riga lcd.print("Umid= "); lcd.setCursor(13, 1); // Cursore alla posizione 13 della seconda riga lcd.print(h); //Scrive l'umidita'  rilevata } // FUNZIONE CHE LEGGE LA TEMPERATURA E L'UMIDITA' void leggi_temperatura() { h = dht.readHumidity(); // Leggo l'umidita'  e la metto in h t = dht.readTemperature(); // Leggo la temperatura in gradi Celsius e la metto in t } // FUNZIONE CHE CALCOLA LA VELOCITA' MEDIA DEI COLPI SPARATI void calcola_media() { for (i=1; i<=n; i++) // n riporta il numero di colpi misurati { Somma=Somma+Letture[i]; // scorro l'array e leggo i valori dei colpi registrati in esso sommandoli dentro Somma } Media=Somma/n; // faccio la media dividendo il totale per il numero di colpi lcd.clear(); // pulisco lo schermo e ci scrivo il risultato lcd.setCursor(0, 0); lcd.print("Media di "); lcd.setCursor(9, 0); lcd.print(n); lcd.setCursor(11, 0); lcd.print(" colpi"); lcd.setCursor(0, 1); lcd.print("m/s = "); lcd.setCursor(6, 1); lcd.print(Media); delay(1000); //aspetto che si levi il dito dal pulsante do{ // Lascio i dati sullo schermo fino a quando non pin2=digitalRead(2); // venga di nuovo pigiato il tasto sul piedino due } while(pin2==1); azzera(); // e chiamo la funzione azzera per pulire tutto e mostrare la V di batteria } void azzera() //FUNZIONE CHE AZZERA TUTTE LE VARIABILI E MOSTRA I VOLT DI BATTERIA { lcd.clear(); // Pulisco lo schermo lcd.setCursor(0, 0); // Posiziono il cursore all'inizio della prima riga lcd.print(" VOLT BATTERIA "); // Scrivo sul display pinA1 = analogRead(A1); // Leggo il piedino analogico 1 Volt = 3*pinA1; // a cui ho applicato la tensione di batteria diviso tre (tre resistenze uguali in serie) Volt=Volt*5/1023; // calcolo i volt corrispondenti lcd.setCursor(0, 1); // posiziono il cursore all'inizio della seconda riga lcd.setCursor(6, 1); // Posiziono il cursore alla sesta posizione della seconda riga lcd.print(Volt); // Scrivo sul display il valore della tensione misurata delay(1000); // Aspetto un secondo per dare modo di leggere quei valori lcd.clear(); // poi ripulisco lo schermo e ci scrivo lcd.setCursor(0, 0); // i campi fissi normali sul display lcd.print("m/s= "); lcd.setCursor(0, 1); lcd.print("Temp= "); lcd.setCursor(8, 1); lcd.print("Umid= "); Metri_Secondo_T2 = 0; // Azzero tutte le variabili Tempo_Start = 0; Tempo_Stop = 0; Tempo = 0; Diodo_Uno = 0; Diodo_Due = 0; t = 0; h = 0; Somma=0; for( x=0; x<10; x++) { // e pulisco il vettore (array) delle letture Letture[x]=0; } n=0; } // Routine dell'interrupt generato dall'overflow del Timer T2 che Conta 255 ogni 128us e poi ricomincia ISR(TIMER2_OVF_vect) // segnale di interrupt che arriva appena il contatore due raggiunge il suo numero massimo (255) { Contatore_degli_overflow++; //incremento il contatore degli overflow } // FUNZIONE CHE LEGGE IL TIMER T2 unsigned long leggi_contatoreT2() { noInterrupts(); //disabilita gli interrupts uint8_t salva_T2 = TCNT2; //salvo il valore attuale del contatore del Timer T2 boolean indicatore_overflow = bitRead(TIFR2,0); //leggo se nel frattempo c'e' stato un overflow if (indicatore_overflow) { //se c'e' stato salvo di nuovo il contenuto attuale del contatore salva_T2 = TCNT2; Contatore_degli_overflow++; //e incremento il contatore degli overflow TIFR2 |= 0b00000001; //azzero l'indicatore di overflow } Conteggi_totali_T2 = Contatore_degli_overflow*256 + salva_T2; //calcola il totale dei clik rilevati (uno ogni mezzo microsecondo) interrupts(); //riabilita gli interrupts return Conteggi_totali_T2; //ritorna il valore calcolato } void azzera_timer_T2() { TCNT2 = 0; //azzero il contatore del Timer T2 TIFR2 |= 0b00000001; //azzero sul Timer T2 l'indicatore di overflow Contatore_degli_overflow = 0; //azzero le altre variabili Conteggi_totali_T2 = 0; } [/code]