Contagiri da 120 a 18000 Giri al Minuto

NE555 Contagiri con Microcontrollore PIC18F per Misurare i Giri al Minuto di un Motore. Dispone di Autosetting per Avere un Valore Preciso da 120 a 18000 Giri…


 
 
 
 




 

INTRO

Per contare i giri al minuto di un motore vi sono due soluzioni, la prima è quella di misurare i giri in un certo periodo di tempo, come ad esempio calcolare i giri in 10  secondi e poi moltiplicare per 6 ottenendo i giri al minuto, l’altra soluzione è quella di misurare il periodo di un segnale con un fronte di salita ad ogni giro e poi ricavare dal periodo i numeri di giri al minuto. La prima soluzione ha lo svantaggio che si misurano i giri medi del motore, anche se necessita un software molto semplice. La seconda soluzione richiede un sistema per autosettare la precisione del sistema visto che se aumenta il numero di giri, diminuisce il tempo tra i fronti di salita e quindi necessita un prescaler sempre più veloce, di contro, se si usa un prescaler fisso molto veloce, se i giri sono pochi al minuto, il timer counter può andare in overflow.

 




 

SEGNALE GENERATO IN BASE AI GIRI

Per avere un segnale periodico che dipende dalla velocità del motore si usa una versione molto semplice di encoder ottico formato da un sensore infrarosso composto da un led infrarosso e un transistor ricevitore infrarosso, in modo tale da creare un raggio infrarosso. Se si polarizza il diodo in modo tale da creare un fascio infrarosso, e se si polarizza il transistor ricevitore, si avrà che quando si interrompe il raggio il transistor è un ramo aperto, se invece non si interrompe il raggio si ha un corto circuito o viceversa, dipende dal tipo utilizzato. Con questo transistor, si può creare una rete di pull up o pull down e avere un segnale alto o basso quando cortocircuitato o viceversa.

Per interrompere il fascio luminoso si possono utilizzare varie soluzioni; la prima, quella in figura, consiste in un disco in qui vi è una finestra o foro. Il disco può essere sia trasparente che nero, l’importante che la finestra o foro sia di diversa composizione dell’intero disco. La soluzione più semplice è quella di avere un disco nero nel quale vi è un solo foro, in questo modo il raggio infrarosso è interrotto normalmente mentre non lo è al passaggio della finestra, generando un segnale simile a quello di figura.

L’altra soluzione sarebbe quella di usare un semicerchio di materiale nero, in questo modo per metà giro il raggio è interrotto e per metà no, creando un segnale con duty cycle di circa il 50%. Un’altra soluzione è quella di avere una linguetta di materiale assorbente sull’asse dal motore in modo tale da avere il raggio sempre presente e interromperlo solo al passaggio di questa linguetta. Il problema di queste soluzioni e che possono squilibrare il motore e creare oscillazioni. Si può adottare qualsiasi soluzione, l’importante è creare un solo fronte di salita ad ogni giro.

Per quanto riguarda il sensore infrarosso, può essere formato da emettitore e ricevitore incapsulati in un unico package, come quelli dei vecchi mouse a rotellina o come quelli delle stampanti, oppure può essere formato da un led infrarossi e un ricevitore. La connessione è in ogni caso quella di figura.

Per quanto riguarda il ricevitore, c’è ne sono di due tipi; il primo tipo può comportarsi da corto circuito se è colpito da raggio infrarosso e circuito aperto in caso contrario, mentre il secondo tipo, ha un comportamento contrario a quello appena descritto. Al fine del progetto non ha importanza quale si usa, vista l’alternanza di fasi con raggio e senza, si viene a creare in ogni caso un segnale ad onda quadra.

 

PRINCIPIO DI FUNZIONAMENTO

Il principio di funzionamento è molto semplice, si va a misurare il tempo tra due fronti di salita e quindi conoscendo questo tempo con la semplice operazione 60/(tempo tra due fronti) si possono conoscere i giri al minuti del motore. Per misurare il tempo tra due fronti si utilizza il modulo Capture con uno dei timer counter presenti. Conoscendo il numero nel contatore, la frequenza e il prescaler si può conoscere il tempo tra due fronti di salita se si resetta il timer counter ad un fronte e si cattura il valore al fronte successivo.

