Anmelden

Archiv verlassen und diese Seite im Standarddesign anzeigen : Tutorial für alle Assembler-Anfänger _



Seiten : 1 2 [3]

izaseba
16.08.2005, 22:35
@ Tekeli

Sorry daß ich Dich übersehen habe,



Sonst kann es ja passieren, dass beim Laden des 16-Bit Counters wir korrupte Werte in dem Counter haben. Smile


Das hast Du super erkannt!
Und nicht nur dabei!
wenn man auf nummer sicher gehen will, muß man sowas entweder in einer Interruptroutine tun (da kann ja nichts zwischen funken)
oder, wenn es im Hauptprogramm erfolgen muß mit cli die Interrupts kurz abschalten
verschieben was man will und mit sei wieder einschalten.

Das ist auch eine Fußangel bei AVR, da sollte man unbedingt drauf achten

Gruß Sebastian

Florian
16.08.2005, 23:38
Herzlichen Glückwunsch zu 500 Posts!
Wir müssen uns langsam mal überlegen, ob wir zusammen ein Tutorial schreiben bzw. alles zusammenfassen!? ;o)
Das wird hier sonst langsam echt zu unübersichtlich!

*edit*:
Habt ihr eigentlich bedacht, dass bei einer Amepl, wenn man ganz pingelig ist, zwischen dem Gelb-Rot- und dem Rot-Gelb-Wechsel beide Lampen kurz zusammen leuchten? *lol*
Wenn ihr soweit fertig seit, könnt ihr ja versuchen dieses Problem noch anzugehen! ;o)


Macht weiter so!

Viele Grüße und weiterhin viel Erfolg
Florian

izaseba
16.08.2005, 23:49
Habt ihr eigentlich bedacht, dass bei einer Amepl, wenn man ganz pingelig ist, zwischen dem Gelb-Rot- und dem Rot-Gelb-Wechsel beide Lampen kurz zusammen leuchten?

Florian, das haben wir doch rot - gelbrot - grün - gelb - rot , oder wie meinst Du das ? :-k

Oder haben wir uns eine Ampel zu kurz angeschaut :-k
Ich kann leider nicht nachgucken, bei uns im ort gibt es keine Ampel :-(
Müßte wohl 5 km fahren :-( :-(

Und wegen aufräumen o ja , das wär echt was ...

Schlag mal vor was sollen wir mit dem Stoff hier machen ?

Gute Nacht

Gruß Sebastian

Florian
17.08.2005, 00:11
Oh ja, jetzt sehe ich's! *Blindheit tut weh -> ich brauche eine neue Brille -> morgen gehe ich sowieso zum Augenartzt*

Hmmm, gute Frage, habt ihr jetzt eigentlich mal Alle meine Endchen gespielt?
Klingt das bei euch auch wirklich nach Musik, oder eher nach möchtegern mit schiefen Tönen? ;o)


Ihr könntet ein Reaktionsspiel bauen, wo man den passenden Knopf zu einer Frabe drücken muss, das wäre ein guter Schnitt zum neuen Thread! *lol*
Wie heißen diese Spiele doch gleich!? *rätsel*

toeoe
17.08.2005, 00:28
Florian: Aber natürlich, wenn schon eine Ampel, dann richtig ;)
Jo, lass uns doch mal zusammen den Thread aufräumen *g*

Hab hier übrigens ein paar Aufgaben gefunden:
http://embedded.crypto.ruhr-uni-bochum.de/kapitel2-asm-aufgabe1.pdf

Gruß und Gute Nacht
Thomas

PS: Und alle meine Endchen hab ich nicht gespielt, muss ich mal machen :-({|=

michaelb
17.08.2005, 19:25
Hallo,
mann oh mann der ganze Tag nix hier los!!!!!!!!!!
Weil ich ja bald in Urlaub fahre und leider nicht mehr hier mitmachen kann! *schluchz* was haltet ihr davon wenn ich die PDF Version von eurem heißgeliebten Tutorial ausdrucke und in meinem Urlaub lese!
Link:
http://www.avr-asm-tutorial.net/beginner_de.pdf
das PDF finde ich sehr toll da dort die ganzen einzelnen Seiten untereinander zusammengefasst sind!
Gruß Michi

izaseba
17.08.2005, 19:46
Hallo Michi, wenn Du das Tutorial durch hast, und auch alles verstanden hast,
dann bist Du verdammt weit.
Es geht zwar nicht auf Schwerpunkte wie LCD, UART, PWM, ADC usw. ein aber das ist dann nur ein Katzensprung...


mann oh mann der ganze Tag nix hier los!!!!!!!!!!

Keine Fragen -> Alles klappt wunderbar :-)

Gruß Sebastian

toeoe
17.08.2005, 19:47
Hi,

ausdrucken ist immer gut, aber ob NUR lesen was bringt? Man muss das ganze ja auch praktisch anwenden und da und da mal was ändern, damit man sieht, was man damit bewirkt. Also nur lesen wird nicht soooo viel bringen. Schalte doch am besten wenigstens mal im Urlaub ab, somit biste nachm Urlaub wieder fit und kannst weiterprogrammieren :)

Gruß
Thomas

michaelb
17.08.2005, 20:29
Hi all,
juhu endlich a bissl was los!!! *freu*
ich denk mir mal wenn ich die wichtigsten Befehle im Kopf hab also auswendig dann brauch ich nicht immer nachschauen! Ich finde das PDF zu dem ich vorher den Link gepostet hab echt gut und ich finds besser das pdf auszudrucken als die einzelnen Seite der Website! Ich denk mal das nächste was ich machen werde ist UART und ADC! Also nen GP2D12 einlesen und über die RS232 an den PC schicken!
Gruß Michi
P.S. Ich hoffe das ich nicht soviel verpasse wenn ich 14 Tage weg bin :(
Nö so ganz abschalten im Urlaub ist mir zu langweilig!!

izaseba
17.08.2005, 21:31
Ich denk mal das nächste was ich machen werde ist UART und ADC! Also nen GP2D12 einlesen und über die RS232 an den PC schicken!

Hallo Michi,

Das ist schon ein wirklich großes Projekt!

Fang am besten damit an, Strings an Uart zu verschicken, es ist eigentlich sehr einfach,
wenn Du allerdings noch Fragen dazu haben solltest, kann ich Dich etwas dabei unterstützen.
ADC dürfte auch kein Problem sein, wo ich allerdings die größte Schwierigkeit sehe ist das
umwandeln von binären Zahlen in ASCII Zeichen(wenn Du den Terminal benutzen solltest)
naja Du weiß in C ist das itoa ...
Mit Zahlen geht es noch relativ einfach, wenn Fragen, hätte ich da eine eigentlich einfache Lösung im Angebot.

Gruß Sebastian

michaelb
17.08.2005, 22:07
Hi Sebastian,
ich lern erstmal die ganzen Standartbefehle von Assembler mit dem pdf-tutorial von avr-asm-tutorial.net! Und dann mach ich mal das mit dem UART und ADC! Ich find's echt toll dass man von euch soviel Unterstützung bekommt! Was das wichtigste ist dass ich jetzt mal selber Assemblercode schreibe und nicht die hier geposteten nur in den atmega progg und mich freu dass es funktioniert!
Gruß Michi
Ich hoff mal dass in dem PDF alle Befehle aufgeführt sind! Aber ich glaube das das pdf synchron der website ist!

toeoe
21.08.2005, 10:17
Um den Thread hier mal wieder aktuell zu halten, habe ich hier wieder einen Code. Ich stelle erstmal die Aufgabe, müsst ihr dann wissen, ob ihr es erstmal selber versuchen wollt oder nicht. Selber versuchen bringt auf jeden Fall mehr :)

Aufgabe: Erstelle ein Lauflicht, bei jeder LED ertönt ein andere Ton aus dem Summer. Wenn das Lauflicht wieder vorne angekommen ist, wiederholen sich die Töne natürlich. Löst diese Aufgabe am besten, indem ihr mit dem Speicher arbeitet, also die Werte mit .db oder .dw (je nachdem, was man braucht) speichert.

Die Aufgaben sind alle speziell für das myAVRBoard 1.4 von myavr.de ausgelegt, können aber auch mit anderen Boards gelöst werden.

Hier nun die Lösung, bitte nicht schummeln :P

;Dieses Programm produziert ein Lauflicht. Bei jedem LED-Wechsel kommt ein kurzer Sound.
.include "m8def.inc"

.equ time1 = 65536-1800 ;Damit wird der Timer1 vorgeladen, für die halbe Sekunde
.equ time0 = 256-57 ;Damit wird der Timer0 vorgeladen, für den Sumer

.equ Summer = PB5 ;Summer an B.5

.def lpm_reg = r0 ;Register, wo Werte von r0 gespeichert werden
.def tmp = r16 ;Mein Universallregister
.def statusLED = r17 ;In diesem Register wird gespeichert, welche LED gerade leuchtet

.org 0x000
rjmp reset ;Interruptvektor "reset:"

.org OVF1addr
rjmp hSekEnde ;Interruptvektor für Timer1 Überlauf, hier springt
;das Programm hin, wenn der Timer überläuft

.org OVF0addr
rjmp tonloop ;Interruptverktor für Timer0 Überlauf, hier springt
;das Programm hin, wenn der Timer überläuft

reset:
;Stack einrichten
ldi tmp, HIGH(RAMEND) ;HIGH-Byte der obersten RAM-Adresse
out SPH, tmp
ldi tmp, LOW(RAMEND) ;LOW-Byte der obersten RAM-Adresse
out SPL, tmp

ldi tmp, 0b11111111
out DDRB, tmp ;PortB als Ausgang
ldi statusLED, 0b00000010
out PORTB, statusLED ;Am Anfang soll LED1 leuchten

;Timer Register für halbe Sekunde werden belegt, hier Timer1
ldi tmp, (1<<CS12) | (1<<CS10) ;Prescaler ist 1024
out TCCR1B, tmp
ldi tmp, HIGH(time1) ;Für den Timer1 (16Bit) benötigen
out TCNT1H, tmp ;wir 2 Register, in denen wir den Wert
ldi tmp, LOW(time1) ;für die 1/2 speichern ->
out TCNT1L, tmp ;"TCNT1H" und TCNT2L"

;Timer Register für Ton werden belegt, hier Timer 0
ldi tmp, (1<<CS02) ;Prescaler ist 256
out TCCR0, tmp ;Register TCCR0 ist für den Prescaller zuständig
ldi tmp, time0 ;Hier wird der Timer vorgeladen
out TCNT0, tmp

ldi tmp, (1<<TOIE1) | (1<<TOIE0);Hier werden Interrupts eingeschaltet
out TIMSK, tmp ;Register TIMSK ist dafür zuständig

;Z-Register mit DB "tonwerte" füllen
ldi ZH, HIGH(tonwerte * 2)
ldi ZL, LOW(tonwerte * 2)

sei ;Interrupts zulassen

main:
rjmp main ;Immer wieder die main durchlaufen

;********************INTERRUPT-TIMER1********************;
;Jede halbe Sekunde wird geprüft, welche LED an ist und dementsprechen die
;nächste LED angemacht. Die aktuelle wird dabei natürlich ausgeschaltet
hSekEnde:
push tmp ;tmp-Register auf Stack sichern
in tmp, SREG
push tmp ;SREG auf Stack sichern

;TIMER1 wird neu geladen
ldi tmp, HIGH(time1) ;Für den Timer1 (16Bit) benötigen
out TCNT1H, tmp ;wir 2 Register, in denen wir den Wert
ldi tmp, LOW(time1) ;für die 1 Sekunde speichern ->
out TCNT1L, tmp ;"TCNT1H" und TCNT2L"
cpi statusLED, 0b00001000 ;Leuchtet die 3. LED?
breq wiederholen ;Wenn JA...

;Wenn NEIN....
adiw ZL, 1 ;Zeiger auf nächstes Byte in "tonwerte"
lsl statusLED ;Register "statusLED" mit 2 multiplizieren
;dadurch verschieben sich alle Bits um 1 nach link ->
;nächste LED blinkt
rjmp endehSek

wiederholen:
sbiw ZL, 2
ldi statusLED, 0b00000010 ;Wieder erste LED leuchten lassen

endehSek:
out PORTB, statusLED ;nächste LED leuchtet
pop tmp
out SREG, tmp ;SREG wiederherstellen
pop tmp ;tmp wiederherstellen
reti ;springe wieder dahin, wo du hergekommen bist

;********************INTERRUPT-TIMER0********************;
tonloop:
push tmp ;tmp-Register auf Stack sichern
in tmp, SREG
push tmp

sbis PINB, Summer ;Ist B.5 = 1?
rjmp umschalten ;NEIN -> auf 1 setzen
cbi PORTB, Summer ;JA -> auf 0 setzen
rjmp endeTon

umschalten:
sbi PORTB, Summer

endeTon:
;Timer neu laden
lpm ;Werte von "tonwerte" in r0 schreiben
mov tmp, lpm_reg
out TCNT0, tmp

pop tmp
out SREG, tmp ;SREG wiederherstellen
pop tmp ;tmp wiederherstellen
reti

;Das sind die Werte, womit der Timer0 (Sound-Timer) vorgeladen wird
;Anzahl der Wert muss GERADE sein
tonwerte:
.db 256-57, 256-14, 256-3, 0
Man hätte es auch mit nur einem Timer lösen können, aber wollte hier mal die Variante mit 2 Timern vorstellen.

Bei Fragen fragen \:D/

Gruß
Thomas

toeoe
21.08.2005, 10:22
Und hier auch gleich die nächste Aufgabe:

Hier könnt ihr das Lauflicht von der Aufgabe davor nehmen. Das Lauflicht läuft natürlich in einer Endlosschleife durch. Beim Drücken eines Tasters soll sich die Laufrichtung aber ändern. Beim nochmaligem Drücken desselben Tasters soll sich die Laufrichtung wieder ändern.

Kleiner Tip: Ihr müsst den Taster entprellen.

Hier nun die Lösung und auch hier gilt: Bitte nicht schummeln ;)

