Forum: Mikrocontroller und Digitale Elektronik AVR-Timer zählt negativ?


von Johannes H. (serverone)


Lesenswert?

Hi,

ich muss für ein Projekt den Timer benutzen. Ansich soll die 
ICP-Funktion genutzt werden. Die Register zu laden geht offenbar, nur 
stürzt der Timer nach 9 Durchläufen ab und startet das Hauptprogramm 
neu.

In der Ausgabe äußert sich das so, dass nach 9 Durchläufen wieder mit 
"1" und "2" begonnen wird.

Zum Debuggen habe ich entsprechend Marken bzw. Timer-Ausgaben in den 
Code eingebunden und war dann sehr überrascht, dass auf einmal "-2631" 
ausgegeben wurde. Möglicherweise ist es auch nicht richtig formatiert 
etc., an dem Programm sitze ich schon ein paar Stunden und da kommen 
öfter Fehler rein als raus.

Grundsatzfrage: kann ich das so laufen lassen, wie es aussieht, oder 
muss ich, um das ICP-Ereignis auszuwerten über die ISR gehen?

Was mir auch komisch vorkommt: immer nach 9 Ausgaben bricht er ab und 
startet ja offenbar main neu, da entsprechende Marken wieder erscheinen. 
Hängt das vielleicht mit einem Overflow zusammen? - So weit ich dem 
Datenblatt entnommen habe setzt das den Timer, nicht aber den AVR 
zurück. Auf Overflow zu "warten" hat dann kein Sinn, denn sobald das 
Flag gesetzt wird, startet das Programm neu und damit kann ich wenn das 
TOV1 aus  TIFR1 gelesen wird nichts mehr machen.

1
#include <stdlib.h>
2
#include <avr/io.h>
3
#include <avr/interrupt.h>
4
#include <avr/signal.h>
5
#include <avr/pgmspace.h>
6
#include <util/delay.h>
7
#include "uart.h"
8
9
10
#define UART_BAUD_RATE      38400
11
12
13
int main(void)
14
{
15
16
uint16_t timerinhalt =0; //fuer ICP-Timer
17
18
uint16_t timerinhalt2 =0; //fuer normalen Timer
19
char timer[6]; //5 Ziffern + \0
20
21
// Richtungsdefinitionen:
22
 DDRB = 0;        // Alles Eingänge, PB0 ist ICP
23
 PORTB = 0xFF;    // Pullups an Eingängen
24
 DDRC = 0xFF;     // Port C als Ausgang
25
26
27
 uart_init( UART_BAUD_SELECT_DOUBLE_SPEED(UART_BAUD_RATE,F_CPU) );
28
 sei();
29
30
 uart_puts("1");
31
32
// Timer1-Init:
33
 TCCR1A = 0x00;                      // normaler Modus
34
 TCCR1B = (1<<CS12) | (1<<CS10) | (1 << ICES1);    // ICP auf steigende Flanke
35
 TIMSK1 = (1<<TOIE1) | (1<<ICIE1);   // ICP und Overflow aktivieren
36
37
 uart_puts("2");
38
39
40
 for(;;)
41
 {
42
43
    timerinhalt = ICR1L;  //lese vom ICP-Timer
44
    timerinhalt += (ICR1H<<8);
45
46
    timerinhalt2 = TCNT1L; //lese vom normalen timer
47
    timerinhalt2 += (TCNT1H<<8);
48
49
  if (TIFR1 & (1<<ICF1)) // wenn ICP ausgeloest
50
   {
51
    uart_puts("3");
52
53
    if (timerinhalt > 0) //und Zeit nicht gerade "0"
54
     {
55
       uart_puts("6");
56
     }
57
    }
58
  else { itoa(timerinhalt2, timer, 10); //sonst gebe aktuellen Timer-wert aus
59
         uart_puts(timer);
60
         uart_putc( "\n");
61
         _delay_ms(1000);}
62
63
 }
64
}

von maus (Gast)


Lesenswert?

du musst definitiv die ISR auch hinschreiben, sonst spingt der irgendwo 
hin beim interrupt

von maus (Gast)


Lesenswert?

schau mal hier: 
http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial/Die_Timer_und_Z%C3%A4hler_des_AVR

da sind auch Beispiele zur Verwendung der Interrupt und deren globale 
Variablen/Flags

von Hc Z. (mizch)


Lesenswert?

Zu den Interrupts wurde alles Nötige schon gesagt,  Du darfst einen 
Interrupt nur dann erlauben, wenn es eine Routine dafür gibt.  Sonst 
gibt es Reset.

Die negative Zahl ergibt sich aus itoa(), das eine int erwartet.  Du 
aber willst eine unsigned int ausgeben.  3mal darfst Du raten, wie die 
Funktion dann heißt.

von Johannes H. (serverone)


Lesenswert?

OK, Danke

ich werde es mal Heute Mittag probieren. Dass er ohne Overflow-ISR 
irgendwo hinspringt könnte denke ich mal eine Erklärung für den 
augenscheinlichen Reset sein.
Gibt es da aber nicht eigentlich eine Standard-Definition für die 
Overflow-ISR?

von Johannes H. (serverone)


Lesenswert?

@Hc Zimmerer

Ah, danke, das wusste ich nicht, dass Interrupts explizit definiert 
werden müssen, wenn sie verwendet werden sollen.

Die Funktion ist dann ja natürlich utoa(); -  Je später der Abend, desto 
mehr "einfache" Fehler.

von Jörg G. (joergderxte)


Lesenswert?

>Gibt es da aber nicht eigentlich eine Standard-Definition für die
>Overflow-ISR?
Wozu? Wenn man den Interrupt nicht braucht schaltet man den nicht an 
(XYZ*IE*-Bits)- der Timer funktioniert ja auch ohne.

hth, Jörg

von Rolf Magnus (Gast)


Lesenswert?

Es gibt bei avr-gcc durchaus eine, und die führt einen Reset durch.

von Rolf Magnus (Gast)


Lesenswert?

> Ah, danke, das wusste ich nicht, dass Interrupts explizit definiert
> werden müssen, wenn sie verwendet werden sollen.

Ach so, was ich vergessen hab: Es ergibt keinen Sinn, einen Interrupt 
verwenden zu wollen, ohne einen dazugehörigen Handler zu schreiben, denn 
der Aufruf dieses Handlers ist ja der Zweck des Interrupts.

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.