Forum: Mikrocontroller und Digitale Elektronik Timerproblem, Werte werden nicht sauber ins Register geschrieben


von A. H. (dernetteeddie1978)


Lesenswert?

Hallo Leute,

will grad nen sinus per PWM erzeugen. Hab dazu nen viertel Sinuns als 
Array in den Flash gelegt und will nun diese Werte per for-schleife als 
Zählgrenzen in den Timer schieben. Leider funktioniert das nicht 
richtig. Hier erst mal der Code:
1
float const SINE [256]= {0, 0.006159947, 0.01231966, 0.018478905, 0.024637449, 0.030795059, 0.036951499,
2
            0.043106538, 0.049259941, 0.055411475, 0.061560906, 0.067708001, 0.073852527,
3
            0.079994251, 0.086132939, 0.092268359, 0.098400278, 0.104528463, 0.110652682,
4
            0.116772702, 0.122888291, 0.128999217, 0.135105247, 0.141206152, 0.147301698,
5
            0.153391655, 0.159475791, 0.165553876, 0.171625679, 0.17769097,  0.183749518,
6
            0.189801093, 0.195845467, 0.201882409, 0.207911691, 0.213933083, 0.219946358,
7
            0.225951287, 0.231947641, 0.237935195, 0.24391372, 0.24988299, 0.255842778,
8
            0.261792857, 0.267733003, 0.27366299, 0.279582593, 0.285491586, 0.291389747,
9
            0.297276851, 0.303152674, 0.309016994, 0.314869589, 0.320710236, 0.326538713,
10
            0.332354799, 0.338158275, 0.343948919, 0.349726511, 0.355490833, 0.361241666,
11
            0.366978792, 0.372701992, 0.37841105, 0.384105749, 0.389785873, 0.395451207,
12
            0.401101535, 0.406736643, 0.412356317, 0.417960345, 0.423548513, 0.429120609,
13
            0.434676422, 0.440215741, 0.445738356, 0.451244057, 0.456732636, 0.462203884,
14
            0.467657593, 0.473093557, 0.478511569, 0.483911424, 0.489292917, 0.494655843,
15
            0.5, 0.505325184, 0.510631193, 0.515917826, 0.521184883, 0.526432163, 0.531659467,
16
            0.536866598, 0.542053356, 0.547219547, 0.552364973, 0.557489439, 0.562592752,
17
            0.567674716, 0.57273514, 0.577773831, 0.582790599, 0.587785252, 0.592757602,
18
            0.597707459, 0.602634636, 0.607538946, 0.612420203, 0.617278221, 0.622112817,
19
            0.626923806, 0.631711006, 0.636474236, 0.641213315, 0.645928062, 0.6506183,
20
            0.65528385, 0.659924535, 0.664540179, 0.669130606, 0.673695644, 0.678235117,
21
            0.682748855, 0.687236686, 0.691698439, 0.696133946, 0.700543038, 0.704925547,
22
            0.709281308, 0.713610154, 0.717911923, 0.72218645, 0.726433574, 0.730653133,
23
            0.734844967, 0.739008917, 0.743144825, 0.747252535, 0.75133189, 0.755382735,
24
            0.759404917, 0.763398283, 0.767362681, 0.771297962, 0.775203976, 0.779080575,
25
            0.78292761, 0.786744938, 0.790532412, 0.79428989, 0.798017227, 0.801714284,
26
            0.805380919, 0.809016994, 0.812622371, 0.816196912, 0.819740483, 0.823252948,
27
            0.826734175, 0.830184031, 0.833602385, 0.836989108, 0.840344072, 0.843667148,
28
            0.846958211, 0.850217136, 0.853443799, 0.856638078, 0.859799851, 0.862929,
29
            0.866025404, 0.869088946, 0.872119511, 0.875116983, 0.878081248, 0.881012194,
30
            0.88390971, 0.886773686, 0.889604013, 0.892400583, 0.895163291, 0.897892032,
31
            0.900586702, 0.903247199, 0.905873422, 0.908465272, 0.911022649, 0.913545458,
32
            0.916033601, 0.918486986, 0.920905518, 0.923289106, 0.92563766, 0.92795109,
33
            0.930229309, 0.932472229, 0.934679767, 0.936851839, 0.938988361, 0.941089253,
34
            0.943154434, 0.945183828, 0.947177357, 0.949134944, 0.951056516, 0.952942,
35
            0.954791325, 0.95660442, 0.958381215, 0.960121645, 0.961825643, 0.963493144,
36
            0.965124085, 0.966718404, 0.968276041, 0.969796936, 0.971281032, 0.972728272,
37
            0.974138602, 0.975511968, 0.976848318, 0.978147601, 0.979409768, 0.98063477,
38
            0.981822563, 0.9829731, 0.984086337, 0.985162233, 0.986200747, 0.98720184,
39
            0.988165472, 0.989091608, 0.989980213, 0.990831253, 0.991644696, 0.99242051,
40
            0.993158666, 0.993859137, 0.994521895, 0.995146916, 0.995734176, 0.996283653,
41
            0.996795325, 0.997269173, 0.99770518, 0.998103329, 0.998463604, 0.998785992,
42
            0.999070481, 0.99931706, 0.99952572, 0.999696452, 0.99982925, 0.99992411,
43
            0.999981027, 1};
