www.mikrocontroller.net

Forum: Compiler & IDEs PWM mit Maskierung


Autor: Julien M. (ljminti)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo

Ich möchte eine PWM erstellen. Allerdings nur auf 4 Bits eines Ports.
Klingt eigentlich einfach, allerdigs habe ich folgenden Code verwendet.

ISR(TIMER0_OVF_vect)
{
static BYTE neuer_wert=0;        // fuer allerersten Aufruf
static BYTE summe[channels];

  PORTD=neuer_wert;            // letztes Ergebnis verzoegert ausgeben
  neuer_wert += neuer_wert;             // schieben fuer naechstes Bit
  if((summe[3]+= wert[3]) >= SCHRITTE) {  // bis Endwert ueberschritten wird
    summe[3] -= SCHRITTE;        // dann Summe korrigieren
    neuer_wert |= 1;          // und Bit setzen (Ueberlauf)
  }
  neuer_wert += neuer_wert;             // schieben fuer naechstes Bit
  if((summe[2]+= wert[2]) >= SCHRITTE) {  // bis Endwert ueberschritten wird
    summe[2] -= SCHRITTE;        // dann Summe korrigieren
    neuer_wert |= 1;          // und Bit setzen (Ueberlauf)
  }
  neuer_wert += neuer_wert;             // schieben fuer naechstes Bit
  if((summe[1]+= wert[1]) >= SCHRITTE) {  // bis Endwert ueberschritten wird
    summe[1] -= SCHRITTE;        // dann Summe korrigieren
    neuer_wert |= 1;          // und Bit setzen (Ueberlauf)
  }
  neuer_wert += neuer_wert;             // schieben fuer naechstes Bit
  if((summe[0]+= wert[0]) >= SCHRITTE) {  // bis Endwert ueberschritten wird
    summe[0] -= SCHRITTE;        // dann Summe korrigieren
    neuer_wert |= 1;          // und Bit setzen (Ueberlauf)
  }
}


Allerdings kann ich PortD nicht einfach so überschreiben, da an PD4 - 
PD7 noch UART, etc. dranhängt und diese Bits nicht verändert werden 
dürfen.

Ich bin noch C-Anfänger und würde mich über eine Lösung freuen.

Gruß Julien

