Oh Gott, schon wieder ein Frage zu PWM

Gast #640273
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?
Gast #640478
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
Gast #640578
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);
#640632
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.
Gast #640660
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);
Gast #640722
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
}
#641176
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;

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren