Forum: Mikrocontroller und Digitale Elektronik Timer0 mit falscher Frequenz


von H. F. (hafisch)


Lesenswert?

Hallo zusammen

Ich habe eine kleine Applikation welche ein sich ständig änderndes 
PWM-Signal zur Generierung einer Melodie mit einem Buzzer generiert.

Doch bei ersten Tests mit meinem PWM-Generierungs-Ablauf habe ich einen 
Effekt welchen ich mir nicht erklären kann.

Ich arbeite mit einem Attiny85, welcher mit 8MHz läuft.
Den Timer0 habe ich mit einem Prescaler von 1024 intialisiert und werde 
den Overflow-Interrupt aus, welchen ich bei jeweils 30 Überläufen zum 
setzen einer LED verwende.

Wenn ich das ganze nun durchrechne müsste dies bei 30 Overflows eine 
Frequenz von 1Hz geben.

T = 1s/8000000Hz ) = 0.0000000125 s
T mit Prescaler = 0.0000000125s * 1024 = 0.000128s
T Überlauf = 0.000128s*256 = 0.032768

Dies gibt pro Sekunde 30 Überläufe.

Wenn ich dies so lade, ist es so dass die LED etwa 1 mal alle 8 Sekunden 
blinkt.

Die Fuses sind folgendermassen eingestellt:

low = D2
high = DF
ext = FF

Der interne Teiler ist also nicht aktiviert.

Hier der entsprechende Code
1
#include <avr/io.h>
2
#include <stdio.h>
3
#include <avr/interrupt.h>
4
5
volatile char iPwm_value = 0;
6
volatile int bOn = 0;
7
8
// --- main routine ---
9
10
int main(){
11
12
    // --- define IO's ---
13
    // Out
14
    DDRB = (1<<PB4);
15
16
    // Timer settigs
17
    TCCR0B |= ((1<<CS00)|(1<<CS02));
18
    TIMSK  |= (1<<TOIE0);
19
    sei();
20
21
    PORTB |= (1<<PB4); // active low LED aus
22
23
    // main-loop
24
    while( 1 ) {
25
26
    }
27
28
  return 1;
29
}
30
31
ISR (TIMER0_OVF_vect)
32
{
33
34
   if (iPwm_value==30){
35
   if (bOn ==0){
36
       PORTB &= ~(1<<PB4); // active low LED an
37
       bOn = 1;
38
   }else{
39
     PORTB |= (1<<PB4); // active low LED aus
40
       bOn = 0;
41
   }
42
   }
43
   iPwm_value++;
44
45
}

An was kann das noch liegen? Hat jemand eine Idee?
Danke für die Hilfe und Gruss

Hafisch

von g457 (Gast)


Lesenswert?

> An was kann das noch liegen?

iPwm_value wird nicht zurückgesetzt.

von Detlef K. (adenin)


Lesenswert?

ISR (TIMER0_OVF_vect)
{

   if (iPwm_value==30){
   iPwm_value=0;  //Wert rücksetzen !!! <----------Wichtig!
  if (bOn ==0){
       PORTB &= ~(1<<PB4); // active low LED an
       bOn = 1;
   }else{
     PORTB |= (1<<PB4); // active low LED aus
       bOn = 0;
   }
   }
   iPwm_value++;

}

von H. F. (hafisch)


Lesenswert?

Uuups... Anfängerfehler.
Danke für die Hilfe und einen schönen Tag.

hafisch

von H. F. (hafisch)


Lesenswert?

Hallo zusammen

Erst mal danke für die schnelle Hilfe.
Allerdings funktioniert dies nach wie vor nicht wie gewünscht.

Wenn ich die LED im Sekundentakt blinken lassen will, habe ich die 
folgende Rechnung gemacht:

CPU-Zykluszeit 8000000 Hz
Prescaler 8
Timertyp 8bit
gewünschte Blinkzeit 1s

1s/(1/8000000)*8*256) = 3906.25 Überläufe

Wenn ich also 3906.25 Überläufe zähle, sollte dies meiner Meinung nach 
eine Blink-Zykluszeit der LED von 1s geben.

Diese liegt allerdings bei etwa 3.5 s.

An was könnte dies noch liegen?

Hier der Code
1
#include <avr/io.h>
2
#include <stdio.h>
3
#include <avr/interrupt.h>
4
5
// pwm data
6
unsigned long udiTmrOvflCntr = 0;
7
8
// --- main routine ---
9
10
int main(){
11
12
  // --- define IO's ---
13
  // Out
14
  DDRB = (1<<PB4);
15
16
  // Timer settigs
17
  TCCR0B |= (1<<CS01);                // prescaler 8
18
  TIMSK  |= (1<<TOIE0);        // Overflow Interrupt einschalten
19
  sei();
20
21
  // main-loop
22
  while( 1 ) {
23
24
  }
25
  return 1;
26
27
}
28
29
ISR (TIMER0_OVF_vect)
30
{
31
32
    // generate PWM
33
    if (udiTmrOvflCntr == 3906){
34
    if ((PORTB & (1<<PB4)) == 0){
35
        PORTB |= (1<<PB4); // active low LED aus
36
    }else{
37
      PORTB &= ~(1<<PB4); // active low LED an
38
    }
39
    udiTmrOvflCntr = 0;
40
    }
41
    udiTmrOvflCntr++;
42
43
}

An was könnte dies noch liegen?

Danke für die Hilde und Grüsse
Hafisch

von Dussel (Gast)


Lesenswert?

Zuerst solltest du dir mal einen besseren Stil angewöhnen.

Deine Rechnung sieht gut aus, aber so schaltet die LED jede Sekunde um. 
Das bedeutet eine Zykluszeit von zwei Sekunden.
Die übliche Frage dabei: Läuft der Controller wirklich mit 8MHz und 
nicht mit internem 4MHz-Takt? Das würde die Zeit erklären.

von H. F. (hafisch)


Lesenswert?

Hallo Danke für die schnelle Antwort

Die Zykluszeit im AvrDude ist auf 80000000 Hz gestellt.
Die Fuses sind wie bereits in der ursprünglichen Frage erwähnt auf:

low = D2
high = DF
ext = FF

Dies ist also der interne 8Mhz RC-Clock, mit ausgeschalteter interner 
Taktteilung.

Kann man sonst noch etwas einstellen was einen Einfluss auf die 
Taktfrequenz hat?

Danke und Gruss
hafisch

von H. F. (hafisch)


Lesenswert?

Hallo nochmals

Ich habe dieselbe Rechnung nochmals mit einem Prescaler von 1024 
gemacht. So komme ich auf einen Überlaufzähler von 30.
Wenn ich dies so einstelle stimmt alles. Die LED blinkt so im 
Sekundentakt.

Dies heisst für mich, dass die Taktfrequenz stimmt.
Es muss also irgendetwas applikatives sein.

Kann mir allerdings nicht genau erklären was.

Danke für die Hilfe und freundliche Grüsse
Hafisch

von Thomas E. (thomase)


Lesenswert?

H. Fisch schrieb:
> unsigned long udiTmrOvflCntr = 0;

Erstens ist unsigned long ein bisschen übertrieben, zweitens muss die 
Variable volatile sein.

mfg.

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.