/* 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-31 V1.08D History: 24-01-30 V1.08D Added Auto Ranging of sigificant digits Added "GATE" LED Borrowed Code: ------------------------------------------------------------------------------------ Michael Novak suggested to use his Capture Method used in his frequency measureing boards Clara-Zetkin-Straße 6, D - 15370 Petershagen / Berlin, Tel. +49 (0)33439 / 82686 Webseite: http://www.mino-elektronik.de Code adapted/imported from: (FMETER_LED328.c) See also: https://www.mikrocontroller.net/topic/563902#7591430 Funktionsbeschreibung: ====================== 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. https://github.com/JChristensen/movingAvg/tree/master */ #include // https://github.com/JChristensen/movingAvg movingAvg avgTemp(16); // define the moving average object // 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 float frequenz; // float-Ergebnis float f_clock; // ggf. mit Korrekturwert const unsigned long period = 1; // RESULTS INTERVALL (angepasst an Michaels Timing) const unsigned long period2 = 5; // Temperature acquisition intervall unsigned long startMillis; unsigned long startMillis2; unsigned long currentMillis; unsigned long currentMillis2; #define ICP_INPUT 8 // Signal Input Pin #define LED_D13 13 #define NUM_AVG 256UL #define LM335_TRIM 1 #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.9996048 MHz, 23 DEGC #define TIMEBASE_TRIM 1.00002435 #define TIMEBASE_TRIM_INV 1.0 / TIMEBASE_TRIM //0.9999755006 #define XTAL_CALIBRATED 16000000.0 * TIMEBASE_TRIM // ------------------------------------------------------------------------------- #define SCALE (float) NUM_AVG * 1024.0 //#define F_CPU 16000390L // 16MHz ggf. anpassen #define F_CPU 16000000L // 16MHz ggf. anpassen #define MESSZEIT 1000 // max. 3 Messungen/Sek. #define TIMEOUT 62500 // max. 62.5s warten /****************************************************************************** *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) { startMillis = currentMillis; mess_dauer++; // ungefaehre Dauer der Messung } } /****************************************************************************** *Function: void michael_setup() *Description: initialisation *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: Collect overflows *Parameters: None *Return Value: None ******************************************************************************/ ISR(TIMER1_OVF_vect) { ueberlauf++; // Ueberlaeufe von T1 ergeben obere 16bit der Messzeit } /****************************************************************************** *Function: ISR(TIMER1_CAPT_vect) *Description: T1 Capture Logic *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 { frequenz = ( (float) mess_ereignisse * f_clock ) / mess_zeit; Serial.print(cnt++); Serial.print(","); Serial.print(mess_zeit / mess_ereignisse); Serial.print(","); auto_range(frequenz); //Serial.print(frequenz,digits); Serial.print(","); Serial.println(degc, 1); } else { messwert_vorhanden = 1; // sperre wieder aufheben } } led_control(mess_status); } void auto_range(float frequenz) { uint32_t temp = (uint32_t) frequenz; if ( temp >= 100000 ){ Serial.print(frequenz,1); return; } if ( temp >= 10000 ){ Serial.print(frequenz,2); return; } if ( temp >= 1000 ){ Serial.print(frequenz,3); return; } if ( temp >= 100 ){ Serial.print(frequenz,4); return; } if ( temp >= 10 ){ Serial.print(frequenz,5); return; } if ( temp >= 1 ){ Serial.print(frequenz,6); return; } Serial.print(frequenz,7); } /****************************************************************************** *Function: void led_control(uint8_t mess_status) *Description: operates Measurement Status LED ("GATE" Indicator) * When "ON" measurement is in progress *Parameters: None *Return Value: ftemp ******************************************************************************/ void led_control(uint8_t mess_status) { static uint8_t old_LED_State = AUSWERTEN + 1; if(mess_status != old_LED_State) { if( mess_status == AUSLESEN ) digitalWrite(LED_D13, HIGH); else digitalWrite(LED_D13, LOW); } } /****************************************************************************** *Function: float get_temperature() *Description: *Parameters: None *Return Value: ftemp ******************************************************************************/ float get_temperature() { static int32_t sensorValue = 0; static float ftemp = 22.0; currentMillis2 = millis(); if ( (currentMillis2 - startMillis2) >= period2) { // LM335 Sensor acquisition with averaging sensorValue = analogRead(A0); ftemp = convert_temperature(sensorValue, 1024); startMillis2 = currentMillis2; } return ftemp; } /****************************************************************************** *Function: float convert_temperature(uint32_t sensorValue, float fscale) *Description: Convert raw temperature to Celsius *Parameters: uint32_t sensorValue, float fscale *Return Value: degc (float) ******************************************************************************/ float convert_temperature(uint32_t sensorValue, uint32_t fscale) { int32_t temp; float degc; temp = sensorValue; temp = ( temp * 5000 ) + random(-20,20); temp = temp / fscale; temp = avgTemp.reading(temp); // calculate the moving average degc = (float) temp / 1000.0; 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 return degc; } // End of Program