Forum: Mikrocontroller und Digitale Elektronik Arduino Micro SPWM


von Black D. (Gast)


Lesenswert?

Hallo zusamen ich bin dabei mir eine SPWM zu programmieren. Leider komme 
ich nur eine Frequenz von 5kHz hin obwohl ich in meiner Berechnung des 
OCR1A 80kHz ausgerechnet habe. Hat da jemand tipps für mich?
Gibt es sonst vielleicht noch eine andere eleganter Lösung das 
Sinussignal zu erzeugen?
1
float p;
2
int m;
3
int n;
4
int plot;
5
int val;
6
7
//Sinussignal
8
signed char S[1600]=
9
{0,0,0,1,1,1,2,2,3,3,3,4,4,5,5,5,6,6,7,7,7,8,8,9,9,9,10,10,10,11,11,12,12,12,13,13,14,14,14,15,15,16,16,16,17,17,17,18,18,
10
19,19,19,20,20,21,21,21,22,22,22,23,23,24,24,24,25,25,26,26,26,27,27,27,28,28,29,29,29,30,30,30,31,31,32,32,32,33,33,33,34,
11
34,34,35,35,36,36,36,37,37,37,38,38,38,39,39,40,40,40,41,41,41,42,42,42,43,43,43,44,44,45,45,45,46,46,46,47,47,47,48,48,48,
12
49,49,49,50,50,50,51,51,51,52,52,52,53,53,53,54,54,54,55,55,55,56,56,56,57,57,57,58,58,58,59,59,59,60,60,60,60,61,61,61,62,
13
62,62,63,63,63,64,64,64,64,65,65,65,66,66,66,67,67,67,67,68,68,68,69,69,69,69,70,70,70,70,71,71,71,72,72,72,72,73,73,73,73,
14
74,74,74,75,75,75,75,76,76,76,76,77,77,77,77,78,78,78,78,79,79,79,79,79,80,80,80,80,81,81,81,81,82,82,82,82,82,83,83,83,83,
15
84,84,84,84,84,85,85,85,85,85,86,86,86,86,86,87,87,87,87,87,88,88,88,88,88,88,89,89,89,89,89,89,90,90,90,90,90,90,91,91,91,
16
91,91,91,92,92,92,92,92,92,92,93,93,93,93,93,93,93,94,94,94,94,94,94,94,94,95,95,95,95,95,95,95,95,96,96,96,96,96,96,96,96,
17
96,96,97,97,97,97,97,97,97,97,97,97,97,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,99,99,99,99,99,99,99,99,99,99,99,99,99,
18
99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,
19
99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,97,97,97,97,97,97,97,
20
97,97,97,97,96,96,96,96,96,96,96,96,96,96,95,95,95,95,95,95,95,95,94,94,94,94,94,94,94,94,93,93,93,93,93,93,93,92,92,92,92,
21
92,92,92,91,91,91,91,91,91,90,90,90,90,90,90,89,89,89,89,89,89,88,88,88,88,88,88,87,87,87,87,87,86,86,86,86,86,85,85,85,85,
22
85,84,84,84,84,84,83,83,83,83,82,82,82,82,82,81,81,81,81,80,80,80,80,79,79,79,79,79,78,78,78,78,77,77,77,77,76,76,76,76,75,
23
75,75,75,74,74,74,73,73,73,73,72,72,72,72,71,71,71,70,70,70,70,69,69,69,69,68,68,68,67,67,67,67,66,66,66,65,65,65,64,64,64,
24
64,63,63,63,62,62,62,61,61,61,60,60,60,60,59,59,59,58,58,58,57,57,57,56,56,56,55,55,55,54,54,54,53,53,53,52,52,52,51,51,51,
25
50,50,50,49,49,49,48,48,48,47,47,47,46,46,46,45,45,45,44,44,43,43,43,42,42,42,41,41,41,40,40,40,39,39,38,38,38,37,37,37,36,
26
36,36,35,35,34,34,34,33,33,33,32,32,32,31,31,30,30,30,29,29,29,28,28,27,27,27,26,26,26,25,25,24,24,24,23,23,22,22,22,21,21,
27
21,20,20,19,19,19,18,18,17,17,17,16,16,16,15,15,14,14,14,13,13,12,12,12,11,11,10,10,10,9,9,9,8,8,7,7,7,6,6,5,5,5,4,4,3,3,3,
28
2,2,1,1,1,0,0,0,0,0,-1,-1,-1,-2,-2,-3,-3,-3,-4,-4,-5,-5,-5,-6,-6,-7,-7,-7,-8,-8,-9,-9,-9,-10,-10,-10,-11,-11,-12,-12,-12,
29
-13,-13,-14,-14,-14,-15,-15,-16,-16,-16,-17,-17,-17,-18,-18,-19,-19,-19,-20,-20,-21,-21,-21,-22,-22,-22,-23,-23,-24,-24,
30
-24,-25,-25,-26,-26,-26,-27,-27,-27,-28,-28,-29,-29,-29,-30,-30,-30,-31,-31,-32,-32,-32,-33,-33,-33,-34,-34,-34,-35,-35,
31
-36,-36,-36,-37,-37,-37,-38,-38,-38,-39,-39,-40,-40,-40,-41,-41,-41,-42,-42,-42,-43,-43,-43,-44,-44,-45,-45,-45,-46,-46,
32
-46,-47,-47,-47,-48,-48,-48,-49,-49,-49,-50,-50,-50,-51,-51,-51,-52,-52,-52,-53,-53,-53,-54,-54,-54,-55,-55,-55,-56,-56,
33
-56,-57,-57,-57,-58,-58,-58,-59,-59,-59,-60,-60,-60,-60,-61,-61,-61,-62,-62,-62,-63,-63,-63,-64,-64,-64,-64,-65,-65,-65,
34
-66,-66,-66,-67,-67,-67,-67,-68,-68,-68,-69,-69,-69,-69,-70,-70,-70,-70,-71,-71,-71,-72,-72,-72,-72,-73,-73,-73,-73,-74,
35
-74,-74,-75,-75,-75,-75,-76,-76,-76,-76,-77,-77,-77,-77,-78,-78,-78,-78,-79,-79,-79,-79,-79,-80,-80,-80,-80,-81,-81,-81,
36
-81,-82,-82,-82,-82,-82,-83,-83,-83,-83,-84,-84,-84,-84,-84,-85,-85,-85,-85,-85,-86,-86,-86,-86,-86,-87,-87,-87,-87,-87,
37
-88,-88,-88,-88,-88,-88,-89,-89,-89,-89,-89,-89,-90,-90,-90,-90,-90,-90,-91,-91,-91,-91,-91,-91,-92,-92,-92,-92,-92,-92,
38
-92,-93,-93,-93,-93,-93,-93,-93,-94,-94,-94,-94,-94,-94,-94,-94,-95,-95,-95,-95,-95,-95,-95,-95,-96,-96,-96,-96,-96,-96,
39
-96,-96,-96,-96,-97,-97,-97,-97,-97,-97,-97,-97,-97,-97,-97,-98,-98,-98,-98,-98,-98,-98,-98,-98,-98,-98,-98,-98,-98,-98,
40
-99,-99,-99,-99,-99,-99,-99,-99,-99,-99,-99,-99,-99,-99,-99,-99,-99,-99,-99,-99,-99,-99,-99,-99,-99,-99,-99,-99,-99,-99,
41
-99,-99,-99,-99,-99,-99,-99,-99,-99,-99,-99,-99,-99,-99,-99,-99,-99,-99,-99,-99,-99,-99,-99,-99,-99,-99,-99,-99,-99,-99,
42
-99,-99,-99,-99,-99,-99,-99,-99,-99,-99,-99,-99,-99,-98,-98,-98,-98,-98,-98,-98,-98,-98,-98,-98,-98,-98,-98,-98,-97,-97,
43
-97,-97,-97,-97,-97,-97,-97,-97,-97,-96,-96,-96,-96,-96,-96,-96,-96,-96,-96,-95,-95,-95,-95,-95,-95,-95,-95,-94,-94,-94,
44
-94,-94,-94,-94,-94,-93,-93,-93,-93,-93,-93,-93,-92,-92,-92,-92,-92,-92,-92,-91,-91,-91,-91,-91,-91,-90,-90,-90,-90,-90,
45
-90,-89,-89,-89,-89,-89,-89,-88,-88,-88,-88,-88,-88,-87,-87,-87,-87,-87,-86,-86,-86,-86,-86,-85,-85,-85,-85,-85,-84,-84,
46
-84,-84,-84,-83,-83,-83,-83,-82,-82,-82,-82,-82,-81,-81,-81,-81,-80,-80,-80,-80,-79,-79,-79,-79,-79,-78,-78,-78,-78,-77,
47
-77,-77,-77,-76,-76,-76,-76,-75,-75,-75,-75,-74,-74,-74,-73,-73,-73,-73,-72,-72,-72,-72,-71,-71,-71,-70,-70,-70,-70,-69,
48
-69,-69,-69,-68,-68,-68,-67,-67,-67,-67,-66,-66,-66,-65,-65,-65,-64,-64,-64,-64,-63,-63,-63,-62,-62,-62,-61,-61,-61,-60,
49
-60,-60,-60,-59,-59,-59,-58,-58,-58,-57,-57,-57,-56,-56,-56,-55,-55,-55,-54,-54,-54,-53,-53,-53,-52,-52,-52,-51,-51,-51,
50
-50,-50,-50,-49,-49,-49,-48,-48,-48,-47,-47,-47,-46,-46,-46,-45,-45,-45,-44,-44,-43,-43,-43,-42,-42,-42,-41,-41,-41,-40,
51
-40,-40,-39,-39,-38,-38,-38,-37,-37,-37,-36,-36,-36,-35,-35,-34,-34,-34,-33,-33,-33,-32,-32,-32,-31,-31,-30,-30,-30,-29,
52
-29,-29,-28,-28,-27,-27,-27,-26,-26,-26,-25,-25,-24,-24,-24,-23,-23,-22,-22,-22,-21,-21,-21,-20,-20,-19,-19,-19,-18,-18,
53
-17,-17,-17,-16,-16,-16,-15,-15,-14,-14,-14,-13,-13,-12,-12,-12,-11,-11,-10,-10,-10,-9,-9,-9,-8,-8,-7,-7,-7,-6,-6,-5,-5,
54
-5,-4,-4,-3,-3,-3,-2,-2,-1,-1,-1,0,0};
55
56
//Dreiecksignal
57
int D[16]={0,137,275,412,550,412,275,137,0,-137,-275,-412,-550,-412,-275,-137};
58
59
void setup(){
60
pinMode(5,OUTPUT);
61
pinMode(6,OUTPUT);
62
pinMode( A0,INPUT);
63
64
// Timer1 instalisieren
65
TCCR1A = 0; //Register definiert zurücksetzten
66
TCCR1B = 0; //zuerst Register definiert zurücksetzen
67
TCNT1 = 0;  //Zählerwert zurücksetzten
68
69
//Timer1 80kHZ einstellen
70
OCR1A = 199; // (16000000)/(80000*1) 1 <65536
71
TCCR1B |= (1 << WGM12); //CTC mode
72
//TCCR1B |= (0 << CS12) | (0 << CS11) | (1 >> CS10); //kein Prescale
73
TCCR1B |= (1 << CS10); // clk/1 prescale 1024
74
TIMSK1 |= (1 << OCIE1A); //Aktivieren des Timer-Vergleichs-Interrupt
75
76
}
77
78
ISR(TIMER1_COMPA_vect){ // Interrupt
79
if (D[n] < val*S[m]) {
80
bitSet(PORTC, 6); // Pin 5 HIGH
81
}
82
else {
83
bitClear(PORTC, 6); // Pin 5 LOW
84
}
85
if (D[n] < val*S[m]) {
86
bitSet(PORTD, 7); // Pin 6 HIGH
87
}
88
else {
89
bitClear(PORTD, 7); // Pin 6 LOW
90
}
91
n=n+1;
92
if(n>15)
93
n=0;
94
m=m+1;
95
if(m>1599)
96
m=0;
97
}
98
void loop() {
99
p = analogRead(A0); // Potiwert
100
plot = map(p, 0, +500, 1, 5); // Amplituden der Sinussignal bestimmen
101
//delay(300);
102
val=plot;
103
}

