Forum: Mikrocontroller und Digitale Elektronik Atmega8 und 16-Bit Timmer


von JTR (Gast)


Lesenswert?

Hallo,
also es geht darum:
Ich messe eine Leistung (funktioniert!) und wenn diese Leistung unter 
einen bestimmten Wert fällt (<20W) soll ein Timer laufen. Nach ca. 1min 
sollte der PortB.0 auf High gehen.

Ich stecke meiner Meinung nach bei der Initialisierung des Timers.
Da 1min doch eine etwas längere Zeit zu messen ist hab ich den 16-Bit 
Timer in Verwendung bei größtem Prescaler = 1024.

Meine CPU Frequenz ist 8MHz.

8MHz/1024 = 7812,5kHz

D.h. mein 16-Bit Register wird 7812 mal in der Sekunde inkrementiert, 
richtig?
Wenn ja, dann wäre nach ca. 6s mein Überlauf und somit mein Overflow 
Interrupt.
In diesem Interrupt erhöhe ich eine weitere Variable. Wenn diese 6 Mal 
inkrementiert wurde bin ich bei ~1min. Hier frag ich im Main() dann 
einfach mit:
1
if(usiMinute>=6)
2
{
3
 usiMinute=0;
4
 PORTB |= 0x01;
5
}

Hier meine Initialisierung und ISR():
1
#include <avr/interrupt.h>
2
3
//Timer Init.
4
void vinitTimer_16Bit();
5
6
.
7
.
8
.
9
10
void vinitTimer_16Bit()
11
{
12
TCCR1B = (1<<WGM12)|(1<<CS12)|(1<<CS10); // CTC + Prescaler 1024 --> CPU/1024
13
                                        // 8MHz/1024=7812,5kHz
14
sei();                  
15
}
16
17
ISR(TIMER0_OVF_vect)
18
{
19
  usiMinute++;
20
}

Mir kommt die Initialisierung vom Timer etwas kurz vor?!
Aber, dass ganze Compare-Zeug brauch ich ja nicht.

Merke: Die Zeit sollte wirklich nur ungefähr 1min sein!

Hoffentlich kann wer drüber schaun und mir bescheid sagen :).

MFG

von Volker S. (volkerschulz)


Lesenswert?


von Karl H. (kbuchegg)


Lesenswert?

JTR schrieb:

> Meine CPU Frequenz ist 8MHz.
>
> 8MHz/1024 = 7812,5kHz

Fast   7812Hz. Nicht kilo-Hz
Aber du rechnest ohnehin mit dem richtigen Wert weiter. Ist also nur ein 
Tippfehler.

> D.h. mein 16-Bit Register wird 7812 mal in der Sekunde inkrementiert,
> richtig?

Richtig.

> Wenn ja, dann wäre nach ca. 6s mein Überlauf und somit mein Overflow
> Interrupt.

Wie kommst du auf 6s?
7812.5 / 65536 = 0.119209
und der Kehrwert davon ist ca. 8.3

> In diesem Interrupt erhöhe ich eine weitere Variable. Wenn diese 6 Mal
> inkrementiert wurde bin ich bei ~1min.

Gedankengang richtig. Zahlenwerte sind noch nicht ok.

> Hier frag ich im Main() dann
> einfach mit:
>
>
1
if(usiMinute>=6)
2
> {
3
>  usiMinute=0;
4
>  PORTB |= 0x01;
5
> }
>

> Hier meine Initialisierung und ISR():

Wenn du sowieso eine Overflow ISR hast, dann gib doch dort das 
Weiterschalten um 1 Minte rein. Das ist da gut aufgehoben.

> Mir kommt die Initialisierung vom Timer etwas kurz vor?!

Ich sehe nirgends die Freigabe vom Overflow Interrupt.
Aber ansonsten: ja das kann schon stimmen

von Walter (Gast)


Lesenswert?

und das übliche:
wie ist usiminute definiert?

von JTR (Gast)


Lesenswert?

