Forum: Mikrocontroller und Digitale Elektronik Hilfe bei Kollisionswarnlicht


von Leo F. (Gast)


Angehängte Dateien:

Lesenswert?

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

von Otto (Gast)


Lesenswert?

Hallo,

an welchenm Portpin hängt die LED - an PB4?

Weshalb setzt du weitere 3 Pins von Port B?

Gruß Otto

von Leo F. (Gast)


Lesenswert?

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

von Stefan M. (derwisch)


Lesenswert?

geht sowas nicht auch mit einem CMOS 4011 Baustein? ( ganz ohne 
programmieren! ).

von Vuvuzelatus (Gast)


Lesenswert?

> 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.

von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

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.

von Leo F. (Gast)


Lesenswert?

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.

von Stefan Z. (Gast)


Lesenswert?

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?

von Vuvuzelatus (Gast)


Lesenswert?

>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.

von Leo F. (Gast)


Lesenswert?

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
Noch kein Account? Hier anmelden.