Il problema di questa soluzione è che utilizzando un prescaler fisso si riescono ad avere valori precisi solo per un certo range di giri al minuto. Quindi è necessario un codice che setta il prescaler in base ai giri. Visto che si utilizza un timer counter da 16 bit, il valore massimo contabile è 65535 dopo di che si va in over flow. Se il valore conato è minore della metà del valore contabile, si potrebbe ottenere un valore ancora più preciso dimezzando il prescaler. Se si ha un valore di prescaler basso e il timer counter va in overflow bisogna aumentare il prescaler.

Per conoscere il valore di giri al minuti, la formula è la seguente:


 




 

CODICE

Il codice per realizzare il contagiri è il seguente:

sbit LCD_RS at RB0_bit; //Definizione libreria LCD sbit LCD_EN at RB1_bit; sbit LCD_D4 at RB2_bit; sbit LCD_D5 at RB3_bit; sbit LCD_D6 at RB4_bit; sbit LCD_D7 at RB5_bit; //Fine definizione libreria LCD sbit LCD_RS_Direction at TRISB0_bit; //Configurazione I/O per LCD sbit LCD_EN_Direction at TRISB1_bit; sbit LCD_D4_Direction at TRISB2_bit; sbit LCD_D5_Direction at TRISB3_bit; sbit LCD_D6_Direction at TRISB4_bit; sbit LCD_D7_Direction at TRISB5_bit; //Fine configurazione I/O per LCD unsigned short int Stato; //variabile che tiene conto del cambio di precisione float Giri; //variabile per convertire da conteggio a giri bit E; //bit per eseguire i cambi di stato unsigned int GiriMin; //variabile per contenere il valore di giri char TxtGiri[7]; //testo che contiene i Giri al minuti void display(float Giri){ //subroutine per visualizzare il valore dei giri  GiriMin = Giri; //passo da floating point a intero  WordToStr(GiriMin, TxtGiri); //trasformo da intero a stringa  Lcd_cmd(_LCD_CLEAR); //pulisci lcd  Lcd_out(2, 3, TxtGiri); //visualizzo la stringa  Lcd_out(1, 3, "Giri/min"); //mostra la stringa "giri/min" sulla riga 1  T1CON.TMR1ON = 1; //riattivo il timer counter } //fine subroutine void TMR_INT() iv 0x0008 ics ICS_AUTO { //interrupt di overflow  PORTB.B7 = 1; //accendo il led di overflow  T1CON = 0b10110001; //timer 1 con prescaler 8  CCP1CON = 0b00000101; //capture ogni fronte di salita  TMR1H = 0; //resetto il timer counter 1  TMR1L = 0;  CCPR1 = 0; //resetto il valore di capture  PIR1.CCP1IF = 0; //reset del flag di capture  PIR1.TMR1IF = 0; //resetto il flag di overflow  Stato = 1; //riporto lo Stato a quello iniziale } //fine subroutine interrupt void main() { //programma principale CCP1CON = 0b00000101; //modalità capture ogni fronte di salita TRISB = 0; //portb uscite TRISC.B2 = 1; //ingresso modulo CCP1 Stato = 1; //inizializzo stato=1 (presc 8 e capture ogni fronte) RCON.IPEN = 0; //disabilito la priorità degli interrupt INTCON.GIE = 1; //attivo gli interrupt INTCON.PEIE = 1; //attivo gli interrupt delle periferie PIE1.TMR1IE = 1; //attivo l'interrupt di overflow di tmr1 IPR1.TMR1IP = 0; //disabilito la priorità dell'interrupt Lcd_init(); //inizializza lcd Lcd_cmd(_LCD_CLEAR); //pulisci lcd Lcd_cmd(_LCD_CURSOR_OFF); //disattiva cursore lcd T1CON = 0b10110001; //timer 1 on, clock interno prescaler 8  while(1){ //ciclo infinito  if(PIR1.CCP1IF==1){ //se si ha l'evento di capture  PORTB.B7 = 0; //resetto il led di overflow  PIR1.CCP1IF = 0; //resetto il flag di capture  T1CON.TMR1ON = 0; //tmr1 off per non avere overflow  E = 1;  switch(Stato){ //switch per selezionare lo stato  case 1:while(E==1){ //esegui una volta sola se Stato = 1  if(CCPR1 < 32700){ //se stato=1 e valore piccolo  T1CON = 0b10100001; //timer 1 on, clock interno, prescaler 4  Stato = 2;   } //prescaler equivalente 4  else{ //se il valore è opportuno  Giri = 7500000/CCPR1; //giri = ((1/tempoconteggio*)60)/CCPR1  display(Giri); //visualizza i giri  }  E = 0; //resetta "E" così da non rieseguire  }  case 2:while(E==1){ //esegui una volta sola se Stato=2  if(CCPR1 < 32700){ //se stato=2 e valore piccolo  T1CON = 0b10010001; //timer 1 on, clock interno, prescaler 2  Stato = 3; //stato= 3 (prescaler = 2, captureogni fronte)  } //prewscaler equivalente 2  else{ //se il valore è opportuno  Giri = 15000000/CCPR1; //giri = ((1/tempoconteggio*)60)/CCPR1  display(Giri); //visualizza i giri  }  E = 0; //resetta "E" così da non rieseguire  }  case 3:while(E==1){ //esegui una volta sola se Stato=3  if(CCPR1 < 32700){ //se stato=3 e valore piccolo  T1CON = 0b10000001; //timer 1 on, clock interno, prescaler 1  Stato = 4; //stato= 4 (prescaler = 1, capture ogni fronte)  } //prescaler equivalente 1  else{ //altrimenti se valore opportuno  Giri = 30000000/CCPR1; //giri = ((1/tempoconteggio*)60)/CCPR1  display(Giri); //visualizza i giri  }  E = 0; //resetta "E" così da non rieseguire  }  case 4:while(E==1){ //esegui una volta sola se Stato=2  if(CCPR1 < 32700){ //se stato=4 e valore piccolo  T1CON = 0b10110001; //timer 1 on, clock interno prescaler 8  CCP1CON = 0b00000111; //modalità capture ogni 16 fronte di salita  Stato = 5; //stato= 5 (prescaler = 4, capture ogni fronte)  } //prescaler equivalente 0.5  else{ //se si ha un valore opportuno  Giri = 60000000/CCPR1; //giri = ((1/tempoconteggio*)60)/CCPR1  display(Giri); //visualizza i giri  }  E = 0; //resetta "E" così da non rieseguire  }  case 5:while(E==1){ //esegui una volta sola se Stato=2  if(CCPR1 < 32700){ //se stato=5 e valore piccolo  T1CON = 0b10100001; //timer 1 on, clock interno prescaler 4  CCP1CON = 0b00000111; //modalità capture ogni 16 fronte di salita  Stato = 6;   } //prescaler euivalente 0.25  else{ //se si ha un valore opportuno  Giri = 120000000/CCPR1; //giri = ((1/tempoconteggio*)60)/CCPR1  display(Giri); //visualizza i giri  }  E = 0; //resetta "E" così da non rieseguire  }  case 6:while(E==1){ //esegui una volta sola se Stato=2  if(CCPR1 < 32700){ //se stato=6 e valore piccolo  T1CON = 0b10010001; //timer 1 on, clock interno prescaler 2  CCP1CON = 0b00000111; //modalità capture ogni 16 fronte di salita  Stato = 7; //stato= 7 (prescaler = 4, capture ogni 4 fronti  } //prescaler equivalente 0.125  else{ //altrimenti se si ha un valore opportuno  Giri = 240000000/CCPR1; //giri = ((1/tempoconteggio*)60)/CCPR1  display(Giri); //visualizza i giri  }  E = 0; //resetta "E" così da non rieseguire  }  case 7:while(E==1){ //se sono nell'ultimo stato...  Giri = 480000000/CCPR1; //giri = ((1/tempoconteggio*)60)/CCPR1  display(Giri); //visualizza i giri  E = 0; //resetta "E" così da non rieseguire  }  }  PIR1.CCP1IF = 0; //resetta flag di capture  while(PIR1.CCP1IF == 0 ){ //se non si ha l'inizio di un ciclo  TMR1H = 0; //rimani bloccato in questo ciclo  TMR1L = 0; //e resetta sempre il timer  }  PIR1.CCP1IF = 0; //reseta il flag per iniziare un nuovo ciclo  }//fine if  }//fine ciclo infinito }//fine 