@Walter
1
//Globale Variablen
2
  unsigned short int usiMinute=0;

So ist es definiert.


@Karl Heinz

Wie immer super Antwor, danke!

>Fast   7812Hz. Nicht kilo-Hz
Klar sind es Hz und nicht kHz^^.

>Wie kommst du auf 6s?
Hab auch keine Ahnung wie ich auf 6 gekommen bin. Hast natürlich recht, 
8 Mal muss der Overflow auftreten damit ich auf ~1min komme.


>Ich sehe nirgends die Freigabe vom Overflow Interrupt.

???, dass ist mir überhaupt nicht bekannt. Muss ich gleich suchen gehen 
:D.

MFG

von Justus S. (jussa)


Lesenswert?

JTR schrieb:
> @Walter
> //Globale Variablen
>   unsigned short int usiMinute=0;
> So ist es definiert.

dann fehlt da ein volatile...

von JTR (Gast)


Lesenswert?

1
  // Overflow Interrupt erlauben
2
  TIMSK |= (1<<TOIE0);


Hier ist es ja :)!

von JTR (Gast)


Lesenswert?

Was macht dieses volatile?

von JTR (Gast)


Lesenswert?

Flüchtig oder Nicht-Flüchtig.

Muss ich das bei Globalen Variablen machen?

von Karl H. (kbuchegg)


Lesenswert?

JTR schrieb:
> Flüchtig oder Nicht-Flüchtig.
>
> Muss ich das bei Globalen Variablen machen?

Nein.
Bitte durchsuche das Forum nach volatile.
Du wirst da sicher fünding.

In kurzen Worten: Es hat mit der Neigung des COmpilers zu Optimierungen 
zu tun. Es hat damit zu tun, dass eine Variable sowohl in main() als 
auch in einer ISR benutzt wird. Es hat damit zu tun, dass der Compiler 
nicht erkennen kann, dass die ISR eine Funktion ist, die aufgerufen 
wird, obwohl für den Compiler kein Funktionsaufruf erkennbar ist.

von JTR (Gast)


Lesenswert?

Ok,

jetzt weiß ich wofür Volatile steht, wurde geändert.
1
//Globale Variablen
2
 volatile unsigned short int usiMinute=0;

Aber irgendwie geht mein Timer immer noch nicht.
1
//Timer Initialisierung
2
void vinitTimer_16Bit()
3
{
4
TCCR1B = (1<<WGM12)|(1<<CS12)|(1<<CS10);  // CTC + Prescaler 1024 --> CPU/1024
5
                      // 8MHz/1024=7812,5Hz
6
7
TIMSK |= (1<<TOIE0);            // Overflow Interrupt erlauben
8
sei();                    // Interrupts erlauben
9
}
10
11
ISR(TIMER0_OVF_vect)
12
{
13
  usiMinute++;              //Merker inkrementieren
14
  PORTB = ~PORTB;              //Kontrollausgabe ob Timer Überlauf kommt
15
    if(usiMinute>=8)          //Nach 8 Überläufen ca. 1min
16
    {
17
      usiMinute=0;          //Merker zurück setzen
18
      PORTB = 0x01;          //Abschalt Signal
19
    }
20
}

Im Main() hab ich 2 if() Abfragen.
Bei der einen Bedingung schalt ich den Timer ein:
1
TCCR1B |= ((1<<CS12)|(1<<CS10));  //Timer einschalten

und bei der anderen if() aus:
1
TCCR1B &= ~(0x03);        //Timer ausschalten

Aber es passiert irgendwie nicht sehr viel :D?!

MFG

von Karl H. (kbuchegg)


Lesenswert?

JTR schrieb:

> Aber es passiert irgendwie nicht sehr viel :D?!

Und das komplette Programm sieht wie aus?

von JTR (Gast)


Lesenswert?

Bitte sehr:

Bevor sich jemand durchkämpft, ADU Initialisierung sollte richtig sein.
1
#include <avr/io.h>
2
#include <avr/interrupt.h>
3
#include <stdint.h>
4
#include <lcd.h>
5
/****************************************************************************************
6
Name; Julian Schild
7
8
C-Programm zur programmierung des µCs für die DA von Schild_Stangl (Simply_Off2009/10).
9
10
*****************************************************************************************/
11
//Globale Variablen
12
 volatile unsigned short int usiMinute=0;
13
14
//Funktionsdeklaration (Prototypen)
15
16
//ADC Init.
17
void vinitADU_8Bit(unsigned short int);
18
//Timer Init.
19
void vinitTimer_16Bit();
20
21
int igetADU_8Bit(unsigned short int);
22
23
//******************************************************************************************
24
void main (void)
25
{//Variablen Definition
26
  char cPuffer[50];
27
  int iPuffer=0,iWait=0,iWait2=0;
28
29
 //Deklaration der PORTS --> "Richtung"
30
  DDRD = 0xff;    //0xff --> Ausgang --> LCD
31
  DDRC = 0x00;    //0x00 --> Eingang --> ADU
32
  DDRB = 0xff;    // Ausgang für Testzwecke --> LEDs
33
  PORTB = 0x00;
34
35
36
 //Initialisierung des ADCs
37
  vinitADU_8Bit(0);
38
 
39
 //Initialisierung des Timers
40
 void vinitTimer_16Bit();
41
42
43
    /* Initialisiere Display, Cursor aus*/
44
    lcd_init(LCD_DISP_ON);
45
  
46
  /* loesche das LCD Display und Cursor auf 1 Zeile, 1 Spalte */
47
    lcd_clrscr();
48
        
49
    /* String auf Display anzeigen */
50
    lcd_puts("Willkommen");
51
 
52
        //Warten, dass Wilkommen nicht gleich wieder weg ist
53
   for (iWait;iWait<1000;iWait++)
54
    {
55
      for (iWait2;iWait2<1000;iWait2++);
56
      iWait2=0;
57
    }
58
    iWait=0;
59
60
   while(1) 
61
   {
62
    if (igetADU_8Bit(2)<5)
63
    {
64
      //TCCR1B |= ((1<<CS12)|(1<<CS10));  //Timer einschalten
65
      iPuffer=(40*igetADU_8Bit(0))/51*100;
66
      // Typ konvertierung für "lcd_puts"- Funktion
67
      itoa(iPuffer,cPuffer, 10);  // (int Variable, char Variable, Basis (binär, dezimal, hex)
68
      
69
      //Ausgabe am LCD
70
      lcd_clrscr();        // LC-Display löschen und Kursor auf Pos. 1
71
      lcd_puts(cPuffer);      // String am Display ausgeben
72
73
    }
74
75
  else if (igetADU_8Bit(2)>50)
76
    {
77
      //TCCR1B &= ~(0x03);        //Timer ausschalten
78
      usiMinute=0;          //Minuten Zähler zurücksetzen
79
80
      lcd_clrscr();          // LC-Display löschen und Kursor auf Pos. 1
81
      lcd_puts("Betrieb");      // String "Betrieb" am Display ausgeben
82
    }
83
   }   
84
}
85
86
87
//////////////////////////////////////////////
88
//Funktionen                //
89
//////////////////////////////////////////////
90
91
void vinitADU_8Bit(unsigned short int usimux)
92
{//Eigene Funktion zur ADU Initialisierung damit diese nicht ständig ausgeführt werden muss
93
int iresult;
94
ADMUX = usimux;   // Kanal waehlen
95
ADMUX |= 0x60;     // AVCC als Referenzspannung nutzen und Ergebnis soll linksbündig sein (nur ADCH)
96
ADCSRA |= 0x85;   // Frequenzvorteiler
97
          // setzen auf 8 (1) und ADC aktivieren (1)
98
99
/* nach Aktivieren des ADC wird ein "Dummy-Readout" empfohlen, man liest
100
also einen Wert und verwirft diesen, um den ADC "warmlaufen" zu lassen*/
101
102
ADCSRA |= (1<<ADSC); // eine ADC-Wandlung
103
104
  while(ADCSRA&(1<<ADSC)) 
105
    {
106
       // auf Abschluss der Konvertierung warten
107
    }
108
109
iresult = ADCH;      // ADCH muss einmal gelesen werden,
110
            // sonst wird Ergebnis der nächsten Wandlung
111
            // nicht übernommen.
112
ADCSRA &= ~(1<<ADEN);   // ADC deaktivieren
113
114
iresult = 0;
115
}
116
117
118
int igetADU_8Bit(unsigned short int usimux)
119
{  int iresult;
120
121
  ADMUX &= 0xF0;
122
  ADMUX |= usimux;     // Kanal waehlen
123
  ADCSRA |= 0x80;     //ADC aktivieren (1)
124
125
126
  ADCSRA |= (1<<ADSC);   // eine Wandlung "single conversion"
127
    while ( ADCSRA & (1<<ADSC) ) 
128
      {
129
        // auf Abschluss der Konvertierung warten
130
      }
131
132
  iresult = ADCH;     // Wandlungsergebnisse abholen
133
  ADCSRA &= ~(1<<ADEN);   // ADC deaktivieren (2)
134
135
  return iresult;
136
}
137
138
//Timer Initialisierung
139
void vinitTimer_16Bit()
140
{
141
TCCR1B = (1<<WGM12)|(1<<CS12)|(1<<CS10);  // CTC + Prescaler 1024 --> CPU/1024
142
                      // 8MHz/1024=7812,5Hz
143
TIMSK |= (1<<TOIE0);            // Overflow Interrupt erlauben
144
sei();                    // Interrupts erlauben
145
}
146
147
ISR(TIMER0_OVF_vect)
148
{
149
  usiMinute++;              //Merker inkrementieren
150
  PORTB = ~PORTB;              //Kontrollausgabe ob Timer Überlauf kommt
151
    if(usiMinute>=8)          //Nach 8 Überläufen ca. 1min
152
    {
153
      usiMinute=0;          //Merker zurück setzen
154
      PORTB = ~0x01;          //Abschalt Signal
155
    }
156
}

von JTR (Gast)


Lesenswert?

1
 //Initialisierung des Timers
2
 void vinitTimer_16Bit();

Das Void wurde entfernt beim Aufruf der Funktion.
Keine Veränderung.

von Karl H. (kbuchegg)


Lesenswert?

JTR schrieb:
1
TCCR1B = (1<<WGM12)|(1<<CS12)|(1<<CS10);  // CTC + Prescaler 1024 --> CPU/1024
2
                      // 8MHz/1024=7812,5Hz
3
TIMSK |= (1<<TOIE0);            // Overflow Interrupt erlauben

Du musst dich entscheiden.
Entweder du nimmst den Timer 1, dann musst du auch den Overflow für 
Timer 1 aktivieren (und eine entsprechende ISR zur Verfügung stellen).
Oder du nimmst den Timer 0, dann solltest du den auch durch setzen eines 
Vorteilers aktivieren.
Aber Timer 1 aktivieren und auf Overflows vom Timer 0 warten, wird nicht 
gehen :-)

von JTR (Gast)


Lesenswert?

Warum fehlen mir jedes mal die Augen für so einen offensichtlichen 
Fehler....

von JTR (Gast)


Lesenswert?

Mal ein FETTES DANKE an Karl Heinz, für deine Mühe :).
Mein Timer funktioniert so weit.

von Christian H. (netzwanze) Benutzerseite


Lesenswert?

JTR schrieb:
> Warum fehlen mir jedes mal die Augen für so einen offensichtlichen
> Fehler....

Mach Dir nichts draus. Das passiert jedem. Vor allem, wenn man erst 
anfängt.
Irgendwann entwickelt man ein Auge dafür. Das kann aber dauern.

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.