Hallo Allerseits, ich bin neu hier im Forum und in der mikrocontroller-welt... Ich hab mir da mal was ausgedacht..^^ Also ich will mit einer Lichtschranke 2 "Lichter" anschalten und danach diese Lichter mit jeweils einem Taster ein und aus schalten. Außerdem soll später noch die Lichtschranke nach erstmaligem aktivieren inaktiv sein...sonst geht ja immer wieder alles an =) Und wenn ich dann aus dem Haus gehe, will ich draußen einen Taster betätigen, mit dem ich Alles aus und die Lichtschranke aktiv schalte. Ich benutze einen Atmega8 und möchte das Ganze gerne in Assmebler machen. An Alle, denen es in den Fingern juckt zu schreiben, dass man das mit ner Hand voll Bistabiler Relais und nen paar Tastern auch machen kann: Jaja, is schon klar...aber ich möcht nun mal gern Assembler lernen :) lieben Gruß und danke schonmal Sascha PS: Ich Poste hier mal was ich bereits habe...und wäre für jeden Vorschlag sehr dankbar...denn bisher gehts garnicht :( PPS: Alle Komponenten habe ich einzelnd getesetet, ein Materialfehler ist auszuschließen. Ich teste zur Zeit mit 4 Tastern und sechs LEDs. .include "m8def.inc" .def temp = r16 .def temp2 = r20 .org 0x000 rjmp main ; Reset Handler main: ; hier beginnt das Hauptprogramm ldi temp, LOW(RAMEND) ;set RAM out SPL, temp ldi temp, HIGH(RAMEND) out SPH, temp ;set RAM ende ldi temp, 0x00 ;Port D als Eingang out DDRD, temp ldi temp, 0xFF ;Port B als Ausgang out DDRB, temp ldi r17, 0xFF ;Alles aus out PORTB, r17 ; lichtschranke an PD0=$01 ;Alles Aus an PD1=$02 ;licht1 an PD2=$04 ;licht2 an PD3=$08 ;licht3 an PD4=$10 lichtschranke: ldi temp, PIND ;Frage Port D ab und lade das Ergebnis in temp ANDI temp, $01 ;Prüfe ob Taste 1 gedrückt ist ( Prüfe ob taste 1 nicht gedrückt ist ) BRNE lichtein ;wenn doch, dann spring nach lichtein und mach alles an allesaus: ; ist der türtaster zum ausschalten ldi temp, PIND ;Frage Port D ab und lade das Ergebnis in temp ANDI temp, $02 ;Prüfe ob Taste 2 gedrückt ist ( Prüfe ob taste 2 nicht gedrückt ist ) BRNE lichtaus ;wenn doch, dann spring nach lichtaus und mach alles aus licht1: ldi temp, PIND ;Frage Port D ab und lade das Ergebnis in temp ANDI temp, $04 ;Prüfe ob Taste 3 gedrückt ist ( Prüfe ob taste 3 nicht gedrückt ist ) BRNE licht1an ;wenn doch, dann spring nach licht1an licht2: ldi temp, PIND ;Frage Port D ab und lade das Ergebnis in temp ANDI temp, $08 ;Prüfe ob Taste 4 gedrückt ist ( Prüfe ob taste 4 nicht gedrückt ist ) BRNE licht2an ;wenn doch, dann spring nach licht2an rjmp lichtschranke ;----------------------------------------------------------------------- ------------------------------------------------------------------------ ------------------------------ ; Subroutinen lichtein: cbi PORTB, 2 cbi PORTB, 3 cbi PORTB, 4 ret lichtaus: sbi PORTB, 2 sbi PORTB, 3 sbi PORTB, 4 ret licht1an: eor PORTB, 2 ret licht2an: eor PORTB, 3 ret
Hallo, was bei dir als main gelabelt ist findest du häufig unter den stichpunkt reset, main ist meistens die hauptschleife nach dem reset,.. Du betreibst das ganze im POLLING modus, d.h. du guckst jedesmal ob der taster gedrückt worden ist, viele werden dir empfehlen das im Interrupt modus laufen zu lassen, d.h. pin INT0 an PULL-DOWN und an TASTER, taster gedrückt zieht auf high interrupt löst aus, je nach status kann dann die lichtschranke an oder aus geschaltet werden, lichtschranke an INT1, interrupt wird ausgelöst wenn pin auf LOW fällt,.. den rest der zeit loopt der µC gemütlich in der main oder spart energie im sleep modus,... die Interrupt vectoren findest du am ende der *.inc und muss oben a la .org 0x... zugewissen werden, der rest wird als subroutine getätigt,.. ich hoffe ich konnte helfen,.. sei gegrüüüßt
Ein dicker Hammer ist noch drin. Du springst in die Subroutinen mit BRNE, und mit RET wieder zurück. Das passt nicht zusammen. Entweder mit RCALL rein und RET raus, oder mit BRNE oder RJMP rein und mit RJMP raus. RET holt die Returnadresse vom Stack, wo in Deinem Fall gar keine ist.
ok, vielen dank soweit... werde das heute abend mal überarbeiten. btw..ich dachte, ich hab nur zwei interrupts (zumindest nutzbare) zur verfügung? und da sollten noch nen paar mehr sachen angeschlossen werden. grüzzie sascha
...und viele werden dir dringend davon abraten (wie ich auch) Tasten mit Interrupts abzufragen. Prellende Taster (und alle mechanischen Taster prellen) erzeugen hier einen ganzen Rattenschwanz von Interrupts. Das ist in vielen Umgebugen (nicht nur für Einsteiger) nur schwer zu beherrschen. In diesem Fall sollte es zwar keine Rolle spielen, aber man gewöhnt sich so schnell an ein gewisses Vorgehen und wird es nur mit Mühe wieder los... Siehe hierzu Entprellung
ok, danke für den tip! habe es schonmal mit tastern und interrupts probiert...hat geklappt...war aber auch nur eine led an und aus... nur wie schauts mit alternativen aus ? wenn ich keine taster zum testen nehmen soll...was dann ? auf allen eva boards sind doch auch welche drauf ? oder geht dein hinweis einfach in die richtung: IMMER entprellen ? gruß sascha
Ohne Entprellung kannste das in den meisten Fällen vergessen. Die sinnvollste Methode ist eigentlich, einen Timer laufen zu lassen, der alle paar ms (bei Tastern reicht eine Abfrage alle 10...50 ms i.d.R. völlig aus) eine Abfrage der angeschlossenen Taster durchführt (Interrupt). Was Zeusi oben schreibt, ist gelinde gesagt ziemlicher Unfug. Werner hat da völlig Recht. Taster an externen Interrupts ist dummes Zeug.
>Taster an externen Interrupts ist dummes Zeug.
So krass würde ich es nicht formulieren.
Optimal nach meiner Meinung ist: Die Taster lösen einen Interrupt aus,
dann wird sofort derjenige Interrupt disabled und der Taster gepollt wie
von Johannes beschrieben.
Vorteil ist, dass vor dem Tastendruck keine CPU-Last besteht.
Stromverbrauch ist kleiner, zeitkritische Sachen wie AD-Wandlungen und
serielle Kommunikation laufen problemloser.
Tom wrote: >>Taster an externen Interrupts ist dummes Zeug. > > So krass würde ich es nicht formulieren. Es gibt imho exakt einen sinnvollen Anwendungsfall für Taster an externen Interrupts, und das ist das Aufwecken des µC aus einem sleep-Modus. Die sleep-Modi machen aber wiederum eigentlich nur bei batteriegestützten Anwendungen wirklich Sinn. Und hier scheint es sich nicht um eine solche zu handeln.
(ich =Zeusi, hatte keine lust einzuloggen) Dennoch Johannes hättest auch nicht unbedingt schreiben müssen es sei dummes zeug, den generell benutze ich taster an PCINT des ATtiny2313, und der hat ein paar davon, diese sind leicht anzuschliesen genauso leicht anzusteuern wie INTn und machen ihre arbeit ohne jegliche entprellung mit einen einfache CLI bzw. einfach spezifische IFLAGs clearen (öfters in dem man sie setzt). Grundprinzipiell sind externe Interrupts dafür da das durch eine eXterne aKtion der µC beflügelt wird etwas zu tun, und genau das habe ich vorgeschlagen, da POLLING zwar manchmal nützlich sein mag (ich nutze es ja auch teilweise)aber zum glück in den seltensten fällen, notfalls enprelle ich lieber als stetig zu pollen, TOM hat die gründe erwähnt. Ob batterieanwendung oder nicht: ich bin CO²NTRA! falls es euch was sagt,.. seid gegrüüßt und nicht genervt g
So sehe ich das auch, Zeusi. Eigentlich sind wir doch alle ereignisgesteuert. Telefonklingeln, Türklopfen, Hunger, Sex, irgendwann kommt der Interrupt und wir beantworten ihn, selbstverständlich nach Prioritäten. Wenn Euch das zu abstrakt ist, auch moderne Betriebssysteme sind ereignisgesteuert. Mausklick, Tastendruck, Bits aus dem Netzwerk, etc. Warum nicht auch so die µCs programmieren? Im Reset nur die Initialisierung und dann sleep, und für jedes Ereignis einen Eventhandler. Das is oft übersichtlicher als die ganzen Statusbits reihum abklappern. Geht natürlich auch, jeder wir er/sie will.
>Grundprinzipiell sind externe Interrupts dafür da das durch eine eXterne >aKtion der µC beflügelt wird etwas zu tun Hört sich richtig an, ist es aber nicht. Externe Interrupts sind dazu da, SCHNELLSTMÖGLICH auf ein externes Ereignis reagieren zu können. "Schnellstmöglich" bedeutet dabei innerhalb weniger Taktzyklen. Dafür gibt es Anwendungsfälle, aber dazu gehört nicht die Abfrage menschbedienter Taster. Menschen, die solche drücken, nehmen Verzögerungszeiten von 20 ms (entsprechen ca. 160000 Taktzyklen) noch als unmittelbare Reaktion wahr. Wers nicht glaubt: AUSPROBIEREN. Fazit: Man schließe Tasten an einen normalen Pin an (Ausnahme: Aus-Sleepmodus-Aufwach-Tasten), polle sie in einem sinnvollen Zeitraster (grob 1...20 ms), und sorge sich nicht über die dadurch verursachte CPU-Last. Wers trotzdem tut, sollte sie mal AUSRECHNEN. Mit F_CPU = 8 MHz, 50 Samples/s und geschätzten 8 Instruktionen fürs Einlesen plus Entscheidung, ob was zu tun ist, komme ich auf eine relative Last von 0.05 %.
>Warum nicht auch so die µCs programmieren? Im Reset nur die >Initialisierung und dann sleep, und für jedes Ereignis einen Eventhandler. Weil der µC manchmal auch eine aufwendige Berechnung zu erledigen hat. Wenn Du ihn das innerhalb eines Interrupthandlers tun läßt, und die Rechnerei dauert 3 ms (d. h. eine "lange" Zeit), dann hast Du das Problem, dass sich die Behandlung aller anderen Interrupts um 3 ms verzögert (*). Um dies zu vermeiden, hast Du zwei Möglichkeiten: a) Du gibst die anderen Interrupts explizit durch Setzen des I-Bits früh wieder frei. Das geht, aber Du würdest damit ein System kreieren, in dem prinzipiell ein *** Stacküberlauf durch externe Ereignisse *** verursacht werden kann (klar, wieso?). Würdest Du DAS wollen? b) Du hältst zeitraubende Aufgaben aus den Interrupts fern. Dies führt auf das bekannte Paradigma, nach dem üblicherweise vorgegangen wird: "1. Alles was viel Zeit in Anspruch nimmt in 'Main'; 2. Alles, was schnell behandelt werden muss, in die Interrupts, 3. Alle Interrupts so kurz wie möglich. Das Mindeste, was man in Interrupts machen muss, ist grob gesagt die Inputs von außen einlesen und in Puffer speichern, und Auszugebendes aus den entsprechenden Puffern lesen und ausgeben. Wie die Erfahrung zeigt, ist b) die eindeutig bessere Alternative. Hier nutzt Du die "Außer-Interrupt-Ausführungsebene", anstatt sie wie bei Deinem Vorschlag ("leere Main") zu verschenken.
@AVRfan: Gut, zugegeben, bei langen Berechnungen macht es Sinn, die konsequente Interruptprogrammierung in Frage zu stellen. Dies ist aber bei vielen Projekten eher die Ausnahme, auch das Projekt des Erstposter scheint eher einfach zu sein. Wie macht es der Mensch oder das Betriebssystem? Verschachteltete Interrupts mit Prioritäten. Hunger, Essen, Telefon, Essen wird unterbrochen und nach dem Telefon wird weitergegessen. Stackoverflow sehe ich nicht so problematisch, denn es gibt ja nur eine begrenzte Anzahl Interrupts, und dann würde man halt ein paar mehr Bytes freihalten. Der Mensch kommt bei seiner Interruptbearbeitung manchmal auch durcheinander, aber es wirkt immer noch intelligenter als ständig zwischen Haustür, Telefondisplay, Kühlschrank etc. hin und her zu rennen. Manchmal denke ich, ob die Eventprogrammierung nicht eine neue Epoche der Programmiertechnik ist. So wie Objekte (80er Jahre), Funktionen (70er) oder Hochsprachen (60er), mit denen sich alte Hasen auch eine Weile schwer taten. Aber vielleicht ist Eventprogrammierung auch nur eine Nischenanwendung für µCs mit kurzen Eventhandlern oder komplexe Aufgaben mit aufwendigem Interrupthandling.
Tom wrote: > Interrupts mit Prioritäten. Hunger, Essen, Telefon, Essen wird > unterbrochen und nach dem Telefon wird weitergegessen. Gegenbeispiel: Dein Postkasten Einmal am Tag gehst du zum Postkasten und siehst nach ob etwas drinnen ist. Die 1 Minute die du dafür brauchst tut dir bei 1440 Minuten am Tag nicht weh und ob du jetzt um 10:00 oder 10:20 zum Kasten gehst spiel auch keine grosse Rolle. Ob dein µC 50 mal in der Sekunde die Tasten abscannt oder nicht, macht in der verbleibenden Rechenzeit so gut wie keinen Unterschied. Dafür kriegst du aber: * Entprellung * Autorepeat * Unterscheidung zw. langem und kurzen Tastendruck
>Gut, zugegeben, bei langen Berechnungen macht es Sinn, die konsequente >Interruptprogrammierung in Frage zu stellen. Dies ist aber bei vielen >Projekten eher die Ausnahme, Bei vielen aber auch nicht. Es genügt, bei einer Regelungsanwendung mit Fließkommazahlen und Funktionen wie Wurzel, x/y, Logarithmus etc. zu operieren. Dann hat der µC schon zu tun. >Wie macht es der Mensch oder das Betriebssystem? Verschachteltete >Interrupts mit Prioritäten. Hunger, Essen, Telefon, Essen wird >unterbrochen und nach dem Telefon wird weitergegessen. Wie ich schon sagte, ist von verschachtelten Interrupts abzuraten. Wie die Erfahrung lehrt, führt das zu einem schwer kontrollierbaren Design nebst Stack-Overflow-Gefahr, bringt aber ansonsten keine Vorteile. >Stackoverflow ehe ich nicht so problematisch, denn es gibt ja nur eine >begrenzte Anzahl Interrupts, und dann würde man halt ein paar mehr Bytes >freihalten. Hast Du verstanden wie Interrupts funktionieren? Bei verschachtelten Interrupts wird sofort mit der Ausführung auch DESSELBEN Interrupts auf der "nächstunteren Ebene" begonnen, sobald er von dem entsprechenden externen Ereignis ausgelöst wird. Simulier es mal im AVRStudio. Also: Ereignis E am Pin --> Programm sichert PC auf Stack und springt in Interrupthandler --> I-Bit wird gesetzt --> µC rechnet --> Ereignis E tritt erneut ein --> Programm sichert PC auf Stack und springt in denselben Interrupthandler (!) --> I-Bit wird gesetzt --> µC beginnt die auf der nächsthöheren Ebene schon halbfertige Rechnung von neuem --> Ereignis E tritt abermals ein --> ... [Kette irgendwann zu ende] ... --> Programm springt nach fertiger Rechung in denselben Interrupthandler auf nächsthöherer Ebene zurück --> muss dort erst noch fertigrechnen........ >Manchmal denke ich, ob die Eventprogrammierung nicht eine neue Epoche >der Programmiertechnik ist. Nein. Du darfst "Event" nicht mit Interrupt gleichsetzten. Interrupts gehören zur Hardware des µCs (oder PCs), Events zum Betriebssystem. Es läuft so ab: Das Betriebssystem läßt seine 12 (Beispielwert) laufenden Prozesse vom Scheduler gesteuert in bestimmten Zeitabschnitten rundum nacheinander rechnen. Einer der 12 Prozesse ist der "Tasten-Abfrage"-Prozess. In ihm werden die zugehörigen Tasten z. B. alle 20 ms gepollt, und auf eventuelle Flanken (nicht gedrückt --> gedrückt, oder umgekehrt) getestet. Sobald eine Flanke erkannt wird, wird DANN das entsprechende Event ("OnKeyPress") ausgelöst (= Nachricht in Warteschlange gelegt, die von anderen Prozessen ausgelesen wird, und darüber zum Aufruf einer passenden Behandlungsfunktion = "Eventhandler" führt). Wie Du siehst, wurde das Tastenflanken-Event *** nicht von einem Interrupt verursacht (jedenfalls nicht direkt) ***. Das ist der entscheidende Unterschied. >Aber vielleicht ist Eventprogrammierung auch nur eine Nischenanwendung >für µCs mit kurzen Eventhandlern oder komplexe Aufgaben mit aufwendigem >Interrupthandling. Im Gegenteil, eventbasierte Programme sind eine sehr natürliche und weitverbreitete Angelegenheit, auch auf PCs.
>Hast Du verstanden wie Interrupts funktionieren? Bei verschachtelten >Interrupts wird sofort mit der Ausführung auch DESSELBEN Interrupts auf >der "nächstunteren Ebene" begonnen, sobald er von dem entsprechenden >externen Ereignis ausgelöst wird. In der Atmel-Doku steht: The I-bit is cleared by hardware after an interrupt has occurred, and is set by the RETI instruction to enable subsequent interrupts. anders würde z.B. ein Level-gesteuerter Interrupt keinen Sinn machen. OK, wenn man in der Int-Routine das I-Bit setzt, dann kann der gleiche Int wiederkommen, bei Level gesteuerten auch ziemlich oft. Das meinst Du wohl mit "bei verschachtelten ...". Dann muss man halt vor dem SEI den auslösenden Int explizit verbieten, z.B. GIMSK/INT0. Stack-Overflows mache ich meistens so: - Rekursive Funktionen - Mist auf den Stack-Pointer geschrieben - zuviel gepusht Vielen Dank auch für Deine ausführlichen Erläuterungen bzgl. Events und so - das muss ich erst mal verdauen.
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.