44
45
float FREQUENCY;
46
unsigned int i;
47
48
int main(void)
49
{
50
  WDTCTL = WDTPW + WDTHOLD;                 // Stop watchdog timer
51
  if (CALBC1_1MHZ==0xFF)          // If calibration constant erased
52
  {
53
    while(1);                               // do not load, trap CPU!!
54
  }
55
  DCOCTL = 0;                               // Select lowest DCOx and MODx settings
56
  BCSCTL1 = CALBC1_1MHZ;                    // Set DCO to 1MHz
57
  DCOCTL = CALDCO_1MHZ;
58
  _BIS_SR(GIE);
59
60
  P1DIR |= BIT2;                     // P1.2 to output
61
  P1SEL |= BIT2;                     // P1.2 to TA0.1
62
63
  FREQUENCY = 1000.0;
64
  CCTL1 = OUTMOD_7;              // CCR1 reset/set
65
  CCTL0 |= CCIE;
66
  TACTL = TASSEL_2 + MC_1;           // SMCLK, up mode
67
68
  while(1)
69
  {
70
    for(i=1;i<256;)
71
    {
72
      CCR0 = FREQUENCY*2;                    // PWM Period
73
      CCR1 = SINE[i]*FREQUENCY+FREQUENCY;         // CCR1 PWM duty cycle
74
    }
75
    for(i=1;i<256;)
76
    {
77
      CCR0 = FREQUENCY*2;                    // PWM Period
78
      CCR1 = SINE[(255-i)]*FREQUENCY+FREQUENCY; // CCR1 PWM duty cycle
79
    }
80
    for(i=1;i<256;)
81
    {
82
      CCR0 = FREQUENCY;                    // PWM Period
83
      CCR1 = FREQUENCY-SINE[i]*FREQUENCY;               // CCR1 PWM duty cycle
84
    }
85
    for(i=1;i<256;)
86
      {
87
      CCR0 = FREQUENCY;                    // PWM Period
88
      CCR1 = SINE[i]*FREQUENCY;               // CCR1 PWM duty cycle
89
      }
90
  }
91
}
92
93
94
#pragma vector=TIMER0_A0_VECTOR
95
__interrupt void Timer_A (void)
96
{
97
  i++;
98
}

Jede for-schleife soll hier ein Viertel eines Sinus erzeugen.
Leider steht nach durchlauf des ersten Viertels immer 1000 statt 2000 in 
CCR1.
Bei den anderen drei Vierteln stehen die richtigen Werte in den 
Registern.

Interessanterweise geht es wenn ich:

statt:
1
CCR1 = SINE[i]*FREQUENCY+FREQUENCY;
2
3
CCR1 = SINE[i]*FREQUENCY+1000.0;

schreibe,

oder den kompletten Interrupt auskommentiere und stattdessen
1
 i++

in die for-schleife setze.

Ich hatte drüber nachgedacht dass das Ganze so ne Art Timingproblem sein 
könnte. Evtl. wird die for-schleife ja mehrmals durchlaufen bevor der 
Zähler bei CCR0 ankommt und damit werden die Werte ja immerwieder neu in 
die Register geschrieben.
Lt. Manual allerdings soll das im Fall von CCR0 nix machen, da der Wert 
2000 ja immer größer als der aktuelle Zählwert ist.

