Analog Komparator Input Capture + Timer

Gast #1275140
Lesenswert?
• ▲
▼
Hallo,

leider muss ich auch nochmal mit dem Thema Analog Komparator anfangen...

Ich versuche ganz einfach die Zeit zwischen 2 Flanken zu messen, und 
verwende dazu Testweise den Timer 1, der alle 1 Sekunde einen überläuft. 
Da die Signalfrequenz aber über 1Hz ist passiert das aber nie, ist also 
nur zu Testzwecken so gewählt.
Erkennt der Komparator eine steigende Flanke sollte ja der Zählerstand 
in das ICR1x Register kopiert werden, welches ich dann gleich über den 
UART verschicke. Danach stelle ich den Timer wieder auf die 1 Sekunde 
ein, so dass die nächste Messung beginnen kann.

Den Timer Initialisiere ich so:
1
void timer_init(void)
2
{
3

4
  TCCR1A = 0;
5
  TCCR1B |= (1<<ICNC1) | (1<<ICES1) | (1<<CS12)| (1<<CS10);  // prescaler 1024
6

7
  ACSR = (1<<ACIC) | (1<<ACIS1) | (1<<ACIS0);// rising edge, timer 1
8

9
  TIMSK |= (1<<TICIE1) | (1<<TOIE1);  // input compare + overflow
10

11
  TCNT1H = 0xC2;  // preset for 1sec interrupts
12
  TCNT1L = 0xF7;
13

14
  TIFR &= ~(1<<ICF1);
15

16
}

Dazu habe ich folgende ISRs:
1
ISR(SIG_COMPARATOR)
2
{
3
    while( (UCSRA & 1<<UDRE) == 0 );
4
      UDR = 10;
5

6

7
}
8

9

10
ISR(TIMER1_CAPT_vect)
11
{
12
    
13
    cli();
14
    c_time = ICR1L;
15
    c_time += (ICR1H<<8);
16
    
17
    c_time -= 49911;  // offset durch preset value  
18
    c_time /= 61;  // scale to 8 bits
19

20

21
    TCNT1H = 0xC2;
22
    TCNT1L = 0xF7;
23
  
24
    TIFR &= ~(1<<ICF1);
25

26
    while( (UCSRA & 1<<UDRE) == 0 );
27
      UDR = c_time;
28

29
    sei();
30
}
31

32

33
ISR(TIMER1_OVF_vect)
34
{
35

36
    while( (UCSRA & 1<<UDRE) == 0 );
37
      UDR = 11;
38

39
    TCNT1H = 0xC2;
40
    TCNT1L = 0xF7;
41

42
}

In der main mache ich nur:
1
int main( void )
2
{
3

4
  timer_init();
5
  uart_init();
6
  sei();
7

8
  while(1){
9

10
  }
11
}
Jetzt habe ich leider noch das Problem, dass ich fast immer 2 mal den 
"Messwert" am PC empfange, und dazwischen sehr viele (~20) 0en gesendet 
werden. Die Signalquelle ist ein Frequenzgenerator der einen 0-5V Sinus 
erzeugt, und hängt an AIN1. AIN0 habe ich über einen Spannungsteiler auf 
2,5V gelegt.

Kann mir irgendjemand sagen was das Problem an meinem Code ist?
#1275173
Lesenswert?
• ▲
▼
Wie schnell wird dein µC getaktet?
Welche Frequenz legst du an den Komperator an?


Lass in einer ISR das Interrupt Flag in Ruhe! sei() und cli() haben in 
einer ISR normalerweise nichts verloren.
Ein Flag Bit in den Interrupt Registern kann man nicht mit
    TIFR &= ~(1<<ICF1);
löschen. Damit löscht du alle anderen Flag-Bits, nur das ICF1 Flag nicht 
:-)

Dein Compiler unterstützt dich beim Auslesen von 16-Bit Pseudoregistern. 
Nutze das!

Entscheide dich für Hex oder Dezimal, je nachdem was in deiner Situation 
am sinnvollsten ist. Aber mische nicht die Zahlensysteme, wenn es nicht 
notwendig ist.

Achte auf deine Einrückungen. Die Ausgabe auf die UART suggeriert durch 
die äussere Form an dieser Stelle, dass sie von der while-Schleife 
wiederholend kontrolliert wird. Dem ist nicht so!
1
ISR(TIMER1_CAPT_vect)
2
{
3
    c_time = ICR1;
4

5
    c_time -= 49911;  // offset durch preset value  
6
    c_time /= 61;  // scale to 8 bits
7

8
    TCNT1 = 49911;
9
  
10
    while( (UCSRA & 1<<UDRE) == 0 )
11
      ;
12
    UDR = c_time;
13

14
    TIFR |= (1<<ICF1);
15
}
Gast #1275448
Lesenswert?
• ▲
▼
Vielen Dank Dir schon mal! Das mit den 16 bit Registern habe ich noch 
nie gesehen und ist wirklich sehr praktisch.

Leider habe ich noch nicht wirklich rausgefunden wo die 0en herkommen, 
aber ansonsten funktioniert es soweit ganz gut.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren