Forum: Mikrocontroller und Digitale Elektronik Ansteuerung/Fading von 12 LED mit IR Empfänger durch PIC oder ATTiny


von Daniel B. (daniel_bach)


Lesenswert?

Hallo zusammen.

Ich möchte ein Modellauto (Trabant 601) im Maßstab 1:18 beleuchten. Dazu 
möchte ich bedrahtete SMD LED´s der Baugröße 0805 bzw 0603 verwenden. 
Die Verschiedenen Leuchtmodi (Blinker links, Blinker rechts, 
Warnblinker, Standlicht, Abblendlicht, Bremslicht usw.) sollen mittels 
IR Empgänger / IR Fernbedienung umschaltbar sein. Als Spannungsquelle 
sollen 3 oder 4 AA Batterien/Akkus dienen.

Zu meinen Fragen:

Welchen µC würdet ihr empfehlen? Ich habe mir einen PIC18F14K22 
ausgesucht, da ich schonmal mit dsPics zu tun hatte. Um das Modell 
realistischer wirken zu lassen, sollen die Blinker dimmen/faden, da ja 
der Trabant herkömmliche Leuchtmittel verbaut hatte und keine LED. Das 
Soll mittels PWM realisiert werden.
Da 12 LED´s recht viel sind, würde ich einen LED-Treiber dazunehmen, 
zumal ich mir unsicher bin ob ich die LED´s direkt an den µC anschließen 
sollte. Die 20 mA welche die LED´s maximal ziehen sind halt genau die 
Grenze was der µC pro PIN als Output schalten kann. Als LED-Treiber habe 
ich mir den TLC 5940 ausgeschaut.

Das ganze soll auf einen kleinen Platine (ca. 4x6 cm ) im Modell seinen 
Platz finden.

Habt ihr Tipps zur Hardware welche ihr verwenden würdet? Gerne auch 
Alternativen zum LED Treiber z.B. durch Multiplexen.

--> 12 LEDs einzeln/paarweise Ansteuern (dimmbar/fading)
--> Analog in für IR-Empfänger
--> Festpannungsregler auf 5 oder halt 3,3 V je nach µC

Ich hätte auch nix gegen Atmel, nur ist die Entwicklungsumgebung für 
Microchip schon da und ich habe damit schon mal gearbeitet.

Sowas soll realisiert werden:

https://www.youtube.com/watch?v=vivnPwefRlo

Danke für eure Tips und ein paar ruhige Feiertage!

von Falk B. (falk)


Lesenswert?

@Daniel Bach (daniel_bach)

>Welchen µC würdet ihr empfehlen?

Da geht fast jeder halbwegs aktuelle Typ.

>Ich habe mir einen PIC18F14K22

Klingt OK.

>der Trabant herkömmliche Leuchtmittel verbaut hatte und keine LED. Das
>Soll mittels PWM realisiert werden.

Normal.

>Da 12 LED´s recht viel sind, würde ich einen LED-Treiber dazunehmen,

Brauchst du nicht, die 20mA/Port können die meisten uCs allein treiben. 
Außerdem braucht man bei ultrahellen LEDs keine 20mA, da wird man eher 
blind! Da reichen 2-5mA locker!

>Grenze was der µC pro PIN als Output schalten kann. Als LED-Treiber habe
>ich mir den TLC 5940 ausgeschaut.

Overkill.

>Das ganze soll auf einen kleinen Platine (ca. 4x6 cm ) im Modell seinen
>Platz finden.

Kriegt man hin.

>Habt ihr Tipps zur Hardware welche ihr verwenden würdet? Gerne auch
>Alternativen zum LED Treiber z.B. durch Multiplexen.

Kein Treiber, kein Multiplexen. Einfach Soft-PWM + IRMP.

>Microchip schon da und ich habe damit schon mal gearbeitet.

Dann bleib dabei.

von Thomas E. (thomase)


Lesenswert?

Daniel B. schrieb:
> Da 12 LED´s recht viel sind, würde ich einen LED-Treiber dazunehmen,
> zumal ich mir unsicher bin ob ich die LED´s direkt an den µC anschließen
> sollte. Die 20 mA welche die LED´s maximal ziehen sind halt genau die
> Grenze was der µC pro PIN als Output schalten kann. Als LED-Treiber habe
> ich mir den TLC 5940 ausgeschaut.