Was da im Falle von CCR1 passiert, dazu hab ich im Manual nichts 
gefunden.

Evtl. sollte ich das ganz anders machen und die Wertzuweisung mit in den 
Interrupt nehmen. Das werde ich mal als nächstes versuchen.

LG

von Ulrich (Gast)


Lesenswert?

Ich kann zwar nicht erkennen für welchen µC der Code ist, aber man 
sollte wenn möglich Fließkommazahlen vermeiden - vor allem wenn der µC 
die nicht in HW unterstützt.

Der Compiler könnte mit einem nicht volatilen i ggf. zu viel 
wegoptimieren. Die Lösung mit Interrupt zum Hochzählen der Indexvariable 
und nutzen im Hauptprogramm ist auch so nicht gelungen.

von Roland .. (rowland)


Lesenswert?

A. H. schrieb:
> for(i=1;i<256;)
>       {
>       CCR0 = FREQUENCY;                    // PWM Period
>       CCR1 = SINE[i]*FREQUENCY;               // CCR1 PWM duty cycle
>       }

Ich weiß zwar nicht, warum das Addieren nicht reichtig funktioniert, 
aber mir kommt etwas anderes komisch vor. Im letzen Viertel müsste die 
Tabelle ja wider rückwärts durchlaufen werden, der Zugriff auf die 
Tabeller erfolgt aber wider in Vorwärtsrichtung.

von A. H. (dernetteeddie1978)


Lesenswert?

Ok, schonmal danke.
Also erstmal - richtig, ich vergaß: MSP430G2452 im Launchpad

Das mit den Kommazahlen wollte ich ursprünglich so auch nicht machen, da 
das Register CCR1 ja eh so erstmal Integer speichert und die 
Nachkommastellen abschneidet.

Die Sache ist, die Fequenz des Sinus soll sich im Laufe des Programms 
noch ändern. Das wollte ich über die Variable Frequanz realisieren, die 
im nächsten Schritt nicht mehr fest sein soll sondern entsprechend 
berechnet wird.

Das ganze soll so ne  Art Sweep werden. Die Schaltung soll ne 
Alarmanlage werden und das hier die Tonausgabe.

Da schien mir den Sinus einfach zwischen -1 und +1 zu definieren und 
dann ensprechend umzurechnen das einfachste.

LG

von A. H. (dernetteeddie1978)


Lesenswert?

>Im letzen Viertel müsste die
>Tabelle ja wider rückwärts durchlaufen werden, der Zugriff auf die
>Tabeller erfolgt aber wider in Vorwärtsrichtung.

Von Null bis 1000. Der Sinus ist um seinen Peak bei 1000 nach oben 
verschoben, damit er nicht ins negative geht.

von Detlef K. (adenin)


Lesenswert?

Und noch ein kleiner Fehler: Arrays beginnen bei Null.
Also so
1
for(i=0;i<256;)

von A. H. (dernetteeddie1978)


Lesenswert?

>Und noch ein kleiner Fehler: Arrays beginnen bei Null.

Im ersten der vier Teile hab ich das so gemacht. Die anderen Drei müssen 
doch aber bei 1 beginnen damit ich nicht denselben Wert zweimal 
hintereinander schreibe. Oder hab ich da was falsch verstanden?

: Bearbeitet durch User
von A. H. (dernetteeddie1978)


Lesenswert?

Okay,

hab das Programm nochmal geändert und die ganze Zählgrenzensetzung in 
die Interruptroutine gelegt. Nun werden die Zählgrenzen nur noch bei 
erreichen des CCR0 geändert.

Allerdings ändert das nichts am Problem. Im ersten viertel werden immer 
genau im letzten Schritt, also bei i=255 1000 statt 2000 nach CCR1 
geschrieben.

Hier der neue Code:
1
float const SINE [256]= {0, 0.006159947, 0.01231966, 0.018478905, 0.024637449, 0.030795059, 0.036951499,
2
            0.043106538, 0.049259941, 0.055411475, 0.061560906, 0.067708001, 0.073852527,
3
            0.079994251, 0.086132939, 0.092268359, 0.098400278, 0.104528463, 0.110652682,
4
            0.116772702, 0.122888291, 0.128999217, 0.135105247, 0.141206152, 0.147301698,
5
            0.153391655, 0.159475791, 0.165553876, 0.171625679, 0.17769097,  0.183749518,
6
            0.189801093, 0.195845467, 0.201882409, 0.207911691, 0.213933083, 0.219946358,
7
            0.225951287, 0.231947641, 0.237935195, 0.24391372, 0.24988299, 0.255842778,
8
            0.261792857, 0.267733003, 0.27366299, 0.279582593, 0.285491586, 0.291389747,
9
            0.297276851, 0.303152674, 0.309016994, 0.314869589, 0.320710236, 0.326538713,
10
            0.332354799, 0.338158275, 0.343948919, 0.349726511, 0.355490833, 0.361241666,
11
            0.366978792, 0.372701992, 0.37841105, 0.384105749, 0.389785873, 0.395451207,
12
            0.401101535, 0.406736643, 0.412356317, 0.417960345, 0.423548513, 0.429120609,
13
            0.434676422, 0.440215741, 0.445738356, 0.451244057, 0.456732636, 0.462203884,
14
            0.467657593, 0.473093557, 0.478511569, 0.483911424, 0.489292917, 0.494655843,
15
            0.5, 0.505325184, 0.510631193, 0.515917826, 0.521184883, 0.526432163, 0.531659467,
16
            0.536866598, 0.542053356, 0.547219547, 0.552364973, 0.557489439, 0.562592752,
17
            0.567674716, 0.57273514, 0.577773831, 0.582790599, 0.587785252, 0.592757602,
18
            0.597707459, 0.602634636, 0.607538946, 0.612420203, 0.617278221, 0.622112817,
19
            0.626923806, 0.631711006, 0.636474236, 0.641213315, 0.645928062, 0.6506183,
20
            0.65528385, 0.659924535, 0.664540179, 0.669130606, 0.673695644, 0.678235117,
21
            0.682748855, 0.687236686, 0.691698439, 0.696133946, 0.700543038, 0.704925547,
22
            0.709281308, 0.713610154, 0.717911923, 0.72218645, 0.726433574, 0.730653133,
23
            0.734844967, 0.739008917, 0.743144825, 0.747252535, 0.75133189, 0.755382735,
24
            0.759404917, 0.763398283, 0.767362681, 0.771297962, 0.775203976, 0.779080575,
25
            0.78292761, 0.786744938, 0.790532412, 0.79428989, 0.798017227, 0.801714284,
26
            0.805380919, 0.809016994, 0.812622371, 0.816196912, 0.819740483, 0.823252948,
27
            0.826734175, 0.830184031, 0.833602385, 0.836989108, 0.840344072, 0.843667148,
28
            0.846958211, 0.850217136, 0.853443799, 0.856638078, 0.859799851, 0.862929,
29
            0.866025404, 0.869088946, 0.872119511, 0.875116983, 0.878081248, 0.881012194,
30
            0.88390971, 0.886773686, 0.889604013, 0.892400583, 0.895163291, 0.897892032,
31
            0.900586702, 0.903247199, 0.905873422, 0.908465272, 0.911022649, 0.913545458,
32
            0.916033601, 0.918486986, 0.920905518, 0.923289106, 0.92563766, 0.92795109,
33
            0.930229309, 0.932472229, 0.934679767, 0.936851839, 0.938988361, 0.941089253,
34
            0.943154434, 0.945183828, 0.947177357, 0.949134944, 0.951056516, 0.952942,
35
            0.954791325, 0.95660442, 0.958381215, 0.960121645, 0.961825643, 0.963493144,
36
            0.965124085, 0.966718404, 0.968276041, 0.969796936, 0.971281032, 0.972728272,
37
            0.974138602, 0.975511968, 0.976848318, 0.978147601, 0.979409768, 0.98063477,
38
            0.981822563, 0.9829731, 0.984086337, 0.985162233, 0.986200747, 0.98720184,
39
            0.988165472, 0.989091608, 0.989980213, 0.990831253, 0.991644696, 0.99242051,
40
            0.993158666, 0.993859137, 0.994521895, 0.995146916, 0.995734176, 0.996283653,
41
            0.996795325, 0.997269173, 0.99770518, 0.998103329, 0.998463604, 0.998785992,
42
            0.999070481, 0.99931706, 0.99952572, 0.999696452, 0.99982925, 0.99992411,
43
            0.999981027, 1.0};
