//timer per esperienza misura della velocita' del suono // costruita intorno ad un pic16f628A // Versione 1.2 aprile 2012 d:\didas\espsuono\crono\crono.c #include #include // queste sono 3 macro per cambiare il valore di un bit #define bitset(var, bitno) ((var) |= 1UL << (bitno)) #define bitclr(var, bitno) ((var) &= ~(1UL << (bitno))) #define testbit(data,bitno) ((data>>bitno)&0x01) //registro di configurazione del PIC __CONFIG(PWRTEN & LVPDIS & WDTDIS & UNPROTECT & MCLREN & LVPDIS & XT & BOREN); #define _XTAL_FREQ 4000000 // il clock e' a 4 MHz #define start 7 // bit 7 (porta B) #define stop 3 // ricordati PORTA, 5 e' clear #define migliaia 4 //bit che controlla transistor del bit delle migliaia #define centinaia 3 #define decine 2 #define unita 1 void converti(); void manda(); void B2_BCD(); unsigned char tmp, tmpout; unsigned char temp, H_byte, L_byte; unsigned char mig, cent, dec, unit; // start_ok e' un bit settato dalla routine di interrupt per segnalare // al main che c'e' stato uno start ed il timer ha iniziato a contare // ricordatevi di resettarlo dopo lo stop se dovete reiniziare la procedura unsigned char start_ok; unsigned int contatore; main(){ // qui inizia il programma inizia: OPTION =0; CMCON = 7; TRISA = 0x20; // porta A usata per pilotare il catodo dei display e segmento A TRISB = 0x88; // porta B usata per start, stop e per bit display (out) // registro di configurazione: no pull-up, interrupt on falling edge rb0, // tmr0 incrementato da clock interno, incremento sul fronte in salita del clock // prescaler assegnato a tmr0, rapporto 1/2. // queste opzioni sono quasi tutte inutili per noi PR2 = 0XFF; PIE1 = 0; PCON = 8; // 4MHz, brown out detect VRCON= 0; // non uso tensione di riferimento T1CON =0; T2CON =0; // timer 2 non usato PIR1 =0; // non serve, azzerato per sicurezza CCP1CON =4; // usero' il "capture mode" TMR1L =6; // tengo conto del ritardo alla partenza TMR1H =0; CCPR1L = CCPR1H=0; INTCON =8; // disabilito tutti gli interrupt tranne port change // successivamente dovro' abilitare gli interrupt globalmente // (bit 7 di INTCON) PORTA =0; // azzero porta A e B PORTB =0; start_ok = 0; converti(); bitset (PORTA, unita); manda(); while (testbit(PORTB, start)) __delay_ms(1); __delay_ms(1); // debouncing while (!testbit(PORTB, stop)) __delay_ms(1); __delay_ms(1); // debouncing // adesso siamo pronti a lavorare: abilito interrupt e annullo i flag INTCON = 0x88; // aspetto lo start while (!start_ok) { asm ("nop"); // non faccio nulla } di(); // impedisco altri interrupt // lo stop deve essere ancora basso, se non lo e' reset per sicurezza if (!testbit(PORTB, stop)) goto inizia; // reset while (testbit(PORTB, stop)) // stop a 0 ? { asm ("nop"); // non ancora } // e' arrivato lo stop H_byte = CCPR1H; // salviamo il risultato L_byte = CCPR1L; bitclr (T1CON, 0); // fermo timer1 CCPR1H = CCPR1L =0; bitclr (PORTA, unita); // spengo tutto B2_BCD(); // convertiamo in decimale (BCD packed) while (1) // loop senza fine per mostrare il risultato sul display { tmp = unit; converti(); manda(); bitset(PORTA, unita); //accendo le unita' bitclr(PORTA, migliaia); // spengo le migliaia __delay_ms(1); // aspetto 1 ms // idem con le decine tmp = dec; converti(); manda(); bitclr (PORTA, unita); bitset(PORTA, decine); __delay_ms(1); tmp = cent; converti(); manda(); bitset(PORTA, centinaia); bitclr(PORTA, decine); __delay_ms(1); tmp = mig; converti(); manda(); bitclr(PORTA, centinaia); bitset (PORTA, migliaia); __delay_ms(1); } } void converti() { // converte una cifra decimale 0-9 nella corrispondente // configurazione del display 7 segment // segmento a su RB7, b su RB6, RB3 non usato, g su RB0. switch (tmp) { case 0: tmpout = 0x77; // 0 return; case 1: tmpout = 0x12; // 1 return; case 2: tmpout = 0xB5; // 2 return; case 3: tmpout = 0xB3; // 3 return; case 4: tmpout = 0xD2; //4 return; case 5: tmpout = 0xE3; // 5 return; case 6: tmpout = 0xE7; // 6 return; case 7: tmpout = 0x32; // 7 return; case 8: tmpout = 0xF7; // 8 return; case 9: tmpout = 0xF2; // 9 return; // compare una E per indicare l'overflow default: tmpout = 0xE5; // E return; } } void manda() { // accendo i 7 segmenti, 6 segmenti sono sulla porta B // il segmento A e' su PORTA, 0 PORTB = tmpout; if (testbit(tmpout, 7)) bitset (PORTA, 0); // lo metto a 1 else bitclr(PORTA,0); // lo azzero return; } void interrupt isr() { unsigned int dummy; // routine di interrupt PORTB = 0; // spengo il display (per debug) if (INTCON & 0x01) // se bit RBIF ==1 { bitset (T1CON,0); //faccio partire il timer dummy = PORTB; //leggo la porta per annullare il cambiamento del bit bitclr (INTCON, 0); // azzero il flag di interrupt start_ok =1; return; } // questa seconda parte e' inutile (verificare) // e' arrivato lo stop, non faccio nulla INTCON = 8; // non riabilito interrupt, dovro' dare reset return; } void B2_BCD() { // estrae le cifre decimali da contatore (cioe' il timer contatore = (unsigned int)H_byte<<8 | (unsigned int)L_byte; // sarebbe opportuno migliorarla in caso di overflow // cioe' contatore > 9999 mig = contatore / 1000; cent = (contatore/100) % 10; dec = (contatore/10) % 10; unit = contatore % 10; return; } // per distinguere i programmi scrivo nella EEPROM // autore e data. // "V1.2 F.F. - Aprile 2012 ",0 // 8 byte per riga __EEPROM_DATA('V', '1', '.', '2', ' ', 'F', '.', 'F'); __EEPROM_DATA('2', '5', '/', '4', ' ', '2', '0', '1'); __EEPROM_DATA('2', 0,0,0,0,0,0,0);