;Dieses Programm produziert ein Lauflicht. Jede halbe Sekunde geht die
;nächste LED an. Drückt man den Taster, ändert sich die Richtung des Lauflichtes
;Das Programm läuft in einer Endlosschleife durch.
;Problem des Prellens soll hier nicht mehr auftreten.
.include "m8def.inc"

.equ time1 = 65536-369 ;Damit wird der Timer1 vorgeladen, für 100ms
.equ Taster = PD2 ;Taster an D.2
.equ sperre = 7 ;Taster sperren (Hilfsvariable)
.equ laufrichtung = 0

.def tmp = r16 ;Mein Universallregister
.def statusLED = r17 ;In diesem Register wird gespeichert, welche LED gerade leuchtet
.def statusTaster = r18 ;Statusregister, wo die Sperre gespeichert ist
.def zaehler = r19 ;Mein Zählregister, hier zähl ich hoch,
;damit ich auf eine halbe Sekunde komme

.org 0x000
rjmp reset ;Interruptvektor "reset:"

.org OVF1addr
rjmp zeitum ;Interruptvektor für Timer1 Überlauf

reset:
;Stack einrichten
ldi tmp, HIGH(RAMEND) ;HIGH-Byte der obersten RAM-Adresse
out SPH, tmp
ldi tmp, LOW(RAMEND) ;LOW-Byte der obersten RAM-Adresse
out SPL, tmp

ldi tmp, 0b11111111
out DDRB, tmp ;PortB als Ausgang

cbi DDRD, Taster ;D.2 als Eingang
sbi PORTD, Taster ;D.2 Pullups aktivieren

ldi statusLED, 0b00000100
out PORTB, statusLED ;Am Anfang soll erste LED leuchten

ldi zaehler, 0b00000000 ;Zähler auf 0 stellen

;Timer Register für 100ms werden belegt, hier Timer1
ldi tmp, (1<<CS12) | (1<<CS10) ;Prescaler ist 1024
out TCCR1B, tmp
ldi tmp, HIGH(time1) ;Für den Timer1 (16Bit) benötigen
out TCNT1H, tmp ;wir 2 Register, in denen wir den Wert
ldi tmp, LOW(time1) ;für die 1/2 speichern ->
out TCNT1L, tmp ;"TCNT1H" und TCNT2L"
ldi tmp, (1<<TOIE1)
out TIMSK, tmp

sei ;Interrupts zulassen

main:
cpi zaehler, 0b00000101 ;Ist zaehler = 5?
breq lauflicht ;JA -> springe zu lauflich
rjmp main ;NEIN -> springe zu main

lauflicht:
clr zaehler ;zaehler auf 0 setzen
sbrs statusTaster, laufrichtung ;Ist Bit0 = 1?
rjmp pruefRechts ;NEIN -> laufe rechtsrum
;JA -> lauf linksrum
pruefLinks:
cpi statusLED, 0b00000100 ;Leuchtet 3. LED?
breq wiederholenLinks ;Wenn JA, spring zu "wiederholen"
lsl statusLED ;Wenn NEIN´, Bit nach links verschieben -> nächste LED
rjmp ende ;spring zu ende

