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


von Kiaa (Gast)


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
}

von Karl H. (kbuchegg)


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?

von Kiaa (Gast)


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! :-)

von Kiaa (Gast)


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 :-(

von Stefan B. (stefan) Benutzerseite


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.

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.