Hallo Leute, ich habe mit einem normalen Atmega16 eine Infrarot Fernbedienung gebaut. Versorgt werden soll dieser mit drei Mignonzellen ohne Spannungsregler [4,5V] wie es in dem Artikel Versorgung aus einer Zelle beschrieben ist. Das Problem dabei ist, dass der normale Atmega16 mit 5V betrieben werden sollte, ich aber momentan keinen anderen uC zur verfügung habe. An einer externen PWm habe ich dann eine Transistorschaltung zur Ansteuerung einer IR-Diode angeschlossen die ich momentan mit 50mA versorge. Beim Testen an dem Projektor hat die Fernbedienung nur manchmal funktioniert. 1) Kann das daran liegen, dass bei der Versorgung der Diode die Batteriespannung einbricht und dadurch dann der uC nicht mehr richtig arbeitet? (manchmal Funktioniert es ja) Wäre eine Stabilisierung sinnvoll? 2) Würde es evt. reichen, Komponenten wie den ADC abzuschalten und evt. einen 8 MHz Oszillator zu nehmen (benutze momentan noch 16 MHz), oder wäre der stabile Betrieb nur mithilfe eines anderen uC's oder einer anderen Spannugnsversorgung realisierbar? Mfg Johannes
Probiers doch einfach mal mit stabilisierten 5V anstatt der Batterien. Welche Werte haben Basis- und Kollektorwiderstand? Sicher dass die IR-Signale richtig erzeugt werden?
Sehr schöner Schaltplan, ganz Analog ;-). Ich habe auch einmal eine IR-Fernbedienung mit einem AVR (mega8) gebaut. Da die Reichweite gering war, habe ich den Strom durch die Diode deutlich erhöht, auf um die 200mA. Probleme mit Spannungseinbrüchen hatte ich jedoch dennoch keine und kann mir auch nicht vorstellen, dass bei Deinen 50mA das zum Problem werden könnte. Bildest Du die Pulsfolge exakt nach? Also speziell die Trägerfrequenz sollte passen, sonst wird das Signal im Empfänger abgeschwächt. Die Kondensatoren paralell zu den Tastern machen sich garnicht gut. Entprelleschaltungen sehen anders aus.
einfache Checkliste 1. saubere 5V Versorgung? 2. SW -> was für einen IR Code verwendest Du? Sind Codierung und Modulationsfreqenz richtig? Das manchmal hört sich auch ein bisschen nach Togglebit im IR Code an - ist das benötigt und berücksichtigt?? Johannes Henkenjohann schrieb: > 2) Würde es evt. reichen, Komponenten wie den ADC abzuschalten und evt. > einen 8 MHz Oszillator zu nehmen (benutze momentan noch 16 MHz), oder > wäre der stabile Betrieb nur mithilfe eines anderen uC's oder einer > anderen Spannugnsversorgung realisierbar? was hat der ADC damit zu tun? und fang doch erst mal mit dem internen 8MHz Takt an, das ist stabil genug. Richtiger IR Code vorausgesetzt spielt die 8MHz Stabilität des µC keine Rolle
Hallo, die Kondensatore parallel zu den Tastern habe ich zur Funkenlöschung angelötet. Entprellen mache ich nicht, da ich ja über externe Interrupts gehe und diese dann deaktiviere und erst nach ca 100 ms wieder freigebe. Ich benutze die externen Interrupts, da ich später noch damit aus dem Power Down Mode aufwecken will. Also die Fernbedienung ist zum Ein- und Ausschalten eines Projektors. Verwendet wird der Sharp-Code und den habe ich komplett nachgebildet. Die Trägerfrequenz ist exakt 38 kHz die ich mit Timer1 als fast PWM nachbilde und über einen anderen Timer dann halt je nachdem, welche Bits ich benötige, an PD5 ausgebe oder nicht. Im angehängten Bild sieht man Beispielsweise ein Signal zum Einschalten des Projektors. Die Pulse sind immer 320 us lang und je nachdem ob es eine '1' oder eine '0' sein soll ist die Pause 1680 us oder 680 us lang. Also eine Eins hat eine "Periodendauer" von 2ms und eine Null halt von 1ms. Das Gesamtsignal hat 15 Bits. Bestehend aus fünf Adressbits, acht Commandbits einem Exp Bit und einem Check Bit. Beim Ein- und Ausschaltsignal werden diese 15 Bit im Abstand von 40ms 5 mal wiederholt und jeweils abwechselnd nicht invertiert und invertiert gesendet. Hab beim uC PD5 am Oszi gemessen und das sah alles super aus, auch über dem Collectorwiderstand. Ich werde die Tage jetzt einen Basiswiderstand von 750 Ohm und einen Collectorwiderstand von 27 Ohm einlöten, um ca. einen Diodenstrom von 100mA zu erhalten. Dies werde ich dann mal mit einer TSOP ausmessen und schaun wies aussieht. Im moment sind Basiswiderstand 1,8kOhm und Collectorwiderstand 77 Ohm verlötet, was sicherlich nicht gut dimensioniert ist. Das mit dem spannungsstabilisiertem Netzteil ist ne gute Idee. Werde ich austesten.
Achso, Tim schrieb: > was hat der ADC damit zu tun? ich wollte evt. einzelne Komponenten im uC wie en ADC abschalten um die Leistungsaufnahme zu verringern, um die Batterie zu schonen. Deswegen dachte ich halt so etwas, wie beispielsweise den ADC ausschalten, weil er glaube ich standardgemäß immer läuft, und halt nen anderen Oszillator.
Nehme mal an du willst dieses Format: http://www.sbprojects.com/knowledge/ir/sharp.php In deinem Bild sind die 12 38kHz cycles pro Bit aber nicht zu erkennen, kannst du mal ein Bit genauer darstellen? Den Basiswiderstand kleiner (z.B. 470), aber die "Funkenlöschkondensatoren" sind (hoffentlich) nicht erforderlich und sollten entfernt werden. Würde hier eher auf ein Software-Problem tippen, zeig doch mal den Code.
:
Bearbeitet durch User
Hi, ja genau das ist der Code, nur das beim Ein- und Ausschaltsignal halt 5*15 Bits gesendet werden (mit Originalfernbedienung gemessen). Das Bild oben ist die Aufnahme für einen 320us Puls der Originalfernbedienung mithilfe einer Photodiode. Sind denn die einzelnen Cicles wichtig? Ich dachte es müsste nur 320us lang das 38kHz Signal gesendet werden. Sind ja dann auch ca 12 cicles. Das obere bild des Gesamtsignals ist mit einer TSOP aufgenommen, daher sieht man die Trägerfrequenz nichtmehr. Ich hab leider kein Bild davon, aber am PD5 habe ich mit dem Oszi genau die richtigen Signale gemessen. Den Code kann ich nacher mal Hochladen, ist aber nicht ordentlich Formatiert fürs Forum, deswegen Kommentiere ich den dann eben nochmal. Bin leider auch noch nicht so erfahren, was Mikrocontroller angeht. Soll ich den Basiswiderstand kleiner wählen, um den Transistor voll zu übersteuern? Mfg Johannes
:
Bearbeitet durch User
Johannes H. schrieb: > Das obere bild des Gesamtsignals ist mit einer TSOP aufgenommen, daher > sieht man die Trägerfrequenz nichtmehr. Sorry, hatte ich falsch verstanden, dachte das wäre am PD5 abgenommen. Zum Basiswiderstand siehe http://www.mikrocontroller.net/articles/Basiswiderstand Bin aber kein Fachmann für das Thema, hatte bei mir diesen Wert verwendet.
:
Bearbeitet durch User
Okay, das ist jetzt der Code, sieht evt. etwas unübersichtiglich aus und ist evt. nicht die optimale Lösung, aber soweit ich mich aufs Oszi verlassen kann funktioniert das.
1 | /*
|
2 | * IR-Fernbedienung
|
3 | *
|
4 | * Created: 12.11.13
|
5 | * Author: Johannes H. & Markus N.
|
6 | */
|
7 | #include <avr/io.h> |
8 | #include <avr/interrupt.h> |
9 | #include <util/delay.h> |
10 | #include <avr/sleep.h> |
11 | void initPwm(void); |
12 | void initInt(void); |
13 | void initPause_680us(void); |
14 | void initPause_1680us(void); |
15 | void initPause_40ms(void); |
16 | void delPwm(void); |
17 | |
18 | //Arrays mit den Bits zum Ein- und Ausschalten
|
19 | int ein_5[] = {1,0,1,1,0,1,0,0,1,0,1,0,1,0,1,2,1,0,1,1,0,0,1,1,0,1,0,1,0,1,0,2,1,0,1,1,0,1,0,0,1,0,1,0,1,0,1,2,1,0,1,1,0,0,1,1,0,1,0,1,0,1,0,2,1,0,1,1,0,1,0,0,1,0,1,0,1,0,1}; |
20 | int aus_5[] = {1,0,1,1,0,1,0,0,1,0,1,1,0,0,1,2,1,0,1,1,0,0,1,1,0,1,0,0,1,1,0,2,1,0,1,1,0,1,0,0,1,0,1,1,0,0,1,2,1,0,1,1,0,0,1,1,0,1,0,0,1,1,0,2,1,0,1,1,0,1,0,0,1,0,1,1,0,0,1}; |
21 | |
22 | volatile int pause40=0; |
23 | volatile int zustand=1; |
24 | volatile int zaehler=0; |
25 | volatile uint16_t tot_overflow=0; |
26 | int main(void) |
27 | {
|
28 | DDRD=0x20; //PD5 auf Ausgang |
29 | PORTD=0x0C; //Interne Pullups für INT0 und INT1 aktivieren |
30 | initInt(); //Interrupts aktivieren |
31 | //initPwm();
|
32 | while(1) |
33 | {
|
34 | }
|
35 | }
|
36 | void initPwm(void) |
37 | {
|
38 | TCCR1A=(1<<WGM11)|(1<<COM1A1); //Timer1 |
39 | TCCR1B=(1<<WGM13)|(1<<WGM12)|(1<<CS10); //als FAST PWM |
40 | ICR1=420; //mit 38 kHz frequenz |
41 | OCR1A=210; |
42 | }
|
43 | void delPwm(void) |
44 | {
|
45 | TCCR1A=0x00; |
46 | TCCR1B=0x00; |
47 | ICR1=0; |
48 | OCR1A=0; |
49 | PORTD=0x0C; |
50 | }
|
51 | void initInt(void) |
52 | {
|
53 | MCUCR = 0x0A; //INT0 und INT1 auf falling edge |
54 | GICR = 0xC0; //INT1 und INT0 freischalten |
55 | TIMSK = 0x45; //TIMER 0/1/2 overflow interrupt enable |
56 | sei(); //Interrups global freigeben |
57 | }
|
58 | void initPause_680us(void) //Timer0 680us laufen lassen |
59 | {
|
60 | TCNT0=86; |
61 | TCCR0=0x03; |
62 | }
|
63 | void initPause_1680us(void) //Timer0 1680us laufen lassen |
64 | {
|
65 | TCNT0=151; |
66 | TCCR0=0x04; |
67 | }
|
68 | void initPause_40ms(void) //Timer2 40ms laufen lassen |
69 | {
|
70 | TCNT2=131; |
71 | TCCR2=0x07; |
72 | }
|
73 | ISR (INT0_vect) //Aus-Signal senden |
74 | {
|
75 | GICR=0x00; //ext. Interrupts deaktivieren |
76 | zaehler=0; //Zählvariable zurücksetzen welche durch die Arrays läuft |
77 | zustand=1; //legt fest, dass das Ausschaltsignal gesendet wird |
78 | initPwm(); //Started das 320us Pulspaket |
79 | }
|
80 | ISR (INT1_vect) //An-Signal senden |
81 | {
|
82 | GICR=0x00; //ext. Interrupts deaktivieren |
83 | zaehler=0; //Zählvariable zurücksetzen |
84 | zustand=2; //An-Signal senden |
85 | initPwm(); //Startet erstes Pulspaket |
86 | }
|
87 | ISR (TIMER1_OVF_vect) |
88 | {
|
89 | tot_overflow++; |
90 | if(tot_overflow==12) //320us Vorbei bei 12 Overflows |
91 | {
|
92 | tot_overflow=0; |
93 | delPwm(); //PWM abschalten |
94 | TCNT1=0; //TImer1 zähler zurücksetzen |
95 | if(zaehler==79) //Wenn gesamtes Signal gesendet wurde ist der Zähler bei 79 |
96 | {
|
97 | zaehler=0; |
98 | zustand=3; |
99 | GICR = 0xC0; //ext. Interrupts wieder freigeben |
100 | }
|
101 | else
|
102 | {
|
103 | if(zustand==1) //Aus-Signal senden |
104 | {
|
105 | if(aus_5[zaehler]==0) |
106 | {
|
107 | initPause_680us(); |
108 | }
|
109 | if(aus_5[zaehler]==1) |
110 | {
|
111 | initPause_1680us(); |
112 | }
|
113 | }
|
114 | if(zustand==2) //Ein-Signal senden |
115 | {
|
116 | if(ein_5[zaehler]==0) |
117 | {
|
118 | initPause_680us(); |
119 | }
|
120 | if(ein_5[zaehler]==1) |
121 | {
|
122 | initPause_1680us(); |
123 | }
|
124 | }
|
125 | if(aus_5[zaehler]==2) |
126 | {
|
127 | initPause_40ms(); |
128 | }
|
129 | zaehler++; |
130 | }
|
131 | }
|
132 | }
|
133 | ISR (TIMER0_OVF_vect) //Pause1 oder Pause2 vorbei |
134 | {
|
135 | TCCR0=0x00; |
136 | initPwm(); //nächstes 320us Paket senden |
137 | }
|
138 | ISR (TIMER2_OVF_vect) //8ms Overflow Vector |
139 | {
|
140 | pause40++; |
141 | TCNT2=131; |
142 | if(pause40==5) //hier sind 40ms vorbei |
143 | {
|
144 | pause40=0; |
145 | TCCR2=0x00; |
146 | initPwm(); //neues Paket |
147 | }
|
148 | }
|
Hab auch schon überlegt, es einfach mit _delay_pause zu erledigen, da der Prozessor eh nichts anderes machen muss in der Zeit. Im Prinzip arbeite ich mich mit den Timern durch das Array. Mfg Johannes
:
Bearbeitet durch User
Ohne jetzt alles durchblickt zu haben: Unbedingt die Tasterabfrage ohne Interrupt machen. Taster prellen und es ist völlig unklar wann da was passiert. Das könnte das "manchmal gehts" erklären. Als nicht so erfahrener Programmierer ist es sicher vernünftig zunächst das delay zu verwenden und auf Interrupts soweit möglich zu verzichten. Besser strukturieren: sendeBit() triggert die 12 cycles und wartet dann die erforderliche Zeit je nachdem ob 1 oder 0. sendeBefehl() ruft sendeBit für jedes zu übertragende Bit auf. sendeEin() ruft sendeBefehl entsprechend 4 mal auf. Und nur wenn sich alles beruhigt hat werden die Taster abgefragt und entsprechend sendeEin oder sendeAus aufgerufen. Das Timing ist nicht sooo kritisch, nur die 38 KHz müssen sauber kommen.
:
Bearbeitet durch User
Wie ich vorhin geschrieben habe möchte ich gerne sobald alles läuft den Controller nach jedem Senden in den power down sleep mode schicken. Da kann man dann super mit Int0/Int1 level interrupts aufwecken und ich hoffe doch dann ganz normal wieder direkt senden lassen. Wenn ich aber im externen Interrupt direkt nach auftreten des Interrupts erst einmal alle externen Interrupts sperre, und die erst nach dem Senden des Befehls wieder freigebe, sollte doch eigentlich nichts unerwartetes passieren oder? Notfalls kann ich ja auch nochmal vor der Freigabe der externen Interrupts die Interruptflags im GIFR Register löschen, falls noch irgendwie ein weiterer Interrupt gemerkt wurde. Ich habe ja dann locker 240ms wo der Taster prellen könnte und nichts passieren kann. Wenn das nicht reicht, könnte ich ja nach dem Signal noch einmal einen Timer ein paar Millisekungen draufpacken und dann erst nach 500ms externe Interrupts wieder freigeben.
Johannes H. schrieb: > 1) Kann das daran liegen, dass bei der Versorgung der Diode die > Batteriespannung einbricht und dadurch dann der uC nicht mehr richtig > arbeitet? (manchmal Funktioniert es ja) > Wäre eine Stabilisierung sinnvoll? Kann es sein, dass deine Taster ohne Pullup betrieben werden?
Doch, die sind in der Main aktiviert. Ich kann das auch leider Dienstag erst wieder testen. Werde erstmal die neuen Widerstände mit einem stabilisiertem Netzteil testen. Evt. Läufts ja dann.
Wenn dein Problem gelöst ist, dann: Schalte mal einen 100µF Elko zur Stabilisierung der Spannung an VCC und GND möglichst nahe am Emitter des Transistors und an den Vorwiderstand (VCC Seite) der LED. Dadurch reduzierst du ungewollte Modulation der Versorgungsspannung und erhöhst den Strom durch die LED. Ich habe damit schon so mancher TV Fernbedienung doppelte Reichweite beigebracht.
Johannes H. schrieb: > Doch, die sind in der Main aktiviert. Ich dachte eigentlich an die externen Pullups für die Taster: http://www.mikrocontroller.net/articles/AVR-Tutorial:_IO-Grundlagen#Hardware
Stefan us schrieb: > Schalte mal einen 100µF Elko zur Stabilisierung der Spannung an VCC und > GND möglichst nahe am Emitter des Transistors und an den Vorwiderstand > (VCC Seite) der LED. Dadurch reduzierst du ungewollte Modulation der > Versorgungsspannung und erhöhst den Strom durch die LED. Danke, das werde ich dann nächste Woche mal probieren. Falk Schilling schrieb: > Ich dachte eigentlich an die externen Pullups für die Taster: Wäre das denn sinnvoller als die internen Pullups zu verwenden? Ich dachte bei den AVR's macht man extra alles mit low active Tastern, um die zuschaltbaren internen Pullups zu verwenden. Johannes H. schrieb: > PORTD=0x0C; //Interne Pullups für INT0 und INT1 aktivieren Mit dieser Zeile aktiviere ich ja die internen Pullups für Pin 16/17, sprich INT0 und INT1. Und an denen hängen ja die Taster.
Johannes H. schrieb: > Wäre das denn sinnvoller als die internen Pullups zu verwenden? > Ich dachte bei den AVR's macht man extra alles mit low active Tastern, > um die zuschaltbaren internen Pullups zu verwenden. Sorry, mein Fehler, du hast Recht.
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.