mikrocontroller.net

Forum: Compiler & IDEs Mal wieder 'ne Software PWM Frage


Autor: Flo K. (Gast)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht 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).

Autor: Benedikt (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Pack alles in den Timer Interrupt, dann flackert nichts mehr.

Autor: Flo K. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Auch schon ausprobiert. Leider das gleiche.

Autor: Benedikt (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Flo K. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich möchte mehrere PWM's mit 8 bit Auflösung. Dazu benötige ich eine
feste PWM Frequenz die 256 mal die Interruptfrequenz ist. Oder verstehe
ich da etwas falsch, bzw. geht das einfacher?

Autor: Sebastian (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Flo K. (Gast)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht 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?

Autor: Flo K. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Lol, habs gerade entdeckt. Die Variable zaehler lief immmer bis 256 und
überschlug dann anstatt nach 100 wieder 0 zu werden.

Autor: Flo K. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
PWM läuft nun einwandfrei sogar mit UART Kommunikation.
#include <avr/io.h> //Standard IO Einstellungen
#include <avr/iom16.h> //Standard Atmega16 Einstellungen
#include <avr/signal.h> //Signal definieren
#include <avr/interrupt.h> //Signal definieren

//Funktionsprototypen
void Timerinit(void);
void UARTinit(void);

//globale Variablen
volatile char zaehler = 0;
volatile char LED = 1;
char PWM1 = 100;
char PWM2 = 100;
char PWM3 = 100;

int main(void)
{
cli();
PORTB=(7<<PB1)|(1<<PB0);
Timerinit();
UARTinit();
DDRB=0xFF;
sei();
while(1)
  {
  }
}

//Timerinitialisierung
void Timerinit()
{
TCCR0 = (1<<CS01);
TIMSK = (1<<TOIE0);
}

void UARTinit()
{
UCSRB |= ( 1 << TXEN )|(1 << RXEN)|(1<<RXCIE);      // UART TX+RX+RXint
einschalten
  UCSRC |= ( 1 << URSEL )|( 3<<UCSZ0 );          // Asynchron 8N1
  UBRRH  = 0;                                   // Highbyte ist 0
  UBRRL  = 64;                                  // Lowbyte ist 51 (
dezimal )
}

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

SIGNAL (SIG_UART_RECV)
{
switch (LED) {
case 1:
  PWM1=UDR;
  LED=2;
  break;
case 2:
  PWM2=UDR;
  LED=3;
  break;
case 3:
  PWM3=UDR;
  LED =1;
  break;
  }
UDR=LED;
}

Autor: Patrick Dohmen (oldbug) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ohne großartig auf die Funktion eingehen zu wollen:
#include <avr/io.h> //Standard IO Einstellungen 
#include <avr/iom16.h> //Standard Atmega16 Einstellungen 

1. Die Kommentare sind nicht ganz korrekt
2. die avr/io.h bindet die jeweils passende avr/ioXYZ.h bei korrekt
eingestellter -mmcu Option automatisch ein.

Autor: Flo K. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
OK, der Quellcode wahr ein kleiner Schnellschuss.
Aber danke nochmal für die schnelle Hilfe.

Autor: Tobias Tetzlaff (tobytetzi)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Matthias Lipinsky (lippy)
Datum:

Bewertung
0 lesenswert
nicht 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:
if (zaehler == 100) 
  {
  PORTB = (7 << PB1);
  zaehler = 0;
  }

Das wird ausgeführt, die LEDs werden AUSgeschaltet (LOW-aktiv)
Der Zähler wird auf Null gesetzt.
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:
..
if ( (zaehler == PWM1) && (zaehler  != 0) ) PORTB &= ~(1<<PB1);
..
if (zaehler++ == 100) 
  {
  if ( PWM1 != 100 )   PORTB |= (1 << PB1);
  ...
  zaehler = 0;
  }
...
// das separate zaehler++; kann entfallen!

Die Reihenfolge ist mit Absicht gedreht worden, damit die LED bei 
PWMx=100 auch angeht

Autor: Tobias Tetzlaff (tobytetzi)
Datum:

Bewertung
0 lesenswert
nicht 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

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.