Mal wieder 'ne Software PWM Frage

Gast #283678
Lesenswert?
• ▲
▼
Hi,

ich hab wie schon viele vor mir eine kleine Frage bezüglich dem
Software PWM Problem. Als Anhang hab ich meinen C-Testcode, der soweit
mit einem PWM-Kanal funktioniert (LED dimmt ohne Flackern auf). Wenn
ich nun aber eine zweite Abfrage in die while-Schleife einfüge klappt
gar nichts mehr. Sollte ich solche Routinen lieber in Assembler
schreiben als in C?
Bzw. Hat jemand vielleicht schon einen Beispielcode mit mehreren PWM
Ausgangskanälen und geringer Systembelastung. (Ich habe übrigens einen
AtMega16 mit einem 10 Mhz Quarz).
Angehängte Dateien:
Gast #283681
Lesenswert?
• ▲
▼
Wiso teilst du im Interrupt die Frequenz nochmal durch 256 ?
Stell doch einfach den den Prescaler au 256.

Wenn es im Interrupt immer noch flackert, dann ist der restliche Code
falsch bzw. schlecht programmiert.
Gast #283683
Lesenswert?
• ▲
▼
du mußt alle pwm-kanäle in der timer-isr bearbeiten. im hauptprogramm
änderst du dann nur noch die werte der einzelnen kanäle

timer z.b. prescaler 256
in der isr zählst du eine variable hoch und vergleichst diese dann mit
den einzelnen pwm kanälen --> wenn der wert gleich ist setz du den
ausgang auf 1. wenn der zähler überlauft setzt du alle kanäle wieder
auf 0.
Gast #283684
Lesenswert?
• ▲
▼
Soweit so gut,
die Idee ist nicht schlecht, danke. Nur hab ich jetzt ein Problem mit
der Frequenz des PWM.

10Mhz /256 (8bit Timer Überlauf) = 40kHz
40kHz /100 (Zählschritte) = 390Hz

Sollte das Oszi eigentlich anzeigen. Nur zeigt es mir jetzt gerade mal
151Hz. Stimmt das was in meiner Rechnung nicht?
Angehängte Dateien:
Gast #283686
Lesenswert?
• ▲
▼
PWM läuft nun einwandfrei sogar mit UART Kommunikation.
1
#include <avr/io.h> //Standard IO Einstellungen
2
#include <avr/iom16.h> //Standard Atmega16 Einstellungen
3
#include <avr/signal.h> //Signal definieren
4
#include <avr/interrupt.h> //Signal definieren
5

6
//Funktionsprototypen
7
void Timerinit(void);
8
void UARTinit(void);
9

10
//globale Variablen
11
volatile char zaehler = 0;
12
volatile char LED = 1;
13
char PWM1 = 100;
14
char PWM2 = 100;
15
char PWM3 = 100;
16

17
int main(void)
18
{
19
cli();
20
PORTB=(7<<PB1)|(1<<PB0);
21
Timerinit();
22
UARTinit();
23
DDRB=0xFF;
24
sei();
25
while(1)
26
  {
27
  }
28
}
29

30
//Timerinitialisierung
31
void Timerinit()
32
{
33
TCCR0 = (1<<CS01);
34
TIMSK = (1<<TOIE0);
35
}
36

37
void UARTinit()
38
{
39
UCSRB |= ( 1 << TXEN )|(1 << RXEN)|(1<<RXCIE);      // UART TX+RX+RXint
40
einschalten
41
  UCSRC |= ( 1 << URSEL )|( 3<<UCSZ0 );          // Asynchron 8N1
42
  UBRRH  = 0;                                   // Highbyte ist 0
43
  UBRRL  = 64;                                  // Lowbyte ist 51 (
44
dezimal )
45
}
46

47
//Interruptroutine PWM
48
SIGNAL (SIG_OVERFLOW0)
49
{
50
if (zaehler == 100) 
51
  {
52
  PORTB = (7 << PB1);
53
  zaehler = 0;
54
  }
55
if (zaehler == PWM1) PORTB &= ~(1<<PB1);
56
if (zaehler == PWM2) PORTB &= ~(1<<PB2);
57
if (zaehler == PWM3) PORTB &= ~(1<<PB3);
58
zaehler++;
59
}
60

61
SIGNAL (SIG_UART_RECV)
62
{
63
switch (LED) {
64
case 1:
65
  PWM1=UDR;
66
  LED=2;
67
  break;
68
case 2:
69
  PWM2=UDR;
70
  LED=3;
71
  break;
72
case 3:
73
  PWM3=UDR;
74
  LED =1;
75
  break;
76
  }
77
UDR=LED;
78
}
#631274
Lesenswert?
• ▲
▼
Hallo,

Ich habe deinen Code mal aufgegriffen,
um eine PWM Frequenz zu nutzen, u damit eine LED zu dimmen.

Wenn ich PWM1 auf 0 stelle, ist die angeschlossene LED immer noch etwas 
an.
Dürfte doch eigentlich nicht sein, da je kleiner der PWM Wert, desto 
dunkler die LED, nicht?
Also müsste die LED bei einem Wert von 0 doch aus sein!?


Gruß Toby
Gast #631298
Lesenswert?
• ▲
▼
@ Tobias Tetzlaff:

Das liegt daran, dass bei der HardwarePWM das Setzen des Auganges beim 
PWM-Wert von Null UNTERDRÜCKT wird. Bei PWM Wert gleich Max wird das 
Abschalten unterdrückt. => Datenblatt Atmel, PWM-Beschreibung
Hier in dieser Software ist das nicht der Fall.
Da folgendes geschieht, wenn zähler=100:
1
if (zaehler == 100) 
2
  {
3
  PORTB = (7 << PB1);
4
  zaehler = 0;
5
  }

Das wird ausgeführt, die LEDs werden AUSgeschaltet (LOW-aktiv)
Der Zähler wird auf Null gesetzt.
1
if (zaehler == PWM1) PORTB &= ~(1<<PB1);
Ist auch erfüllt für PWM1=0:
Somit wird die LED fälschlicherweise wieder zugeschaltet.

Es sollte so gemacht werden:
Da folgendes geschieht, wenn zähler=100:
1
..
2
if ( (zaehler == PWM1) && (zaehler  != 0) ) PORTB &= ~(1<<PB1);
3
..
4
if (zaehler++ == 100) 
5
  {
6
  if ( PWM1 != 100 )   PORTB |= (1 << PB1);
7
  ...
8
  zaehler = 0;
9
  }
10
...
11
// das separate zaehler++; kann entfallen!

Die Reihenfolge ist mit Absicht gedreht worden, damit die LED bei 
PWMx=100 auch angeht
#632121
Lesenswert?
• ▲
▼
Hallo,

ich habe einfach die Led an/aus Befehle getauscht.

Nun ist die LED bei PWM == 100 aus, bei PWM == 0 ganz an.

So gehts auch, danke!

//Interruptroutine PWM
SIGNAL (SIG_OVERFLOW2)
{
  if (zaehler == 100)
  {
    //PORTB = (7 << PB1);
    //Set_All_LEDs(0xFF);
    Clear_All_LEDs();
    zaehler = 0;
  }
  if (zaehler == PWM1)
  {
    //Clear_All_LEDs();
    Set_All_LEDs(0xFF);
  }
//PORTB &= ~(1<<PB1);
//if (zaehler == PWM2) PORTB &= ~(1<<PB2);
//if (zaehler == PWM3) PORTB &= ~(1<<PB3);
zaehler++;
}


Gruß Toby

Antwort schreiben

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.

Formatierung
  • [c]C-Code[/c]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] – Link zu einem Artikel
  • Verweis auf einen anderen Beitrag: Rechtsklick auf dessen Beitrags-ID (#8078628), „Adresse kopieren“, in den Text einfügen

Mehr zur Formatierung

Längeren Sourcecode als Anhang, nicht in den Text. JPG nur für Fotos und Scans; Zeichnungen und Screenshots als PNG oder GIF. Siehe Bildformate.

Schon registriert? Anmelden

Wird nicht angezeigt. Wir schicken dir einen Link; sobald du damit bestätigst, erscheint dein Beitrag.

Mit dem Abschicken legst du einen kostenlosen Account an und erkennst die Nutzungsbedingungen und die Datenschutzerklärung an.