Hallo Leute ich ahbe ewin problem aber finde den fehler nicht ich
schreibe OK in mein LCD lege dann in r18 die zahl 20ab und vergleiche
beim nächsten laden r18 und die zahl 20 wenn beides gleich ist soll er
die funktion in der er das display neu beschreibt überspringen die
lcd-routines.asm kommt hier ausem tut
1
;main.asm
2
.include "m8515def.inc" ; Definitionsdatei für den Prozessortyp einbinden
3
4
.def temp1 = r16 ; register bestimmen
5
.def temp2 = r17
6
.def temp3 = r18
7
8
ldi temp1, LOW(RAMEND) ; LOW-Byte der obersten RAM-Adresse
9
out SPL, temp1
10
ldi temp1, HIGH(RAMEND) ; HIGH-Byte der obersten RAM-Adresse
rjmp main
Wie wärs mit einem einfachen RET?
rcall lcd_flash_string ; Unterprogramm gibt String aus der
Und wohin springt das Programm ab hier?
Auch hier fehlt ein RET
rcall lcd_flash_string
ist eine lcd routine die den Text ans LCD weitergiebt
wohin soll ich zurückspringen? und reintehortis ist es doch egal weil
das r19 ja auf 20 gesetzt wurde und somit einfach beim nächsten
durchlauf zur main zurückgesprungen wird.
wenn es geht könntet iht mir rin beispiel machen ich bin anfänger was
asm angeht
ja das tue ich ja durch eure beispiele :) ich lerne beim abtippen in dem
ichmir die aufgaben der funktionen vor augen halte
aber... habe das gerade mal eingefügt und aufen avr geladen aber er
aktualisiert noch immer dauerhaft i-was passt da nich
Sven M. schrieb:> aber... habe das gerade mal eingefügt und aufen avr geladen aber er> aktualisiert noch immer dauerhaft i-was passt da nich
Watchdog aktiv?
und ich kann nunmal nicht in einer extraschleife warten... weil nachher
sollen dort abfragen gemacht werden und diese rufen nunmal bei jdem
durchlauf lcd_ok auf
Sven M. schrieb:> ja das tue ich ja durch eure beispiele :) ich lerne beim abtippen
Das glaub ich ehrlich gesagt so nicht ganz
> in dem> ichmir die aufgaben der funktionen vor augen halte
Du beachtest die Details viel zu wenig.
Irgendwo hast du den Befehl rcall gesehen und jetzt verwendest du ihn
ohne zu wissen was er GENAU macht und wann man ihn einsetzt.
> aber... habe das gerade mal eingefügt und aufen avr geladen aber er> aktualisiert noch immer dauerhaft i-was passt da nich
Wie sieht dein Programm jetzt aus?
Es gibt hunderte Möglichkeiten was du beim 'jetzt einsetzen' wieder
falsch gemacht haben kannst. Und genau deswegen ist abtippen so
problematisch. Viel besser wäre es, wenn Hinweise ausreichen würden, du
darüber nachdenkst und dann selbst auf die Änderung kommst. Ein fertiges
Ergebnis nachzuvollziehen ist zwar ein erster Schritt, aber es ist eben
nur nachvollziehen und nicht selbst draufkommen. (Das ist die Sache mit
dem Ei des Kolumbus. Sich eine Lösung präsentierten zu lassen ist
einfach, auf eine Lösung zu kommen ist ungleich schwieriger)
da gehört kein rjmp hin.
Du bist über einen rcall an diese Stelle gekommen. Dass du zwischendurch
mal einen breq gemacht hast ist irrelevent. Der rcall von main wartet
immer noch auf seine Auflösung durch einen ret. Machst du ihn nicht,
geht dir irgendwann der Stack über.
Das ist doch nicht so schwer.
Mittels rcall springst du irgendwo hin. Dabei wird die Adresse des
Befehls nach dem rcall auf den Stack abgelegt. Am Sprungziel kannst du
dann machen was du willst, du musst nur:
* den Stack wieder in den gleichen Zustand bringen wie nachdem der rcall
gesprungen ist. Sprich immer gleich viele Push wie Pop haben
* mittels einem RET wieder zurück zu der Stelle springen, von wo der
rcall gekommen ist. Das geht deswegen, weil ja die Adresse vom rcall auf
dem Stack abgelegt wurde.
Verletzt du eine der beiden Voraussetzungen, dann läuft dir unweigerlich
irgendwann der Stack über und grausame Programmabstürze bzw. seltsames
Programmverhalten sind die Folge.
Hallo Leute,
sry muss euch noch ein mal nerfen undzwar geht es darum kann ich auch
nur 1Pin von z.B. PortD als eingang benutzen und die restlichen als
ausgang?, wenn ja wie mach ich das mit dem auslesen des pins und mit den
ausgeben von signalen über die anderen Pins?
Hi
>sry muss euch noch ein mal nerfen undzwar geht es darum kann ich auch>nur 1Pin von z.B. PortD als eingang benutzen und die restlichen als>ausgang?,
Ja.
> wenn ja wie mach ich das mit dem auslesen des pins und mit den>ausgeben von signalen über die anderen Pins?
sbic
sbis
sbi
cbi
and(i)
MfG Spess
Sven M. schrieb:> Hallo Leute,> sry muss euch noch ein mal nerfen undzwar geht es darum kann ich auch> nur 1Pin von z.B. PortD als eingang benutzen und die restlichen als> ausgang?, wenn ja wie mach ich das mit dem auslesen des pins und mit den> ausgeben von signalen über die anderen Pins?AVR-Tutorial
gleich das erste Kapitel in dem das erste mal programmiert wird.
ehhmm ....
ich bin gerade dabei ein timer zu programmeren aber sobald ich
.org OVF1addr
rjmp power_on ; Timer Overflow Handler
bestimme wo hin der overflow gehen soll wird meine LCD ausgabe nur noch
swartz
1
main.asm!!
2
3
.include "m8515def.inc" ; Definitionsdatei für den Prozessortyp einbinden
4
5
.def temp1 = r16 ; register bestimmen
6
.def temp2 = r17
7
.def temp3 = r18
8
.def temp4 = r20
9
10
.org OVF1addr
11
rjmp power_on ; Timer Overflow Handler
12
13
ldi temp1, LOW(RAMEND) ; LOW-Byte der obersten RAM-Adresse
14
out SPL, temp1
15
ldi temp1, HIGH(RAMEND) ; HIGH-Byte der obersten RAM-Adresse
16
out SPH, temp1
17
ldi temp1, 0xFF ; I/O's setzen
18
out DDRC, temp1 ; Port C als ausgang setzen
19
ldi temp1, 0xb00000011 ; I/O's setzen
20
out DDRA, temp1 ; PortA Pin A0 un A1 als ausgang setzen
Hi
>und eigendlich habe ich kein fehler gemacht :/ oder seht ihr einen?
Einen?
An den Anfang des Programms (Adresse $0000) gehört ein Sprung zum
eigentlichen Programmanfang.
Interrupts werden mit 'reti' abgeschlossen.
Was soll der Mist mit 'rcall main'?
MfG Spess
an der Adresse $0000 beginnen die Sprungvektoren
der erste an adr.0 zeigt auf die adr. wo der Proz. nach einem Reset
seine Programausführung startet.
Ich hab mir grad mal das tut angesehen und musste leider feststellen das
darauf nicht eingegangen wird . In dem guten glauben das der Proz seinen
Speicher linear abgrast und schon das macht was er machen soll wenn er
an der entsprechenden Stelle ankommt, was ja leider auch zu 90% klappt.
Aber ein sauberer Programmierstil ist es nicht , und führt halt dazu das
wenn Programmteile abgeschrieben und verändert werden die funktionalität
nicht mehr gewährleistet ist.
mfg
HI
>kannst du mir das mal erklären?
Ja. Der Controller fängt nach einem Reset An der Adresse $0000 an das
Programm abzuarbeiten. Ab Adresse, je nach Controller, $0001 oder $0002
beginnt die Interruptvektortabelle. Um diese zu 'überspringen' setzt man
an auf $0000 einen Sprung zum eigentlichen Programmanfang.
Bei mir sieht der Rumpf eines Programms wie im Anhang aus.
Nachtrag:
In Interrupts muss man SREG sichern.
>ja das tue ich ja durch eure beispiele :) ich lerne beim abtippen in dem>ichmir die aufgaben der funktionen vor augen halte>aber... habe das gerade mal eingefügt und aufen avr geladen aber er>aktualisiert noch immer dauerhaft i-was passt da nich
Irgendwie klappt das nicht so richtig. Deine Programmiererei sieht
Sch... aus.
MfG Spess
Hi
Henrik schrieb:> Niemand hat hier übrigens etwas gegen Punkt oder Kommasetzung. Vllt> gehts nur mir so, aber deine Texte sind schwierig zu lesen...
Rate mal, weshalb das Programm so konfus ist.
MfG Spess
okay soweit habe ich jetzt verstanden wie ihr das meint :)
danke schonmal nur jetzt meine letzte frage is Timer 1 so richtig
initalisiert?
1
ldi temp4, 0xB1
2
out TCNT1L, temp4 ; set preset in
3
ldi temp4, 0xE0
4
out TCNT1H, temp4 ; set preset in
5
ldi temp4, 0b00000001 ; CS00 setzen: Teiler 1
6
out TCCR1B, temp4
7
ldi temp4, 0b00000100 ; TOIE1: Interrupt bei Timer Overflow
8
out TIMSK, temp4
also der timer soll alle 20sek einen Overflow erzeugen bei einer frquenz
von 1Mhz
ichweiß halt nich ob das mit dem vorladen richtig ist also der Wert
45536 sollte vorgeladen werden.
Stimmt das alles so?
> ldi temp4, 0b00000100 ; TOIE1: Interrupt bei Timer Overflow
8
> out TIMSK, temp4
9
>
Tu das nicht. (Schön langsam werde ich es leid immer wieder dasselbe
predigen zu müssen).
So muss jeder im Datenblatt nachsehen, ob zb 0b00000100 wirklich das
TOIE1 Bit in TIMSK ist.
Schreibst du es so
1
ldi temp4, (1<<TOIE1)
2
out TIMSK, temp4
braucht zumindest dieses Detail niemand nachschlagen.
Wenn du den Timer mit 45536 vorladen willst, dann ist das dümmste was du
tun kannst, dir selber diese Zahl in Hex umzuwandeln und dann die Bytes
zuzuweisen
1
ldi temp4, Low(45536)
2
out TCNT1L, temp4 ; set preset in
3
ldi temp4, High(45536)
4
out TCNT1H, temp4 ; set preset in
Kannst du sehen, warum diese Schreibweise sehr viel besser ist als
deine?
Das Tutorial ist voll mit derartigen Kleinigkeiten, die man nicht alle
im Text beschrieben wiederfindet. Nur muss man den Code auch aufmerksam
studieren! Nicht auf jeden Pfurz wird man extra hinbgewiesen, vieles
muss man sich selbst erarbeiten, indem man sich fremde Programme
ansieht. Und zwar genau ansehen! Nicht einfach drüberlesen und 'Aha'
sagen, sondern studieren! Wie hat der Autor bestimmte Dinge gelöst? Was
ist die Idee hinter einer SChreibweise? Welchen Vorteil hat sie? Was
bringt sie mir als Programmierer? Welchen Fehler kann ich dadurch
vermeiden? Welches Fehlerpotential gibt es überhaupt an dieser Stelle,
so dass man eine bestimmte Schreibweise bevorzugt um ihn nicht zu
machen? etc. etc. Vielleicht hat der Autor auch geschlampt und genau
etwas gemacht, was man so nicht macht.
Das ist 'Studieren eines Codes' und nicht einfach nur 'abschreiben'.
Durch 'studieren' lernst du. Durch 'abschreiben' lernst du nichts.
Und arbeite an deinem Codestil. Alles an den linken Rand zu quetschen
ist kein Codestil!
In einem gewissen Sinne hat Spess weiter oben nämlich schon recht. Die
Programmierer mit dem grauslichsten, unübersichtlichsten Code sind
meistens auch diejenigen, die die meisten (dummen) Fehler machen.
Ein dummer Fehler ist es zb. erst das Low-Register und erst dann das
High Register zu beschreiben. Ob das jetzt das Count Register vom Timer
oder der Stackpointer ist, spielt keine Rolle. Oder findest du im
Tutorial ein Beispiel dafür wo der Stackpointer genau anders herum (wie
bei dir) initialisiert wird?
Hi
>Stimmt das alles so?
Nein.
>ldi temp4, 0xB1>out TCNT1L, temp4 ; set preset in>ldi temp4, 0xE0>out TCNT1H, temp4 ; set preset in
Beim Schreiben von 16-Bit_Registern erst H-Teil. dann L-Teil. Beim Lesen
umgedreht.
Dem Timer ist es ziemlich egal, wo er anfängt. Der nächste Durchlauf
fängt dann wieder bei Null an. Preload ist Müll. Dafür gibt es CTC.
Tu bitte dir, und uns einen Gefallen und lies dir das Datenblatt von
deinem Controller durch und arbeite dich durch das Tutorial. Oder wie
lange meinst du, will hier irgend jemand ständig den Müll, den du durch
deine vermeidbare Unkenntnis produzierst, korrigieren. Fang erst mal mit
kleineren Brötchen an.
MfG Spess