Hi, ich brauche mal eine erklärung. Ich habe mal dieses Programm geschrieben: .include "tn13def.inc" .def ref = r16 rjmp Schleife Schleife: rcall walkcenter rjmp Schleife walkcenter: rcall led1 rcall led12 rcall led2 rcall led11 rcall led3 rcall led10 rcall led4 rcall led9 rcall led5 rcall led8 rcall led6 rcall led7 ret Led1: ldi ref,17 out ddrb,ref ldi ref,1 out portb,ref rcall Delay ret Led2: ldi ref,17 out ddrb, ref ldi ref,16 out portb,ref rcall Delay ret Led3: ldi ref,18 out ddrb,ref ldi ref,2 out portb,ref rcall Delay ret Led4: ldi ref,18 out ddrb,ref ldi ref,16 out portb,ref rcall Delay ret Led5: ldi ref,20 out ddrb,ref ldi ref,4 out portb,ref rcall Delay ret Led6: ldi ref,20 out ddrb,ref ldi ref,16 out portb,ref rcall Delay ret Led7: ldi ref,9 out ddrb,ref ldi ref,1 out portb,ref rcall Delay ret Led8: ldi ref,9 out ddrb,ref ldi ref,8 out portb,ref rcall Delay ret Led9: ldi ref,10 out ddrb,ref ldi ref,2 out portb,ref rcall Delay ret Led10: ldi ref,10 out ddrb,ref ldi ref,8 out portb,ref rcall Delay ret Led11: ldi ref,12 out ddrb,ref ldi ref,4 out portb,ref rcall Delay ret Led12: ldi ref,12 out ddrb,ref ldi ref,8 out portb,ref rcall Delay ret Delay: ldi r17,75 DelayA: ldi r18,255 DelayB: dec r18 brne DelayB dec r17 brne DelayA ret Nun meine Frage zum Ziel: Ich will, dass led1 und led12 gleichzeitig an gehen. Die leds sind in einer Multiplex schaltung aufgebaut. genauso sollen led2 und led11, usw gleichzeitig an gehen, sodass sich led6 und led7 in der "mitte" treffen. ich bei diesem programm geht erst 1, dann 12, dann 2, dann 11 usw. an. Da das aber nicht sonderlich mein ziel erfüllt suche ich hier nach einer Lösung. ich habe schon mehreres ausprobiert mit z.b. ldi r17,20 rcall led1 rcall led12 dec r17 brne.... in der hoffnung dass so led1 und led12 abwechselnd schnell an und aus gehen, sodass es aussieht als würden sie "dauerleuchten". dann habe ich noch probiert, im selben system immer led1 und led2, led2 und led3, led3 und led4 usw. als lauflicht zu programmieren. Das habe ich bis jetzt leider auch nicht hinbekommen. Kann mir jemand helfen und erklären was der Chip bei jedem Befehl macht? Danke schonmal im Vorraus.
:
Verschoben durch User
ac93 schrieb: > Nun meine Frage zum Ziel: > > Ich will, dass led1 und led12 gleichzeitig an gehen. Die leds sind in > einer Multiplex schaltung aufgebaut. ehe du das tust, solltest du dir erst mal darüber Gedanken machen, wie du dein Programm massiv vereinfachen kannst. Bildlich gesprochen hast du gerade die Addition entdeckt und willst jetzt Flugzeugtriebwerke berechnen, wobei du alle Multiplikationen durch entsprechend viele Additionen ersetzt, weil das das einzige ist, was du hinkriegst. AVR-Tutorial Dein Lauflicht kann MASSIV vereinfacht werden! Zum einen sind die LED immer an den gleichen Ports. Es besteht daher überhaupt keine Notwendigkeit immer das DDRB umzustellen. Die Einstellung der DDR Register erfolgt im Normalfall am Anfang des Programms und bleibt dann immer gleich. Nur in ein paar Ausnahmefällen ist man gezwungen, einen Portpin mal von Eingang auf Ausgang oder vice versa umzustellen. Aber soweit bist du noch lange nicht. Zum anderen fehlt dir zum vernünftigen Multiplexen noch mindestens eine andere Zutat: nämlich Timer und deren Interrupt Routine. Auch wenn man Multiplexen ohne hinbekommt, sinnvoll ist es nicht. Die Timerinterruptroutine geht ständig alle LED durch und schaltet sie ganz kurz ein. Schnell genug dass wir das nicht sehen. Davon losgelöst, kommt dann deine spezielle Lauflichtstrategie mit den wandernden LED ins Spiel. Du musst hier die Dinge trennen. Auf der einen Seite ist der Multiplex, der dir erlaubt, jede beliebige Kombination deiner LED aufleuchten zu lassen auch wenn das zunächst hardwaretechnisch gar nicht möglich ist. Und auf der anderen Seite steht dann die darauf aufbauende Anwendung eines Lauflichts, die einfach nur sagt: diese und jene LED jetzt einschalten bzw. ausschalten und sich nicht mehr darum zu kümmern hat, mit welchem Trick (nämlich Multiplex) das realsiert ist. Link-Tip: AVR-Tutorial
Hi Ich vermisse die Zuweisung vom Stack. Vermutlich hast du noch gar nicht bemerkt, das dein Programm nicht so läuft, wie es soll, sondern irgend was macht.... Grundsätzlich: in Assembler muß der Stack gesetzt werden. Hochsprachen wie BASCOM und C erledigen das von selbst, aber nicht Assembler. Auch die Include-Datei wird das nicht einhalten. Lies mal die Tutorials durch. Zum Programm, du kannst es so machen, klar. Aber K.H.B. Hat recht, es geht wesentlich einfacher. Und nun bist du dran, zu erkennen, wie du dein Programm anders aufbaust. Zuerst einmal optische Ordnung. Du kannst mit Kommentarzeilen vieles deutlich machen. Z.B. ;*********************************** ;* Dies ist das Hauptprogramm * ;*********************************** ;*********************************** ;* Ausgabe am Port X * ;*********************************** Delay's solltest du dir gar nicht erst angewöhnen. Zumindest nicht solche, die dein Programm aufhalten. Dafür gibt es Timer, aus deren Interrupt verschiedene Zeiten abgeleitet werden können. So kannst du Bspw. im Programm für eine Zeitverzögerung ein Bit setzen und eine Variable auf einen Wert. In der Timer-ISR fragst du ab, ob das Bit gesetz ist und zählst die Variable herunter. In deinem Programm kontrollierst du den Counter auf 0 und gesetztem Bit. Wenn die Zeit abgelaufen ist, stößt du die Aktion an, die dann ausgeführt werden soll und setzt das Bit für die Zeit zurück. Angenommen, dein Timer ISR bringt jede ms einen Interrupt. Du brauchst ein paar Variable: ms0, ms1,ms2,sekunde, minute.... was auch immer.
1 | Timer_ISR: |
2 | Push .... ; alle Register sichern, da Interrupt |
3 | LDS RegX, ms0 ; ms laden |
4 | Inc RegX ; erhöhen |
5 | CPI RegX,10 ; Grenzwert abfragen |
6 | BREQ Set_ms1 ; eine Dekade weiter wg. Überlauf |
7 | STS ms0, RegX ; zurückschreiben |
8 | RJMP End_Timer ; und fertig |
9 | Set_ms1: ; nächste Dekade |
10 | CLR RegX |
11 | STS ms0, RegX ; zuerst Millesekunden auf 0 und ablegen |
12 | LDS RegX, ms1 ; nächste Dekade Laden |
13 | Inc RegX ; erhöhen |
14 | CPI RegX,10 ; Grenzwert abfragen |
15 | BREQ Set_ms2 ; eine Dekade weiter, wg. Überlauf |
16 | STS ms1, RegX |
17 | RJMP End_Timer |
18 | Set_ms2: |
19 | .... |
20 | |
21 | End_Timer: |
22 | POP ..... |
23 | RETI |
Je nachdem welche Zeitbasis du brauchst, setzt du einen Aufruf in den entsprechenden Abschnitt und bearbeitest dort das Bit. Nennen wir mal die Variable dazu Time_Ctrl
1 | Time_Ctrl: .Byte ; Bit 0 Pause angefordert und läuft= 1 |
2 | ; Bit 1 Zeit ist abgelaufen |
3 | ; ..... weitere Steuerbits |
4 | Time_Val: . Byte |
Im Programm setzt du Time_Val auf einen Wert und Bit 0 von Time_Ctrl. In der Timer_ISR rufst du ein Unterprogramm auf, in dem du das Bit 0 prüfst. Ist es "1" decrementierst du die Time_Val und prüfst, ob sie 0 ist. Wenn ja, löscht du Bit 0 und setzt Bit 1 von Time_Ctrl. Im Hauptrogramm prüfst du nur Bit 1. ist es gesetzt, aufruf eines Unterprogrammes mit der Aktion, und anschließendem löschen von Bit 1. Damit wird dieses Programm nur bearbeitet, wenn die Zeit abgelaufen ist. Beachte aber: alle Programmteile, die aus einer Interruptroutine aufgerufen werden , müssen die verwendeten Register sichern. Der Vorteil: Du kannst jede Zeitverzögerung zeitlich definieren und dein Programm macht auch weiterhin seinen Job schnell und reagiert auf andere Bedingungen. Gruß oldmax
Hi >Grundsätzlich: in Assembler muß der Stack gesetzt werden. Hochsprachen >wie BASCOM und C erledigen das von selbst, aber nicht Assembler. Stimmt nicht ganz. Bei neueren AVRs wird der Stackpointer nach RESET automatisch auf RAMEND initialisiert. Allerdings schadet es nicht den Stackpointer manuell zu setzen. MfG Spess
spess53 schrieb: > Bei neueren AVRs wird der Stackpointer nach RESET automatisch auf RAMEND initialisiert. Ich habe gerade mal beim ATmega48/88 nachgelesen. Dort ist das noch nicht zu finden. Welche neueren AVRs meinst du? Thomas
Hi >Ich habe gerade mal beim ATmega48/88 nachgelesen. Dort ist das noch >nicht zu finden. Welche neueren AVRs meinst du? Z.B. auch ATmega48/88 Im Datenblatt zu finden unter: AVR CPU Core->Stack Pointer->Initial Value MfG Spess
>>Ich habe gerade mal beim ATmega48/88 nachgelesen. Dort ist das noch >>nicht zu finden. Welche neueren AVRs meinst du? >Z.B. auch ATmega48/88 >Im Datenblatt zu finden unter: >AVR CPU Core->Stack Pointer->Initial Value Tatsächlich, Danke. Das Kleingedruckte habe ich nicht gelesen ;-) Werde das demnächst mal ausprobieren. Thomas
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.