pruefRechts:
cpi statusLED, 0b00000001 ;Leuchtet 1. LED?
breq wiederholenRechts ;Wenn JA, spring zu "wiederholen"
lsr statusLED ;Wenn NEIN, Bit nach rechts verschieben -> vorherige LED
rjmp ende ;spring zu ende

wiederholenLinks:
ldi statusLED, 0b00000001
rjmp ende

wiederholenRechts:
ldi statusLED, 0b00000100

ende:
out PORTB, statusLED ;nächste LED leuchtet
rjmp main ;springe wieder zur main

;*****************INTERRUPTROUTINE FÜR TIMER1***************************
zeitum:
push tmp ;Rette Universallregister
out SREG, tmp ;Rette Statusregister
push tmp
inc zaehler ;Zähler erhöhen

sbis PIND, Taster ;Ist Taste gedrückt?
rjmp zeitum1 ;NEIN -> springe zu zeitum1

zeitum0: ;JA -> hier weiter machen
sbrs statusTaster, sperre ;Ist Sperre gesetzte?
rjmp zeitum2 ;NEIN -> springe zu zeitum1
rjmp zeitum3 ;JA -> springe zu zeitum2

zeitum1:
cbr statusTaster, (1<<sperre) ;Sperre löschen
rjmp zeitum3

zeitum2:
sbr statusTaster, (1<<sperre) ;Sperre setzen

;Aktion durchführen die beim Drücken des Tasters passieren soll
sbrs statusTaster, laufrichtung ;Ist Bit0 = 1?
rjmp setzeBitLauf ;NEIN -> auf 1 setzen
cbr statusTaster, (1<<laufrichtung);JA -> auf 0 setzen
rjmp zeitum3 ;Ende der Routine

setzeBitLauf:
sbr statusTaster, (1<<laufrichtung)

zeitum3:
;Timer1 neu laden
ldi tmp, HIGH(time1)
out TCNT1H, tmp
ldi tmp, LOW(time1)
out TCNT1L, tmp

pop tmp ;stelle SREG wieder her
out SREG, tmp
pop tmp ;stelle Universalregister wieder her
reti ;die Interrupt-Routine wird verlassen
;und es wird weiter im Hauptprogramm gearbeitet

Diesmal wurde nur mit einem Timer gearbeitet, dafür ist dann eben eine zusätzliche Abfrage nötig.

Bei Fragen wieder fragen ;)

Gruß
Thomas

Achja, alle Timer-Werte, die ich hier poste, sind auf 3,6864 MHz ausgelegt. Müsst ihr dann evlt. dementsprechend anpassen.

izaseba
21.08.2005, 11:08
Hallo Thomas, schön daß Du solche Programme schreibst, ist gut um wirklich mit Assembler
vertraut zu werden....

Kleine Anmerkung...
man bräuchte doch den R17 bzw. Statusled nicht, oder ?
man kann doch genauso PINB abfragen und PORTB verändern, oder ?
Jetzt seh das nicht als Fehler, sondern als Tip, daß es auch anders geht, am sonsten
finde ich Deine Programme gut, weiter so!

toeoe
21.08.2005, 11:15
Hallo Sebastian,

ja, das stimmt :-s So würde man noch ein Register sparen :)

Danke für den Tip.
Gruß
Thomas

toeoe
22.08.2005, 19:52
So, hier mal wieder eine Aufgabe:

Lauflicht, mal wieder. Also das Lauflicht soll 2x schnell laufen und 1x kurz. Bei dem 1x kurz soll aber wieder Ton pro LED abgespielt werden. Und das dann bitte in einer Endlosschleife :)

Bevor ihr die Aufgaben nicht versteht, fragen ;)

Hier die Lösung und mal wieder nicht schummeln ;)

.include "m8def.inc"

.equ Summer = PC5
.equ time0 = 256-57

;Adressen im RAM, wo die Tonwerte stehen
.equ ton1 = 0x60
.equ ton2 = 0x61
.equ ton3 = 0x62

.def lpm_reg = r0 ;Hier werden die Werte von db/dw gespeichert
.def tmp = r17 ;Universallregister
.def zaehler = r18 ;Zaehlregister

.org 0x000
rjmp reset ;Am Anfang des Programms erstmal zu "reset:" springen

.org OVF1addr
rjmp zeitumLauf ;Läuft Timer1 über, dann spring zu "zeitumLauf:"

.org OVF0addr
rjmp timerSummer ;Läuft Timer0 über, dann spring zu "timerSummer:"



reset:
;Stack einrichten
ldi tmp, HIGH(RAMEND) ;HIGH-Byte der obersten RAM-Adresse
out SPH, tmp
ldi tmp, LOW(RAMEND) ;LOW-Byte der obersten RAM-Adresse
out SPL, tmp

ldi tmp, 0b11111111
out DDRB, tmp ;PortB als Ausgang
sbi DDRC, Summer ;C.5 als Ausgang
ldi tmp, 0b00000001
out PORTB, tmp ;Am Anfang soll erste LED leuchten

clr zaehler ;Zaehlregister auf 0 setzen

;Tonwerte in den RAM schreiben

;Z-Register mit DW "zeitwerte" füllen
ldi ZH, HIGH(zeitwerte * 2)
ldi ZL, LOW(zeitwerte * 2)

;X-Zeiger zeigt nun auf 0x60
ldi XH,HIGH(ton1)
ldi XL,LOW(ton1)

;Tonwerte in RAM schreiben, da wo X hinzeigt
ldi tmp, 256-57
st X+, tmp
ldi tmp, 256-14
st X+, tmp
ldi tmp, 256-3
st X, tmp

;Timer Register für die Abstände im Lauflicht werden belegt, hier Timer1
ldi tmp, (1<<CS12) | (1<<CS10) ;Prescaler ist 1024
out TCCR1B, tmp

lpm ;Wert von "zeitwerte" in r0 schreiben
mov tmp, lpm_reg ;Wert von r0 in tmp schreiben
push tmp ;LOW-Byte sichern
adiw ZL, 1 ;Z um 1 erhöhen -> zeigt nun auf das HIGH-Byte
lpm
mov tmp, lpm_reg
out TCNT1H, tmp ;HIGH-Byte in TCNT1H schreiben
pop tmp ;gesichertes LOW-Byte wiederholen
out TCNT1L, tmp ;LOW-Byte in TCNT1L schreiben

ldi tmp, (1<<TOIE1) | (1<<TOIE0);Hier werden Interrupts nach Timer1 Überlauf eingeschaltet
out TIMSK, tmp ;Register TIMSK ist dafür zuständig

sei ;Interrupts zulassen

main:
rjmp main ;immer wieder zur "main:" springen

;***************ROUTINE FÜR TIMER1-INTERRUPT***************;
;Z-Zeiger wird auf das erste Element von "zeitwerte" gesetzt
;Wenn zaehler größer oder gleich 6 ist, wird der Zeitwert der
;langsamen zeit geladen
zeitumLauf:
push tmp ;tmp sichern
in tmp, SREG
push tmp ;SREG sichern

inc zaehler ;zaehler um 1 erhöhen

;Z-Register auf den 1. Wert zeigen lassen
ldi ZH, HIGH(zeitwerte * 2)
ldi ZL, LOW(zeitwerte * 2)

cpi zaehler, 0b00000110 ;Ist zaehler >= 6?
brsh langzeit ;JA -> langsamen Zeit laden
rjmp LEDpruefen ;NEIN -> spring direkt zu "LEDpruefen:"

;Hier wird nur hingesprungen, wenn das Lauflicht schon 2x schnell
;durchlaufen ist.
;Wenn zaehler = 8 ist, wird wieder der Zeitwert der schnellen
;Zeit geladen und der zaehler wieder auf 0 zurückgesetzt
langzeit:
;Timer0 aktivieren
ldi tmp, (1<<CS02)
out TCCR0, tmp

cpi zaehler, 0b00001001 ;Ist zaehler = 9?
breq clrzaehler ;JA -> springe zu "clrzaehler:"
adiw ZL, 2 ;Z um 2 erhöhen -> zeigt auf das LOW-Byte der
;langsamen Zeit

cpi zaehler, 0b00000110 ;Ist zaehler = 6?
breq ton01 ;1. Tonwert laden
cpi zaehler, 0b00000111 ;Ist zaehler = 7?
breq ton02 ;2. Tonwert laden
cpi zaehler, 0b00001000 ;Ist zaehler = 8?
breq ton03 ;3. Tonwert laden

ton01:
sbiw XL, 2 ;X-Zeiger um 2 vermindern -> auf ton1 zeigen
ld tmp, X
out TCNT0, tmp
rjmp LEDpruefen ;zu "LEDpruefen:" springen

ton02:
adiw XL, 1 ;X-Zeiger um 1 erhöhen -> auf ton2 zeigen
ld tmp, X
out TCNT0, tmp
rjmp LEDpruefen ;zu "LEDpruefen:" springen

