Forum: Mikrocontroller und Digitale Elektronik Input Capture Atmega16 Problem


von Blubber (Gast)


Lesenswert?

Hallo Leute,
Will zur Übung mit uCs und aus Spaß an der Freude eine DCF77-Uhr bauen.
Zuerst wollte ich mir dazu auf irgendeine Weise das Signal ausgeben 
lassen. Meine erster Ansatz: ich lasse mir die Pulsdauer (als einfacher 
Timerwert) auf ein 2x16 Display schreiben.

Conrad DCF Modul an PortD 
http://www.conrad.de/ce/de/product/641138/Conrad-DCF-Empfaengerplatine
P.Fleurys LCD-Bib, LCD an PORTA 
http://homepage.hispeed.ch/peterfleury/avr-software.html#libs
easyAVR6-Board (Pullups/downs am Board werden nicht genutzt)
Atmega16, 8Mhz int.RC, Timer1, Prescaler 1024.

Erwarten würde ich, dass ich, da Input Capture ja sowohl auf fallende 
als auch steigende Flanken reagieren sollte, für die 0,1-Sek.-Pulse 
ICR1-Werte um 780(für 0,2-Sek.-Pulse um 1550, für 0,9-Sek.-Pausen um 
7000, für 0,8-Sek.-Pausen 6250) bekommen würde.
Dem ist aber leider überhaupt nicht so. Die ausgegebenen Werte liegen 
alle etwa in den Bereichen 8800+-100, 8050+-100, 7200+-100.

Die einzige Erklärung die ich dafür finden konnte ist, dass nicht alle 
Flanken erkannt werden. Ist diese Erklärung evtl falsch? Wenn ja, wo ist 
mein Denkfehler? Wenn nein, woran könnte es liegen, bzw. was kann ich 
dagegen tun?

1
#include <avr/io.h>
2
#include <avr/interrupt.h>
3
#include <stdio.h>
4
#include <string.h>
5
6
#include "lcd.h"
7
#define LCD_BL 2
8
9
volatile long int pulsewidth1=0;
10
volatile long int pulsewidth2=0;
11
volatile uint8_t a=0;
12
char LCD_string[10];
13
14
15
int main(void){  
16
  lcd_init(LCD_DISP_ON);
17
  DDRA|=(1<<LCD_BL);  // Pin unbelegt -> Ausgang
18
  PORTA|=(1<<LCD_BL);
19
  
20
  DDRD&=~(1<<DDD6);  // PD6 Eingang
21
  PORTD=(1<<PD6);    // Pullup, da DCF-Modul OpenCollector
22
  
23
  TCCR1B|=(1<<CS12)|(1<<CS10)|(1<<ICNC1);  // Normal-Mode, Prescaler 1024
24
  TIMSK|=(1<<TOIE1)|(1<<TICIE1);           // Timer 1 Ovf-Interrupt und Capt-Event-Interrupt
25
  sei();
26
  while(1){
27
    if(a){
28
      sprintf(LCD_string,"%#8ld", pulsewidth1);
29
      lcd_gotoxy(6,0);
30
      lcd_puts(LCD_string);
31
    }
32
    else{
33
      sprintf(LCD_string,"%#8ld", pulsewidth1);
34
      lcd_gotoxy(6,1);
35
      lcd_puts(LCD_string);
36
    }
37
  }
38
  cli();
39
}
40
41
ISR(TIMER1_CAPT_vect){
42
  pulsewidth1=ICR1;    // bei 8Mhz,Psc=1024: 781,25=0,1s | 1562,5=0,2s | 7812,5=1s
43
                       // 7031,25=0,9s | 6250=0,8s | 14843,75=1,9s | 14062,5=1,8s
44
  if(a==0){a=1;}
45
  else{a=0;}
46
  TCNT1=0;
47
}
48
49
ISR(TIMER1_OVF_vect){ // eigentlich irrelevant
50
  PORTC++;
51
}

Vielen Dank schonmal im voraus!

von Blubber (Gast)


Lesenswert?

Nachtrag: Der einzige sinnvolle Wert kommt jede Minute beim 
ausgelassenen 59. Bit, welches einer Pause von 1,8 Sek bzw 1,9 Sek (also 
Timerwert um ca 15000) entspricht.

von c-hater (Gast)


Lesenswert?

K. S. schrieb:

> Erwarten würde ich, dass ich, da Input Capture ja sowohl auf fallende
> als auch steigende Flanken reagieren sollte, für die 0,1-Sek.-Pulse
> ICR1-Werte um 780(für 0,2-Sek.-Pulse um 1550, für 0,9-Sek.-Pausen um
> 7000, für 0,8-Sek.-Pausen 6250) bekommen würde.

Soweit erstmal nachvollziehbare Überlegungen. Und da es lobens- und 
fördernswert ist, wenn noch jemand selber denkt, tatsächlich noch ein 
kleiner Hinweis:

> Dem ist aber leider überhaupt nicht so. Die ausgegebenen Werte liegen
> alle etwa in den Bereichen 8800+-100, 8050+-100, 7200+-100.

Und was passiert, wenn du vor jeder Ausgabe erstmal das Display komplett 
löschst (oder zumindest den Bereich, in dem die Ausgaben erfolgen, also 
wenigstens 4 Zeichen)...

Problem erkennt?

von test (Gast)


Lesenswert?

K. S. schrieb:
> Erwarten würde ich, dass ich, da Input Capture ja sowohl auf fallende
> als auch steigende Flanken reagieren sollte...

Richtig!

Entweder wird auf die fallende oder auf die steigende Flanke reagiert. 
Welche davon, das wird durch Bit ICES1 in TCCR1B festgelegt.

von Blubber (Gast)


Lesenswert?

c-hater schrieb:
> Und was passiert, wenn du vor jeder Ausgabe erstmal das Display komplett
> löschst (oder zumindest den Bereich, in dem die Ausgaben erfolgen, also
> wenigstens 4 Zeichen

Das stimmt natürlich, danke.

test schrieb:
> Entweder wird auf die fallende oder auf die steigende Flanke reagiert.
> Welche davon, das wird durch Bit ICES1 in TCCR1B festgelegt.

Dieses Bit ist mir überhaupt nicht aufgefallen, danke. Das heißt also, 
ich müsste das Bit jedes Mal im Interrupt Checken und entsprechend 
setzen bzw. löschen.
1
ISR(TIMER1_CAPT_vect){
2
  pulsewidth_new=ICR1;
3
  TCNT1=0;
4
  if(TCCR1B&&(1<<ICES1)){   // Wenn steigende Flanke aktiv
5
    TCCR1B&=~(1<<ICES1);    // fallende aktivieren
6
  }
7
  else{                      // Wenn fallende Flanke aktiv
8
    TCCR1B|=(1<<ICES1);     // steigende aktivieren
9
  }
10
}

Sehe ich das richtig?

von Blubber (Gast)


Lesenswert?

K. S. schrieb:
>
1
if(TCCR1B&&(1<<ICES1))

Ist natürlich ein '&' zu viel. Vielen Dank für eure Hilfe. Klappt!

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.