Per visualizzare il valore dei giri al minuto si utilizza un LCD, quindi il primo passo del codice è quello di scrivere la configurazione tra LCD e microcontrollore, e in particolare si utilizza la PORTB. Dopo di che servono alcune variabili, la prima tiene conto di quale prescaler si ha, poi vi è il numero di giri, una variabile per l’esecuzione di una parte di programma, poi si ha la variabile per il valore convertito in giri al minuti e infine vi è il testo per visualizzare il valore di giri.

Poi vi è una subroutine che riceve il numero di giri in floating, lo trasforma in un numero senza virgola e lo trasforma in stringa, infine questa stringa viene visualizzata sull’LCD insieme alla stringa “giri/min” e infine resetta il valore del timer counter.

L’altra subroutine è una subroutine di interrupt,  ovvero dell’interrupt di over flow. Quando si ha over flow si attiva un led che avverte dell’overflow, poi si riporta il prescaler al valore 8 e poi si porta nello stato iniziale e infine  si resettano il timer counter e i flag. Purtroppo nella subroutine di interrupt non è possibile inserire le stringhe per visualizzare l’overflow su LCD, quindi per questo si utilizza il LED.

Nel codice principale si inizializzano le porte, l’interrupt, l’LCD, il timer counter con prescaler 8 e il modulo capture con catturo ad ogni fronte di salita. Dopo di che si ha un ciclo infinito.

Nel ciclo infinito si controlla se si ha un evento di capture. Se questo è avvenuto si va a spegnere il timer counter. Dopo di che si va a controllare lo stato, inizialmente si parte da prescaler 8, dopo di che si va a controllare il valore catturato. Se questo è minore di metà del massimo, potrei ottenere una precisione maggiore dimezzando il prescaler, ed è proprio quello che si fa, e se si setta un prescaler 4 si va nello stato 2. Se il valore è opportuno si va a dividere 750000 ((4000000*60)/4*8) per il valore catturato.

Dopo di che si continua questo controllo finchè non si ha un valore opportuno di prescaler con un valore catturato opportuno.

Purtroppo dentro i case non si riesce ad inserire un if else a meno che non si racchiude tutto in un while. Per fare ciò si utilizza una variabile “E” che viene inizializzata a 1 prima del case e poi viene resettata dopo l’if else.

Finito il case si resetta il flag del modulo capture, visto che durante i processi del case potrebbe avvenire un evento di capture. Finchè il flag è 0 si tiene resettato il timer counter, in questo modo si riesce a contare perfettamente tra due fronti di salita.
 

SCHEMA

Il circuito è il seguente:

Per pilotare il led infrarosso si utilizza un led da 220ohm mentre per pilotare il transistor fotosensibile si utilizza una resistenza di pull up da 1Kohm. Il circuito di oscillazione è formato da un cristallo da 4MHz e due condensatori da 22pF. L’alimentazione è da 5V e vi è la resistenza da 10K che tiene non resettato il microcontrollore. La resistenza RV1 è la resistenza per il contrasto dell’LCD. I pin di alimentazione del microcontrollore sono i pin 8 e 19 per GND mentre 20 per VCC. Il microcontrollore scelto è il PIC18F252 e potrebbe lavorare anche a frequenze più elevate però aumenta il numero di giri minimi e massimi misurabili, mentre se si riduce a frequenza si riduce anche il numero minimo e massimo di giri misurabili.

È inoltre necessario un led con resistenza di protezione sul pin 28 ovvero PB7 se si vuole avere l’informazione di quando si ha overflow. Lo schema realizzato su breadboard è il seguente:


 

DOWNLOAD

Per il download del codice, dell’HEX da inserire nel microcontrollore e per la simulazione cliccate sul seguente LINK!!!





 

5106 Visite totali 53 Visite di oggi
Contagiri da 120 a 18000 Giri al Minuto ultima modifica: 2016-05-30T16:51:07+00:00 da ne555

Lascia un commento

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *