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.