Forum: Mikrocontroller und Digitale Elektronik (Co-)Sinus-Kennlinie und LED


von Jörg (Gast)


Lesenswert?

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
unsigned short i;
7
unsigned char cosinus[] = {
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
int main(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
  return 0;
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!

von Jörg (Gast)


Lesenswert?

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

von Jörg G. (joergderxte)


Lesenswert?

Welchen AVR hast du da ?
1
/* Bist du hier sicher:*/
2
TCCR1A |= ((1<<WGM10) | (1<<WGM12));
3
/* WGM12 ist wahrscheinlich in TCCR1B */
ist die LED eigentlich high- oder low-active?
 rtfm, Jörg

von Jörg (Gast)


Lesenswert?

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

von Falk B. (falk)


Lesenswert?

@  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

von Philipp B. (philipp_burch)


Lesenswert?

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.

von Johann (Gast)


Lesenswert?

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.

von Johann (Gast)


Lesenswert?

Was ich als erstes ändern würde: die zwei ISR löschen und die beiden 
Einträge in das TIMSK-Register entfernen

von Jörg (Gast)


Lesenswert?

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
unsigned short i;
7
unsigned char cosinus[] = {
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
int main(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
  return 0;
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

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.