Das stimmt, die eine-Sekunde-Vergleichsmessung wird wohl (vorerst) nicht benötigt 
Doch würde mich das wirklich interessieren, wie man gleichzeitig eine Sekunde und beispielsweise 5ms-Takte gleichzeitig mit einem Timer zu zählen vermag. Im Moment brauche ich das nicht besonders, doch die Anzahl der Timer ist immer zu wenig und man lernt immer mehr dazu 
In kürzester Zeit spiele ich den Code drauf und melde mich wieder zu Wort. Versuchen werde ich das wohl erst einmal mit Messung einer Periode - nur im Notfall ändere ich das in mehrere.
Anbei poste ich den Code für die Nachfolger und würde natürlich dankbar sein, wenn ihr auch Optimierungstipps für mich hättet - so ein Microcontroller hat nicht allzuviel Toleranz (sprich:Speicher), was nicht-optimierte Programmierung betrifft 
MfG Nik
Code:
/*****************************************************************
Frequenzzähler, im Bereich von 1Hz bis mind. benötigte 1400Hz.
Unter Zuhilfenahme eines externen Quarzes (16MHz) wird das an
PPB0(ICP1) des ATmega8 anliegende TTL-Signal ausgewertet und anschließend
auf einer vierstelligen 7-Segment-Anzeige im Multiplexbetrieb
dargestellt.
Für etwaige kleinere Abweichungen wurde der Korrekturfaktor eingeführt,
welcher durch Abgleich die Ungenauigkeit der Messung arithmetisch "glättet".
******************************************************************/
#define F_CPU 16000000UL // uC läuft mit 16MHz
#ifndef TRUE
#define TRUE 1
#define FALSE 0
#endif
#include <avr/io.h>
#include <avr/interrupt.h>
volatile unsigned short z=0; // Zählvariable des Timer1
volatile unsigned short UpdateDisplay; // Verzögerung
volatile unsigned long Zeitdifferenz = 0;
volatile uint8_t tausender, hunderter, zehner, einer; // Speicher für die eizelnen Digits
volatile uint8_t position = 0;
unsigned int zaehler1_ovf = 0; // Anzahl der Überläufe des Timer1
unsigned long zaehlschritte = 0;
uint8_t bitmaske = 0b00010000; // Funktion: Keinen Strom auf PortD4 geben, da TTL
uint16_t freq = 0;
float korrekturfaktor = 1; // für Abgleich anpassen (z.B. 0.9997)
const int8_t numbers[11] = // Array zur Darstellung der Zeichen auf der 7-Seg-Anz.
{
0b01101111, // 0
0b00000110, // 1
0b10101011, // 2
0b10001111, // 3
0b11000110, // 4
0b11001101, // 5
0b11101101, // 6
0b00000111, // 7
0b11101111, // 8
0b11001111, // 9
0b00000000 // leere Anzeige
};
ISR(TIMER1_OVF_vect)
{
z++;
TIFR = (1<<TOV1); //Beim Überlauf von Timer1 und dem anschließenden Interrupt erfolgt eine Zurücksetzung auf Null
//Braucht nicht gelöscht zu werden. Jeder Interrupt löscht automatisch sein eigenes Flag beim Aufruf der ISR.
}
ISR(TIMER1_CAPT_vect)
{
// static bedeutet, dass auf die Funktion/Variable nur in der Datei, in der sie steht, zugegriffen werden kann.
static unsigned short ErsteFlanke = TRUE;
static unsigned long Startzeit = 0;
static unsigned int LowByte = 0;
static unsigned int HighByte = 0;
if(UpdateDisplay) // Das Display wurde mit den Ergebnissen der vorhergehenden
{ // Messung noch nicht aktualisiert. Die nächste Messung
return; // verzögern, bis die Start- und EndTime-Variablen wieder
} // gefahrlos beschrieben werden können
LowByte = ICR1L; // LowByte zuerst, HighByte später gepuffert
HighByte = ICR1H;
// Overflow verpasst, wenn ICR1H klein und wartender Overflow Interrupt
if ((HighByte < 128) && (TIFR & (1<<TOV1)))
{
// wartenden Timer Overflow Interrupt vorziehen
++z;
TIFR = (1<<TOV1); // Timer Overflow int. löschen, da schon hier ausgeführt
}
// Bei der ersten Flanke beginnt die Messung, es wird der momentane
// Timer beim Input Capture als Startwert gesichert
if(ErsteFlanke)
{
Startzeit = ICR1;
z = 0;
ErsteFlanke = FALSE; // Nach der nächsten Flanke beginnt die Ausgabe
}
// das ist die zweite Flanke im Messzyklus. Die Messung wird gestoppt
else
{
Zeitdifferenz = ICR1 - Startzeit;
UpdateDisplay = TRUE; // Eine vollständige Messung. Sie kann ausgewertet werden
ErsteFlanke = TRUE; // Bei der nächsten Flanke beginnt der nächste Messzyklus
}
}
ISR (TIMER0_OVF_vect) // timer0 overflow interrupt
{
TCNT0 += 6; // WorkAround, CTC-Mode-"Simulation"
PORTC = 0b00000000; // alle Digits aus
/*****************************************************************
Die Prozedur ist gesondert zu schildern. Die Funktion switch(position)
enthält nicht nur den eigentlichen Multiplex-Vorgang zum
timer1-abhängigen Wechsel der jeweiligen 7-Segment-Anzeige, sondern
entfernt, mithilfe verknüpfter case-if-Abfragen auch die unnötigen
Nullen, die vor der eigentlichen Frequenzanzeige angezeigt werden würden.
******************************************************************/
switch (position) // aktuelle Stelle ausgeben
{
case 0 : if (tausender==0)
{digit(10, PC0);}
else
{digit(tausender, PC0);}
break;
case 1 : if ((tausender==0)&&(hunderter==0))
{digit(10, PC1);}
else
{digit(hunderter, PC1);}
break;
case 2 : if ((tausender==0)&&(hunderter==0)&&(zehner==0))
{digit(10, PC2);}
else
{digit(zehner, PC2);}
break;
case 3 : {digit(einer, PC3);}
break;
}
position++; // beim nächsten Mal nächstes Digit
if(position == 4) // wenn alle Digits durch
{
position = 0; // von vorne beginnen
}
}
/*********************************************************************
Die Funktion digit() sorgt für die eigentliche Darstellung der Zahlen
an der jeweiligen Stelle. Sie filtert unter Zuhilfenahme der Bitmaske
den für das TTL-Signal freigehaltenen Pin (T0) und holt sich aus dem
numbers[]-Array die Portzuweisungen.
*********************************************************************/
void digit(uint8_t wert, uint8_t pin)
{
PORTD = (PORTD & bitmaske) | numbers[wert];
PORTC |= (1 << pin); // entsprechendes Digit an
}
void zahl_ausgeben(uint16_t zahl)
{
tausender = zahl/1000; // Tausender Dezimalstelle
zahl = zahl % 1000;
hunderter = zahl/100; // Hunderter Dezimalstelle
zahl = zahl % 100;
zehner = zahl/10; // Zehner Dezimalstelle
zahl = zahl % 10;
einer = zahl; // Einer Dezimalstelle
}
int main(void)
{
// Definition von Ein- und Ausgängen des uC Boards
DDRB = 0xFE; // Mit Ausnahme des ICP1-Pins alles als Ausgang
DDRC = 0xFF; // PORTC als Ausgang - über PORTC werden die jeweiligen Segmente einer 7-Seg. Anzeige gesteuert
DDRD = 0xFF; // PORTD als Ausgang
PORTC = 0b00000000;
TIMSK = (1<<TICIE1) | (1<<TOIE1); // Interrupts akivieren, Capture und Overflow
TCCR1B = (1<<ICES1) | (1<<CS10); // Input Capture Edge, kein Prescaler
TIMSK |= (1 << TOIE0); // Interrupt aktivieren, Overflow
TCCR0 |= (1 << CS01) | (1 << CS00); // Vorteiler auf 64
sei(); // Interruptbehandlung ein
while(1) // unendliche Schleife
{
if(UpdateDisplay) // Erst nach zweiter Flanke ausführen
{
zaehler1_ovf = z; // Anzahl der Überläufe wird in zaehler1_ovf kopiert
z= 0;
zaehlschritte = (unsigned long)(0.5+(65536.0*zaehler1_ovf) + Zeitdifferenz);
if (zaehlschritte==0)
{
freq = 0;
}
else
{
// Die abschließende Berechnung der Schritte pro Sekunde
freq = (uint16_t) (F_CPU/(zaehlschritte));
}
zahl_ausgeben(freq);
UpdateDisplay = FALSE;
}
}
return 0;
}
Lesezeichen