44
45
float FREQUENCY;
46
unsigned int i=1;
47
int PERIOD=1;
48
49
int main(void)
50
{
51
  WDTCTL = WDTPW + WDTHOLD;                 // Stop watchdog timer
52
  if (CALBC1_1MHZ==0xFF)          // If calibration constant erased
53
  {
54
    while(1);                               // do not load, trap CPU!!
55
  }
56
  DCOCTL = 0;                               // Select lowest DCOx and MODx settings
57
  BCSCTL1 = CALBC1_1MHZ;                    // Set DCO to 1MHz
58
  DCOCTL = CALDCO_1MHZ;
59
  _BIS_SR(GIE);
60
61
  P1DIR |= BIT2;                     // P1.2 to output
62
  P1SEL |= BIT2;                     // P1.2 to TA0.1
63
64
  FREQUENCY = 1000.0;
65
  CCTL1 = OUTMOD_7;              // CCR1 reset/set
66
  CCTL0 |= CCIE;
67
  CCR0=FREQUENCY*2;              //first start of timer
68
  CCR1= SINE[0]*FREQUENCY+FREQUENCY;
69
  TACTL = TASSEL_2 + MC_1;           // SMCLK, up mode
70
71
}
72
73
74
#pragma vector=TIMER0_A0_VECTOR
75
__interrupt void Timer_A (void)
76
{
77
  if (PERIOD==1)                //first quarter of sine, count up
78
    CCR1 = SINE[i]*FREQUENCY+FREQUENCY;
79
  else if (PERIOD==2)              //second quarter of sine count back down to offset
80
    CCR1 = SINE[255-i]*FREQUENCY+FREQUENCY;
81
  else if (PERIOD==3)              //third quarter of sine count below offset down to zero
82
    CCR1 = FREQUENCY-SINE[i]*FREQUENCY;
83
  else if (PERIOD==4)              //fourth quarter of sine count back up to offset
84
    CCR1 = SINE[i]*FREQUENCY;
85
86
  i++;
87
88
  if ((i>255) && (PERIOD==1))            //switch between quarters of sine
89
  {
90
    i=1;
91
    PERIOD=2;
92
    CCR0 = FREQUENCY*2;
93
  }
94
  else if ((i>255) && (PERIOD==2))
95
  {
96
    i=1;
97
    PERIOD=3;
98
    CCR0 = FREQUENCY;
99
  }
100
  else if ((i>255) && (PERIOD==3))
101
  {
102
    i=1;
103
    PERIOD = 4;
104
    CCR0 = FREQUENCY;
105
  }
106
  else if ((i>255) && (PERIOD==4))
107
  {
108
    i=0;
109
    PERIOD=1;
110
    CCR0 = FREQUENCY*2;
111
  }
112
}

von Karl H. (kbuchegg)


Lesenswert?

A. H. schrieb:

> Die Sache ist, die Fequenz des Sinus soll sich im Laufe des Programms
> noch ändern.

Schön.
Aber deswegen brauchst du die Amplitudenwerte ja nicht als Flisskomma 
ausführen.

Du scheinst Amplitude mit Frequenz zu verwechseln.
Die Frequenz ist, einfach gesagt, wie schnell die Werte abgearbeitet 
werden. Die Amplitude ist, wie weit die Schwingung aus der 0-Lage 
herausschwingt.

von A. H. (dernetteeddie1978)


Lesenswert?

Ne,

das ist schon klar. Das Problem ist ja dass ich die Frequenz über den 
CCR0 einstellen muss. Dadurch muss ich ja den Zählbereich zwischen Null 
und CCR0 sinusförmig aufteilen. Wenn ich die Werte nun beispielsweise 
mit Faktor Tausend multiplizieren würde, so hätte ich ja so liegen ja 
die letzten Werte nur noch knapp drunter. Für CCR0 =400 für 400kHz 
beispielsweise würden die Werte des Arrays zu groß werden.

Die Frequenz soll ja aber später so zwischen 400Hz und 2Khz variabel 
werden. Da müsste ich das Array ja immer anpassen. Daher schien es mir 
das flexibelste zu sein es zwischen Null und Eins zu halten und dann 
immer den CCR0 für die Setzung von CCR1 einzurechnen.

