www.mikrocontroller.net

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


Autor: Jörg (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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...
#include <stdlib.h>
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>

unsigned short i;
unsigned char cosinus[] = {
0,0,0,0,1,1,1,1,
1,2,2,2,2,2,3,3,
3,4,4,4,5,5,5,6,
6,7,7,8,8,9,9,10,
10,11,12,12,13,14,14,15,
16,16,17,18,19,20,20,21,
22,23,24,25,26,27,28,29,
30,31,32,33,34,35,36,37,
38,39,40,41,42,44,45,46,
47,48,50,51,52,53,55,56,
57,58,60,61,62,64,65,66,
68,69,71,72,73,75,76,78,
79,80,82,83,85,86,88,89,
91,92,94,95,97,98,100,101,
103,104,106,107,109,110,112,114,
115,117,118,120,121,123,124,126,
128,129,131,132,134,135,137,138,
140,141,143,145,146,148,149,151,
152,154,155,157,158,160,161,163,
164,166,167,169,170,172,173,175,
176,177,179,180,182,183,184,186,
187,189,190,191,193,194,195,197,
198,199,200,202,203,204,205,207,
208,209,210,211,213,214,215,216,
217,218,219,220,221,222,223,224,
225,226,227,228,229,230,231,232,
233,234,235,235,236,237,238,239,
239,240,241,241,242,243,243,244,
245,245,246,246,247,247,248,248,
249,249,250,250,250,251,251,251,
252,252,252,253,253,253,253,253,
254,254,254,254,255,255,255,255
};

int main(void)
{
  DDRD = 0xFF;
  PORTD = 0x00;

  // Fast PWM, TOP = 0xFF
  TCCR1A |= ((1<<WGM10) | (1<<WGM12));

  TIMSK |= (1<<OCIE1A);
  TIMSK |= (1<<TOIE1);

// Prescaler einstellen, Timer1 starten
  TCCR1B |= (1<<CS10);

  sei();

  while(1)
  {
    for(i = 1; i < 255; i++)
    {
      OCR1A = cosinus[i];
      _delay_ms(10);
    }

    for(i = 255; i > 1; i--)
    {
      OCR1A = cosinus[i];
      _delay_ms(10);
    }
  }
  
  return 0;
}

ISR(TIMER1_COMPA_vect)
{
  PORTD = 0x00;
}

ISR(TIMER1_OVF_vect)
{
  PORTD = 0xE0;
}

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!

Autor: Jörg (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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 :( ...

Autor: Jörg G. (joergderxte)
Datum:

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

Autor: Jörg (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Falk Brunner (falk)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Philipp Burch (philipp_burch)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Johann (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Johann (Gast)
Datum:

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

Autor: Jörg (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi!
Vielen Dank nochmal für die Tipps und Anregungen. Ich hab das Programm 
jetzt wie folgt verändert:
#include <stdlib.h>
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>

unsigned short i;
unsigned char cosinus[] = {
1,1,1,1,1,1,1,1,
1,2,2,2,2,2,3,3,
3,4,4,4,5,5,5,6,
6,7,7,8,8,9,9,10,
10,11,12,12,13,14,14,15,
16,16,17,18,19,20,20,21,
22,23,24,25,26,27,28,29,
30,31,32,33,34,35,36,37,
38,39,40,41,42,44,45,46,
47,48,50,51,52,53,55,56,
57,58,60,61,62,64,65,66,
68,69,71,72,73,75,76,78,
79,80,82,83,85,86,88,89,
91,92,94,95,97,98,100,101,
103,104,106,107,109,110,112,114,
115,117,118,120,121,123,124,126,
128,129,131,132,134,135,137,138,
140,141,143,145,146,148,149,151,
152,154,155,157,158,160,161,163,
164,166,167,169,170,172,173,175,
176,177,179,180,182,183,184,186,
187,189,190,191,193,194,195,197,
198,199,200,202,203,204,205,207,
208,209,210,211,213,214,215,216,
217,218,219,220,221,222,223,224,
225,226,227,228,229,230,231,232,
233,234,235,235,236,237,238,239,
239,240,241,241,242,243,243,244,
245,245,246,246,247,247,248,248,
249,249,250,250,250,251,251,251,
252,252,252,253,253,253,253,253,
254,254,254,254,254,254,254,254
};

int main(void)
{
  DDRB = 0xFF;
  DDRD = 0xFF;
  PORTD = 0x00;

  // PWM, Phase-Correct, TOP = 0xFF
  TCCR1A |= ((1<<WGM10));

  TIMSK |= (1<<OCIE1A);

// Prescaler einstellen, Timer1 starten
  TCCR1B |= (1<<CS11);

  sei();

  while(1)
  {
    for(i = 1; i < 255; i++)
    {
      OCR1A = cosinus[i];
      _delay_ms(5);
    }

    for(i = 255; i > 1; i--)
    {
      OCR1A = cosinus[i];
      _delay_ms(5);
    }
  }
  
  return 0;
}

ISR(TIMER1_COMPA_vect)
{
  PORTD ^= ((1<<PD5) | (1<<PD6));
}
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

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.