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?
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
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.
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
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);
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.
>> 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);
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 | }
|
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; |
Danke Karl heinz ! Ich stolpere immer wieder, wenn die Typen aus mehr als zwei Wörtern bestehen ;-) ++ Jörg
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.