www.mikrocontroller.net

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


Autor: JTR (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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:
if(usiMinute>=6)
{
 usiMinute=0;
 PORTB |= 0x01;
}

Hier meine Initialisierung und ISR():
#include <avr/interrupt.h>

//Timer Init.
void vinitTimer_16Bit();

.
.
.

void vinitTimer_16Bit()
{
TCCR1B = (1<<WGM12)|(1<<CS12)|(1<<CS10); // CTC + Prescaler 1024 --> CPU/1024
                                        // 8MHz/1024=7812,5kHz
sei();                  
}

ISR(TIMER0_OVF_vect)
{
  usiMinute++;
}

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

Autor: Volker Schulz (volkerschulz)
Datum:

Bewertung
0 lesenswert
nicht lesenswert

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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:
>
>
if(usiMinute>=6)
> {
>  usiMinute=0;
>  PORTB |= 0x01;
> }
>

> 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

Autor: Walter (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
und das übliche:
wie ist usiminute definiert?

Autor: JTR (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@Walter
//Globale Variablen
  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

Autor: Justus Skorps (jussa)
Datum:

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

dann fehlt da ein volatile...

Autor: JTR (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
  // Overflow Interrupt erlauben
  TIMSK |= (1<<TOIE0);


Hier ist es ja :)!

Autor: JTR (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Was macht dieses volatile?

Autor: JTR (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Flüchtig oder Nicht-Flüchtig.

Muss ich das bei Globalen Variablen machen?

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: JTR (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ok,

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

Aber irgendwie geht mein Timer immer noch nicht.
//Timer Initialisierung
void vinitTimer_16Bit()
{
TCCR1B = (1<<WGM12)|(1<<CS12)|(1<<CS10);  // CTC + Prescaler 1024 --> CPU/1024
                      // 8MHz/1024=7812,5Hz

TIMSK |= (1<<TOIE0);            // Overflow Interrupt erlauben
sei();                    // Interrupts erlauben
}

ISR(TIMER0_OVF_vect)
{
  usiMinute++;              //Merker inkrementieren
  PORTB = ~PORTB;              //Kontrollausgabe ob Timer Überlauf kommt
    if(usiMinute>=8)          //Nach 8 Überläufen ca. 1min
    {
      usiMinute=0;          //Merker zurück setzen
      PORTB = 0x01;          //Abschalt Signal
    }
}

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

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

Aber es passiert irgendwie nicht sehr viel :D?!

MFG

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
JTR schrieb:

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

Und das komplette Programm sieht wie aus?

Autor: JTR (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Bitte sehr:

Bevor sich jemand durchkämpft, ADU Initialisierung sollte richtig sein.
#include <avr/io.h>
#include <avr/interrupt.h>
#include <stdint.h>
#include <lcd.h>
/****************************************************************************************
Name; Julian Schild

C-Programm zur programmierung des µCs für die DA von Schild_Stangl (Simply_Off2009/10).

*****************************************************************************************/
//Globale Variablen
 volatile unsigned short int usiMinute=0;

//Funktionsdeklaration (Prototypen)

//ADC Init.
void vinitADU_8Bit(unsigned short int);
//Timer Init.
void vinitTimer_16Bit();

int igetADU_8Bit(unsigned short int);

//******************************************************************************************
void main (void)
{//Variablen Definition
  char cPuffer[50];
  int iPuffer=0,iWait=0,iWait2=0;

 //Deklaration der PORTS --> "Richtung"
  DDRD = 0xff;    //0xff --> Ausgang --> LCD
  DDRC = 0x00;    //0x00 --> Eingang --> ADU
  DDRB = 0xff;    // Ausgang für Testzwecke --> LEDs
  PORTB = 0x00;


 //Initialisierung des ADCs
  vinitADU_8Bit(0);
 
 //Initialisierung des Timers
 void vinitTimer_16Bit();


    /* Initialisiere Display, Cursor aus*/
    lcd_init(LCD_DISP_ON);
  
  /* loesche das LCD Display und Cursor auf 1 Zeile, 1 Spalte */
    lcd_clrscr();
        
    /* String auf Display anzeigen */
    lcd_puts("Willkommen");
 
        //Warten, dass Wilkommen nicht gleich wieder weg ist
   for (iWait;iWait<1000;iWait++)
    {
      for (iWait2;iWait2<1000;iWait2++);
      iWait2=0;
    }
    iWait=0;

   while(1) 
   {
    if (igetADU_8Bit(2)<5)
    {
      //TCCR1B |= ((1<<CS12)|(1<<CS10));  //Timer einschalten
      iPuffer=(40*igetADU_8Bit(0))/51*100;
      // Typ konvertierung für "lcd_puts"- Funktion
      itoa(iPuffer,cPuffer, 10);  // (int Variable, char Variable, Basis (binär, dezimal, hex)
      
      //Ausgabe am LCD
      lcd_clrscr();        // LC-Display löschen und Kursor auf Pos. 1
      lcd_puts(cPuffer);      // String am Display ausgeben

    }

  else if (igetADU_8Bit(2)>50)
    {
      //TCCR1B &= ~(0x03);        //Timer ausschalten
      usiMinute=0;          //Minuten Zähler zurücksetzen

      lcd_clrscr();          // LC-Display löschen und Kursor auf Pos. 1
      lcd_puts("Betrieb");      // String "Betrieb" am Display ausgeben
    }
   }   
}


//////////////////////////////////////////////
//Funktionen                //
//////////////////////////////////////////////

void vinitADU_8Bit(unsigned short int usimux)
{//Eigene Funktion zur ADU Initialisierung damit diese nicht ständig ausgeführt werden muss
int iresult;
ADMUX = usimux;   // Kanal waehlen
ADMUX |= 0x60;     // AVCC als Referenzspannung nutzen und Ergebnis soll linksbündig sein (nur ADCH)
ADCSRA |= 0x85;   // Frequenzvorteiler
          // setzen auf 8 (1) und ADC aktivieren (1)

/* nach Aktivieren des ADC wird ein "Dummy-Readout" empfohlen, man liest
also einen Wert und verwirft diesen, um den ADC "warmlaufen" zu lassen*/

ADCSRA |= (1<<ADSC); // eine ADC-Wandlung

  while(ADCSRA&(1<<ADSC)) 
    {
       // auf Abschluss der Konvertierung warten
    }

iresult = ADCH;      // ADCH muss einmal gelesen werden,
            // sonst wird Ergebnis der nächsten Wandlung
            // nicht übernommen.
ADCSRA &= ~(1<<ADEN);   // ADC deaktivieren

iresult = 0;
}


int igetADU_8Bit(unsigned short int usimux)
{  int iresult;

  ADMUX &= 0xF0;
  ADMUX |= usimux;     // Kanal waehlen
  ADCSRA |= 0x80;     //ADC aktivieren (1)


  ADCSRA |= (1<<ADSC);   // eine Wandlung "single conversion"
    while ( ADCSRA & (1<<ADSC) ) 
      {
        // auf Abschluss der Konvertierung warten
      }

  iresult = ADCH;     // Wandlungsergebnisse abholen
  ADCSRA &= ~(1<<ADEN);   // ADC deaktivieren (2)

  return iresult;
}

//Timer Initialisierung
void vinitTimer_16Bit()
{
TCCR1B = (1<<WGM12)|(1<<CS12)|(1<<CS10);  // CTC + Prescaler 1024 --> CPU/1024
                      // 8MHz/1024=7812,5Hz
TIMSK |= (1<<TOIE0);            // Overflow Interrupt erlauben
sei();                    // Interrupts erlauben
}

ISR(TIMER0_OVF_vect)
{
  usiMinute++;              //Merker inkrementieren
  PORTB = ~PORTB;              //Kontrollausgabe ob Timer Überlauf kommt
    if(usiMinute>=8)          //Nach 8 Überläufen ca. 1min
    {
      usiMinute=0;          //Merker zurück setzen
      PORTB = ~0x01;          //Abschalt Signal
    }
}

Autor: JTR (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
 //Initialisierung des Timers
 void vinitTimer_16Bit();

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

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
JTR schrieb:
TCCR1B = (1<<WGM12)|(1<<CS12)|(1<<CS10);  // CTC + Prescaler 1024 --> CPU/1024
                      // 8MHz/1024=7812,5Hz
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 :-)

Autor: JTR (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Warum fehlen mir jedes mal die Augen für so einen offensichtlichen 
Fehler....

Autor: JTR (Gast)
Datum:

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

Autor: Christian H. (netzwanze) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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.

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.