Du brauchst keinen Treiber. Die 20mA sind viel zu viel. Allerdings weder 
für die Leds noch für den Controller, sondern für deine Augen. Geh mal 
davon aus, daß maximal 5mA ausreichen. Die roten Leds(Rück-, Bremslicht) 
könntest du bei Vcc=5V zudem in Reihe schalten. Bei den gelben Blinkern 
(jeweils links/rechts) sollte das auch noch klappen. Nur die weißen 
müssen einzeln angesteuert werden.

: Bearbeitet durch User
von Daniel B. (daniel_bach)


Lesenswert?

Hallo zusammen,

da Projekt existiert noch und hat fortschrittte gemacht.
Ich habe mich für einen PIC18F45k22 entschieden, als IR-Receiver 
verwende ich einen TSOP4838. Das Verfahren zum decodieren gibt´s ja im 
Netz nachzulesen, ich verwende eine Arduino-Fernbedienung welche mit dem 
NEC Protokoll arbeitet. LED ansteuern funktioniert also schonmal.

Nun hänge ich an einer wahrscheinlich banalen Stelle. Das Verfahren zum 
Decodieren setzt bei erfolgreicher Dekodierung eine Variable auf TRUE 
welche dann als Bedingung einer Weilschleife dient. Im Hauptprogramm 
kann ich dann je nach gedrückter Taste verschiedene Ports anschalten 
usw.

Ich möchte jedoch das so realisieren, dass eine Unterfunktion, z.B. 
Led-Fading solange ausgeführt wird bis ich die Taste erneut drücke.

Wenn ich die Codierung mit if abfrage, rollt er einmal durch die 
Fading-Funktion und das wars.

Wenn ich Taste a drücke soll er praktisch solange etwas machen bzw 
starten bis ich die Taste nochmal drücke.

Ich hänge mal meinen Code hier an, vllt ist die Lösung ja so simpel als 
das ich nicht drauf komme.

Hauptprogramm:
1
void main(void)
2
{
3
  Pmd_Init();
4
  Ports_Init();
5
  Config_Init();
6
  Timer_Init();
7
  Irq_Init();
8
 
9
  __delay_ms(1000);   // wait 1 second
10
 
11
  while(1)
12
  {
13
    while (!remote_decoder_g_decode_ok);   // wait until NEC code receiver
14
 
15
    remote_decoder_g_decode_ok = 0;   // reset decoding process
16
    remote_decoder_g_decode_status = 0;
17
    T1CONbits.TMR1ON    = 0;   // disable Timer1
18
    
19
    U8_T empfang_code = 0u;
20
 
21
    empfang_code = remote_decoder_g_remote_code;    
22
   
23
    if(empfang_code == 0x3f)
24
    {
25
        Led_Control_Fade_On();
26
        Led_Control_Fade_Off();
27
        
28
        empfang_code = 0;
29
    }
30
   
31
    INTCONbits.RBIE = 1;    // enable PORTB change interrupt
32
 
33
  }
34
 
35
}

