www.mikrocontroller.net

Forum: Compiler & IDEs Oh Gott, schon wieder ein Frage zu PWM


Autor: flyingwolf (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Jau! Aber eine zu der ich keine Antwort fand.
Problem:
Ich möchte mir 2 Funktionen schreiben. Fadein() und Fadeout().
der Takt für die PWN wird von einem Timer generiert (leider alle 8 
Takte!).
Dieser Timer löst, wenn Fadein oder Fadeout aktiv sind,  einen Interrupt 
aus, der einen Zähler hoch bzw runterzählt und damit die Pulsweite 
zwischen 1/255 tel und 254/255tel bestimmt.
Was der Routine fehlt, ist eine Möglichkeit den Port der ein- oder 
ausgeblendet wird, zu übergeben.
Meine Alternative ist ein Bit in einem char, das gesetzt oder gelöscht 
wird und dann über eine if-Abfrage den entsprechend zugeordneten Port 
bedient, das ist aber sehr umständlich und dauert bei mehreren 
If-Abfragen länger als der Impuls lang sein soll und eine If-Schleife 
für 8 Ports in einer ISR scheint mir auch nicht so optimal.
Gibt es dafür eine "professionelle" Lösung?

Autor: Jörg X. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
suchst du nur sowas:
http://www.mikrocontroller.net/articles/AVR-GCC-Tu...
?
sonst wäre mindestens ein Code-Beispiel ganz praktisch

hth. Jörg

Autor: flyingwolf (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Das ließe sich zumindest vorteilhaft einbauen, denke ich. Auf jedem Fall 
bringt es mich weiter, also schon ein Danke an Dich.
Ich bin aber trotzdem an weiteren Vorschlägen interessiert.

Autor: Jörg X. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
mmh, Was genau machst du da/willst du machen?
- Willst du ein PWM-Signal an einem beliebigen Pin ein- und ausfaden?
- Willst du das signal an einem OCnx Pin faden?
- Sieht das Signal ganz anders aus, d.h. keine durchgehendes PWM-Signal?

Ich versteh grad nicht was du vor hast, poste mal klarere Info/Code 
bitte!

?! Jörg

Autor: flyingwolf (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
ich will bei Bedarf einen "beliebigen" Pin via PWM ein- oder 
ausschalten. d.h. binnen 2 - 3 sec. zählt ein Zähler vom einem 
Interrupttimer bedient von 1 bis 255 hoch.
Bei Fade in ist der Port am Anfang 0
Im Ersten Durchlauf bei 1 = 1 bei 2-255 = 0;
im zweiten Durchlauf von 1-2 = 1 von 3 - 255 = 0
usw.
Bei 255 angekommen ist der Port dauerhaft 1 und der Interrupt wird zur 
Entlastung des Proz abgeschaltet.
Fadeout läuft in gleicher Weise rückwärts.
Der Aufruf soll dann etwa so aussehen z.B.


if (sollwert > istwert && !checkbit(??PORTB PB1 ??)) Fadein(PORTB,PB1);
if (sollwert == istwert && checkbit(??PORTB PB1 ??)) Fadeout(PORTB,PB1);

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Du weist, wie du eine Software-PWM machen kannst?

Ist im Grunde sehr simpel:
Setze einen Timer auf, der dir einen regelmässigen Interrupt
liefert. Im Interrupt zählst du einen Counter ständig von 0
bis 255 (kann auch zb. nur bis 64 oder eine andere Zahl zählen).
Das ist dein PWM Counter, der einen Takt vorgibt.
Für deine LED hast du jetzt noch eine zusätzliche Variable,
die den tatsächlichen PWM Wert für die LED vorgibt.
In der Interrupt Funktion vergleichst du nun beides:
Ist der Zähler größer als der PWM Wert, schaltest du die LED
aus, ansonsten ein.

so ungefähr:
uint8_t PWMCounter;
volatile uint8_t PWMLed;

ISR( .... )
{
  PWMCounter++;

  if( PWMCounter == 64 )
    PWMCounter = 0;

  if( PWMCounter > PWMLed )
    // Led ausschalten
  else
    // Led einschalten
}

Damit kannst du schon mal durch Verändern des PWM-Wertes die
LED auf unterschiedliche Helligkeiten setzen. Alles was noch
bleibt, ist den PWM Wert für die LED ebenfalls zeitabhängig
zu machen. Zb. Im selben Interrupt
uint8_t PWMCounter;
volatile uint8_t PWMLed;
volatile uint8_t FadeIn;
volatile uint8_t FadeOut;

ISR( .... )
{
  PWMCounter++;

  if( PWMCounter == 64 )
    PWMCounter = 0;

  if( PWMCounter > PWMLed )
    // Led ausschalten
  else
    // Led einschalten

  if( FadeIn ) {
    if( PWMLed < 64 )
      PWMLed++;
    else
      FadeIn = 0;
  }

  if( FadeOut ) {
    if( PWMLed > 0 )
      PWMLed--;
    else
      FadeOut = 0;
  }
}

So in etwa. Die Details musst du dir noch überlegen, wie zb
eine Steuerung in welchem Zeitraum das FadeIn bzw. FadeOut
erfolgen soll, etc.

Autor: flyingwolf (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>>   if( PWMCounter > PWMLed )
    // Led ausschalten
  else
    // Led einschalten
<<

Da ist das Loch in meinem Programm denn PWMLed soll wahlweise z.B.
PORTB PB1
PORTB PB2
PORTC PC3
PORTD PD1
oder was auch immer sein können. (und es wird keine led sein ... ;-)  )

Möglich wäre es wenn ich eben x Zähler in der ISR aufmache, die ich 
zählen lasse und dann jeden Port der zur Anwendung kommen kann mit einem 
Bit aus einer Dummy Variablen verheirate und dann mit einer Unzahl von 
if-Abfragen in der ISR die Ports setze oder lösche.

Die Frage ist aber

Geht es auch in der Form
if (sollwert > istwert && !checkbit(??PORTB PB1 ??)) Fadein(PORTB,PB1);

Autor: Jörg X. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Naja, wenn du immer nur einen Pin fadest, kannst du ja der ISR einen 
Pointer mitgeben:
/* global:
 * keine Garantie, das soll ein volatile Pointer auf volatile uint8_t sein
 */
volatile (volatile uint8_t) *port; 
volatile uint8_t pinnr;

// ISR vorbereiten:
//z.B.:
port = &PORTB;
pinnr = (1<<PB1); //dann muss nicht in der ISR geshiftet werden

//...

//in der ISR:
ISR(..._vect)
{
//...
/setzen:
*port |= pinnr;
//loeschen:
*port &= ~pinnr;
}

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Jörg X. wrote:

>
> /* global:
>  * keine Garantie, das soll ein volatile Pointer auf volatile uint8_t
> sein
>  */
> volatile (volatile uint8_t) *port;
> 

Fast.
Das wäre dann ein
volatile uint8_t * volatile port;

Autor: Jörg X. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Danke Karl heinz !
Ich stolpere immer wieder, wenn die Typen aus mehr als zwei Wörtern 
bestehen ;-)

++ Jörg

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Jörg X. wrote:
> Danke Karl heinz !
> Ich stolpere immer wieder, wenn die Typen aus mehr als zwei Wörtern
> bestehen ;-)
>
> ++ Jörg

Das ist eigentlich recht einfach:
volatile und const sind Modifier. Die wirken immer auf das 'Teil'
links von ihnen. Es sei denn das const oder volatile steht schon
ganz links, dann wirken sie auf das 'Teil' rechts von ihnen :-)

d.h. es ist egal ob man
  const char c;
oder
  char const c;
schreibt. Ist in beiden Fällen dasselbe.

Fang an mit der 'undekorierten' Deklaration
  uint8_t * pPtr;

was soll volatile sein?
Der Pointer, angezeigt durch den '*'. Also muss rechts vom * ein
volatile stehen (weil ja volatile, const auf das 'Teil' links von
ihnen wirken)
  uint8_t * volatile pPtr;    // der Pointer ist volatile

Wenn das worauf der Pointer zeigt volatile sein soll, also der uint8_t,
dann muss rechts vom uint8_t ein volatile stehen
  uint8_t volatile * pPtr;    // der uint8_t ist volatile

Beides zusammen
  uint8_t volatile * volatile pPtr;   // sowohl der Pointer selbst
                                      // als auch das worauf er zeigt
                                      // sind volatile

Nimmt man jetzt noch die Ausnahme Regel (wirkt immer nach links,
es sei denn ganz links, dann wirkt es nach rechts) hinzu, dann
hat man
  volatile uint8_t * volatile pPtr;

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.