Forum: Mikrocontroller und Digitale Elektronik Wieder mal ein PWM Beitrag (Atmega8)


von N. B. (saint1234)


Lesenswert?

Hallo liebe Community,

ein Freund hat mich beauftragt eine Kleinigkeit für Ihn zu basteln.
Dafür ist ein PWM von Nöten welche später die Helligkeit einiger LEDs 
über ein analog eingelesenes Audiosignal regelt.

Ich habe mir eine 8Bit PWM genommen mit 32 Helligkeitsstufen (im Bsp. 
nur mit 8).
Da ich das ganze Modular angehe ist mein erster Schritt die reine PWM.

(Ich bin kein totaler Anfänger und habe auch alle Beiträge bezüglich 
PWM's gelesen und verstanden, dennoch würde ich gerne meine eigene 
schreiben und nicht die Routine des Soft-PWM Beitrags nehmen)

Angaben: Fuses eingestellt auf internen 8MHz Takt

•
1
#define F_CPU 8000000L
2
#define LED_AN  PORTC &= ~(1<<PINC5)
3
#define LED_AUS PORTC |=(1<<PINC5)
4
5
6
#include <avr/io.h>
7
#include <avr/Interrupt.h>
8
9
10
void initialize(void)
11
{
12
  DDRC=0xff;
13
  TCCR0 |= (1<<CS00);                      //hier ist das Problem
14
  TCCR1B |= (1<<CS11) | (1<<CS10);
15
  TIMSK |= (1<<TOIE0) | (1<<TOIE1);
16
17
  sei();
18
}
19
20
21
volatile uint16_t pwm_state = 0;
22
volatile uint8_t fading_flag = 0;
23
volatile uint16_t pwm_setting[8]={0,1,2,3,....}; //hier pwm Werte
24
25
int main(void)
26
{
27
  initialize();
28
29
  while(1)
30
  {
31
   
32
    if(fading_flag==2)       //"Fadinglänge"
33
    {
34
     pwm_state++;            //erhöhen der Helligkeitsstufe
35
     fading_flag=0;
36
    }
37
38
      if(pwm_state==8) pwm_state=0;
39
40
41
  }
42
43
}
44
45
ISR(TIMER0_OVF_vect)
46
{
47
  counter++;
48
 
49
 if(counter<=pwm_setting[pwm_state])LED_AN;
50
 else LED_AUS;
51
52
 if(counter==255)counter=0;
53
  
54
}
55
56
ISR(TIMER1_OVF_vect)
57
{
58
 fading_flag++;           // Eventflag für Zeitdauer 
59
}


Meine Problem ist, das die LED bei einem Timer0 Vorteiler von über 8 
anfängt deutlich zu blinken obwohl die Frequenz doch immer noch 
ausreichend sein müsste:

8000000 / 64 (als Bsp.) / 256 = ~ 500Hz

Wie kann das sein? Sind meine Berechnungen falsch oder etwas im 
Programm? Die Fadingschritte sind variabel und hier nur als Bsp.

Ich bin über jede Hilfe Dankbar!!!

Mit freundlichen Grüßen,
saint


P.s (leider habe ich den Sourcecode nicht zur Hand da ich auf Arbeit 
bin, aber dieser sollte sich nicht unterscheiden zu dem angegebenen)

von Thomas E. (thomase)


Lesenswert?

Nico Bochmann schrieb:
 > 8000000 / 64 (als Bsp.) / 256 = ~ 500Hz
>
> Wie kann das sein? Sind meine Berechnungen falsch oder etwas im
> Programm? Die Fadingschritte sind variabel und hier nur als Bsp.

In deiner Rechnung fehlt die PWM-Auflösung von 256. Das sind die 256 
Schritte (counter), mit denen der Puls zusammengebastelt wird. Also 
nochmal durch 256 teilen. Das müsste aber bei Prescaler = 8 (15Hz), wenn 
man nicht sehr wohlwollend ist, auch schon flackern.


mfg.

von N. B. (saint1234)


Lesenswert?

Thomas Eckmann schrieb:

> In deiner Rechnung fehlt die PWM-Auflösung von 256. Das sind die 256
> Schritte (counter), mit denen der Puls zusammengebastelt wird. Also
> nochmal durch 256 teilen. Das müsste aber bei Prescaler = 8 (15Hz), wenn
> man nicht sehr wohlwollend ist, auch schon flackern.
>
> mfg.

Danke für den Tipp Herr Eckmann! die 256 waren in meiner Rechnung 
bereits "Counter" aber ich habe total vergessen die 8Bit (256 Schritte) 
des Timer0 mi einzubeziehen. Ja das Flackern kam bereits beim Prescaler 
8.

Da ich keinen externen 16MHz Quarz nutzen möchte bleibt mir also nur die 
Stellschraube der PWM Auflösung bzw die Veränderung über das TCNT0 
Register.

Ist diese Annahme richtig?

von Thomas E. (thomase)


Lesenswert?

Mit Prescaler = 1 würde es paasen. Dann kommt allerdings alle 256 Takte 
ein Interrupt. Deshalb nur ein Flag setzen und die PWM in der 
Hauptschleife machen. Wenn da mal ein Step verschluckt wird, ist das 
weniger tragisch, als wenn die Timer-ISR den Controller blockiert. 
Ansonsten mal drüber nachdenken ob nicht auch 64 oder vielleicht sogar 
nur 32 PWM-Stufen ausreichen.

Einen PWM-Kanal kann der Atmega8 auch im Timer0 in Hardware. Das 
entspannt das Timing dann völlig.
Ein Atmega88 hat natürlich, genauso wie in den anderen Timern, 2 davon 
und kann auch im Timer0 CTC. Aber auf mich hört ja keiner.

mfg.

von N. B. (saint1234)


Lesenswert?

Thomas Eckmann schrieb:
> Mit Prescaler = 1 würde es paasen. Dann kommt allerdings alle 256 Takte
> ein Interrupt. Deshalb nur ein Flag setzen und die PWM in der
> Hauptschleife machen. Wenn da mal ein Step verschluckt wird, ist das
> weniger tragisch, als wenn die Timer-ISR den Controller blockiert.
> Ansonsten mal drüber nachdenken ob nicht auch 64 oder vielleicht sogar
> nur 32 PWM-Stufen ausreichen.

Ich habe es jetzt angepasst da ich mir meine PWM Frequenz auf 1KHz 
festgelegt habe

 8000000/8/256/x = 1KHz
 x=3.90... ~ 4

darauß folgt das mein Zähler nur 4 schritte zählen darf (TCTN0 = 251) 
damit ich eine PWM Frequenz von 1KHZ bekomme.

Die PWM Stufen runter drehen wäre mein nächster Schritt.

Thomas Eckmann schrieb:
> Einen PWM-Kanal kann der Atmega8 auch im Timer0 in Hardware. Das
> entspannt das Timing dann völlig.
> Ein Atmega88 hat natürlich, genauso wie in den anderen Timern, 2 davon
> und kann auch im Timer0 CTC. Aber auf mich hört ja keiner.

Momentan würde auch ein Hardware-PWM funktionieren und wäre auch 
definitiv sinnvoller. Allerdings werden im späteren Projekt mehrere PWM 
Kanäle benötigt weshalb mir eine Software PWM hier nur in Frage kommt.

Vielen Dank für die schnelle Hilfe!!!

von Thomas E. (thomase)


Lesenswert?

Ein Preload von 251 zählt 5x bis zum Überlauf: 2, 3, 4, 5, 0.
Nimm aber lieber Timer2. Der kann CTC. Damit geht das viel eleganter.

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.