Der Witz ist ja auch dass es eigentlich funktioniert, bis auf den 
letzten Wert des ersten Viertels

CCR1 = SINE[255]*FREQUENCY+FREQUENCY

liefert 100 statt 2000. SINE[255] ist aber genau 1.0.

von Rudolph (Gast)


Lesenswert?

A. H. schrieb:
> Die Schaltung soll ne
> Alarmanlage werden und das hier die Tonausgabe.

Wofür dann der Aufwand? Hast Du da auch hochwertige Lautsprecher und 
eine Endstufe die nicht rauscht ohne Klirrfaktor hinter?

von HertzFrequenz (Gast)


Lesenswert?

Was wir noch garnicht wissen, ist, auf welche Weise im Detail, Du 
feststellst, das das Produkt 2000 ist. Beschreib bitte wie Du das 
erkennst.

Auch wäre es interessant zu wissen, was für einen Prozessor Du benutzt.

von Amateur (Gast)


Lesenswert?

Ich kenne keinen Prozessor, der etwas mit Fließkommazahlen anfangen 
kann. Zumindest im Zusammenhang mit der PWM-Ausgabe/-Programmierung.
Rechne das Ganze in Ganzzahlen um und spar' Dir somit die heißen 
Fingerkuppen und den unnötigen Speicherverbrauch.
Übrigens: Die endlose und immer gleiche Umrechnung von float in integer 
kostet auch einiges an unnötiger Rechenzeit.

von wendelsberg (Gast)


Lesenswert?

HertzFrequenz schrieb:
> Auch wäre es interessant zu wissen, was für einen Prozessor Du benutzt.

Und die alles entscheidende Frage: wieviele Stufen kann denn die PWM des 
benutzten Prozessors ueberhaupt?

wendelsberg

von A. H. (dernetteeddie1978)


Lesenswert?

HertzFrequenz schrieb:
> Was wir noch garnicht wissen, ist, auf welche Weise im Detail, Du
> feststellst, das das Produkt 2000 ist. Beschreib bitte wie Du das
> erkennst.
>
> Auch wäre es interessant zu wissen, was für einen Prozessor Du benutzt.

Ich schau im Debugger ins Register.

Der Chip ist ein MSP430G2452.

von HertzFrequenz (Gast)


Lesenswert?

Du hast hier aus meiner Sicht mehrere Ansatzpunkte.

1. Float-Multiplikation ist sehr teuer, auf einem Prozessor, der keine 
Fliesskomma-Einheit hat. Wird zwar nicht Dein eigentliches Problem sein, 
aber kann zu unerwarteten Ergebnissen führen, da Du mit dem Code nicht 
eigentlich Kontrolle über den Zeitablauf beim Debuggen hast.

2. Die Konstantenbenennung ist falsch, da Du mit dem Produkt
1
CCR1 = SINE[255]*FREQUENCY+FREQUENCY
eigentlich erstmal einen Wert proportional zur Amplitude ausrechnest, 
der dann aber einer Zeit der PWM gleich ist. Muss man nicht unbedingt 
ändern, wäre aber vielleicht klarer. Mir leuchtet eigentlich auch der 
letzte Summand FREQUENCY nicht eigentlich ein, aber das kann die 
Vorfreude auf den Weihnachtsmann sein, die mein Urteilsvermögen trübt.

Ich würde vorschlagen, das Du zunächst einmal die Berechnung des 
PWM-Verlaufes völlig aus dem Interrupt herauslöst und schlicht einmal 
ganz den Sinusverlauf in einer Schleife berechnest.
Es gibt nämlich durchaus Stellen an denen Du als Ergebnis 1000 erhälst. 
Vielleicht erwischst Du die aus Versehen.

Also ungefähr so:
1
  while(1)
