|
|
|
|
#1 |
|
Registered User
|
Contagiri con PIC
Ciao a tutti, non sono un esperto programmatore, sto imparando e vorrei realizzare un contagiri con un PIC. Il modello del PIC utilizzatoè il 16F72.
L'idea è quella di prelevare un segnale impulsivo proveniente da un filo avvolto sul cavo della candela di un motore a scoppio. Ho preso spunto da un contagiri commerciale che ho visto applicato ad un rasaerba e che aveva questo principio di funzionamento. Suppongo che ad ogni giro del motore corrisponda un umpulso di candela che per mutua induzione viene a generale un fem indotta sul filo avvolto. Credo sia questo il principio. Ad ogni modo per provare a fare qualcosa mi sono procurato un frequenzimetro tarato su 50 hz (ho preso un valore a caso) con forma d'onda quadra e ho sfruttato il modulo CCP in modalità "capture" del pic. L'ingresso del pic a cui collegare la forma d'onda quadra è il pin RC2. Vi allego il programma che ho fatto per ora. Vi chiedo scusa per le porcate che posso avere scritto ma mi sto dilettando a tempo perso nella programmazione in mikroC dei PIC. // Inizializzazione LCD su cui visualizzo il numero di giri/min sbit LCD_RS at RB2_bit; sbit LCD_EN at RB3_bit; sbit LCD_D4 at RB4_bit; sbit LCD_D5 at RB5_bit; sbit LCD_D6 at RB6_bit; sbit LCD_D7 at RB7_bit; sbit LCD_RS_Direction at TRISB2_bit; sbit LCD_EN_Direction at TRISB3_bit; sbit LCD_D4_Direction at TRISB4_bit; sbit LCD_D5_Direction at TRISB5_bit; sbit LCD_D6_Direction at TRISB6_bit; sbit LCD_D7_Direction at TRISB7_bit; char txt1[]="RPM"; int ricevuto=0; char pp[16]; char cont=0; int flag_primoInterrupt=1; unsigned int tempo; unsigned int Periodo; volatile unsigned int Giri_min; unsigned char tmp; static unsigned char contatore; //Qui non sò se è giusto perchè ho ragionato di avere due interrupt legati a due fronti di salita per poterne //misurare il periodo void interrupt() { if(PIR1.CCP1IF) { PIR1.CCP1IF=0; //Se è il primo interrupt if(flag_primoInterrupt==1) { //AZZERO ILTIMER1 flag_primoInterrupt=0; TMR1H = 0; TMR1L = 0; PIR1.TMR1IF=0; } else { Periodo = (CCPR1H<<8 + CCPR1L); flag_primoInterrupt = 1; ricevuto=1; } } } void main() { TRISB = 0x01; PORTB = 0xFE; TRISC2_bit=1; RC2_bit = 0; //Settaggio interrupt INTCON=0xC0; PIE1.CCP1IE = 1; T1CON = 0x31; CCP1CON = 0x05; PIE1.TMR1IE = 1; Lcd_Init(); // Initialize LCD Lcd_Cmd(_LCD_CLEAR); // Clear display Lcd_Cmd(_LCD_CURSOR_OFF); // Cursor off Lcd_Out(1,1,txt1); // Write text in first row while(1) { if(ricevuto==1) { Giri_min=(1/Periodo)*60; ByteToStr(Giri_min,pp); Lcd_Out(2,1,pp); // Write text in first row ricevuto=0; } } A questo punto collego l'uscita del frequenzimetro al pin RC2 del PIC e ciò che visualizzo sull'LCD è un numero fisso pari a 196. Anche se cambio frequenza leggo sempre quel valore appena collego il pin RC2 del PIC. Il microcontrollore ha un quarzo esterno a 4Mhz. Vorrei sapere se possibile capire dove sto sbagliando. Saluti |
|
|
|
|
|
#2 |
|
Credendo Vites
|
Non posso correggerti il codice perchè usi un linguaggio che non conosco, comunque attento che non avrai un impulso ad ogni rotazione del motore, ma ci sono costanti moltiplicative di mezzo, ad esempio se il motore è quattro tempi avrai (mi pare) quattro impulsi ogni giro completo dell'albero, parimenti se è un due tempi avrai (sempre mi pare) due impulsi per giro.
__________________Non solo, ma credo che il numero di scintille della candela è funzione anche del rapporto di riduzione del volano. In pratica fai prima a mettere una coppia di trasmettitore luminoso, e relativo ricevitore sulla cinghia di trasmissione (con la macchina in folle, freno a mano tirato e numero di giri minimo, quindi non accelerata), poi conti il numero di impulsi che hai sul tuo accoppiamento induttivo e con una semplice divisione hai il rapporto di conversione.
Il tempo è il miglior maestro, purtroppo uccide tutti i suoi allievi.
|
|
|
|
|
|
#3 |
|
Registered User
|
Ah ok, è che più che un'auto mi serviva per un motore a scoppio di un rasaerba (è un due tempi). Comunque pensavo fosse un impulso candela ad ogni giro e ti ringrazio per la delucidazione.
A titolo informativo il codice è in C scritto con il pacchetto software mikroC. Per ora ti ringrazio. Saluti |
|
|
|
|
|
#4 |
|
Registered User
|
facciamo un po di teoria.......
se ho un motore a 4 tempi, avrò per ogni cilindro uno scoppio ogni due risalite del pistone, e quindi unio scoppio ogni 2 giri. occhio però che dipende da quante bobine ci sono sul motore, se ho una bobina per tutti i cilindri le cose stanno così, (beninteso leggendo il file della bobina dopo lo spinterogeno), se invecie ci sono due cilindri per ogni bobina ovviamente la scintilla sarà una per giro. se leggo invecie un motore a 2 tempi, avrò uno scoppio ogni risalita del pistone, percui una scintilla al giro, solitamente sono ad 1 cilindro, se multicilindri valgono le considrazioni precedenti. |
|
|
|
|
|
#5 |
|
Tecnico ERMETICO!
|
Anche in molti motori a 4 tempi si manda 1 scintilla per giro,per questione di semplicità,si chiama scintilla persa,che si usa anche oggi nelle autovetture moderne.
__________________ |
|
|
|
|
|
#6 |
|
RockModerator
|
Innanzitutto mi accerterei che i valori letti CCP1RH e CCP1RL variano con il variare della frequenza applicata su RC2, magari visualizzando separatamente il valore dei due registri. Solo dopo mi preoccuperei dei fattori correttivi, come ad esempio il numero di impulsi per giro ecc..
__________________ |
|
|
|
|
|
#7 | |
|
Registered User
|
Quote:
se invecie ci sono due cilindri per ogni bobina ovviamente la scintilla sarà una per giro. mi pare che sia così. |
|
|
|
|
|
|
#9 |
|
Registered User
|
OK.
non conosco il tipo di compilatore da te usato, per cui la sintassi non mi sembra chiara, comunque non capisco questa riga: Periodo = (CCPR1H<<8 + CCPR1L); suppongo che CCPR1H e CCPR1L siano due varibili, e potrei pensare che siano di 8 bit, nel qualcaso pesarei anche che sia errato scorrere di 8bit un valore in una variabile di 8 bit, lo porterei a zero. |
|
|
|
|
|
#10 |
|
Registered User
|
Eccomi. Scusate per l'assenza. Intanto vi ringrazione tutti per le risposte. Sono riuscito a far funzionare il circuito anche se non è una soluzione molto "tecnica". Diciamo che alla fine il risultato l'ho un pò forzato, nel senso che faccio molta fatica a filtrare il segnale e quindi i valori visualizzati sul display variano troppo rapidamente. Con una serie di "IF" ho stabilizzato meglio il segnale. Ad ogni modo su un piccolo rasaerba a due tempi questo programmino funziona. Non dico sia un bel programma perchè come programmatore sono molto scarso, però al momento mi funziona. Se capisco come ottimizzare il programma ve lo dico. Ad ogni modo ogni idea o suggerimento è ben accetta. Vi allego il programma che ho riscritto nel caso a qualcuno possa servire per prendere qualche spunto. Grazie a tutti. Alla prossima.
// Inizializzazione LCD su cui indicare i giri/min sbit LCD_RS at RB2_bit; sbit LCD_EN at RB3_bit; sbit LCD_D4 at RB4_bit; sbit LCD_D5 at RB5_bit; sbit LCD_D6 at RB6_bit; sbit LCD_D7 at RB7_bit; sbit LCD_RS_Direction at TRISB2_bit; sbit LCD_EN_Direction at TRISB3_bit; sbit LCD_D4_Direction at TRISB4_bit; sbit LCD_D5_Direction at TRISB5_bit; sbit LCD_D6_Direction at TRISB6_bit; sbit LCD_D7_Direction at TRISB7_bit; char txt1[]="Tachometer"; char txt2[]="wait..."; char txt3[]="RPM"; int ricevuto=0; char pp[16]; char cont=0; int flag_primoInterrupt=1; unsigned int tempo; unsigned long Periodo; unsigned long Giri_min; unsigned char tmp; static unsigned char contatore; unsigned tOld, tNew; char th,tl; char edge = 0; char capture = 0; unsigned tword,tword2; char txt[6]; void interrupt() { if(PIR1.CCP1IF){ if(!edge){ tOld = (256*CCPR1H)+CCPR1L; edge = 1; }else{ tNew = (256*CCPR1H)+CCPR1L; capture = 1; // completa capture edge = 0; } PIR1.CCP1IF = 0; //clear CCP flag } } void main() { char i; TRISB = 0x01; PORTB = 0xFE; //Settaggio interrupt CCP1CON = 0x05; // Capture mode every rising edge TRISC.F2 = 1; // RC2 come input T1CON = 0x01; // timer1 ON, internal clock Fosc/4, prescaler 1:1 INTCON.GIE = 1; INTCON.PEIE =1; PIE1.CCP1IE = 1; // enable interrupt capture PIR1.CCP1IF = 0; //clear CCP flag //PIE1 = 0; // PIE1.TMR1IE = 1; //INTCON.GIE=1; //INTCON.INTE=1; Lcd_Init(); // Inizializza LCD Lcd_Cmd(_LCD_CLEAR); // Clear display Lcd_Cmd(_LCD_CURSOR_OFF); // Cursor off Lcd_Out(1,1,txt3); // Scrive il testo nella prima riga while(1){ if(capture){ PIE1.CCP1IE = 0; // Disabilita interrupt mentre processo capture = 0; // clear flag // Calcola periodo tra due impulsi successivi tword = ~tOld + tNew+1; tword2=(1/((tword/2)*0.000002))*60; tword2=tword2/10; if(tword2<=500) tword2=500; if((tword2>500)&&(tword2<=1000)) tword2=1000; if((tword2>1000)&&(tword2<=1500)) tword2=1500; if((tword2>1500)&&(tword2<=2000)) tword2=2000; if((tword2>2000)&&(tword2<=2500)) tword2=2500; if((tword2>2500)&&(tword2<=3000)) tword2=3000; if((tword2>3000)&&(tword2<=3500)) tword2=3500; if((tword2>3500)&&(tword2<=4000)) tword2=4000; if((tword2>4000)&&(tword2<=4500)) tword2=4500; if((tword2>4500)&&(tword2<=5000)) tword2=5000; if((tword2>5000)&&(tword2<=5500)) tword2=5500; if((tword2>5500)&&(tword2<=6000)) tword2=6000; if((tword2>6000)&&(tword2<=6500)) tword2=6500; if((tword2>6500)&&(tword2<=7000)) tword2=7000; if((tword2>7000)&&(tword2<=7500)) tword2=7500; if((tword2>7500)&&(tword2<=8000)) tword2=8000; if((tword2>8000)&&(tword2<=8500)) tword2=8500; if((tword2>8500)&&(tword2<=9000)) tword2=9000; if((tword2>9000)&&(tword2<=9500)) tword2=9500; if((tword2>9500)&&(tword2<=10000)) tword2=10000; if((tword2>10000)&&(tword2<=10500)) tword2=10500; if((tword2>10500)&&(tword2<=11000)) tword2=11000; if((tword2>11000)&&(tword2<=11500)) tword2=11500; if((tword2>11500)&&(tword2<=12000)) tword2=12000; if((tword2>12000)&&(tword2<=12500)) tword2=12500; if(tword2>12500) tword2=13000; WordToStr(tword2, txt); // converte in stringa Lcd_Out(2,1,txt); delay_ms(100); PIR1.CCP1IF = 0; //clear CCP flag delay_ms(300); PIE1.CCP1IE = 1; // enable interrupt } } } Ultima Modifica di mfsaul : 14-04-2011 09.14.39. |
|
|
|
|
|
#11 |
|
Registered User
|
io userei una variabile, alla quale incrementeri 1 oppure decrementerei 1 a seconda che il numero dei giri letto sia superiore oppure inferiore al valore della variaile in quel momento, ottenendo di fatto una media dei valori letti, la cui velocità di variazione è funzione dalla velocità con cui la aggiorni.
|
|
|
|
|
|
#12 | |
|
Registered User
|
Quote:
Codice:
#define INCREM 500
for(udummy=INCREM;udummy<=13000;udummy+=INCREM){
if(tword2<=udummy){
tword2=udummy;
break; // Esce dal ciclo for.
}
}
Camillo
Internet ti fa vedere tutto ma non ti fa toccare niente. (Camillo Ferrari) |
|
|
|
|
|
|
#13 | ||
|
Registered User
|
Quote:
Quote:
|
||
|
|
|
![]() |
Per le vostre immagini su questo forum potete usare PcTunerUp! Iscriviti gratuitamente alla nostra newsletter. |
| Utenti attualmente attivi che stanno leggendo questa discussione: 1 (0 utenti e 1 visitatori) | |
| Strumenti Discussione | |
| Modalità Visualizzazione | |
|
|