von Black D. (Gast)


Angehängte Dateien:

Lesenswert?

Hier noch mal ein Screenshot vom scope

von Tom (Gast)


Lesenswert?

Ich habe vor längerer Zeit mal mit dem Micro einen Blitzer gebaut und 
hatte ähnliche Probleme. Die Lösung war das Umstellen einer Fuse damit 
das Ding mit 16MHz lief. In der Liefereinstellung waren es nur 1Mhz.

Gruß, Tom

von Black D. (Gast)


Lesenswert?

Hast du dafür vielleicht noch eine Anleitung?

von Andre (Gast)


Lesenswert?

Black D. schrieb:
> Hast du dafür vielleicht noch eine Anleitung?

Die Fuses solltest du definitiv im Datenblatt oder Wiki nachlesen, bevor 
du dich aussperrst!

von Falk B. (falk)


Lesenswert?

Black D. schrieb:
> Hallo zusamen ich bin dabei mir eine SPWM zu programmieren.

Was soll das denn sein? Eine Sinus PWM?
Der PWM ist es egal, mit welchem Signal sie moduliert wird, der Begriff 
SPWM ist Unfug.

> Leider komme
> ich nur eine Frequenz von 5kHz hin obwohl ich in meiner Berechnung des
> OCR1A 80kHz ausgerechnet habe. Hat da jemand tipps für mich?