ton03:
adiw XL, 1 ;X-Zeiger um 1 erhöhen -> auf ton3 zeigen
ld tmp, X
out TCNT0, tmp
rjmp LEDpruefen ;zu "LEDpruefen:" springen

clrzaehler:
;Timer0 abstellen
ldi tmp, (0<<CS02)
out TCCR0, tmp

clr zaehler ;zaehler wieder auf 0 setzen

;Prüfen, ob letzte LED an ist, wenn das der Fall ist, dann wieder
;die erste LED an machen, sonst um 1 nach links rücken
LEDpruefen:
in tmp, PINB
cpi tmp, 0b00000100 ;Ist letzte LED an?
breq ersteLED ;JA -> spring zu "ersteLED:"
lsl tmp ;tmp mit 2 multiplizieren -> jedes Bit verschiebt
;sich um 1 nach links
rjmp zeitumEnde ;zum Ende der Routine springen

ersteLED:
ldi tmp, 0b00000001 ;wieder erste LED anmachen

zeitumEnde:
out PORTB, tmp ;den aktuellen LED-Status an PORTB ausgeben

;Timer1 neu laden
lpm ;Wert von "zeitwerte" in r0 schreiben
mov tmp, lpm_reg ;Wert von r0 in tmp schreiben
push tmp ;LOW-Byte sichern
adiw ZL, 1 ;Z um 1 erhöhen -> zeigt nun auf das HIGH-Byte
lpm
mov tmp, lpm_reg
out TCNT1H, tmp ;HIGH-Byte in TCNT1H schreiben
pop tmp ;gesichertes LOW-Byte wiederholen
out TCNT1L, tmp ;LOW-Byte in TCNT1L schreiben

pop tmp
out SREG, tmp ;SREG wiederholen
pop tmp ;tmp wiederholen

reti ;Gehe wieder dahin, wo du hergekommen bist

timerSummer:
push tmp ;tmp sichern
in tmp, SREG
push tmp ;SREG sichern
sbis PORTC, Summer ;Ist C.5 = 1?
rjmp umschalten ;NEIN -> auf 1 setzen
cbi PORTC, Summer ;JA -> auf 0 setzen
rjmp summerEnde ;zum Ende der Routine springen

umschalten:
sbi PORTC, Summer

summerEnde:
;Timer0 neu laden
ld tmp, X
out TCNT0, tmp

pop tmp
out SREG, tmp ;SREG wiederholen
pop tmp ;tmp wiederholen

reti ;Gehe wieder dahin, wo du hergekommen bist

;Das sind die Werte, womit der Timer1 (Lauflicht-Timer) vorgeladen wird
;Anzahl der Werte muss GERADE sein
zeitwerte:
.dw 65536-1000, 65536-3600

cmc
10.04.2007, 21:35
Hi an euch ich habe den Alten Tread gefunden, ich hoffe es anwortet mir noch jemand drauf. Ich suche die ganze Zeit schon eine Routine für PWM
um einen Servo anzusteuern, ich habe auch erst in Assembler angefangen zu coden, muss aber sagen ich habe vor 15 Jahren auf dem Brotkasten (c64) in Assembler Programmiert und die Befehle sind fast identischt bis auf ausnahmen. Das mit den Intterups habe ich jetzt auch einigermasen gerafft. Nur das mit dem PWM verstehe ich nicht ganz muss auch sagen es ist echt mühsam das Englische Manuel von Atmega16/32 durchzulesen.
Zum entwickeln hab ich ein Dragon und ein StK500 und noch ein Selbstgebautes Board.

Danke schon mal für die Hilfe.

PS. Hab die Tread von vorne bis zum Letzten Durchgelesen.

Christopher1
10.04.2007, 22:27
Ich habs auch durchgelesen und einiges draus gelernt.
Das Tutorial von izaseba find ich auch gut gelungen, wirklich estrem leicht geschrieben. http://www.izaseba.roboterbastler.de/
MfG Christopher

izaseba
11.04.2007, 07:18
Hallo Ihr beiden,


Das Tutorial von izaseba find ich auch gut gelungen, wirklich estrem leicht geschrieben.

Danke, leider habeich zur Zeit keine Zeit weiter zu schreiben, weil ich voll im Umzug bin ](*,)

