Guten Abend, Für ein kleines Flugmodell wollte ich gern ein per Fernsteuerung ein- und ausschaltbares Blitzlicht bauen. Es soll ein Attiny 13 verwendet werden, an PB0 kommt das Signal vom Empfänger, bei Impulslängen >1,7mS werden PB3:PB1 für etwaige Positionslichter high geschaltet und an PB4 liegt das mit dem Empfängersignal synchonisierte Blinksignal von etwa 1Hz und sehr kleinem Tastverhältnis an. Der Ablauf des Programms lässt sich folgendermaßen beschreiben: Zu Beginn werden Dinge wie die Datenrichtung und Pull- Up- Widerstände am Eingang eingestellt, der Power- Down Sleep Mode und der Pin- Change Interrupt PCINT0 auf PB0 freigegeben und der µC dann schlafen geschickt. Während des Interrupts wird das Register "Dauer" so lange inkrementiert, wie PB0 high ist, um danach mit der Konstante "Schwelle" verglichen zu werden. Ist "Dauer" >= "Schwelle", was einer Impulslämge von etwa 1,7 mS entspricht, dann werden PB3:PB1 high gesetzt sowie das Register "Anzahl" inkrementiert und mit 50 verglichen. Ist Anzahl=50, was etwa einer Sekunde entspricht, erfolgt ein Sprung in das Unterprogramm "blitzen", welches PB4 für etwa 10mS high setzt. Ist der Impuls <1,7mS, wird PB4:PB1 low gesetzt. Und nun zum eigentlichen Problem: Das Blinken an PB4 bei Impuls >1,7mS funktioniert zwar, bei PB3:PB1 jedoch wird lediglich der Pull- Up eingeschaltet, und der Ausgang im selben Takt wie PB4 High gesetzt. Dadurch ergibt sich ein sehr schwaches, von einem 1Hz- Blinken überlagertes Dauerlechten, was natürlich nicht im Sinne des Erfinders ist. Leider kann ich mir nicht erklären, wie das zustande kommt, und bräuchte daher eure Hilfe. Anbei der Quelltext, zur besseren Lesbarkeit auch noch im Anhang als .asm: .include "tn13def.inc" .equ MCUCRwPD = 0b00110000 ; Sleep Mode Power down .equ GIMSKwPC = 0b00100000 ; Pin Change Interrupt .equ PCMSKwP0 = 0b00000001 ; PCINT 0 auf PB0 .equ Schwelle = 171;~ 1,7mS .def temp = r16 .def dauer= r17 .def Anzahl=r18 .cseg ; Hier geht es los! .org 0x0000 rjmp Anfang .org 0x0001 reti .org 0x0002 rjmp PinChange; PCINT0 .org 0x0003 reti .org 0x0004 reti .org 0x0005 reti .org 0x0006 reti .org 0x0007 reti .org 0x0008 reti .org 0x0009 reti Anfang: ldi temp, 0b00011110 out ddrb, temp; PB4:PB1 als Ausgang com temp out portb, temp; Pull- Up an allen anderen ein ldi temp, RAMEND out SPL, temp; Stackpointer initialisieren sbi ACSR, ACD; AC ausschalten ldi temp, GIMSKwPC out GIMSK, temp ldi temp, PCMSKwP0 out PCMSK, temp ldi temp, MCUCRwPD out MCUCR, temp Schlafen: SEI ;Globaler Interrupt frei SLEEP rjmp Schlafen PinChange: clr Dauer; initialisieren Schleife: inc Dauer ; 1Takt nop nop nop nop nop nop nop nop sbic Pinb, 0 ; 1Takt rjmp Schleife; 2 Takte ;High so lange hochzählen, wie PB0= 1 } 12 Takte cpi Dauer, Schwelle brsh ein ; Ein, wenn Dauer ueber der Schwelle aus: ldi temp, 0b00100001 out portb, temp reti ein: ldi temp, 0b00101111 out portb, temp inc anzahl cpi anzahl, 50 breq blitzen reti blitzen: clr anzahl sbi portb, 4 ldi temp, 128 aussen: dec temp ldi Dauer, 32 Innen: dec Dauer brne Innen brne aussen ; } ~ 10mS cbi portb, 4 reti ; wird bei jedem Signal aufgerufen vielen Dank im Voraus Leo
Hallo, an welchenm Portpin hängt die LED - an PB4? Weshalb setzt du weitere 3 Pins von Port B? Gruß Otto
Hallo Otto , an PB4 haengt ein N- MOSFET, der die weisse LED beim blitzen einschaltet. PB3:PB1 dienen dazu, Positionslichter an den Flaechenenden anzuschalten. Gruss, Leo
geht sowas nicht auch mit einem CMOS 4011 Baustein? ( ganz ohne programmieren! ).
> geht sowas nicht auch mit einem CMOS 4011 Baustein? ( ganz ohne > programmieren! ). Bestimmt. Fragt sich nur, ob das ein guter Deal wäre. Du musst die Funktionalität der Schaltung dann durch externe Bauteile realisieren und im Ergebnis wird "ohne Programm, dafür größer und schwerer" herauskommen. Vor allem schwerer ist bei Modellflugzeugbauern aber ausgesprochen unbeliebt.
Ein Pinchange IRQ wird bei ansteigender und abfallender Flanke getriggert - evtl. solltest du doch lieber einen Timer nehmen oder eben nur den High Pulse messen. Es ist vermutlich auch günstiger, die Blinkerei nicht direkt in der Pinchange ISR zu machen, sondern diese nur ein Flag setzen zu lassen (oder zu löschen ) . Denn während es blinkt, gehen die anderen Pulse verloren. Scahde, das die 8-beiner keinen Capture haben, so musst du diesen emulieren. Bei ansteigender Flanke den Timer starten und bei abfallender Flanke den Timer stoppen und auslesen. Den ausgelesenen Wert dann bequem im Hauptprogramm prüfen und entsprechend reagieren. Die Pinchange Routine könnte nebenbei noch ein Blinkintervall hochzählen.
Vuvuzelatus schrieb: > Vor allem schwerer ist bei Modellflugzeugbauern aber > ausgesprochen unbeliebt. @ Vuvuzelatus: Du sprichst mir aus der Seele... Matthias Sch. schrieb: > Ein Pinchange IRQ wird bei ansteigender und abfallender Flanke > getriggert @ Matthias: Darüber habe ich auch schon nachgedacht, aber solange sich der Prozessor im Interrupt Handler befindet, kann kein neuer Interrupt ausgelöst werden. Der Interrupt Handler wird ja erst [relativ] lange nachdem PB0 wieder low ist, also nach der fallenden Flanke, beendet. Es gibt doch kein Register, in dem ausstehende Interrupts gespeichert werden, oder ? Das Blitzen habe ich absichtlich an das Signal vom Empfänger gekoppelt, es passt ja mit seinen 10mS Länge noch gut in die 18- 19 mS lange Pause zwischen zwei High- Impulsen [siehe http://www.mikrocontroller.net/articles/AVR-Tutorial:_Servo ] und erspart mir den Ärger mit einem Timer Interrupt, der womöglich noch in die Signalerkennung hineinpfuscht.
Kann es sein, dass die weiße LED zuviel Strom zieht und die Betriebsspannung des µC beeinflusst? Kannst du statt der weißen LED mit FET probeweise eine einfache LED mit Vorwiderstand anschließen?
>Es gibt doch kein Register, in dem ausstehende Interrupts gespeichert >werden, oder ? Oh doch, und das ist sogar der wahrscheinliche Grund für das Verhalten Deines Programms! Jeder Interrupt hat ein Vormerk-Flag (engl. pending = anmelden), das beim Auftreten der Interruptbedingung von der Hardware gesetzt wird. Das passiert sofort und unabhängig davon, was im µC interruptmäßig sonst grad los ist. Der Sprung in die Vektortabelle erfolgt dagegen nicht sofort, sondern erst dann, wenn das I-Bit im SREG gesetzt und kein anderer Interrupt mit höherer Priorität angemeldet ist (sonst ist der zuerst dran). Der Sprung findet also so früh wie möglich statt, aber das kann eben auch lange nach der Interruptbedingung bedeuten. Wenn kurze Interrupt-Latenzzeiten wichtig sind, realisiert man das durch schlanke Interrupthandler, in denen nur das absolut Nötigste erledigt wird, meistens das Speichern irgendwelcher Daten von Hardwareregistern ins RAM. Das Pending-Flag für die Pin-Change-Interrupts ist das Bit PCIF im GIFR. In Deinem Programm wird der PCINT-Handler bei jeder Flanke einmal durchlaufen, d. h. unerwünschterweise auch bei jeder fallenden (kannst ja mal überlegen, wie man das einfach testen könnte). Eine mögliche Lösung: Statt des PCINT-Interrupts den INT0 benutzen. Der kann zwischen steigenden und fallenden Flanken unterscheiden.
Guten Abend, ich habe das Programm noch mal umgeschrieben, sodass das PCIF Bit im GIFR nach Verlassen der Schleife für die Zeitmessung gelöscht wird, jedoch ohne Erfolg. Daraufhin habe ich einen komplett anderen Aufbau genommen, der Timer wird gestartet und löst nach jedem n-ten Overflow Interrupt das Blitzen aus. Über INT0 wird wieder in der Zählschleife die Länge des Impulses gemessen und bei Längen zwischen 0,9 und 1,7 mS der Timer zurückgesetzt. Code folgt, da ich gerade vom Eipott aus schreibe. Gruss, Leo
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.