/* Test Program to evaluate T1 Capture performance Input configured for falling edge detection Application Requirement Range is 1ms-10s T1 clocked at 16MHz Capture input (coupled with 4n7 and 1K Pullup) Input using D8 (PB0) pin Calibrated TTL Test Generator with 0.1Hz-100kHz Output range 24-01-29 V1.08 Borrowed Code: ------------------------------------------------------------------------------------ Michael suggested to use his Capture Method used in his frequency measureing boards imported from: (FMETER_LED328.c) https://www.mikrocontroller.net/topic/563902#7591430 Am Capture-Wert (ICR1) kann man erkennen, wie es um den Überlauf steht. Ist der Wert im Bereich 0x8000 - 0xffff kann in der letzten Zeit kein Überlauf stattgefunden haben. Das OVF-Flag kann unbeachtet bleiben. Wird ICR1 als 0x0000 - 0x7fff gelesen und OVF_Flag ist gesetzt, dann ist die OVF-ISR zurückgestellt (pending) und wird erst nach der CAPT-ISR ausgeführt. In der CAPT-ISR wird daher der Zeitpunkt (korrigierend) um 0x10000 erhöht, obwohl T1OVF_ctr noch um 1 zu klein ist. Nach Verlassen der CAPT-ISR wird die OVF-ISR ausgeführt und T1OVF_ctr++ ausgeführt. Dann passt wieder alles zusammen. Damit das ungestört ablaufen kann, darf man weder das OVF-Flag noch T1OVF_ctr in der CAPT-ISR manipulieren oder löschen. Die Bereichsgrenze 0x8000 von ICR1 ist so gewählt, daß auch eine lange Interruptsperre nicht stört. Timer1 ist somit recht 'geduldig'. Bei einem 8-Bit Timer ist die Bereichsgrenze mit 0x80 deutlich kritischer, da bei einem 16 MHz Timer schon nach 8 µs ISR-Sperre ein gesetztes OVF-Flag nicht mehr eindeutig zugeordnet werden kann. Webseite: http://www.mino-elektronik.de */ // Setups for Michaels Code enum status {MESSEN=0, AUSLESEN, AUSWERTEN}; // die Phasen der Messung volatile uint8_t messwert_vorhanden, // nur gueltige Messungen anzeigen mess_status; // Ablaufsteuerung volatile uint16_t zeit_low, // Timer1-Anteil zeit_high, // T1 Ueberlauf-Anteil mess_dauer, // minimale Wartezeit ueberlauf; volatile uint32_t start_ereignis, // Impulse zu Beginn der Messung end_ereignis, // Impulse am Ende der Messung start_zeit, // rel. Zeit: Beginn der Messung end_zeit, // Zeitpunkt der Auswertung mess_zeit, // genaue Zeit der Messung mess_ereignisse; // Impulse der Messung const unsigned long period = 1; // RESULTS INTERVALL (angepasst an Michaels Timing) const unsigned long period2 = 25; // unsigned long startMillis; unsigned long startMillis2; unsigned long currentMillis; #define ICP_INPUT 8 volatile unsigned long old_T1OVF_Ctr = 0; volatile unsigned long ICP_val = 0; volatile unsigned long T1OVF_Ctr = 0; bool bMEASUREMENT_READY = false; #define NUM_AVG 192UL #define LM335_TRIM 1.2 #define LM335_KELVIN_OFFSET 2.732 // Correct Pro-Mini Board XTAL trimming as measured against high accuracy standard // FSG7 (0.1Hz - 100kHz) // PM board runs at 15.999608 MHz, 23.5 DEGC #define TIMEBASE_TRIM 1.00002435 #define TIMEBASE_TRIM_INV 1.0 / TIMEBASE_TRIM //0.9999755006 #define XTAL_CALIBRATED 16000000.0 * TIMEBASE_TRIM float scale = (float) NUM_AVG * 1024.0; /****************************************************************************** *Function: void init_InputCapture() *Description: setup for ICP *Parameters: None *Return Value: None ******************************************************************************/ void init_InputCapture() { TCCR1A = 0; TCCR1B = 0; TIMSK1 = 0; TCNT1 = 0; // ICNC1 ICES1 – WGM13 WGM12 CS12 CS11 CS10 TCCR1B = (1<= period) { mess_dauer++; // ungefaehre Dauer der Messung startMillis = currentMillis; } michael_control(); // Michaels measurement code in here } float frequenz; // float-Ergebnis float f_clock; // ggf. mit Korrekturwert #define F_CPU 16000000L // 16MHz ggf. anpassen /****************************************************************************** *Function: void michael_setup() *Description: *Parameters: None *Return Value: None ******************************************************************************/ void michael_setup() { mess_status = MESSEN; // zuerst messen messwert_vorhanden = 0; // 1.Ergebnis unterdruecken, da es falsch ist f_clock = F_CPU; } /****************************************************************************** *Function: ISR(TIMER1_OVF_vect) *Description: *Parameters: None *Return Value: None ******************************************************************************/ ISR(TIMER1_OVF_vect) { ueberlauf++; // Ueberlaeufe von T1 ergeben obere 16bit der Messzeit } /****************************************************************************** *Function: ISR(TIMER1_CAPT_vect) *Description: *Parameters: None *Return Value: None ******************************************************************************/ ISR(TIMER1_CAPT_vect) // Eingangsimpulse mit genauem Zeitpunkt erfassen { static unsigned long count; // Impulse per Interrupt count++; if(mess_status == AUSLESEN) { // Ergebnisse synchron zum Eingangsimpuls auslesen+ablegen end_ereignis = count; // Anzahl der Impulse lesen zeit_low = ICR1; // capture-reg lesen: untere 16bit zeit_high = ueberlauf; // dazu die oberen 16bit if((TIFR1 & 1< TIMEOUT ) { // Messung abbrechen mess_dauer = 0; sei(); messwert_vorhanden = 0; // nächstes Ergebnis verwerfen Serial.println("Timeout"); } cli(); if( ( mess_status == MESSEN ) && ( mess_dauer >= MESSZEIT ) ) { mess_status = AUSLESEN; // Auswertung starten mess_dauer = 0; // neue Messzeit abwarten } sei(); if( mess_status == AUSWERTEN ) { end_zeit = zeit_high * 0x10000 + zeit_low; mess_zeit = end_zeit - start_zeit; // Zeit-Differenz bilden start_zeit = end_zeit; // neue startzeit merken mess_ereignisse = end_ereignis - start_ereignis; // Impuls-Differenz start_ereignis = end_ereignis; // fuers naechste Intervall mess_status = MESSEN; // neue Messung beginnen if( messwert_vorhanden ) // und gültigen Wert anzeigen { Serial.print(cnt++); frequenz = ((float) mess_ereignisse * f_clock) / mess_zeit; Serial.print(","); Serial.println(frequenz,7); } else { messwert_vorhanden = 1; // sperre wieder aufheben } } } /* EE 146 SZ 198499776 ZH 3541 EZ 232100602 MZ 33600826 SZ 198499776 ME 21 SE 125 5,21 */ /****************************************************************************** *Function: void InputCapture() *Description: *Parameters: None *Return Value: None ******************************************************************************/ /* void InputCapture_out() { static long cnt=0; double Freq = 0.0; static uint8_t i=0; uint8_t statusbyte = 0; static uint32_t Accumulator = 0; static uint32_t sensorValue = 610 * NUM_AVG ; char buff[10]; double ftemp = 16000000; static float degc = 0; currentMillis = millis(); if ( (currentMillis - startMillis2) >= period2) { // LM335 Sensor acquisition with averaging Accumulator += analogRead(A0); if(++i == NUM_AVG) { i=0; Accumulator += NUM_AVG / 2; sensorValue = Accumulator; Accumulator = 0; } startMillis2 = currentMillis; degc = sensorValue * (5.0 / scale); degc = degc - LM335_KELVIN_OFFSET; // Subtract 273.2 DEG from result degc = degc * 100.0; // Multiplier to get DEGC degc = degc - LM335_TRIM; // Instead of LM335 Trim Pot } // Run printouts at defined intervalls //if ( (currentMillis - startMillis) >= period) if( (bMEASUREMENT_READY == true) && ( (currentMillis - startMillis) >= period) ) { bMEASUREMENT_READY = false; if(ICP_val > 0){ ftemp = (double) ICP_val; Freq = XTAL_CALIBRATED / ftemp; // Correct for AVR XTAL tolerance at 23.5 DEGC ftemp = ftemp * TIMEBASE_TRIM_INV; // Correct for AVR XTAL tolerance } // Flag a missed OVF in 1 Hz range if(Freq > 1.000001) { statusbyte = 1; }else{ statusbyte = 0; } Serial.print(cnt++); Serial.print(","); Serial.print(ftemp,1); Serial.print(","); Serial.print(T1OVF_Ctr/65536UL); Serial.print(","); Serial.print(Freq, 7); Serial.print(","); Serial.print(degc, 2); Serial.print(","); Serial.println(statusbyte); startMillis = currentMillis; } } */ /****************************************************************************** *Function: ISR(TIMER1_OVF_vect) *Description: Keep track of overflows from T1 counter *Parameters: None *Return Value: None ******************************************************************************/ /* ISR(TIMER1_OVF_vect) { T1OVF_Ctr += 65536UL; // Add 16-bit overflow to current value } */ /****************************************************************************** *Function: ISR(TIMER1_CAPT_vect) *Description: respond to ICP transitions and compute result *Parameters: Return global: Freq, ICP_val *Return Value: None ******************************************************************************/ /* ISR(TIMER1_CAPT_vect) { static uint8_t toggle = 0; static uint32_t TL; uint32_t TD, TH; if(!toggle) { // First Capture Event old_T1OVF_Ctr = T1OVF_Ctr; // Record value of OVF-Ctr at begin of measurement TL = ICR1; // Get current 16-bit Captured count from T1 toggle = 1; // After start capture, switch to end capture logic }else{ // end capture event TH = ICR1; // Get currend end-period capture value // Calculate total period count TD = TH + ( T1OVF_Ctr - old_T1OVF_Ctr ) - TL; ICP_val = TD; toggle = 0; // Synchronize read of data with production bMEASUREMENT_READY = true; } } */