Tja. Siehe AVR Fuses.

> Gibt es sonst vielleicht noch eine andere eleganter Lösung das
> Sinussignal zu erzeugen?

Naja, dein Interrupt ist etwas merkwürdig. Was soll das denn werden? 
Eine PWM, welche mit einem Sinus moduliert wird, und dann noch ein 
Dreieck?
Deine Sinutabelle verschwendet 1600 Bytes RAM. Die kann man direkt in 
den Flash legen und auch direkt daraus lesen. Geht mit normalem C als 
auch Arduino-Style.

https://www.arduino.cc/reference/en/language/variables/utilities/progmem/

In deinem Programm wird aber nirgendwo die PWM neu eingestellt. Wie soll 
da ein veränderliches Tastverhältnis rauskommen?

Zum Thema Sinus und PWM siehe hier

https://www.mikrocontroller.net/articles/Pulsweitenmodulation#Siehe_auch

>Hier noch mal ein Screenshot vom scope

Naja, der ist eher verwirrend. Wenn man sehen will, was die PWM so 
macht, muss man wieder DEMODULIEREN,  sprich, filtern. Ein RC-Tiefpass 
mit vielleicht 1k+100nF sollte es tun, die Grenzfrequenz sollte im 
Bereich von 1-10% der PWM-Frequenz liegen.

von Falk B. (falk)


Lesenswert?

Ahhhh, jetzt kapier ich den Ansatz! Ohje! So nicht! Das ist eine 
verkorkste Soft-PWM! Wozu denn das? Dein Arduino kann eine PWM per 
Hardware erzeugen, das sogar auf vielen Kanälen. Das sollte man nutzen! 
Dann klappt das auch mit höheren Frequenzen!

Beitrag "Re: SPWM auf Atmega8, bitte um Feedback hinsichtlich Optimierung"

Beitrag "Re: SPWM auf Atmega8, bitte um Feedback hinsichtlich Optimierung"

: Bearbeitet durch User
von Black D. (Gast)


Lesenswert?

Ich greife einfachmal diesen Beitrag wieder auf weil es immer noch um 
eine sinusförmige PWM geht nur diesmal versuche ich das ganze mit zwei 
AD9833 Boards. Wie im Code zu sehen erzeugt eine Platine ein Sinussignal 
mit 50Hz und die andere Platine ein Dreiecksignal mit 25kHz. Beide 
Signale lese ich über A1 und A2 ein. Diese werden dann noch mit map 
skaliert und in die Variable S und D geschrieben.

Ich brauche bestimmt noch ein delay oder millis um die Werte richtig 
einzulesen? Wie programmiere ich die?
Die Werte muss ich dann bestimmt in einem Interrupt Timer vergleichen 
damit ich auch die 25kHz des Dreiecksignals in dem sinusförmigen PWM 
Signal ausgeben kann?
1
#include<AD9833.h>
2
AD9833 Sin(10);
3
AD9833 Triangle(9);
4
5
int Poti, mapPoti;
6
int AD9833_sin, mapAD9833_sin, S;
7
int AD9833_triangle, mapAD9833_triangle, D;
8
9
void setup()
10
{
11
  //Sinussignal 50Hz
12
  Sin.Begin();              
13
  Sin.EnableOutput(true);
14
  Sin.ApplySignal(SINE_WAVE,REG0,50);
15
 
16
  //Dreiecksignal 25kHz
17
  Triangle.Begin();              
18
  Triangle.EnableOutput(true);
19
  Triangle.ApplySignal(TRIANGLE_WAVE,REG0,25000);
20
}
21
22
void loop()
23
{
24
  Poti = analogRead(A0);                
25
  mapPoti = map(Poti, 0, +500, 1, 5);   
26
27
  AD9833_sin = analogRead(A1);
28
  mapAD9833_sin = map(AD9833_sin,0,127,-99,99);
29
  S = mapAD9833_sin * mapPoti;  
30
31
  AD9833_triangle = analogRead(A2);
32
  mapAD9833_triangle = map(AD9833_triangle,0,127,-550,550);
33
  D = mapAD9833_triangle;
34
}

von Falk B. (falk)


Lesenswert?

Black D. schrieb:
> Ich greife einfachmal diesen Beitrag wieder auf weil es immer noch um
> eine sinusförmige PWM geht nur diesmal versuche ich das ganze mit zwei
> AD9833 Boards. Wie im Code zu sehen erzeugt eine Platine ein Sinussignal
> mit 50Hz und die andere Platine ein Dreiecksignal mit 25kHz. Beide
> Signale lese ich über A1 und A2 ein. Diese werden dann noch mit map
> skaliert und in die Variable S und D geschrieben.