2
  {
3
    for(i=1;i<256;)
4
    {
5
      CCR0 = FREQUENCY*2;                    // PWM Period
6
      CCR1 = SINE[i]*FREQUENCY+FREQUENCY;         // CCR1 PWM duty cycle
7
    }
8
    for(i=1;i<256;)
9
    {
10
      CCR0 = FREQUENCY*2;                    // PWM Period
11
      CCR1 = SINE[(255-i)]*FREQUENCY+FREQUENCY; // CCR1 PWM duty cycle
12
    }
13
    for(i=1;i<256;)
14
    {
15
      CCR0 = FREQUENCY;                    // PWM Period
16
      CCR1 = FREQUENCY-SINE[i]*FREQUENCY;               // CCR1 PWM duty cycle
17
    }
18
    for(i=1;i<256;)
19
      {
20
      CCR0 = FREQUENCY;                    // PWM Period
21
      CCR1 = SINE[i]*FREQUENCY;               // CCR1 PWM duty cycle
22
      }
23
  }
wobei Du CCR0 und CCR1 durch Variablen ersetzt.
Dann schaust Du Dir Schritt für Schritt, vor allem aber an den 
Übergängen zwischen den Sinusabschnitten die Ergebnisse an.

von Roland .. (rowland)


Lesenswert?

Was ändert das Register 'CCR0' eigentlich? Ich nehme jetzt an, dass der 
Wert darin die PWM-Frequenz ändert. Du willst aber - so verstanden - die 
Sinusfrequenz ändern. Diese steht jedoch nahezu in keierlei Zusammenhang 
mit der PWM-Frequenz. Du musst - wie Karl Heinz schon erwähnt - die 
Zählgeschwindigkeit deines Tabellenzeigers ändern (i). Alternativ kannst 
Du auch Tabellwerte überspringen und das Ganze im Stil der direkten 
digitalen Synthese machen.

http://de.wikipedia.org/wiki/Direct_Digital_Synthesis

von wir warten aufs ... (Gast)


Lesenswert?

A. H. schrieb:
> FREQUENCY = 1000.0;
und
A. H. schrieb:
> CCR0=FREQUENCY*2;

Warum nimmst du float um ein int Register zu beschreiben?

Du weisst, wie der Compiler float nach uint16_t wandelt? Er läßt die 
Nachkommastellen weg! Das ist kein Runden.


Ist die Frequenz variabel? Wenn nicht gibt man sie konstant vor
1
#define FREQUENCY  1000

Du kürzt die float auf uint16_t. Warum rechnest du nicht gleich in 
Ganzzahlen? Wenn die Frequenz mindestens 1kHz beträgt, kannst du in der 
Tabelle den Faktor 1000 ansetzen und selber vernünftig runden. Für die 
Tabelle reichen dann 16Bit Werte anstatt 32Bit.

HertzFrequenz schrieb:
> CCR1 = SINE[i]*FREQUENCY+FREQUENCY;

Diese Berechung braucht nicht zur Laufzeit erfolgen. Der berechnete Wert 
kann direkt in der Tabelle hinterlegt werden. (bei konstanter f)

