Liste der Anhänge anzeigen (Anzahl: 1)
robo_wolf,
an Deiner Grafik kann man gut die Struktur erkennen, die Dir vorschwebt - dafür sind diese grafischen Darstellungen sehr praktisch.
Ich lese Dein Bild so:
Du hast vor, zwei von einander unabhängige Programmteile aufzubauen:
1. einer liest den Tastenzustand aus
2. der andere wertet den Tastenzustand aus und führt abhängig davon eine Aktion aus
(LEDs ein und aus).
Der 1. Teil, der vom Timerinterrupt angestossen wird, ist für die Entprellung zuständig. Dazu gibt's im Anhang noch etwas Ausführlicheres ;-) . Der 2. Teil reagiert auf die Tastenzustände, wie er sie vom 1. Teil "vorgekaut" vorfindet. Diese Einteilung gefällt mir sehr gut, weil sie voneinander unabhängige Aufgaben getrennten Programmteilen zuordnet.
Zum 1. Teil fallen mir noch folgende Gesichtspunkte ein: Jeder Taster hat die beiden Zustände “betätigt“/“nicht betätigt“. Welche Pegel dabei am Portpin anstehen, hängt von der Art des Tasters („Öffner“ oder „Schliesser“) und von der Beschaltung ab. Ein Öffner zwischen Portpin (mit aktiviertem pull-up-Widerstand)und Masse liefert im betätigten Zustand eine logische Eins, ein Schliesser eine logische Null. Um aller möglichen Verwirrung vorzubeugen, ist es gute Praxis, wenn der 1. Programmteil immer denselben logischen Zustand liefert, wenn der Taster betätigt wird, z.B. den Zustand „hoch“ (= logisch Eins), ganz unabhängig davon, ob das jetzt 5V oder 0V am Pin entspricht.
Wenn man's nicht so macht, muss man sich später im 2. Programmteil immer wieder daran erinnern, wie die Hardware aussieht. Als ich noch mit sehr umfangreichen, mit Relais aufgebauten Steuerungen (naja, das war in den 1980ern ;-) ) zu tun hatte, habe ich mich mir mit sowas mehr als einmal fast das Gehirn verstaucht.
Der erste Programmteil ist ein „Treiber“, der die Hardware kapselt. D.h. alle Programmteile, die die Tasterzustände verarbeiten, die der Treiber liefert, brauchen nichts über die Hardware zu wissen. Wird irgendwann mal ein Taster von Öffner auf Schliesser getauscht, dann braucht man nur den 1. Programmteil anzupassen. Alle anderen Teile können so bleiben, wie sie sind.
Im 2. Teil hast Du die möglichen Tastenzustände, die er vorfindet, in den drei hellbraunen Kästchen aufgezählt. Da fehlt aber einer, nämlich der „Taste losgelassen“. Es ist sehr wichtig, sich immer eine vollständige Liste aller möglichen Zustände aufzuschreiben, damit man ja nicht vergisst, für alle Zustände die Reaktion festzulegen. Und wenn man einen Zustand ausser Acht lassen will, dann ist ganz besonders wichtig, genau dafür die Begründung aufzuschreiben. Man glaubt gar nicht, wie schnell man die Gründe für das Weglassen vergessen hat. Liest man dann später das Programm, hält man das Weglassen erstmal für einen Fehler. Es kostet erfahrungsgemäss sehr viel Zeit, bis man schliesslich wieder dahinterkommt, dass man schon damals so ein schlaues Kerlchen gewesen war...
In Deinem Fall hast Du festgelegt, dass nichts passieren soll, wenn der Taster gedrückt gehalten wird oder wenn er dauernd nicht gedrückt ist. Nur, wenn der Taster gerade gedrückt worden ist, soll das LED umgeschaltet werden. Für das Loslassen hast Du keine Reaktion vorgesehen. Das führt dazu, dass die LED bei jedem zweiten Tastendruck wieder ausgeht. Es gibt also keine ein-eindeutige Zuordnung von Taster- und LED-Zustand. Aber - vielleicht wolltest Du's ja so haben :-) .
Noch ein Vorschlag: Lass' uns diese Version erstmal für eine einzige Taste zum Laufen bringen, danach kümmern wir uns um die Behandlung von mehreren Tasten. Da können wir dann man gucken, wie man vorgeht, wenn man mehr Variablen als Register verfügbar hat...
Ciao,
mare_crisium
Edit: Im Anhang den Fehler korrigiert, auf den robo_wolf in seinem Posting vom 01.02.2010 hinweist.
Liste der Anhänge anzeigen (Anzahl: 1)
robo_wolf,
jau, danke für den Hinweis auf den Fehler - ist schon korrigiert!
Es macht richtig Spass, mitzulesen, wie Du Dich in das Thema hineinwühlst :-) ! Am Besten gefällt mir Deine Schlussfolgerung:
Zitat:
Zitat von robo_wolf
Aber dieses Thema einmal komplett durchdacht und abgearbeiten - kann mann diesen Treiber immer wieder verwenden, in andere Projecte includen.
Zu genau demselben Schluss bin ich nach ein paar Monaten auch gekommen und bin damit seither gut gefahren. Ein Programm-Modul deckt bei mir jeweils eine Funktion komplett ab (im Sinne von Kapselung, wie man sie von objektorientiertem Programmieren her kennt). Z.B. steckt die Handhabung des TWI-Busses und meines eigenen TWI-Protokolls in einem Modul. Wenn ich Daten über den Bus versenden will, schreibe ich sie byteweise in die Ausgangs-FIFO, rufe im TWI-Modul die Prozedur TWI_SEND auf und weiter geht's. Über die ganze interne Abwicklung im Modul brauche ich nie mehr ( ;-) ) Gedanken zu machen.
Die Module werden einfach per "include"-Anweisung eingebunden. Z.B. sieht der "include"-Block in meinem 13kB-Programm so aus:
Code:
.include "ASTWI16_V01.asm" ; Modul zur TWI-Abwicklung
.include "ASTWIIF16_V04.asm" ; Interface zwischen Hauptprogramm und TWI-Modul, enthält die Dialogstruktur
.include "FIFOk16_V01.asm" ; Ein- und Ausgangs-Datenpuffer für TWI-Bus
.include "System16_V02.asm" ; div. Utilities, z.B. ASCII_to_hex u.ä.
.include "MathLibSF24_16_V07.asm" ; 32-Bit Fliesskomma Bibliothek
.include "M2KNavigation_16_V08.asm" ; Koppelnavigations-Algorithmus
.include "ADNS2610SPI16_V05.asm" ; SPI-Kommunikation mit dem Maussensor
.include "ASADNS2610IF16_V04.asm" ; Interface zwischen Hauptprogramm und Maussensoren
.include "ZstAutomat16_V04.asm" ; der Zustandsautomat zum Hochfahren und Überwachen der Maussensoren usw.
Dieses Vorgehen führt zu etwas erhöhtem Zeitbedarf, weil man sich bestimmte Vorschriften setzen und sie einhalten muss. Z.B. werden bei mir alle verwendeten Register mit "push"- und "pop"-Anweisungen gesichert, damit ich nicht jedesmal nachgucken muss, welche Register verändert werden. Trotzdem hat das Verfahren sich sehr bewährt, weil es mir erlaubt, mit Assembler fast wie in einer Hochsprache Programme zu schreiben. -
Der Vollständigkeit halber habe ich im Anhang noch die Geschichte mit dem Zustandsautomaten zuendegeführt. Bin gespannt auf Dein nächstes "Lernprogramm". Als Takt für den Timer-Interrupt schlage ich vor, zunächst mit so 2 bis 5 Hz anzufangen; da kann man das Flackern noch sehen. Wenn dann alles fehlerfrei läuft, kannst Du's immer noch schneller machen.
Ciao,
mare_crisium
@oberallgeier,
ja, für diese Anwendung könnte ein endlicher Zustandsautomat ein gangbarer Weg sein. Natürlich nur, wenn er in Assembler programmiert ist, nicht in cäh ;-) !
mare_crisium
Liste der Anhänge anzeigen (Anzahl: 1)
robo_wolf,
wenn sich einer zu schämen hat, dann wohl ich, weil ich's nicht gut genug erklärt habe :oops: . Wenn's Dir nichts ausmacht, dann lass' uns die Sache in kleineren Schritten angehen (siehe Anhang).
Ciao,
mare_crisium
Edit 1:
im .pdf haben sich folgende Fehler eingeschlichen:
1. "...mit der „ldi2-Anweisung setzen kann." Gemeint ist die "ldi"-Anweisung.
2. Im Programm-Ausschnitt "; LEDs von Tasten 1 und 2 steuern" müssen die Skip-Anweisungen nicht "sbrs r19,bFLANKE0" und "sbrs r19,bFLANKE1" sondern "sbrc r19,bFLANKE0" und "sbrc r19,bFLANKE1" heissen.