Und was soll die Aktion? Nur umständlicher und sinnfreier kann man keine 
PWM erzeugen!

von Black D. (Gast)



Lesenswert?

Ich möchte damit einen Vollbrücken Wechselrichter ansteuern.
So soll die PWM aussehen:

von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

Black D. schrieb:
> So soll die PWM aussehen:

Ist schon klar, aber dazu braucht man keine anderen Boards ausser einem 
einzigen Mikrocontroller. Der kann sogar 3 Phasen gleichzeitig erzeugen, 
wenn man möchte:
https://www.mikrocontroller.net/articles/3-Phasen_Frequenzumrichter_mit_AVR

: Bearbeitet durch User
von Falk B. (falk)


Lesenswert?

Black D. schrieb:
> Ich möchte damit einen Vollbrücken Wechselrichter ansteuern.
> So soll die PWM aussehen:

Und warum nutzt du dann nicht die Hardware-PWM IM AVR?

von Black D. (Gast)


Lesenswert?

Mein erster Versuch war es zwei Arrays zu erzeugen, die einmal das 
Sinussignal und das Dreiecksignal darstellen sollen. Durch den Timer1 
der auf 80kHz eingestellt ist wird aus dem Sinusarray ein Signal mit 
50Hz und aus dem Dreieckarray ein Signal mit 5kHz.
Ich habe auch schon die Werte den Timer1 und die Werte im Sinusarray auf 
25kHz angepasst nur ist das wohl für den Timer1 zu viel. Gemessen 
bekomme ich als sinusförmige PWM nur 7kHz. Ich weiß das mit den beiden 
arrays sieht sehr umständlich aus. Auf eine andere Idee bin ich bisher 
nicht gekommen.
1
//Variablen
2
int n = 0;
3
int plot;
4
int val;
5
int q = 0;
6
int idx = 0;
7
int Sinus;
8
float p;
9
10
//Sinussignal
11
signed char S[400]=
12
{0,0,1,1,2,2,2,3,3,3,4,4,5,5,5,6,6,7,7,7,8,8,9,9,9,10,10,10,11,11,12,12,12,13,13,14,14,14,15,15,15,16,16,17,17,17,18,
13
18,19,19,19,20,20,20,21,21,22,22,22,23,23,23,24,24,25,25,25,26,26,26,27,27,28,28,28,29,29,29,30,30,31,31,31,32,32,32,
14
33,33,34,34,34,35,35,35,36,36,36,37,37,38,38,38,39,39,39,40,40,40,41,41,41,42,42,43,43,43,44,44,44,45,45,45,46,46,46,
15
47,47,47,48,48,48,49,49,49,50,50,50,51,51,51,52,52,52,53,53,53,54,54,54,55,55,55,56,56,56,57,57,57,58,58,58,59,59,59,
16
59,60,60,60,61,61,61,62,62,62,63,63,63,63,64,64,64,65,65,65,65,66,66,66,67,67,67,67,68,68,68,69,69,69,69,70,70,70,71,
17
71,71,71,72,72,72,72,73,73,73,73,74,74,74,75,75,75,75,76,76,76,76,77,77,77,77,78,78,78,78,78,79,79,79,79,80,80,80,80,
18
81,81,81,81,81,82,82,82,82,83,83,83,83,83,84,84,84,84,84,85,85,85,85,85,86,86,86,86,86,87,87,87,87,87,87,88,88,88,88,
19
88,89,89,89,89,89,89,90,90,90,90,90,90,91,91,91,91,91,91,91,92,92,92,92,92,92,92,93,93,93,93,93,93,93,94,94,94,94,94,
20
94,94,94,95,95,95,95,95,95,95,95,95,95,96,96,96,96,96,96,96,96,96,96,97,97,97,97,97,97,97,97,97,97,97,97,97,98,98,98,
21
98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,
22
99,99};
23
24
//Dreiecksignal
25
int D[16]={0,137,275,412,550,412,275,137,0,-137,-275,-412,-550,-412,-275,-137};
26
27
void setup(){
28
pinMode(A0,INPUT);
29
pinMode(5,OUTPUT);
30
pinMode(6,OUTPUT);
31
32
//Timer1 instalisieren
33
TCCR1A = 0;                     //Register definiert zurücksetzten
34
TCCR1B = 0;                     //zuerst Register definiert zurücksetzen
35
TCNT1 = 0;                      //Zählerwert zurücksetzten
36
37
OCR1A = 199;                    //Timer1 80kHZ einstellen
38
TCCR1B |= (1 << WGM12);         //CTC mode
39
//TCCR1B |= (0 << CS12) | (0 << CS11) | (1 >> CS10); //kein Prescale
40
TCCR1B |= (1 << CS10);          // kein Prescaler
41
TIMSK1 |= (1 << OCIE1A);        //Aktivieren des Timer-Vergleichs-Interrupt
42
43
//Abfrage der Frequenz von Timer1 an Pin9 Arduino Micro
44
TCCR1A |= B01000000;
45
DDRB |= B01101111;
46
}
47
48
ISR(TIMER1_COMPA_vect){         //Interrupt
49
50
//Signalvergleich Sinus Positiv
51
  if (D[n] < val*Sinus) {          //Dreiecksignal kleiner als Sinussignal
52
  bitSet(PORTC, 6);               //Pin 5 HIGH
53
  bitSet(PORTD, 7);               //Pin 6 HIGH
54
  }
55
  else {                          //Dreiecksignal größer als Sinussignal
56
  bitClear(PORTC, 6);             //Pin 5 LOW
57
  bitClear(PORTD, 7);             //Pin 6 LOW
58
  }
59
60
//Sinusarray durchlaufen
61
if(idx<399) {
62
  idx++;
63
}
64
else {
65
  idx = 0;
66
  if(q<3) q++;
67
  else q = 0;
68
}
69
70
switch (q) {
71
  case 0: Sinus = S[idx];         break;
72
  case 1: Sinus = S[399 - idx];   break;
73
  case 2: Sinus = -S[idx];        break;
74
  case 3: Sinus = -S[399 - idx];  break;
75
}
76
77
//Dreieckarray durchlaufen
78
n=n+1;
79
if(n>15)
80
n=0;
81
}
82
83
void loop() {
84
p = analogRead(A0);             //Potiwert 0 bis 10kΩ einlesen
85
plot = map(p, 0, +500, 1, 5);   //Potiwert einlesen und von 0 bis 500 in 1 bis 5 wandeln
86
delay(300);
87
val=plot;                                      //Werte von 1 bis 5
88
}

