Hi Forum!
Ich dachte mir vorhin, daß ich ja mal eine
Sinus-/Cosinus-/WasAuchImmer-Kennlinie programmieren könnte. Dafür habe
ich ein Array mit 256 Elementen angelegt, welches die Vergleichswerte
für die PWM beinhalten soll. Die Formel dafür ist
"GANZZAHL(128+128*-COS((x/256)*PI())*0,999)" (OpenOffice). Mit x-werten
von 0-256 bekomme ich Cosinus-Werte von 0-255.
Soweit ok. Nur blendet die LED, die ich z.Z. zum Test angeschlossen
habe, recht eigenartig: sie ist zu Beginn des Programms kurz komplett
an, dann blendet sie ein und wieder aus und ist dann wieder kurz ganz
an. Als ob es Probleme mit kleinen Werten im OCR1A gibt...
Im Folgenden mal der Code. Ich hab schon viel dran rum gedoktort, aber
ich komm nicht drauf...
1
#include<stdlib.h>
2
#include<avr/io.h>
3
#include<util/delay.h>
4
#include<avr/interrupt.h>
5
6
unsignedshorti;
7
unsignedcharcosinus[]={
8
0,0,0,0,1,1,1,1,
9
1,2,2,2,2,2,3,3,
10
3,4,4,4,5,5,5,6,
11
6,7,7,8,8,9,9,10,
12
10,11,12,12,13,14,14,15,
13
16,16,17,18,19,20,20,21,
14
22,23,24,25,26,27,28,29,
15
30,31,32,33,34,35,36,37,
16
38,39,40,41,42,44,45,46,
17
47,48,50,51,52,53,55,56,
18
57,58,60,61,62,64,65,66,
19
68,69,71,72,73,75,76,78,
20
79,80,82,83,85,86,88,89,
21
91,92,94,95,97,98,100,101,
22
103,104,106,107,109,110,112,114,
23
115,117,118,120,121,123,124,126,
24
128,129,131,132,134,135,137,138,
25
140,141,143,145,146,148,149,151,
26
152,154,155,157,158,160,161,163,
27
164,166,167,169,170,172,173,175,
28
176,177,179,180,182,183,184,186,
29
187,189,190,191,193,194,195,197,
30
198,199,200,202,203,204,205,207,
31
208,209,210,211,213,214,215,216,
32
217,218,219,220,221,222,223,224,
33
225,226,227,228,229,230,231,232,
34
233,234,235,235,236,237,238,239,
35
239,240,241,241,242,243,243,244,
36
245,245,246,246,247,247,248,248,
37
249,249,250,250,250,251,251,251,
38
252,252,252,253,253,253,253,253,
39
254,254,254,254,255,255,255,255
40
};
41
42
intmain(void)
43
{
44
DDRD=0xFF;
45
PORTD=0x00;
46
47
// Fast PWM, TOP = 0xFF
48
TCCR1A|=((1<<WGM10)|(1<<WGM12));
49
50
TIMSK|=(1<<OCIE1A);
51
TIMSK|=(1<<TOIE1);
52
53
// Prescaler einstellen, Timer1 starten
54
TCCR1B|=(1<<CS10);
55
56
sei();
57
58
while(1)
59
{
60
for(i=1;i<255;i++)
61
{
62
OCR1A=cosinus[i];
63
_delay_ms(10);
64
}
65
66
for(i=255;i>1;i--)
67
{
68
OCR1A=cosinus[i];
69
_delay_ms(10);
70
}
71
}
72
73
return0;
74
}
75
76
ISR(TIMER1_COMPA_vect)
77
{
78
PORTD=0x00;
79
}
80
81
ISR(TIMER1_OVF_vect)
82
{
83
PORTD=0xE0;
84
}
Ich würde mich feuen, wenn ihr einmal kurz drüber gucken würdet.
Vielleicht pringt euch ja der Haken ins Auge...
Dankeschön schonmal!
Jörg
PS: konstruktiv geäußerte Verbesserungsvorschläge sind immer willkommen!
Ach ja, ürsprünglich wollte ich das im Phase-Correct-PWM Modus laufen
lassen, und dann beim Compare-Match-Interrupt die Pins einfach toggeln
mit "PORTD ^= 0xE0;". Also beim Hochzähl-Compare-Match die Pins aus, und
dann beim Runterzähl-Compare-Match Pins wieder an. Aber das ging auch
nicht :( ...
Hey, ein Namensvetter :)
danke für die Antwort... die LED ist active high. Müsste also einen
nicht-invertierende PWM sein. Ich benutze einen mega8 und schaue mal
grad in DB... ja, du hast recht, WGM12 ist im TCCR1B. Aber so richtig
geholfen hat das auch nicht. Es wird ein- und wieder ausgeblendet, dann
blinkts einmal und dann wieder von vorne...
Noch eine Idee? Vielleicht dazu, in welchem Wertebereich die OCRxy-Werte
sein dürfen/müssen, wenn das mit Phase-Correct-PWM laufen soll? So hatte
ich es ja ursprünglich, aber das ging ja nicht...
Danke,
Jörg
@ Jörg (Gast)
>Soweit ok. Nur blendet die LED, die ich z.Z. zum Test angeschlossen>habe, recht eigenartig: sie ist zu Beginn des Programms kurz komplett>an, dann blendet sie ein und wieder aus und ist dann wieder kurz ganz>an. Als ob es Probleme mit kleinen Werten im OCR1A gibt...
Wenn dein Programm OK ist, hast du die nichtlineare Kennlinie des Auges
wiederentdeckt, siehe LED-Fading.
MfG
Falk
Falk Brunner schrieb:
> @ Jörg (Gast)>>>Soweit ok. Nur blendet die LED, die ich z.Z. zum Test angeschlossen>>habe, recht eigenartig: sie ist zu Beginn des Programms kurz komplett>>an, dann blendet sie ein und wieder aus und ist dann wieder kurz ganz>>an. Als ob es Probleme mit kleinen Werten im OCR1A gibt...>> Wenn dein Programm OK ist, hast du die nichtlineare Kennlinie des Auges> wiederentdeckt, siehe LED-Fading.
So wie er das Problem beschreibt, liegt das nicht an der Kennlinie des
Auges. Ich tippe eher darauf, dass es mit "gleichzeitigen" Interrupts
ein Problem gibt, die bei OCR=0 fast zwangsweise auftreten müssen
(Übergang von 255 nach 0 erzeugt gleichzeitig einen OVF- und einen
COMP-Interrupt). Die Prioritäten habe ich jetzt gerade nicht im Kopf,
doch wenn COMPA höher ist als OVF, dann wird der zuerst ausgeführt (LED
aus) und unmittelbar anschliessend der OVF-Interrupt, der die LED wieder
einschaltet. Folglich bleibt sie dann für einen ganzen Zyklus an, was
man eben sieht.
Abhilfe: Mit der PWM nur bis 1 runtergehn, nicht bis 0.
Die zwei Interruptquellen bei einem Prescaler von 1 haben mich auch
irritiert.
Des Weiteren: meines Wissens nach arbeitet die PWM automatisch wenn sie
aktiviert wurde: sprich der OC1A-Pin muss nur noch auf Ausgang gesetzt
werden, der Rest läuft dann von alleine.
Hi!
Vielen Dank nochmal für die Tipps und Anregungen. Ich hab das Programm
jetzt wie folgt verändert:
1
#include<stdlib.h>
2
#include<avr/io.h>
3
#include<util/delay.h>
4
#include<avr/interrupt.h>
5
6
unsignedshorti;
7
unsignedcharcosinus[]={
8
1,1,1,1,1,1,1,1,
9
1,2,2,2,2,2,3,3,
10
3,4,4,4,5,5,5,6,
11
6,7,7,8,8,9,9,10,
12
10,11,12,12,13,14,14,15,
13
16,16,17,18,19,20,20,21,
14
22,23,24,25,26,27,28,29,
15
30,31,32,33,34,35,36,37,
16
38,39,40,41,42,44,45,46,
17
47,48,50,51,52,53,55,56,
18
57,58,60,61,62,64,65,66,
19
68,69,71,72,73,75,76,78,
20
79,80,82,83,85,86,88,89,
21
91,92,94,95,97,98,100,101,
22
103,104,106,107,109,110,112,114,
23
115,117,118,120,121,123,124,126,
24
128,129,131,132,134,135,137,138,
25
140,141,143,145,146,148,149,151,
26
152,154,155,157,158,160,161,163,
27
164,166,167,169,170,172,173,175,
28
176,177,179,180,182,183,184,186,
29
187,189,190,191,193,194,195,197,
30
198,199,200,202,203,204,205,207,
31
208,209,210,211,213,214,215,216,
32
217,218,219,220,221,222,223,224,
33
225,226,227,228,229,230,231,232,
34
233,234,235,235,236,237,238,239,
35
239,240,241,241,242,243,243,244,
36
245,245,246,246,247,247,248,248,
37
249,249,250,250,250,251,251,251,
38
252,252,252,253,253,253,253,253,
39
254,254,254,254,254,254,254,254
40
};
41
42
intmain(void)
43
{
44
DDRB=0xFF;
45
DDRD=0xFF;
46
PORTD=0x00;
47
48
// PWM, Phase-Correct, TOP = 0xFF
49
TCCR1A|=((1<<WGM10));
50
51
TIMSK|=(1<<OCIE1A);
52
53
// Prescaler einstellen, Timer1 starten
54
TCCR1B|=(1<<CS11);
55
56
sei();
57
58
while(1)
59
{
60
for(i=1;i<255;i++)
61
{
62
OCR1A=cosinus[i];
63
_delay_ms(5);
64
}
65
66
for(i=255;i>1;i--)
67
{
68
OCR1A=cosinus[i];
69
_delay_ms(5);
70
}
71
}
72
73
return0;
74
}
75
76
ISR(TIMER1_COMPA_vect)
77
{
78
PORTD^=((1<<PD5)|(1<<PD6));
79
}
Jetzt scheint es auch zu funktionieren. Ich hab es so gemacht, wie ich
ja ursprünglich vor hatte (siehe 2. Post). Der Fehler lag bei
Vergleichswerten von 0 und 255, die Tabelle wurde angepasst. Auch der
Vorteiler wurde von 1 auf 8 angepasst, und jetzt gehts.
Würde mir vielleicht jemand kurz erklären warum?
Danke und vG,
Jörg