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


von flyingwolf (Gast)


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?

von Jörg X. (Gast)


Lesenswert?

suchst du nur sowas:
http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial#IO-Register_als_Parameter_und_Variablen
?
sonst wäre mindestens ein Code-Beispiel ganz praktisch

hth. Jörg

von flyingwolf (Gast)


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.

von Jörg X. (Gast)


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

von flyingwolf (Gast)


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);

von Karl H. (kbuchegg)


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:
1
uint8_t PWMCounter;
2
volatile uint8_t PWMLed;
3
4
ISR( .... )
5
{
6
  PWMCounter++;
7
8
  if( PWMCounter == 64 )
9
    PWMCounter = 0;
10
11
  if( PWMCounter > PWMLed )
12
    // Led ausschalten
13
  else
14
    // Led einschalten
15
}

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
1
uint8_t PWMCounter;
2
volatile uint8_t PWMLed;
3
volatile uint8_t FadeIn;
4
volatile uint8_t FadeOut;
5
6
ISR( .... )
7
{
8
  PWMCounter++;
9
10
  if( PWMCounter == 64 )
11
    PWMCounter = 0;
12
13
  if( PWMCounter > PWMLed )
14
    // Led ausschalten
15
  else
16
    // Led einschalten
17
18
  if( FadeIn ) {
19
    if( PWMLed < 64 )
20
      PWMLed++;
21
    else
22
      FadeIn = 0;
23
  }
24
25
  if( FadeOut ) {
26
    if( PWMLed > 0 )
27
      PWMLed--;
28
    else
29
      FadeOut = 0;
30
  }
31
}

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

von flyingwolf (Gast)


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);

von Jörg X. (Gast)


Lesenswert?

Naja, wenn du immer nur einen Pin fadest, kannst du ja der ISR einen 
Pointer mitgeben:
1
/* global:
2
 * keine Garantie, das soll ein volatile Pointer auf volatile uint8_t sein
3
 */
4
volatile (volatile uint8_t) *port; 
5
volatile uint8_t pinnr;
6
7
// ISR vorbereiten:
8
//z.B.:
9
port = &PORTB;
10
pinnr = (1<<PB1); //dann muss nicht in der ISR geshiftet werden
11
12
//...
13
14
//in der ISR:
15
ISR(..._vect)
16
{
17
//...
18
/setzen:
19
*port |= pinnr;
20
//loeschen:
21
*port &= ~pinnr;
22
}

von Karl H. (kbuchegg)


Lesenswert?

Jörg X. wrote:

>
1
> /* global:
2
>  * keine Garantie, das soll ein volatile Pointer auf volatile uint8_t
3
> sein
4
>  */
5
> volatile (volatile uint8_t) *port;
6
>

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

von Jörg X. (Gast)


Lesenswert?

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

++ Jörg

von Karl H. (kbuchegg)


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
1
  const char c;
oder
1
  char const c;
schreibt. Ist in beiden Fällen dasselbe.

Fang an mit der 'undekorierten' Deklaration
1
  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)
1
  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
1
  uint8_t volatile * pPtr;    // der uint8_t ist volatile

Beides zusammen
1
  uint8_t volatile * volatile pPtr;   // sowohl der Pointer selbst
2
                                      // als auch das worauf er zeigt
3
                                      // 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
1
  volatile uint8_t * volatile pPtr;

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.