von Falk B. (falk)


Lesenswert?

Black D. schrieb:
> Mein erster Versuch war es zwei Arrays zu erzeugen, die einmal das
> Sinussignal und das Dreiecksignal darstellen sollen. Durch den Timer1
> der auf 80kHz eingestellt ist wird aus dem Sinusarray ein Signal mit
> 50Hz und aus dem Dreieckarray ein Signal mit 5kHz.

Bist du ein Troll oder einfach nur total begriffsstutzig?
Hast du meine Beiträge und die Links mal gelesen? Und vielleicht auch 
verstanden? Ich fürchte, keine Sekunde!

Diesen Unfug mit dem Dreieck braucht man nicht, wenn man mit einem 
Mikrocontroller voll digital eine PWM erzeugt! Diese 
Dreieck-Vergleichsgeschichte ist ein Prinzip aus Lehrbüchern, das man 
noch in analogen Lösungen mit OPVs und Komparatoren macht. Nicht aber 
digital! (Naja, irgendwie schon, der Zähler ist das digitale Dreieck).

> Ich habe auch schon die Werte den Timer1 und die Werte im Sinusarray auf
> 25kHz angepasst nur ist das wohl für den Timer1 zu viel. Gemessen
> bekomme ich als sinusförmige PWM nur 7kHz. Ich weiß das mit den beiden
> arrays sieht sehr umständlich aus. Auf eine andere Idee bin ich bisher
> nicht gekommen.

LESEN und versuchen zu verstehen. Du bist mordsmäßig auf dem Holzweg!

von Black D. (Gast)


Lesenswert?

Höchstwahrscheinlich letzteres. Hab wie du schon geschrieben hast die 
ganze zeit immer an dem Sinus und Dreieckvergleich gehangen. Habe aber 
in einem der Links die du gepostet hast, die ich mir auch schon vorher 
mal durch gelesen habe, jetzt das passende Stichwort gefunden und werde 
mich mal damit auseinander setzten. Danke nochmal.

von Falk B. (falk)


Angehängte Dateien:

Lesenswert?

Nun ja, hier mal die Lehrbuchvariante. Sogar zeitgemäß mit Video! Siehe 
Anhang.

https://youtu.be/m22a6_-RQJ8

Ein Klassiker. Mittels DDS und PWM wird ein einfacher 
DA-Wandler gebildet, welcher hier mit einem Sinusmuster gefüttert 
wird. Die Parameter Amplitude, Frequenz und Phase (des 2. Kanals) sind 
variabel und können vom Programm eingestellt werden.

https://www.mikrocontroller.net/articles/Pulsweitenmodulation#DA-Wandlung_mit_PWM

Das Bild zeigt auf Kanal 1 TP1, das digitale PWM SIgnal. Kanal2 zeigt 
TP2, das gefilterte (demodulierte) Signal. Damit kann man was anfangen, 
mit Kanal 1 eher nicht. Im Video sind dann TP2 und TP3 gemessen worden.

Viel Spaß

: Bearbeitet durch User
von Black D. (Gast)


Angehängte Dateien:

Lesenswert?

Danke Falk, das hat sehr geholfen. Ich habe jetzt ein kleines Problem. 
Ich möchte die Frequenz von 244Hz auf 50Hz einstellen. Dafür ist 
Höchswahrscheinlich ICR1 zuständig? Wenn ich den Wert auf 1250 Stelle 
(62,5kHz/50Hz) sieht das Signal aus wie auf dem Screenshot. Liegt das an 
der Dimensionierung der Bauteile?
1
void setup(){
2
3
  pinMode(A0,INPUT);
4
  pinMode(11,OUTPUT);   // OCR1A
5
  pinMode(12,OUTPUT);   // OCR1B
6
7
  // Timer1 initialisieren
8
  // Mode 14, Fast PWM (ICR1), nichtinvertierte PWM, Prescaler 1
9
  // OCR1A, OCR1B aktiv
10
  TCCR1A  = (1<<COM1A1) | (1<<COM1B1) | (1<<WGM11);
11
  TCCR1B  = (1<<WGM13)  | (1<<WGM12)  | (1<<CS10);
12
  ICR1    = 1250;
13
  OCR1A   = TIMER_RELOAD / 2;   // PWM Startwerte, zum statischen testen
14
  OCR1B   = TIMER_RELOAD / 4; 
15
  TIMSK1 |= (1 << ICIE1);      // Aktivieren des Timer-Reload Interrupts (ICR1)
16
17
  frequenz  = 256;
18
  amplitude = 255;
19
}

von Falk B. (falk)


Lesenswert?

Black D. schrieb:
> Danke Falk, das hat sehr geholfen.

Das wäre schön, wenn . . .

>Ich habe jetzt ein kleines Problem.

Eher ein größeres . . .

> Ich möchte die Frequenz von 244Hz auf 50Hz einstellen. Dafür ist
> Höchswahrscheinlich ICR1 zuständig?

Nö.

> Wenn ich den Wert auf 1250 Stelle
> (62,5kHz/50Hz) sieht das Signal aus wie auf dem Screenshot. Liegt das an
> der Dimensionierung der Bauteile?

Es liegt an deiner Lesefaulheit und Begriffsstutzigkeit.
Mein Gott, wofür wird wohl die Variable frequenz gut sein?

von Black D. (Gast)


Lesenswert?

Stimmt, war dumm. Hab den Teil komplett rausgeschmissen weil ich davon 
aus ging dass ich ja keine Variable Frequenz brauche...

von Falk B. (falk)


Lesenswert?

Ok, hier nochmal eine grundlegende Erklärung. Es gibt im Projekt ja 
mehrere Frequenzen.

1.) F_CPU, das ist ein #define, welches von der Arduino-IDE festgelegt 
wird und meist bei 160000000 (16MHz) steht. Das ist der CPU und auch 
Timer-Eingangstakt.

2.) F_Timer, das ist die Ausgangsfrequenz des Timers, welcher die 
PWM-erzeugt. In diesem Beispiel auch gleichzeitig die Updatefrequenz der 
PWM (ISR) und damit die Ausgabefrequenz unseres DA-Wandlers, denn 
die PWM + RC Filter ist ein DA-Wandler.

https://www.mikrocontroller.net/articles/Pulsweitenmodulation#DA-Wandlung_mit_PWM

F_TIMER = F_CPU / (TIMER_RELOAD+1)

Damit wirtd aber auch die Auflösung der PWM und damit des DA-Wandlers 
festgelegt. Ich habe die 62,5kHz gewählt, weil man damit auf exakt 256 
Schritte für die PWM kommt. Wenn man das ändert, muss man die 
Sinustabelle anpassen.

3.) Die Frequenz des Sinussignals. Diese ist VARIABEL, zumindest wenn 
man es will, im Bereich 0-F_TIMER/2.

Die Formeln für die jeweiligen Beziehungen stehen im Quelltext in den 
defines bzw. der Beschreibung.

Hier noch ein paar Luxusfunktionen
1
// Setzte Frequenz in Hz
2
set_frequenz(uint16_t frequ_Hz) {
3
  frequenz = ((uint32_t)frequ_Hz<<16)/F_TIMER;
4
}
5
6
// Setze Phase in Grad
7
set_phase(uint16_t phase_deg) {
8
  phase = (phase_deg << 8) / 360;
9
}
10
11
// Setze Amplitude in Prozent
12
set_amplitde(uint16_t amplitude_prozent) {
13
  amplitude = (amplitude_prozent <<8)/100;
14
}

von Black D. (Gast)


Angehängte Dateien:

Lesenswert?

Vielen Dank nochmal. Ich habe schon einiges hinbekommen. Auch das mit 
der Frequenz. Ist zwar nicht so elegant gelöst wie du es beschrieben 
hast aber ich glaube es funktioniert. Mir ist jetzt aber eine 
Kleinigkeit im Signal an TP1 aufgefallen. Und zwar gibt es da einen 
Sprung und ich weiß nicht wo der her kommt. Wenn ich eine anderes 
Programm mit einer Pulsdauermodulation nehme und messe gibt es da keinen 
Sprung.
1
void setup(){
2
3
  pinMode(A0,INPUT);
4
  pinMode(9,OUTPUT);    //OCR1A
5
  pinMode(10,OUTPUT);   //OCR1B
6
7
  //Timer1 initialisieren
8
  //Mode 14, Fast PWM (ICR1), nichtinvertierte PWM, Prescaler 1
9
10
  TCCR1A = (1<<COM1A1) | (1<<COM1B1) | (1<<WGM11);
11
  TCCR1B = (1<<WGM13) | (1<<WGM12) | (1<<CS10);
12
  ICR1 = TIMER_RELOAD;   //multiplizieren mit 2 = 31kHz
13
14
  //OCR1A, OCR1B aktiv
15
  OCR1A = TIMER_RELOAD / 2; // PWM Startwerte, zum statischen testen
16
  OCR1B = TIMER_RELOAD / 4; 
17
  TIMSK1 |= (1 << ICIE1);   // Aktivieren des Timer-Reload Interrupts (ICR1)
18
19
  //
20
  Frequenz = 52;
21
}
22
23
void loop(){
24
  Amplitude = map(analogRead(A0),0,1023,5,245);      //Amplitudenhöhe
25
}
26
27
//Interrupt für Timer 1, Frequenz F_PWM
28
//Nachladen der PWM
29
ISR(TIMER1_CAPT_vect){        
30
  
31
  //Index in der Sinustabelle, Festkommazahl, 8 Bit Vorkomma, 8 Bit Nachkomma  
32
  i += Frequenz;  //i = i + frequenz
33
34
  //
35
  OCR1A = 128+(((int8_t)pgm_read_byte(&Sinus[i>>8])*(int16_t)Amplitude)>>8);
36
  OCR1B = 128+(((int8_t)pgm_read_byte(&Sinus[i>>8])*-(int16_t)Amplitude)>>8);
37
}

von Falk B. (falk)


Lesenswert?

Black D. schrieb:
> Vielen Dank nochmal. Ich habe schon einiges hinbekommen.

Hmm. Die absolut fundamentale Änderung von frequenz auf Frequenz.

>   ICR1 = TIMER_RELOAD;   //multiplizieren mit 2 = 31kHz

Solche Kommentare sind sinnlos. Es gibt extra ein #define, wo man die 
Frequenz eintragen kann! Das ist selbsterklärend!

> Kleinigkeit im Signal an TP1 aufgefallen.

Wie kommt man auf die Idee, vor allem DORT zu messen? Ist dir das 
gefilterte Signal zu sauber, zu klar verständlich?

> Und zwar gibt es da einen
> Sprung und ich weiß nicht wo der her kommt. Wenn ich eine anderes
> Programm mit einer Pulsdauermodulation

Welches denn?

 nehme und messe gibt es da keinen
> Sprung.

Tja. Da gibt es wohl in einer Rechnung einen arithmetischen Überlauf. Da 
ist eine Variable zu klein oder hat das falsche Format (unsigned, 
signed).

> 128+(((int8_t)pgm_read_byte(&Sinus[i>>8])*-(int16_t)Amplitude)>>8);

Kann es sein, daß du nicht an TP1, sondern eher an OCR1B gemessen hast? 
Kann sein, daß die Zeile das macht (180° Phasenverschiebung), was du 
willst, kann aber auch nicht sein. Man kann es auch so schreiben.

128-(((int8_t)pgm_read_byte(&Sinus[i>>8])*(int16_t)Amplitude)>>8);

: Bearbeitet durch User
von Black D. (Gast)


Lesenswert?

> Hmm. Die absolut fundamentale Änderung von frequenz auf Frequenz.

Naja es halt die kleinen Dinge. Ich habe einige Sachen die ich nicht 
brauche rausgeworfen und das Programm läuft noch ausserdem, was man hier 
jetzt nicht sehen kann, habe ich die OCR1A geändert damit es auf einem 
Arduino micro läuft. Wie gesagt es sind die kleinen Dinge.


> Wie kommt man auf die Idee, vor allem DORT zu messen? Ist dir das
> gefilterte Signal zu sauber, zu klar verständlich?

Der geglättete Sinus ist zwar schon und gut aber nicht das was ich 
brauche. Ich möchte mit dem Rechtecksignal einen Vollbrücken 
Wechselrichter ansteuern.

> Tja. Da gibt es wohl in einer Rechnung einen arithmetischen Überlauf.
> Da ist eine Variable zu klein oder hat das falsche Format (unsigned,
> signed).
Dann muss ich mich mal damit genauer befassen.

> Kann es sein, daß du nicht an TP1, sondern eher an OCR1B gemessen hast?
Nee ich habe schon an TP1 gemessen.

von Falk B. (falk)


Lesenswert?

Black D. schrieb:
>> Wie kommt man auf die Idee, vor allem DORT zu messen? Ist dir das
>> gefilterte Signal zu sauber, zu klar verständlich?
>
> Der geglättete Sinus ist zwar schon und gut aber nicht das was ich
> brauche. Ich möchte mit dem Rechtecksignal einen Vollbrücken
> Wechselrichter ansteuern.

Schon klar, aber das gefilterte Signal ist für die Fehlersuche 
deutlich besser geeignet.

>> Kann es sein, daß du nicht an TP1, sondern eher an OCR1B gemessen hast?
> Nee ich habe schon an TP1 gemessen.

Was hast du denn noch so geändert? Zeig mal das VOLLSTÄNDIGE Programm.

von Black D. (Gast)


Angehängte Dateien:

Lesenswert?

Ich habe jetzt grad die Atomic Block Funktion wieder eingebaut. Kann es 
aber morgen erst testen ob es daran lag.

von Falk B. (falk)


Lesenswert?

Black D. schrieb:
> Ich habe jetzt grad die Atomic Block Funktion wieder eingebaut. Kann es
> aber morgen erst testen ob es daran lag.

Meister, warum fummelst du planlos an Dingen herum, die a) funktionieren 
und b) du nicht wirklich weiß, warum sie so sind, wie sie sind?

Warum hast du static int i nicht in der ISR gelassen, wo es hingehört?
Und auch die Sache mit dem Atomic? Da steht auch noch extra dabei, WARUM 
das gemacht wird! Siehe Interrupt.
Aber dein Test wird sinnlos sein, denn Frequenz ist bei dir ja konstant.

Unter welchen Bedingungen tritt denn das falsche PWM Muster auf? Welche 
Frequenz und welche Amplitude?

von Black D. (Gast)


Angehängte Dateien:

Lesenswert?

Also ich hab das nochmal gemessen. Vorher habe ich aber "static uint16_t 
i;" wieder in den ISR rein geschrieben. Warum ich den da raus genommen 
habe weiß ich auch nicht mehr. Als Frequenz vom geglätteten Sinus Signal 
habe ich 50Hz genommen. Gemessen habe ich am OCR1A bei einer Amplitude 
von 5, 128 und 245.

von Falk B. (falk)


Lesenswert?

Miss doch einfach mal NACH dem Tiefpaß! Der ist nicht umsonst da! Die 
Nullinie des Ausgangs liegt bei VCC/2, d.h das Bild mit 5% Amplitude 
erscheint plausibel, denn die Aussteuerung ist gering, der Mittelwert

Ahhhhh, MOMENT!!!! Du hast ALIASING!!! Bei 200ms/DIV schaltet dein Oszi 
auf eine recht niedrige Abtastfrequenz runter. Damit erscheinen 
hochfrequente Signale, hier deine 62,5kHz PWM als extrem niederfrequent! 
Dreh mal die Zeitauflösung auf 20us/DIV, dann sieht das ganz anders aus.

Man kann das Aliasing sehr leicht sichtbar machen.

Stell deine Amplitude auf 0. Dann dreh die Zeitauflösung auf 5us/DIV. 
Dann sieht man eine Rechtecksignal mit 62,5kHz und 50% Tastverhältnis. 
Jetzt dreht man die Zeitskalierung hoch, sprich in Richtung mehr 
Zeit/DIV. 100us, 1ms etc. Zuerst sieht man nur ein Rauschband, die 
Einzelpulse sind nicht mehr sichtbar. Aber irgendwann sieht man wieder 
ein Rechtecksignal, aber mit um Größenordnung niedrigerer Frequenz. Das 
ist Aliasing. Sowas passiert nur bei Digitaloszis. Analogoszis haben das 
Problem prinzipiell nicht.

: Bearbeitet durch User
von Black D. (Gast)


Angehängte Dateien:

Lesenswert?

So sieht es bei 20us/DIV aus. Nach dem Tiefpass bekomme ich eine schöne 
Sinuskurve raus.

Dann gucke ich mal wo ich ein Oszilloskop mit schneller Abtastfrequenz 
her bekomme.

Danke.

von Forist (Gast)


Lesenswert?

Black D. schrieb:
> Auf eine andere Idee bin ich bisher nicht gekommen.

Du hättest inzwischen mal die Hinweise zum Posten lesen können:
"Wichtige Regeln - erst lesen, dann posten!"
...
"Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang"

Falls du mit dem Verständnis Probleme hast - frag einfach.

von Falk B. (falk)


Lesenswert?

Black D. schrieb:
> Dann gucke ich mal wo ich ein Oszilloskop mit schneller Abtastfrequenz
> her bekomme.

Das reicht nicht. Nahezu alle Digitaloszis reduzieren ihre Abtastrate 
bei hohen Zeit/DIV Auflösungen. Bei 200ms/DIV arbeitet keins mit 
100Msmps, dann das wären 20Mpunkte/DIV bzw. 200MPunkte/Bildschirm. Das 
einzige Gegenmittel mit begrenzter Wirkung ist das erhöhen der 
Speichertiefe, das kann man bei den meisten einstellen, wieviele Punkte 
aufgezeichnet werden sollen. Dann kann man die Aliasinggrenze etwas 
verschieben, aber nicht vollständig verhindern.

Aber all das ist nicht nötig, wenn man hinter dem Tiefpass mißt. Genau 
DAFÜR (und andere Dinge) ist der da!

: Bearbeitet durch User
von Falk B. (falk)


Lesenswert?

Hmmm, ich versuche gerade, mit meinem "ollen" Rigol DS1052E Aliasing 
darzustellen, es funktioniert aber nicht! Kann es sein, daß dieses 
Billigoszi an der Stelle besser ist als diverse Profigeräte ala LeCroy? 
Kann es sein, daß das Oszi IMMER mit voller Abtastrate arbeitet und die 
niedrigeren Samplingraten durch echte Mittelwertbildung erfolgen? Das 
würde es erklären.

von Black D. (Gast)


Lesenswert?

Danke das Programm läuft soweit auch mit meiner Schaltung. Am Ende kommt 
ein Sinus raus genau so wie ich ihn vorher nach dem Tiefpass gemessen 
habe.
Ich gucke mal ob ich noch ein analoges Oszilloskop finde damit ich mir 
die Ausgänge direkt angucken kann. Aber ja du hast Recht es ist 
wesentlich Sinnvoller nach dem Tiefpass zu messen.

Drei Fragen habe ich aber doch noch.
1. Wie kann ich das Signal von OCR1B negieren?
 Ich habe erst überlegt einfach "^1" ein XOR zu nehmen aber da weiß ich 
nicht wo ich das hinsetzen kann.

2. Wo muss ich das hinschreiben?

Falk B. schrieb:
> // Setzte Frequenz in Hz
> set_frequenz(uint16_t frequ_Hz) {
>   frequenz = ((uint32_t)frequ_Hz<<16)/F_TIMER;
> }

3. Warum müssen OCR1A und OCR1B unterschiedliche Werte haben? Da habe 
ich bisher noch keine Richtige Erklärung gefunden.
1
OCR1A = TIMER_RELOAD / 2; // PWM Startwerte, zum statischen testen
2
OCR1B = TIMER_RELOAD / 4;

von Falk B. (falk)


Lesenswert?

Black D. schrieb:
> Drei Fragen habe ich aber doch noch.
> 1. Wie kann ich das Signal von OCR1B negieren?

An verschiedenen Stellen. Entweder mit dem - in der Formel in der ISR.

>  Ich habe erst überlegt einfach "^1" ein XOR zu nehmen aber da weiß ich
> nicht wo ich das hinsetzen kann.

Nein, das geht hier nicht, denn OCR1B wird von der Hardware generiert. 
Man kann es aber auch per Hardware invertieren. Bei der Konfiguration 
mit den COM1Bx Bits. Siehe Datenblatt.
1
  //Timer1 initialisieren
2
  //Mode 14, Fast PWM (ICR1), nichtinvertierte PWM, Prescaler 1
3
  // OCR1A nicht invertiert, OCR1B invertiert
4
  TCCR1A = (1<<COM1A1) | (1<<COM1B1) | (1<<COM1B0) | (1<<WGM11);
5
  TCCR1B = (1<<WGM13) | (1<<WGM12) | (1<<CS10);
6
  ICR1 = TIMER_RELOAD;

> 3. Warum müssen OCR1A und OCR1B unterschiedliche Werte haben? Da habe

Das müssen sie nicht, das war nur zum statischen Test ganz am Anfang der 
Entwicklung, ob beide OCR1A/B laufen, bevor die ISR freigeschaltet 
wurde.

von Black D. (Gast)


Lesenswert?

Falk B. schrieb:
> Entweder mit dem - in der Formel in der ISR.

Du meinst so?
1
OCR1B = 128-(((int8_t)pgm_read_byte(&Sinus[i>>8])*(int16_t)Amplitude)>>8);
Dadurch bekomme ich nur eine Verschiebung des zweiten Signals hin.

Mit den beiden Zeilen klappt die Negierung.
1
TCCR1A = (1<<COM1A1) | (1<<COM1B1) | (1<<COM1B0) | (1<<WGM11);
2
TCCR1B = (1<<WGM13) | (1<<WGM12) | (1<<CS10);

Kann ich Änderung auch im loop machen? Ich möchte mit einem Schalter 
zwischen der Negierung von OCR1B und einer 180°  Phasenverschiebung 
wechseln können.

von Falk B. (falk)


Lesenswert?

Black D. schrieb:
> Falk B. schrieb:
>> Entweder mit dem - in der Formel in der ISR.
>
> Du meinst so?OCR1B =
> 128-(((int8_t)pgm_read_byte(&Sinus[i>>8])*(int16_t)Amplitude)>>8);
> Dadurch bekomme ich nur eine Verschiebung des zweiten Signals hin.

Was das nicht dein Ziel? Außerdem ist es keine Verschiebung, es ist eine 
echte, frequenzunabhängige Invertierung

> Mit den beiden Zeilen klappt die Negierung.TCCR1A = (1<<COM1A1) |
> (1<<COM1B1) | (1<<COM1B0) | (1<<WGM11);
> TCCR1B = (1<<WGM13) | (1<<WGM12) | (1<<CS10);

Ist doch toll, oder?

> Kann ich Änderung auch im loop machen? Ich möchte mit einem Schalter
> zwischen der Negierung von OCR1B und einer 180°  Phasenverschiebung
> wechseln können.

Das ist das Gleiche . . .

von Black D. (Gast)


Angehängte Dateien:

Lesenswert?

Dann stehe ich grad auf dem Schlauch um was für eine Verschiebung es 
sich bei PDM_2 handelt.

von Madzel (stumpi)


Lesenswert?

Falk B. schrieb:
> Das Bild zeigt auf Kanal 1 TP1, das digitale PWM SIgnal. Kanal2 zeigt
> TP2, das gefilterte (demodulierte) Signal. Damit kann man was anfangen,
> mit Kanal 1 eher nicht. Im Video sind dann TP2 und TP3 gemessen worden.

Wenn man die RC-Glieder weglässt kann man dann mit den beiden Signalen 
direkt auf die Eingänge eines L6202 gehen?

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.