Forum: Compiler & IDEs PWM mit Maskierung


von Julien M. (ljminti)


Lesenswert?

Hallo

Ich möchte eine PWM erstellen. Allerdings nur auf 4 Bits eines Ports.
Klingt eigentlich einfach, allerdigs habe ich folgenden Code verwendet.
1
ISR(TIMER0_OVF_vect)
2
{
3
static BYTE neuer_wert=0;        // fuer allerersten Aufruf
4
static BYTE summe[channels];
5
6
  PORTD=neuer_wert;            // letztes Ergebnis verzoegert ausgeben
7
  neuer_wert += neuer_wert;             // schieben fuer naechstes Bit
8
  if((summe[3]+= wert[3]) >= SCHRITTE) {  // bis Endwert ueberschritten wird
9
    summe[3] -= SCHRITTE;        // dann Summe korrigieren
10
    neuer_wert |= 1;          // und Bit setzen (Ueberlauf)
11
  }
12
  neuer_wert += neuer_wert;             // schieben fuer naechstes Bit
13
  if((summe[2]+= wert[2]) >= SCHRITTE) {  // bis Endwert ueberschritten wird
14
    summe[2] -= SCHRITTE;        // dann Summe korrigieren
15
    neuer_wert |= 1;          // und Bit setzen (Ueberlauf)
16
  }
17
  neuer_wert += neuer_wert;             // schieben fuer naechstes Bit
18
  if((summe[1]+= wert[1]) >= SCHRITTE) {  // bis Endwert ueberschritten wird
19
    summe[1] -= SCHRITTE;        // dann Summe korrigieren
20
    neuer_wert |= 1;          // und Bit setzen (Ueberlauf)
21
  }
22
  neuer_wert += neuer_wert;             // schieben fuer naechstes Bit
23
  if((summe[0]+= wert[0]) >= SCHRITTE) {  // bis Endwert ueberschritten wird
24
    summe[0] -= SCHRITTE;        // dann Summe korrigieren
25
    neuer_wert |= 1;          // und Bit setzen (Ueberlauf)
26
  }
27
}

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

von Dirk (Gast)


Lesenswert?

Hallo, mache es dir doch nicht so schwer.
1
#define pwm_kanal 5
2
3
4
PORTD &=~(1<<pwm_kanal);    // BitNo. logisch 0
5
    
6
PORTD |=(1<<pwm_kanal);     // BitNo. logisch 1

von Julien M. (ljminti)


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ß

von FBI (Gast)


Lesenswert?

Hi,

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

von FBI (Gast)


Lesenswert?

... oder so:
1
PORTD = (PORTD & 0xf0) | (neuer_wert & 0x0f);

von Julien M. (ljminti)


Lesenswert?

Hallo,

vielen Dank für die Antworten

Leider will meine PWM auf dem ATtiny2313 nicht laufen.

Hier nochmal mein kompletter Code
1
#include <avr/io.h>
2
#include <avr/interrupt.h>
3
4
typedef unsigned char BYTE;
5
typedef unsigned short WORD;
6
7
#define    channels 4      // number used Channels
8
#define    F_CPU 20000000      // CPU Clock    
9
#define   SCHRITTE  255    // PWM Auflösung 8-bit
10
11
BYTE data[channels];                    // Data-Array
12
13
void reset(void)
14
{
15
  cli();
16
  DDRD  &= ~(1<<PD0)|(1<<PD2);    // PD0, PD2 als Eingang
17
  DDRD  |= (1<<PD3)|(1<<PD4)|(1<<PD5)|(1<<PD6);  
18
  DDRB  = 0xff;        // PB0-7 als Eingang
19
  PORTB  = 0x00;        // aktiv low
20
21
  //PORTD  |= (1<<PD3)|(1<<PD4)|(1<<PD5)|(1<<PD6);
22
23
  data[0] = 255;            
24
  data[1] = 170;            
25
  data[2] = 100;            
26
  data[3] = 50;            
27
28
  
29
  TIFR = (1 << TOV0);          // Timer0 Interuptflag löschen
30
  TCCR0B   |= (1<<CS00);        // Timer0 ohne Vorteiler
31
    TIMSK   |= (1<<TOIE0);         // Timer0 Overflow-int enable
32
33
}
34
35
36
// TIMER OVERFLOW INTERUPT
37
ISR(TIMER0_OVF_vect)
38
{
39
40
char savesreg = SREG;
41
42
static unsigned char neuer_wert=0;  // fuer allerersten Aufruf
43
static unsigned char summe[channels];
44
45
  PORTD = (PORTD & 0xf0) | (neuer_wert & 0x0f);   // letztes Ergebnis verzoegert ausgeben
46
  if((summe[3]+= data[3]) >= SCHRITTE) {  // bis Endwert ueberschritten wird
47
    summe[3] -= SCHRITTE;    // dann Summe korrigieren
48
    neuer_wert |= 1;      // und Bit setzen (Ueberlauf)
49
  }
50
  neuer_wert += neuer_wert;           // schieben fuer naechstes Bit
51
  if((summe[2]+= data[2]) >= SCHRITTE) {  // bis Endwert ueberschritten wird
52
    summe[2] -= SCHRITTE;    // dann Summe korrigieren
53
    neuer_wert |= 1;      // und Bit setzen (Ueberlauf)
54
  }
55
  neuer_wert += neuer_wert;           // schieben fuer naechstes Bit
56
  if((summe[1]+= data[1]) >= SCHRITTE) {  // bis Endwert ueberschritten wird
57
    summe[1] -= SCHRITTE;    // dann Summe korrigieren
58
    neuer_wert |= 1;      // und Bit setzen (Ueberlauf)
59
  }
60
  neuer_wert += neuer_wert;           // schieben fuer naechstes Bit
61
  if((summe[0]+= data[0]) >= SCHRITTE) {  // bis Endwert ueberschritten wird
62
    summe[0] -= SCHRITTE;    // dann Summe korrigieren
63
    neuer_wert |= 1;      // und Bit setzen (Ueberlauf)
64
  }
65
66
  SREG = savesreg;
67
}
68
69
// MAIN
70
int main(void)
71
{
72
    reset();
73
    sei();      //enable global interrupts
74
    for (;;) ;
75
    return (0);
76
77
}

Vielleicht findet Ihr den Fehler!

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

Gruß

von Patrick D. (oldbug) Benutzerseite


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.

von johnny.m (Gast)


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.

von Julien (Gast)


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

von unsichtbarer WM-Rahul (Gast)


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:
1
ISR(TIMER0_OVF_vect)
2
{
3
4
char savesreg = SREG;
5
6
static unsigned char neuer_wert=0;  // fuer allerersten Aufruf
7
static unsigned char zaehler=0;
8
9
if (zaehler == 0) neuer_wert = 0xFF; // Ausgänge einschalten
10
if((zaehler == data[3])  neuer_wert &= ~0x08;
11
if((zaehler == data[2])  neuer_wert &= ~0x04;
12
if((zaehler == data[1])  neuer_wert &= ~0x02;
13
if((zaehler == data[0])  neuer_wert &= ~0x01;
14
PORTD = neuer_wert;
15
zaehler ++;
16
}

von schmichael (Gast)


Lesenswert?

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

Gruß Michael

von unsichtbarer WM-Rahul (Gast)


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...

von Julien M. (ljminti)


Lesenswert?

Hallo WM-Rahul,

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

Gruß Julien

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.