HertzFrequenz schrieb:
> for(i=1;i<256;)
>     {
>       CCR0 = FREQUENCY*2;                    // PWM Period
Da sich der Wert in der Schleife nicht ändert, kann man ihn einmalig vor 
der Schleife berechnen und zuweisen.

A. H. schrieb:
> for(i=1;i<256;)

Wie kommt eine kontrollierte Zeit in die Ausgabe? Es hängt nur von der 
CPU Geschwindigkeit ab. Der Interrupt ist völlig deplatziert.

Ein Ansatz:
Die als - uint16_t berechnete -Tabelle sollte per Timer-Interrupt 
ausgegeben werden.

von A. H. (dernetteeddie1978)


Angehängte Dateien:

Lesenswert?

Oookay - nun zurück aus dem Weihnachtsurlaub seh ich grad die vielen 
Posts von euch. Erstmal riesen Dankeschön für das Engagement.

Nun - fangen wir mal damit an:

Ich hab nun grad den Crystal auf das Launchpad gelötet und auf einmal 
gehts. Am Code hab ich nichts geändert, allerdings hab ich nach dem 
Auflöten noch ein Testprogramm für den Crystal laufen lassen (Ich habs 
mal angehängt für die, die es interessiert). Das hab ich im Netz 
gefunden und einfach mal reingeschoben. Danach hab ich wieder mein 
Sinusprogramm geladen (das aus dem zweiten Post) und plötzlich machts 
was es soll. Das ist schon merkwürdig, denn der Code nutzt den Crystal 
ja gar nicht. Mal sehen ob das nun so bleibt oder ob das Programm dann 
plötzlich doch wieder Fehler produziert.

Nun zu euren diversen Antworten:

>Und die alles entscheidende Frage: wieviele Stufen kann denn die PWM des
>benutzten Prozessors ueberhaupt?

Keine Anhung, da steht nix im Datenblatt. Wie ist die Frage denn 
gemeint?


>1. Float-Multiplikation ist sehr teuer

Ich möchte ja CCR1 sinusförmig erhöhen. Da ich die Frequenz später zw. 
ca. 400 und 1000 Hz variieren will müssen die 256 Schritte für die 
Viertelperiode je nach Frequenz entsprechend verteilt werden. Daher 
schien mir eine Tabelle mit den ungewichteten Werten zwischen 0 und PI/2 
als einfachste Lösung um sie mit der jeweiligen Frequenz zu 
multiplizieren und so die Verteilung zu erzeugen.

>Mir leuchtet eigentlich auch der letzte Summand FREQUENCY nicht >eigentlich ein

Der Sinus geht ja von-1 bis +1.
Einen negativen CCR1 macht ja aber keinen Sinn, da der Chip ja auch nur 
Spannungen von 0 bis Vcc ausgibt. D.h. ich muss den Sinus ja ins 
positive nach oben schieben. Daher die Addition der Frequenz als 
Amplitudenwert.


>Ich würde vorschlagen, das Du zunächst einmal die Berechnung des
>PWM-Verlaufes völlig aus dem Interrupt herauslöst und schlicht einmal
>ganz den Sinusverlauf in einer Schleife berechnest.

Das hatte ich ja im ersten Beispiel ganz zu Anfang des Threads. Gab 
dasselbe Fehlerbild.



>Diese steht jedoch nahezu in keierlei Zusammenhang
>mit der PWM-Frequenz.

Wieso nicht? Der Sinus entsteht doch durch die sinusförmige Änderung von 
CCR1.


>Du weisst, wie der Compiler float nach uint16_t wandelt? Er läßt die
>Nachkommastellen weg!

Ja, ist aber egal, da die Frequenz dann ja noch hochmultipliziert wird 
und die Nachkommastellen dann nicht mehr ins Gewicht fallen.



>Wie kommt eine kontrollierte Zeit in die Ausgabe? Es hängt nur von der
>CPU Geschwindigkeit ab.

Das ist richtig. Das sollte dann der nächste Schritt werden dafür zu 
sorgen dass aus CCR0= 1000 auch 1000Hz werden. Mein Denkansatz kam aus 
folgendem Link:

[http://www.mikrocontroller.net/articles/MSP430_Codebeispiele#PWM]

Konkret aus der Formel und dem Beispiel zur PWM.

timing_0 = 1.0e6  8  125 = 1000

Das funktioniert so einfach für mein Beispiel aber nicht, da ja eine 
Viertelperiode schon in 256 Schrite unterteilt ist.

>Der Interrupt ist völlig deplatziert

Wieso? Ich kenn mich mit Interrupts noch nicht so aus. Das ist eines der 
ersten µC Programme das ich schreibe.

>Die als - uint16_t berechnete -Tabelle sollte per Timer-Interrupt
>ausgegeben werden.

Ich wollte die Werte urprünglich direkt im Code berechnen lassen, aber 
der Compiler streikte. Es kam immer eine Fehlermeldung von wegen der 
Stack sei zu klein.

Abschließend noch folgendes:

Bei meinen ersten Versuchen den Flash zu beschreiben hab ich den Bereich 
in dem die Interrupt Vektoren stehen gelöscht. Daa wurde mir aber in 
einem anderen Post bereits gesagt dass die sowieso immer wieder neu 
geschrieben würden. Siehe hierzu meinen anderen Post:

[Beitrag "Re: MSP430 Gleitkommazahl in Flash speichern"]

Allerdings erhalte ich nun beim Kompilieren immer Warnungen für die 
diversen Interrupts seihen keine Vektoren vorhanden. Der Timerinterrupt 
ist in den Warnungen wiederum aber nicht vorhenden. Die Warnungen hab 
ich mal als Screenshot angehängt.

Gruß
Eddie

: Bearbeitet durch User
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.