/* Beispielprogramm 'reziproker Frequenzzaehler' mit GPS-Signal stabilisiert fuer ATmega162 und IAR-Kickstart: Berechnung mit 64-bit double! Funktionsbereich mit Vorteiler 0,004Hz - >50MHz bei 16MHz Prozessortakt Neben der üblichen Frequenzmessung an ICP1 wird zusätzlich über ICP3 die interne Taktfrequenz anhand eines 1pps GPS-Signals ermittelt und für die genaue Auswertung der Frequenz verwendet. Hierzu muß das GPS-Signal über min. 4 Sekunden stabil anliegen und wird über 4 Intervalle gefiltert. Fehlt dieses Signal, wird der zuletzt errechnete Wert von 'ref_frequenz' verwendet. Wird es wieder erfasst, muß es ueber 4 Perioden stabil (+/- 100ppm) anliegen. Das Programm ist mit IAR-Kichstart 5.0 entwickelt; die 'fuses' für XTAL (16MHz) müssen gesetzt und CKDIV8 gelöscht sein; BOD sollte auf 4,3V eingestellt sein. http://www.mino-elektronik.de Alle Angaben wie immer ohne Gewaehr ! 2011-12-14 */ #define nTEST_LAUF // testweise die int. Taktfrequenz anzeigen #define F_CPU 16000000 // 16MHz ggf. an eff.Frequenz anpassen #define VORTEILER_FAKTOR 256 // fuer 74HC393 #define ENABLE_BIT_DEFINITIONS #include #include #define MIN_REF (F_CPU - (F_CPU/10000l)) // -100ppm #define MAX_REF (F_CPU + (F_CPU/10000l)) // +100ppm #define T3_FIL_LEN 4 // gleitenden Mittelwert ueber 4s bilden #define GPS_TIMEOUT 250 // Referenzfrequenz zu klein / fehlt #define STELLEN 7 // angezeigte Stellen, max. Auflösung #define MESSZEIT 100 // max. 2,5 Messungen/Sek. (100 x 4,1ms) #define ZEIT_100MS 25 // 0,1 Sek. (25 x 4,1ms) #define FERTIG_LED_BIT 5 // PORTD.5 #define GPS_LED_BIT 6 // PORTD.6 #define VORTEILER_LED_BIT 7 // PORTD.7 #define VORTEILER_AKTIV (ACSR & (1< PortA.3 temp |= c>>4; PORTA = temp; lcd_impuls(); } void lcd_out(char z,char mode) // Ausgabe von Daten (mode==1) oder CMDs (mode==0) { if(mode) PORTA |= (1<= 0.001) { // 1mHz ist Untergrenze if(zeige_periode) { x = 1/x; // Kehrwert bilden dimension=5; // und in Sekunden als Dimension } while(x<1.0) {x*=1000.0;dimension++;} // in den Hz-Bereich bringen while(x>=1000.0) {x*=0.001;dimension--;} while(x >= 10.0) { x *= 0.1; dez_punkt++; } } else { x = 0.0; // sonst 0.000000 Hz ausgeben } if(stellen == STELLEN) { // nur bei regulaerer Ausgabe x += 5e-7; // runden if(x >= 10.0) { // Ueberlauf bei Rundung x *= 0.1; dez_punkt++; if(dez_punkt > 2) { // Ueberlauf der Dimension dimension--; dez_punkt = 0; } } } for(i=0;i= ZEIT_100MS) { n = 0; sync_flag = 1; // ca. alle 100ms } if(fertig_led_cnt) { // 'Messung fertig' fertig_led_cnt--; // LED Einschaltdauer abzaehlen PORTD |= 1<= GPS_TIMEOUT) { // 1Hz-Referenz fehlt t3_tout_cnt = 0; t3_timeout = 1; // und registrieren } } #pragma vector = TIMER3_CAPT_vect __interrupt void t3capt_int() // Eingangsimpulse mit genauem Zeitpunkt erfassen { t3_zeit_low = ICR3; // capture-reg lesen: untere 16bit t3_zeit_high = t3_ueberlauf; // dazu die oberen 16bit if((ETIFR & 1< MIN_REF) { // im Bereich +/- 100ppm t3_fil_sum -= t3_fil[t3_fil_index]; // letzen Wert abziehen t3_fil_sum += temp_frequenz; // neuen Wert addieren t3_fil[t3_fil_index++] = temp_frequenz; // und ablegen if(t3_fil_index >= T3_FIL_LEN) t3_fil_index = 0; t3_fil_cnt++; // mitzaehlen, ob Filter 'gefuellt' if(t3_fil_cnt >= T3_FIL_LEN) { // Filter ist 'eingeschwungen' t3_fil_cnt = T3_FIL_LEN; // nicht weiter zaehlen ref_frequenz = ((double)t3_fil_sum) / T3_FIL_LEN; // Mittelwert verwenden gps_led_cnt = GPS_TIMEOUT; // Dauerlicht durch Nachtriggern } else { gps_led_cnt = GPS_TIMEOUT/3; // Blinken, wenn Filter noch nicht voll ist } } #ifdef TEST_LAUF // nur bedingt anzeigen lcd_cmd(ZEILE2+4); // 2.Zeile, 6.Spalte zeige_x(ref_frequenz,0,9); // Quarzfrequenz mit 8 Stellen anzeigen #endif } } // Hauptprogramm __task main(void) // fuer main() keine Register retten { char temp; unsigned long mess_zeit, mess_ereignisse; PORTE = 0x1; // Pullup ICP1-Eingang PORTD = 0x8; // Pullup ICP3-Eingang DDRA = 0x3f; // fuer Lc-Anzeige DDRD = 0xe0; // fuer LEDs TCCR0 = 0x07; // T0 zaehlt Impulse des Vorteilers init_lcd(); ref_frequenz = F_CPU; // startwert ACSR |= 1< 40) { // Vorteiler ab ca. 100kHz zuschalten PORTD |= 1<= MESSZEIT) { mess_status=AUSLESEN; // Auswertung starten mess_dauer = 0; // wieder Messzeit abwarten } TIMSK |= 1<