Hallo, ich bin ein absoluter Newbie in sachen AVR Assembler, möchte zum anfang eine art Lauflicht programmieren. Ich würde gern eine Pause in ein einzelnes Unterprogramm schreiben und diese immer aufrufen wenn ich sie brauche. Die Pausen sollte ich in einem Register eintragen können, variieren zw. 10ms und 2000ms. Wie kann ich das nun realisieren? Ich arbeite mit dem STK500, AVR Studio V4 und mit einem 8515. Im AVRStudio bekomme ich angezeigt dass das Board mit einer Frequenz von 3.69MHz läuft, ob der Wert richtig ist weiß ich aber nicht genau, wie kann ich das rausfinden? Bin für jede Hilfe dankbar. MFG kinglazee
Hier läuft gerade ein Lauflicht-Thread von Karl. Schau dir das erstmal an, das hilft bestimmt...
Naja die Zeitverzögerung kannst du mit ineinander verschachtelten Zeitschleifen realisieren. Oder du nimmst einen Timer. Den Takt des µC findest du so heraus, indem du einfach den quarz auf dem board suchst und schaust was draufsteht. Vieleicht hilft dir das: ;***********LAUFLICHT****************** .include "2313def.inc" ;include definition files .org 0x00 ;set Prog.Count. to 0 .def comleft=r19 ;r19 is named to comleft .def comright=r20 ;r20 is named to comright .def movevalue=r17 ;r17 is named to movevalue .def time1=r21 ;r21 is named to time1 .def time2=r22 ;r22 is named to time2 .def time3=r24 ;r23 is named to time3 rjmp reset ;jump to reset reset: ldi r16,0xff ;load value 0xff into r16 out ddrb,r16 ;set directionregister from port b to output ldi r16,ramend ;init_stackpointer ;brauchst du damit du in ein unterprogramm springen kannst out spl,r16 ldi comleft,0b10000000 ;load 0b10000000 into comleft(r17) ldi comright,0b00000001 ;load 0b00000001 into comright(r20) ldi movevalue,0b00000001 ;load 0b00000001 into movevalue(r17) left: rcall Zeitschleife out portb,movevalue ;put value from movevalue on port b out rol movevalue ;rotate the value from movevalue one stead left cpse movevalue,comleft ;compare if movevalue equals to comleft ;if condition is true skip the next command rjmp left ;jump to left rjmp right ;jump to right right: rcall Zeitschleife out portb,movevalue ;put value from movevalue on port b out ror movevalue ;rotate the value from movevalue one stad right cpse movevalue,comright ;compare if movevalue equals to comright ;if condition is true skip the next command rjmp right rjmp left Zeitschleife: ;das ist dein Unterprogramm. ldi time3,0xff pos2: Ldi time2,0xff pos1: ldi time1,0x20 pos: dec time1 ;3 ineinander verschachtelte Zeitschleifen brne pos ;schleife wird 255x255x20 mal durchlaufen dec time2 ;allerdings musst du noch darauf achten wieviele clocks der prozessor für die ;einzelnen befehle braucht. brne pos1 dec time3 brne pos2 ret
die initalisierung des stackpointers ist allerdings nicht bei allen µcs gleich.. beim 8515 müsste es so gehen. ldi temp, LOW(RAMEND) out SPL, temp ldi temp, HIGH(RAMEND) out SPH, temp aber schau lieber nochmal im datenblatt nach... dort steht es drinnen.
Also ich habe mir den Thread von Karl mal durchgelesen, werde aber leider nicht direkt schlau drauß, vielleicht muss ich mich damit noch intensiver beschäftigen. Aber ich haben unten mal mein Programm kopiert, wie gesagt, bin newbie und es soll nur zur übung sein. Kann mir jemand sagen was ich jetzt tun muss um z.b. eine Pause von 250ms bei einem Takt von 3,69MHz in das Unterprogramm "Pause" zu bekommen? P.S. So läuft mein Programm, ich habe ins Unterprogramm Pause einfach jede menge "NOP"'s eingefügt um zu sehen obs hinhaut. aber das ist sicherlich keine gute Lösung. .NOLIST .INCLUDE "8515def.inc" .LIST .DEF mp = R16 rjmp main main: ;Initiate Stackpointer ldi mp,LOW(RAMEND) out SPL,mp ldi mp,HIGH(RAMEND) out SPH,mp ;Port D für lesen vorbereiten ldi mp,0x00 ; 8 Nullen in Universalregister out DDRD,mp ; an Datenrichtungsregister ;Pull-Up's reinschalten (1 bei Tastendruck) ldi mp,0xFF ; 8 Einsen in Universalregister out PORTD,mp ; und an Port D (das sind jetzt die Pull-Ups!) ;LED's ausschalten ldi mp,0xFF ; 8 Einsen in Universalregister out DDRB,mp ; und in Datenrichtungsregister(1=Ausgehend) out PORTB,mp ; und an alle Ausgänge (1=Aus) rjmp lauflicht lauflicht: cbi portb,0 rcall pause sbi portb,0 cbi portb,1 rcall pause sbi portb,1 cbi portb,2 rcall pause sbi portb,2 cbi portb,3 rcall pause sbi portb,3 cbi portb,4 rcall pause sbi portb,4 cbi portb,5 rcall pause sbi portb,5 cbi portb,6 rcall pause sbi portb,6 cbi portb,7 rcall pause sbi portb,7 rjmp lauflicht pause: ;Unterprogramm für Wartezeit ret
Das sind mehrere Threads, hast du die alle schon durch? Blättere mal einige Tage zurück, dann findest du sie. Im ersten ging es wohl um ein "ganz besonderes Lauflicht". Frohen Rest vom Fest...
http://www.mikrocontroller.net/forum/read-1-95311.html#new http://www.mikrocontroller.net/forum/read-1-101885.html#new http://www.mikrocontroller.net/forum/read-1-122901.html#new http://www.mikrocontroller.net/forum/read-1-124555.html#new http://www.mikrocontroller.net/forum/read-1-136203.html#new http://www.mikrocontroller.net/forum/list-1-1.html?filter=Lauflicht http://www.mikrocontroller.net/forum/read-1-137732.html#new http://www.mikrocontroller.net/forum/read-1-138015.html#new
Hallo, also ich bin wirklich erstaunt was sich innerhalb von einem Tag in diesem Thread alles getan hat, Leute ich bin in einigen Foren (viele versch. Themen) aber ich habe selten eins gesehen das so gut besucht ist und man so schnell sämtliche Hilfestellungen bekommt. DICKES FETTES LOB an euch...! So jetzt zum Thema: Ich habe mir alle geposteten Threads durchgelesen, nur ich glaube dass ich noch ein zu großer Anfänger bin um damit was anfangen zu können. Wäre es zuviel verlangt mir ein Stück Source Code anzupassen damit ich es einfach reinkopieren kann? Wäre wirklich sehr dankbar. Wie das ganze dann Funktioniert werde ich mir aus meinen Befehlen rauslesen und genau nachschauen warum was gemacht wird. MFG kinglazee
Tja, es hat sich viel getan hier. Es scheint hier also nicht nur (königliche) Faulpelze zu geben. Aber Lesen und Verstehen musst du schon selber... ...HanneS...
Wäre auch dankbar wenn mir jemand ein Tutorial zeigen könnte in dem Wirklich genau die Timerfunktion erklärt ist, habe mittlerweile schon viel gegoogelt und nichts gefunden! MFG kinglazee
Also, ich habe mal weiter gesucht, bin mal auf diese Seite gestoßen: http://www.mc-project.de/Pages/home.html --> Timer Ich finde das tutorial sehr gut, aber leider ist das C++ und davon hab ich auch noch keinen Plan. Könnte jemand den Quelltext übersetzen oder mir einen Link geben in dem man weiteres nachlesen kann? Ich will doch nur eine billige Zeitverzögerung, kann ja so schwer ned sein, ich schaff nur den Sprung in diese Programmiersprache nicht so richtig. Ich hoffe ihr könnt mir helfen...
Quelltext übersetzen? Ich habe mir die Seite angesehen und finde, dass sie die Funktion des Timer-Überlauf Interrups gut erklärt. Im Prinzip muss man ja nur im I/O-Bereich einige Bits in den Registern setzen bzw. einige Werte in Register schreiben. Welche Register das sind, ist von AVT-Typ zu AVR-Typ leicht unterschiedlich und muss komkret im Datenblatt nachgeschlagen werden. Was ist nun dieser "I/O-Bereich"?? Dazu müsste man erstmal die dementsprechenden Adressbereiche auseinander halten können um zu verstehen, was mit I/O-Bereich gemeint ist. Denn es gibt im AVR: - Flash-Speicher - EEPROM-Speicher - 16 "eingeschränkt nutzbare" Register - 16 "vollwertige" Register - 32 "vollwertige" I/O-Register - 32 "eingeschränkt nutzbare" I/O-Register - SRAM Nun recherchiere erstmal, was ich damit meine, ohne die dabei gewonnenen Erkenntnisse hat es keinen Sinn, weiter zu machen, denn dann kannst du den Rest ja nicht verstehen... Das wäre ja so, als wolle man ein Buch schreiben, ohne das Alfabet zu kennen. Im nächsten Schritt kannst du ergründen: Wie kann man nun in Assembler den I/O-Bereich eines AVR ansprechen? Dazu gibt es Assembler-Befehle. Diese sind am Ende des Datenblattes in einer Tabelle zusammengefasst. Man sollte sich die Tabelle schon mal ausdrucken und da hin hängen, wo man sich oft aufhält, denn von alleine lernt (und versteht!!!) sich die nicht. Da wirst du unter Anderem auf folgende Befehle stoßen: in, out, sbi, cbi - Mit diesen kann man auf I/O zugreifen. Nun musst du noch das Register, das du nach I/O kopieren willst, mit einem bestimmten Wert (nennt man das "Konstante"?) laden. Dazu dienen entsprechende Befehle wie ldi, clr, ser... Man kann aber auch einzelne Bits der Register verändern: andi, ori, and, or, eor, sbr, cbr... Um nun einen Timer-Überlauf-Int zu programmieren, muss man nun (in ASM) Folgendes tun: - Include-Datei einbinden - Reset-Vektor auf Reset-Routine setzen - Interrupt-Vektoren auf die ISR's (Interrupt-Service-Routinen) setzen - Reset-Routine schreiben (mit Label beginnen) in Reset-Routine: - Stackpointer initialisieren - genutzte Ports initialisieren - Timer-Vorteiler setzen (und damit Timer einschalten) (tccr0) - Timer-Startwert definieren und setzen (tcnt0) - Timer-Überlauf-Interrupt-Maske setzen (timsk) - Interrupt global freischalten (sei) - Ein "Hauptprogramm" schreiben, in dem (vorerst) eigentlich nix gemacht wird: "main: rjmp main" - Eine Timer-ISR schreiben, die Folgendes macht: - SREG sichern - Timer-Startwert ausgeben (tcnt0) - Ein oder mehrere Register hoch(oder runter)zählen, mit denen du die Anzahl der Interrupts zählst und damit Zeiten zählen kannst. - In Abhängigkeit der Zählregister bestimmte Arbeiten ausführen oder eben nicht (man kann bei genügend großem Int-Abstand sogar das gesamte Hauptprogramm in der Timer-ISR ausführen). - Das SREG wiederherstellen - Die ISR mit RETI beenden Beispiele dazu findest du in den weiter oben genannten Links. Lesen und verstehen solltest du das aber schon selbst. Konkrete Fragen beantworte ich dir gerne, allgemeine Fragen jetzt nicht mehr. Guten Rutsch... ...HanneS...
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.