Decodierroutine:
1
void __interrupt() EXT(void)
2
{
3
/*************** start external interrupt ISR ***************/
4
  if (INTCONbits.RBIF && (PORTBbits.RB4 || !PORTBbits.RB4))   // PORTB change ISR (& clear mismatch condition)
5
  {
6
    INTCONbits.RBIF = 0;   // clear PORTB interrupt flag bit
7
    if(remote_decoder_g_decode_status != 0)
8
    {
9
      remote_decoder_g_timer_val = (TMR1H << 8) | TMR1L;  // store Timer1 value
10
      TMR1H = TMR1L = 0;     // reset Timer1
11
    }
12
 
13
    switch(remote_decoder_g_decode_status)
14
    {
15
     case 0 :              // start receiving IR data (we're at the beginning of 9ms pulse)
16
       TMR1H = TMR1L = 0;  // reset Timer1
17
       T1CONbits.TMR1ON = 1;         // enable Timer1
18
       remote_decoder_g_decode_status = 1;      // next state: end of 9ms pulse (start of 4.5ms space)
19
       remote_decoder_g_fill_up_bits = 0;
20
       break;
21
 
22
     case 1 :                                       // End of 9ms pulse
23
       if((remote_decoder_g_timer_val > 19000) || (remote_decoder_g_timer_val < 17000))
24
       { // invalid interval ==> stop decoding and reset
25
         remote_decoder_g_decode_status = 0;  // reset decoding process
26
         T1CONbits.TMR1ON = 0;     // disable Timer1
27
       }
28
       else
29
         remote_decoder_g_decode_status = 2;  // next state: end of 4.5ms space (start of 562µs pulse)
30
       break;
31
 
32
     case 2 :                                       // End of 4.5ms space
33
       if((remote_decoder_g_timer_val > 10000) || (remote_decoder_g_timer_val < 8000))
34
       { // invalid interval ==> stop decoding and reset
35
         remote_decoder_g_decode_status = 0;  // reset decoding process
36
         T1CONbits.TMR1ON = 0;     // disable Timer1
37
       }
38
       else
39
         remote_decoder_g_decode_status = 3; // next state: end of 562µs pulse (start of 562µs or 1687µs space)
40
       break;
41
 
42
     case 3 :    // End of 562µs pulse
43
       if((remote_decoder_g_timer_val > 1400) || (remote_decoder_g_timer_val < 800))
44
       { // invalid interval ==> stop decoding and reset
45
         T1CONbits.TMR1ON = 0;     // disable Timer1
46
         remote_decoder_g_decode_status = 0;  // reset decoding process
47
       }
48
       else
49
         remote_decoder_g_decode_status = 4;  // next state: end of 562µs or 1687µs space
50
       break;
51
 
52
       case 4 :
53
       if((remote_decoder_g_timer_val > 3600) || (remote_decoder_g_timer_val < 800))
54
       { // invalid interval ==> stop decoding and reset
55
         T1CONbits.TMR1ON = 0;     // disable Timer1
56
         remote_decoder_g_decode_status = 0;  // reset decoding process
57
       }
58
 
59
       else
60
       {
61
         if( remote_decoder_g_timer_val > 2000)  // if space width > 1ms (short space)
62
           remote_decoder_g_remote_code |=   (U32_T)1 << (31 - remote_decoder_g_fill_up_bits);   // write 1 to bit (31 - remote_decoder_g_fill_up_bits)
63
 
64
         else    // if space width < 1ms (long space)
65
           remote_decoder_g_remote_code &= ~((U32_T)1 << (31 - remote_decoder_g_fill_up_bits));  // write 0 to bit (31 - remote_decoder_g_fill_up_bits)
66
         remote_decoder_g_fill_up_bits++;
67
 
68
         if(remote_decoder_g_fill_up_bits > 31)
69
         {
70
           remote_decoder_g_decode_ok = 1;   // decoding process OK
71
           INTCONbits.RBIE = 0;     // disable PORTB change interrupt 
72
         }
73
 
74
         else
75
           remote_decoder_g_decode_status = 3;  // next state: end of 562µs pulse (start of 562µs or 1687µs space)
76
         
77
         break;
78
       }  // end " else "
79
       
80
    }  // end " switch(remote_decoder_g_decode_status) "
81
 
82
  }  // end " if (RBIF && (RB0 || !RB0)) "
83
/*************** end external interrupt ISR ***************/
84
 
85
/*************** start Timer1 ISR ***************/
86
  if (PIR1bits.TMR1IF)         // Timer1 ISR
87
  {
88
    PIR1bits.TMR1IF    = 0;   // clear Timer1 overflow flag bit
89
    remote_decoder_g_decode_status = 0;   // reset decoding process
90
    T1CONbits.TMR1ON    = 0;   // disable Timer1
91
  }
92
}/* end function */
93
94
/* EOF */

von Daniel B. (daniel_bach)


Lesenswert?

Hallo, eine LED mit pwm zu betreiben funktioniert soweit, und zwar mit 
Timer Interrupt und dem Timer 0. Der Chip läuft mit 16 MHz, der Timer 
ist so eingestellt dass alle 30 µs ein Überlauf und somit ein 
Timer-Interrupt ausgelöst wird. In der ISR wird nun eine Variable 
hochgezählt(time), und mit einem voreingestellten Wert pwm_val 
verglichen. Ist der Zählerwert kleiner als der PWM-Wert (time<pwm_val) 
wird der Pin an dem die LEd angeschlossen isr auf 1 gestellt, ansosnten 
0. Somit kann ich mit unterschiedlichen Werten von pwm_val die 
Helligkeit der LED einstellen.