Autor: Dirk (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo, mache es dir doch nicht so schwer.
#define pwm_kanal 5


PORTD &=~(1<<pwm_kanal);    // BitNo. logisch 0
    
PORTD |=(1<<pwm_kanal);     // BitNo. logisch 1


Autor: Julien M. (ljminti)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Dirk,

Nun das mit dem Bit setzten ist mir schon irgendwie klar, allerdings ist 
es ja so dass ich meine zu setztenden bzw. löschenden Bits in Bit0-3 der 
variablen "neuer_wert" drin stehen.

Bsp.

1. PortD = 0bxxxx1010
2. neuer_wert = 0b00001101

SOLL: PortD = 0bxxxx1101

...

Und wenn ich das richtig sehen mus ich diese beiden "Variablen" 
miteinander so verknüpfen dass Bit0-3 des PortD gelöscht bzw. gesetzt 
werden.

Leider leuchtet mir gerade nicht ein, wie ich das mit Deinem Vorschlag 
umsetzen kann.

Gruß

Autor: FBI (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi,

z.B. so:
PORTD ^= (PORTD ^ neuer_wert) & 0x0f;
CU Frank

Autor: FBI (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
... oder so:
PORTD = (PORTD & 0xf0) | (neuer_wert & 0x0f);

Autor: Julien M. (ljminti)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

vielen Dank für die Antworten

Leider will meine PWM auf dem ATtiny2313 nicht laufen.

Hier nochmal mein kompletter Code
#include <avr/io.h>
#include <avr/interrupt.h>

typedef unsigned char BYTE;
typedef unsigned short WORD;

#define    channels 4      // number used Channels
#define    F_CPU 20000000      // CPU Clock    
#define   SCHRITTE  255    // PWM Auflösung 8-bit

BYTE data[channels];                    // Data-Array

void reset(void)
{
  cli();
  DDRD  &= ~(1<<PD0)|(1<<PD2);    // PD0, PD2 als Eingang
  DDRD  |= (1<<PD3)|(1<<PD4)|(1<<PD5)|(1<<PD6);  
  DDRB  = 0xff;        // PB0-7 als Eingang
  PORTB  = 0x00;        // aktiv low

  //PORTD  |= (1<<PD3)|(1<<PD4)|(1<<PD5)|(1<<PD6);

  data[0] = 255;            
  data[1] = 170;            
  data[2] = 100;            
  data[3] = 50;            

  
  TIFR = (1 << TOV0);          // Timer0 Interuptflag löschen
  TCCR0B   |= (1<<CS00);        // Timer0 ohne Vorteiler
    TIMSK   |= (1<<TOIE0);         // Timer0 Overflow-int enable

}


// TIMER OVERFLOW INTERUPT
ISR(TIMER0_OVF_vect)
{

char savesreg = SREG;

static unsigned char neuer_wert=0;  // fuer allerersten Aufruf
static unsigned char summe[channels];

  PORTD = (PORTD & 0xf0) | (neuer_wert & 0x0f);   // letztes Ergebnis verzoegert ausgeben
  if((summe[3]+= data[3]) >= SCHRITTE) {  // bis Endwert ueberschritten wird
    summe[3] -= SCHRITTE;    // dann Summe korrigieren
    neuer_wert |= 1;      // und Bit setzen (Ueberlauf)
  }
  neuer_wert += neuer_wert;           // schieben fuer naechstes Bit
  if((summe[2]+= data[2]) >= SCHRITTE) {  // bis Endwert ueberschritten wird
    summe[2] -= SCHRITTE;    // dann Summe korrigieren
    neuer_wert |= 1;      // und Bit setzen (Ueberlauf)
  }
  neuer_wert += neuer_wert;           // schieben fuer naechstes Bit
  if((summe[1]+= data[1]) >= SCHRITTE) {  // bis Endwert ueberschritten wird
    summe[1] -= SCHRITTE;    // dann Summe korrigieren
    neuer_wert |= 1;      // und Bit setzen (Ueberlauf)
  }
  neuer_wert += neuer_wert;           // schieben fuer naechstes Bit
  if((summe[0]+= data[0]) >= SCHRITTE) {  // bis Endwert ueberschritten wird
    summe[0] -= SCHRITTE;    // dann Summe korrigieren
    neuer_wert |= 1;      // und Bit setzen (Ueberlauf)
  }

  SREG = savesreg;
}

// MAIN
int main(void)
{
    reset();
    sei();      //enable global interrupts
    for (;;) ;
    return (0);

}


Vielleicht findet Ihr den Fehler!

Es leuchtet prinzipiell immer PD0 auch wenn alle Daten den wert 0 haben.

Gruß

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

Bewertung
0 lesenswert
nicht lesenswert
Deine Behandlung für das SREG ist etwas merkwürdig.
Beim Eintritt in die ISR sicherst Du es und beim Austritt stellst Du den 
Ursprünglichen Zustand wieder her. Du schaltest aber zwischendurch die 
Interrupts nicht ab. Dadurch können Dir natürlich Interrupts verloren 
gehen.

Autor: johnny.m (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Das Sichern des SREG in der ISR wird vom Compiler automatisch gemacht. 
Da brauchst Du Dir als C-Programmierer keine Gedanken drum zu machen.

Autor: Julien (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

Ok das mit dem SREG ist später entstanden und kann bedenkenlos auch 
weggelassen werden.

Mir geht es um die eigentliche PWM, die nicht funktioniert.

Wenn die if-Funktionen richtig funktionieren, dann kann ich mir nur 
vorstellen dass etwas mit dem PORTD nicht stimmt.

Es ist ein ATtiny2313 und der hatr ja nur PDO - PD6, also nur 7Bit.
Kann es da zu problemen kommen?

oder gibt es eine einfachere aber stabile Software-PWM version in C die 
funktioniert?

Gruß Julien

Autor: unsichtbarer WM-Rahul (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>Wenn die if-Funktionen richtig funktionieren, dann kann ich mir nur
>vorstellen dass etwas mit dem PORTD nicht stimmt.

Genau da habe ich ein Verständnisproblem:
Wie soll deine PWM funktionieren?
Wann wird dein Ausgang wieder zurückgesetzt?

Vielleicht solltest du die Soft-PWM erst mal mit einem Ausgang 
ausprobieren und dann erweitern.
Eigentlich ist es doch ganz einfach:
Man hat einen Zähler, der in Overflow-ISR hochgezählt wird.
Diesen vergleicht man mit den verschiedenen Grenzwerten der einzelnen 
Ausgängen.
Wurde der entsprechende Wert überschritten, wird der jeweilige Ausgang 
wieder ausgeschaltet.
Eingeschaltet werden die Ausgänge übrigens, wenn der Zähler wieder bei 
Null angekommen ist.

Also:
ISR(TIMER0_OVF_vect)
{

char savesreg = SREG;

static unsigned char neuer_wert=0;  // fuer allerersten Aufruf
static unsigned char zaehler=0;

if (zaehler == 0) neuer_wert = 0xFF; // Ausgänge einschalten
if((zaehler == data[3])  neuer_wert &= ~0x08;
if((zaehler == data[2])  neuer_wert &= ~0x04;
if((zaehler == data[1])  neuer_wert &= ~0x02;
if((zaehler == data[0])  neuer_wert &= ~0x01;
PORTD = neuer_wert;
zaehler ++;
}


Autor: schmichael (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Nur kurz im Überfliegen.
In deinem Code wird immer nur das Bit 0 gesetzt (neuer_wert |= 1;)

Gruß Michael

Autor: unsichtbarer WM-Rahul (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>Nur kurz im Überfliegen.
>In deinem Code wird immer nur das Bit 0 gesetzt (neuer_wert |= 1;)

Hättest es dir doch etwas genauer angucken sollen:

>neuer_wert += neuer_wert;           // schieben fuer naechstes Bit

Zwar total umständlich, geht aber...

Autor: Julien M. (ljminti)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo WM-Rahul,

Ich habe jetzt alles nochmal geändert.
Jetzt funktioniert die PWM.
Vielen Dank.

Gruß Julien

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.