@cmc,
was verstehst Du an PWM nicht ?
Zugegeben, es gibt viele Möglichkeiten PWM zu erzeugen.
Fang am besten mit Timer 2 an.
Der ist ja nur 8 Bit breit und hat eine direkte Pinanbindung.
Stell den Prescaller ein, damit er einfach vor sich hin läuft.

Mit den Bits COM20 und Com21 erreichst Du, daß der OC2 Pin bei Timerwert 0 auf low geht und bei Compare Match auf High.
Jetzt nur noch in OCR2 Register Deinen Wert bei dem Comparematch auftreten soll (0x80 gibt z.B 50 % Duty Cycle) , fertig
OCR2 kannst Du dir dann verändern, wie Du willst.
Mehr mußt Du nicht machen, der Timer läuft ohne Dein zutun, auf OC2 kriegst Du schön Dein PWM Signal, nur vergiß nicht den als Ausgang zu konfigurieren !
Wenn Du noch fragen hast, oder es doch nicht klappt, schicke ich Dir gerne ein Beispielprogramchen.

Gruß Sebastian

cmc
11.04.2007, 07:43
Danke für die Antwort werde mich heute mal drann machen.

oberallgeier
23.10.2007, 10:26
Hallo izaseba,


.........Wenn Du noch fragen hast, dann frag...Gruß Sebastian
Na ja, ich hätte da grad eine klitzekleine zu dem Thema (suche grad verzweifelt rum und find nix)
>>> Kann ich im AVRStudio einen Timer-Interrupt (erstmal den, später auch andere...) auslösen? Wie geht das? Ich sehe in "Debug" nur so "... geh bis zum nächsten Breakpoint..." aber ICH kann keinen Interrupt auslösen :(. Ich habs schon mit dem Setzen von OCF0A, OCF0B und TOV0 (der Reihe nach und auch zusammen) im TIFR0 probiert - hilft nix, ich erreiche nie den Breakpoint in der ISR. Dabei steht im Handbuch (Seite 60) "... TOV0 can be used for generating a CPU interrupt ...". Weisst Du da einen Rat?

Danke schon mal jetzt.

izaseba
23.10.2007, 19:40
Hallo Joe,
Wie willst Du den Interrupt auslösen ?
Durch setzen einer 1 in TOV0 ?
Du ich glaube, das geht nicht, Das wäre dann etwa ein Softwareinterrupt.
Durch schreiben einer 1 in TOV0 (wie auch viele andere Flags) wird der Flag gelöscht !
Es gibt also meiner Meinung nach keine Möglichkeit den Interrupt per Hand auszulösen :-k
Da mußt Du schon den Timer richtig laufen lassen, klappt das nicht in AVRStudio?
Ich bin mir ziemlich sicher, das es klappt.

Gruß Sebastian

oberallgeier
23.10.2007, 21:30
Schönen Abend, izaseba,

danke, aus Deiner Antwort sehe ich, dass es keinen allzu einfachen Weg in der Simulation gibt. Das hilft mir (hatte schon Angst, dass ich etwas übersehen hätte).

Mittlerweile spiele ich real an meinem tiny13 mit dem CTC Interrupt und einer relativ langen ISR. Die Laufzeit der ISR messe ich mit der stop watch im AVRStudio - in einer "ganz normalen Routine". Und rechne die auf meinen Prozessortakt um. Klappt ziemlich gut. Und ich finde mich damit ab, dass es "um die Ecke" gedacht bzw. getestet ist.

Danke für Deinen Rat.

oberallgeier
27.10.2007, 08:26
Hallo Sebastian,


Hallo Joe,
Wie willst Du den Interrupt auslösen ?
Durch setzen einer 1 in TOV0 ?
Du ich glaube, das geht nicht, Das wäre dann etwa ein Softwareinterrupt.
Durch schreiben einer 1 in TOV0 (wie auch viele andere Flags) wird der Flag gelöscht !
Es gibt also meiner Meinung nach keine Möglichkeit den Interrupt per Hand auszulösen :-k
Da musst Du schon den Timer richtig laufen lassen, klappt das nicht in AVRStudio?
Ich bin mir ziemlich sicher, das es klappt.

Gruß Sebastian

JAAAAA - es klappt mit dem Interrupt - aber nicht "von Hand". Ich habe im AVRStudio/Debugmodus die Routine laufenlassen und einen Breakpoint am ersten statement in der ISR gesetzt, und - siehe da - dort wird hingesprungen. Es sieht gut aus!!!