Nun zu meinem Anliegen: wie kann ich damit ein sanftes ein/aus faden 
machen? Es soll damit einmal ein Blinken mit ein/ausfaden von 4 LEDs 
verwirklicht werden.
Ansatz: Ich würde einen 2. Timer nehmen (ca. alle 50ms ein Interrupt, 
und da bei jedem Interrupt die Variable pwm_val ändern welche wiederum 
die Helligkeit der LED beeinflusst.

Ich würde gerne das hier auf der Seite gezeigte Verfahren mit Soft-PWM 
benutzen, leider bekomme ich es einfach nicht hin das für den Atmega32 
gedachte Beispiel auf meine PIC18F45K22 umzumünzen.

Init:
1
  
2
  /* Timer 0 */
3
  T0CON  = 0x88;
4
  TMR0H = 0xFF;
5
  TMR0L = 0x88;
6
  INTCONbits.GIE = 1;
7
  T0CONbits.TMR0ON = 1;

PWM Funktion:
1
U16_T time = 0;
2
const U8_T pwm_val = 1;
3
 /*************************** main function *********************/
4
void main(void)
5
{
6
  Pmd_Init();
7
  Ports_Init();
8
  Config_Init();
9
  Timer_Init();
10
  Irq_Init();
11
 
12
  __delay_ms(1000);   // wait 1 second
13
 
14
    while(1)
15
    {
16
        if (INTCONbits.T0IF)
17
        { 
18
            INTCONbits.T0IF = 0;
19
            TMR0H   = 0xFF;
20
            TMR0L   = 0x88;
21
            
22
            time++;
23
            
24
            if (time>20) 
25
            {
26
                time=0;
27
            }
28
29
            if (time<pwm_val)
30
            {
31
                 LATCbits.LATC7 = 1;
32
            }
33
            else
34
            {
35
                 LATCbits.LATC7 = 0;
36
            }
37
        }
38
    
39
 
40
    }
41
}
42
/*************************** end main function ********************************/

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Daniel B. schrieb:
> Nun zu meinem Anliegen: wie kann ich damit ein sanftes ein/aus faden
> machen?

Artikel LED-Fading

von Daniel (Gast)


Lesenswert?

Danke, das Beispiel habe ich mir natürlich mehrfach durchgelesen vorher, 
sosnt hätte ich nicht die Frage geschrieben.
Das das Beispiel hier für den AVR war, war die Umsetzung mit einem PIC 
nicht ganz trivial.
Das Problem wurde jedoch gelöst und ich habe mittels Timer-Interrupt 
welcher einen PWM-Multiplexer erstellt. Sanftes an/ausfaden 
funktioniert.

Mein Problem ist nun dass ich den Dekodiervorgang (max. ca. 100ms) der 
Fernbedienung und die Soft-PWM vereinen muss. Da der Timer Interrupt für 
das PWM ca. alle 500 µs kommt, müsste ich den Dekodiervorgang der 
Fernbedienung mit NEC Protokoll so anpassen / aufsplitten dass die neuen 
Werte für die PWM trotzdem alle 500 µs erstellt werden und nicht ca. 
100ms gewartet wird bis der dekodiervorgang abgeschlossen ist.

Der Code zum dekodieren steht schon weiter oben (Post vom 23.11.2018).
Meine Idee wäre nach jedem Timer Interrupt (evtl. mit einem 2. Timer) am 
Portpin an dem der IR Empfänger angeschlossen ist zu schauen ob sich der 
Pegel geändert hat.

Hat jemand eine Idee wie man den Dekodiervorgang sinnvoll aufsplitten 
kann ohne 100ms warten zu müssen?

von Axel S. (a-za-z0-9)


Lesenswert?

Daniel schrieb:
> Das Problem wurde ... gelöst und ich habe mittels Timer-Interrupt
> welcher einen PWM-Multiplexer erstellt. Sanftes an/ausfaden
> funktioniert.

Schön. Und Soft-PWM nimmst du, weil dein PIC keine Hardware-PWM kann? 
Also ich hätte ja lieber nach einem µC Ausschau gehalten, der das hat.

> Mein Problem ist nun dass ich den Dekodiervorgang (max. ca. 100ms) der
> Fernbedienung und die Soft-PWM vereinen muss. Da der Timer Interrupt für
> das PWM ca. alle 500 µs kommt, müsste ich den Dekodiervorgang der
> Fernbedienung mit NEC Protokoll so anpassen / aufsplitten dass die neuen
> Werte für die PWM trotzdem alle 500 µs erstellt werden und nicht ca.
> 100ms gewartet wird bis der dekodiervorgang abgeschlossen ist.

Aka "verschachtelte Interrupts". Das englische Wort wäre "nested"

> Hat jemand eine Idee wie man den Dekodiervorgang sinnvoll aufsplitten
> kann ohne 100ms warten zu müssen?

Das einzige, was an der IR-Empfangs ISR zeitkritisch ist, ist das 
Abtasten des Pins, an dem der IR-Empfänger hängt. Der Rest danach darf 
verzögert werden (aber natürlich nicht länger als bis kurz vor dem 
nächsten Interrupt).

Auf einem AVR wird das I-Flag beim Eintritt in eine ISR gelöscht, was 
weitere Interrupts blockiert. Hier würde man das so lösen, daß man in 
der IR-Empfangs ISR direkt nach dem Abtasten des Pins ein sei() 
unterbringt, was Interrupts (die jetzt die ISR unterbrechen) erlaubt. 
Beim PIC sollte etwas ähnliches gehen. Ich erinnere mich dunkel, gelesen 
zu haben, daß es da ohnehin zwei Interrupt-Level gibt. Da würde es dann 
reichen, das so zu konfigurieren, daß der PWM-Interrupt die IR-Empfangs 
ISR unterbrechen kann.

von Michael B. (hardwarepunktbas)


Lesenswert?

Auch ich denke, dass Low-Power-LEDs für
dieses Modell gehen, um Treiber zu vermeiden.
Meine Empfehlung für den Chip wäre allerdings
ein AVR, programmiet in BASCOM, denn einen halben
Roman für ein entsprechendes kompliziertes
Programm zu schreiben, erachte ich als unnötige
Zeitverschwendung
VG Micha

von Daniel (Gast)


Lesenswert?

Der PIC würde bewusst gewählt, da ich damit schon mal zu tun hatte und 
mir so die Entwicklungsumgebung und Einstellungen bekannt waren. 
Weiterhin habe ich schon einen Prgrammer für den PIC hier liegen. Warum 
keine Hardware PWM?  Weil es keinen Mikrocontroller mit 13 unabhängigen 
PWM-Kanälen gibt und man durch Soft PWM flexibler ist.
Für mich wäre es Zeit (und Geld) Verschwendung wenn ich mir erst einen 
neuen Chip kaufen muss inkl. Programmer und ihn in einer mir unbekannten 
Sprache programmieren muss (BASCOM)
wahrscheinlich ist meine Frage im Microchip Forum besser aufgehoben.

von Harald A. (embedded)


Lesenswert?

Bevor du dich mit PWM quälst, sei es nun HW oder SW PWM, nehme doch 
einfach WS2812 LEDs. Die kannst du schön von Ort zu Ort durchverbinden 
und hast die gewünschte Farbe und Helligkeit. Sicher, Du brauchst nicht 
an jedem Ort alle Farben, aber das ist bei dem Preis egal. Am Ende 
einfach ein Arduino Nano, da gibt es fertige LIBSs und die Anwendung ist 
in einem Tag komplett fertig, auch für weniger Geübte.

Die WS2812 gibt es als Strip (schneiden und mit Litze verlängern), auf 
Einzelplatine, als SMD und auch bedrahtet.

Verdrahtung ist gegenüber klassischen LEDs vermutlich eleganter.

Noch besser finde ich persönlich APA102 LEDs, die haben ein fast 
klassisches SPI Interface und sind absolut zeitunkritisch in der 
Ansteuerung. Ist dann ein Draht mehr von LED zu LED.

: Bearbeitet durch User
von Harald A. (embedded)


Lesenswert?

Die APA102 gibt es auch superklein im 2020 Gehäuse, falls es mal 
irgendwo eng wird.

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.