mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik Hardwaretimer für eigene Delay-Funktion nutzen


Autor: Kiaa (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo zusammen!
Ich habe hier eine Delay-Funktion programmiert, die auf einem ATTiny 
2313 mit 8Mhz laufen soll. Leider tut diese garnichts :-(

Ich würde mich sehr freuen wenn ihr mal kurz drüberschauen und 
vielleicht einen (dummen Anfänger-)Fehler finden würdet ;-)

// Defines the different prescalers
typedef enum
{
  PRESCALE_1,
  PRESCALE_8,
  PRESCALE_64,
  PRESCALE_256,
  PRESCALE_1024
} Prescaler;


// Wait micro (10^-6) seconds
void Timing_wait_us( uint us )
{
  Timing_setupHardwareTimer( 8, PRESCALE_1, us );
  Timing_startHardwareTimer();
}

// Sets up the registers to simplify timer usage
void Timing_setupHardwareTimer( uchar compareValue, Prescaler prescaler, 
uint repititions )
{
  // Store number of repetitions
  timerRepititions = repititions;

  // Clear counter on compare match
  TCCR0A = (1 << COM0A1);

  // Output compare register
  OCR0A = compareValue;

  // Prescaler
  TCCR0B = (prescaler+1);

  // Enable interrupts
  TIMSK = 2;
}

// Starts the hardware timer and waits for it to finish
void Timing_startHardwareTimer( void )
{
  // Reset timer
  timerHasFinished = false;
  TCNT0 = 0;

  // Let's go
  sei();
  while( !timerHasFinished ) {;}
  cli();
}

// Timer interrupt
ISR(TIMER0_OVF_vect)
{
  if( timerRepititions > 0 )
  {
    timerRepititions--;
    if( timerRepititions == 0 )
      timerHasFinished = true;
  }//end if
}

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

Bewertung
0 lesenswert
nicht lesenswert
Kiaa schrieb:

> // Defines the different prescalers
> typedef enum
> {
>   PRESCALE_1,
>   PRESCALE_8,
>   PRESCALE_64,
>   PRESCALE_256,
>   PRESCALE_1024
> } Prescaler;

das ist gefährlich.
Der Compiler beginnt mit der Zuweisung von Zahlenwerten zu den Enum 
Werten bei 0.
Da du hier darauf angewiesen bist, dass die Konstanten mit spezifischen 
Zahlenwerten verknüpft werden, solltest du da für Klarheit sorgen

 typedef enum
 {
   PRESCALE_1     = 1
   PRESCALE_8     = 2
   PRESCALE_64    = 3
   PRESCALE_256   = 4
   PRESCALE_1024  = 5
 } Prescaler;

ob die Bitwerte der Zahlen jetzt zu den Konstanten laut Datenblatt 
passen, hab ich nicht kontrolliert.

> // Sets up the registers to simplify timer usage
> void Timing_setupHardwareTimer( uchar compareValue, Prescaler prescaler,
> uint repititions )
> {
>   // Store number of repetitions
>   timerRepititions = repititions;

timerRepititions  ....  Datentyp? volatile vergessen?

>
>   // Clear counter on compare match
>   TCCR0A = (1 << COM0A1);
>
>   // Output compare register
>   OCR0A = compareValue;
>
>   // Prescaler
>   TCCR0B = (prescaler+1);
>
>   // Enable interrupts
>   TIMSK = 2;

Bis hierher war ich versucht zu sagen: schöner Code

> // Starts the hardware timer and waits for it to finish
> void Timing_startHardwareTimer( void )
> {
>   // Reset timer
>   timerHasFinished = false;

timerHasFinished   ...  Datentyp?  volatile vergessen?

An dieser Stelle ist das nicht besonders gut aufgehoben.
Du solltest das Flag löschen, ehe du den Timer laufen lässt.
Was, wenn bei kurzen Zeiten der Timer schon abgelaufen ist, wenn das 
Programm hier her kommt?

>   TCNT0 = 0;

Ditto

Timereinstellungen macht man bevor der Timer sein Go bekommt. Und sein 
Go kriegt er mit dem Setzen des Vorteilers. Danach läuft der Timer.

>
>   // Let's go
>   sei();
>   while( !timerHasFinished ) {;}
>   cli();
> }

du schaltest den Timer nicht wieder ab?

Autor: Kiaa (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Danke für deinen qualifizierten Input. Ich habe den Code jetzt gemäß 
deiner Vorschläge umgestellt, und siehe da: es läuft!

Allerdings ziemlich genau um den Faktor 2 zu langsam, aber das bekomme 
ich auch noch raus...

Danke! :-)

Autor: Kiaa (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hm, also leider will es immer noch nicht so ganz. Es timed zwar, 
allerdings viel zu langsam. Die "normalen" Funktionen (_delay_ms) 
funktionieren wunderbar...

Hier mal der überarbeitete Code:

// Local flag to signalize finished timing
volatile bool timerHasFinished = false;

// Cou8nter used for timing
volatile uint timerRepititions = 0;




// Wait micro (10^-6) seconds
void Timing_wait_us( uint us )
{
  Timing_startHardwareTimer( 8, PRESCALE_1, us );
}

// Wait milli (10^-3) seconds
void Timing_wait_ms( uint ms )
{
  Timing_startHardwareTimer( 125, PRESCALE_64, ms );
}

// Wait seconds
void Timing_wait_s( uint s )
{
  Timing_wait_ms( s*1000 );
}


// Sets up the registers to simplify timer usage
void Timing_startHardwareTimer( uchar compareValue, Prescaler prescaler, 
uint repititions )
{
  // Stop timer
  TCCR0B = 0;

  // Store number of repetitions
  timerRepititions = repititions;

  // Clear counter on compare match
  TCCR0A = (1 << COM0A1);

  // Output compare register
  OCR0A = compareValue;

  // Enable compare match interrupt
  TIMSK = 2;

  // Reset timer
  timerHasFinished = false;
  TCNT0 = 0;

  // Prescaler
  sei();
  TCCR0B = (prescaler+1);

  // Let's go
  while( !timerHasFinished ) {;}

  // Stop timer
  TCCR0B = 0;
  cli();
}


// Timer interrupt
ISR(TIMER0_OVF_vect)
{
  // Decrease repititions
  if( timerRepititions > 0 )
  {
    timerRepititions--;
    if( timerRepititions == 0 )
      timerHasFinished = true;
  }
  else
  {
    timerHasFinished = true;
  }//end if
}


Ich kann mir wirklich nicht erklären wo das Problem liegt :-(

Autor: Stefan B. (stefan) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>  // Output compare register
>  OCR0A = compareValue;

Bei den angegebenen Werten ist der compareValue um +1 zu hoch.
=> AVR-GCC-Tutorial/Die Timer und Zähler des AVR

> // Enable compare match interrupt
> TIMSK = 2;
> ISR(TIMER0_OVF_vect)

Sicher OVERFLOW, und nicht COMPARE MATCH (CTC)? Ich denke im Moment ist 
es um den Faktor 2 zu langsam :-)

Mit welcher physikalischen Taktrate läuft dein AVR? (Hardware Taktquelle 
ist? AVR Fuses sind? AVR ist?)

Ein komplettes kompilierbares und simulierbares Listing wäre zur 
Ferndiagnose hilfreich. Tipp: Längere Listings (größer ca. eine 
Bildschirmseite) bitte in den Anhang.

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.