LCD wird immer aktualisiert

Gast #2001090
Lesenswert?

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
11
out SPH, temp1
12
ldi temp1, 0xFF ; I/O's setzen
13
out DDRC, temp1 ; Port C als ausgang setzen
14

15
rcall lcd_init ; Display initialisieren
16
rcall lcd_clear ; Display löschen
17
rcall main
18

19
main:
20
rcall lcd_ok ; lcd Ausgabe OK aufrufen
21

22
.include "lcd-routines.asm" ; lcd Arbeitsbefehle laden
23
.include "lcd-ausgaben.asm" ; lcd ausgaben laden
1
;lcd-ausgaben.asm
2

3
lcd_ok:
4
  cpi r19, 20
5
  brne lcd_ok_1
6
  ldi r19, 20
7
  rjmp main
8

9
lcd_ok_1:
10
  ldi ZL, LOW(text_ok*2) ; Adresse des Strings in den
11
  ldi ZH, HIGH(text_ok*2) ; Z-Pointer laden
12
  rcall lcd_flash_string ; Unterprogramm gibt String aus der
13

14
text_ok:
15
.db "OK",0 ; Ausgabe bei keinen fehler
Gast #2001117
Lesenswert?

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
Moderator (Firma: Titel) Persönliche Seite #2001218
Lesenswert?

Sven M. schrieb:
> wohin soll ich zurückspringen?
Für dich uninteressant.
Das ret springt schon an die richtige Stelle zurück.
1
lcd_ok:
2
  cpi r19, 20
3
  brne lcd_ok_1
4
  ldi r19, 20
5
  ret
6

7
lcd_ok_1:
8
  ldi ZL, LOW(text_ok*2) ; Adresse des Strings in den
9
  ldi ZH, HIGH(text_ok*2) ; Z-Pointer laden
10
  rcall lcd_flash_string ; Unterprogramm gibt String aus der
11
  ret
Aber es ist klar, dass da dauernd was geschrieben wird, denn danach:
1
main:
2
rcall lcd_ok ;  lcd Ausgabe OK aufrufen
Wird irgendwann wieder von vorn begonnen....

So wird in der Mainloop gewartet:
1
main:
2
rcall lcd_ok ;  lcd Ausgabe OK aufrufen
3
mainloop:
4
rjmp mainloop

> sry... aber ich kann nunmal nix für mein unwissen
Aber dagegen: Lernen.
Gast #2001231
Lesenswert?

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
#2001292
Lesenswert?

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)
Gast #2001368
Lesenswert?

im übrigen auch ausgelagert läufts jetzt
1
.include "m8515def.inc" ; Definitionsdatei für den Prozessortyp einbinden
2

3
.def temp1 = r16 ; register bestimmen
4
.def temp2 = r17
5
.def temp3 = r18
6

7
ldi temp1, LOW(RAMEND) ; LOW-Byte der obersten RAM-Adresse
8
out SPL, temp1  
9
ldi temp1, HIGH(RAMEND) ; HIGH-Byte der obersten RAM-Adresse
10
out SPH, temp1
11
ldi temp1, 0xFF ; I/O's setzen
12
out DDRC, temp1 ; Port C als ausgang setzen
13

14
ldi r25, 10
15

16
rcall lcd_init ; Display initialisieren
17
rcall lcd_clear ; Display löschen
18
rcall main
19

20
main:
21
rcall lcd_ok
22

23
rjmp main
24

25
.include "lcd-routines.asm" ; lcd Arbeitsbefehle laden
26
.include "lcd-ausgaben.asm" ; lcd ausgaben laden
1
lcd_ok:
2
  cpi r25, 10
3
  breq lcd_ok_ja
4
  ldi r25, 11
5
  ret
6

7
lcd_ok_ja:
8
  ldi r25, 11
9
  ldi ZL, LOW(text_ok*2) ; Adresse des Strings in den
10
  ldi ZH, HIGH(text_ok*2) ; Z-Pointer laden
11
  rcall lcd_flash_string ; Unterprogramm gibt String aus der
12
  rjmp main
13
text_ok:
14
.db "OK",0 ; Ausgabe bei keinen fehler
#2001380
Lesenswert?

Immer noch falsch
1
lcd_ok_ja:
2
  ldi r25, 11
3
  ldi ZL, LOW(text_ok*2) ; Adresse des Strings in den
4
  ldi ZH, HIGH(text_ok*2) ; Z-Pointer laden
5
  rcall lcd_flash_string ; Unterprogramm gibt String aus der
6
  rjmp main

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.
Gast #2001738
Lesenswert?

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?
Gast #2001747
Lesenswert?

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
Gast #2002816
Lesenswert?

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
21

22
ldi r25, 10
23

24
rcall lcd_init ; Display initialisieren
25
rcall lcd_clear ; Display löschen
26
rcall power
27
rcall main
28

29
main:
30
rcall lcd_ok
31

32
rjmp main
33

34
.include "lcd-routines.asm" ; lcd Arbeitsbefehle laden
35
.include "lcd-ausgaben.asm" ; lcd ausgaben laden
36
.include "power_supply.asm" ; 50hz ausgabe laden
37

38

39

40
lcd-ausgaben.asm!!!
41

42

43

44
lcd_ok:
45
  cpi r25, 10
46
  breq lcd_ok_ja
47
  ldi r25, 11
48
  ret
49

50
lcd_ok_ja:
51
  ldi r25, 11
52
  ldi ZL, LOW(text_ok*2) ; Adresse des Strings in den
53
  ldi ZH, HIGH(text_ok*2) ; Z-Pointer laden
54
  rcall lcd_flash_string ; Unterprogramm gibt String aus der
55
  ret
56
text_ok:
57
.db "OK",0 ; Ausgabe bei keinen fehler
58

59

60

61
power_supply.asm!!!
62

63

64

65
power:
66
ldi temp4, 0xB1
67
out TCNT1L, temp4         ; set preset in
68
ldi temp4, 0xE0
69
out TCNT1H, temp4         ; set preset in
70
ldi temp4, 0b00000001 ; CS00 setzen: Teiler 1
71
out TCCR1B, temp4
72
ldi temp4, 0b00000100 ; TOIE1: Interrupt bei Timer Overflow
73
out TIMSK, temp4
74
sei
75
ldi temp4, 0b00000001
76
ret
77

78
power_on:
79
cpi temp4, 0b00000001
80
breq power_low
81
ldi temp4, 0b00000001
82
out PORTA, temp4
83
ret
84

85
power_low:
86
ldi temp4, 0b00000010
87
out PORTA, temp4
88
ret

und eigendlich habe ich kein fehler gemacht :/ oder seht ihr einen?
Gast #2002830
Lesenswert?

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
Gast #2002881
Lesenswert?

zBsp.
1
 
2

3
.include "2313def.inc"
4
;.device AT90S2313
5

6
.def  T1    =r1
7
.def  T2    =r2
8

9

10
.equ  PreScal  =3  ;timer prescale by 64
11
.equ  C  =119  ;time 
12

13
;********************************************************
14
.eseg
15
.org 0              
16
    .db 89,6,79,2,71,4  
17
    .db 79,4,63,4,71,4  
18
    .db 79,2,94,2,89,4
19
    
20

21
;*******************************************************
22
.cseg
23
.org $0000                    !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
24

25
  rjmp RESET   ; Reset Handler
26
  reti     ;rjmp EXT_INT0 ; IRQ0 Handler
27
  reti     ;rjmp EXT_INT1 ; IRQ1 Handler
28
  reti     ;rjmp TIM_CAPT1 ; Timer1 Capture Handler
29
  reti     ;rjmp TIM_COMP1 ; Timer1 Compare Handler
30
  reti     ;rjmp TIM_OVF1 ; Timer1 Overflow Handler
31
  rjmp TIMER  ;    TIM_OVF0 ; Timer0 Overflow Handler
32
  reti     ;rjmp UART_RXC ; UART RX Complete Handler
33
  reti     ;rjmp UART_DRE ; UDR Empty Handler
34
  reti     ;rjmp UART_TXC ; UART TX Complete Handler
35
  reti     ;rjmp ANA_COMP ; Analog Comparator Handler
36

37
RESET:  
38
    ldi r16,low(RAMEND); Main program start
39
    out SPL,r16      ; !!!!! Set Stack pointer

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
Gast #2002887
Lesenswert?

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
Angehängte Dateien:
Gast #2002931
Lesenswert?

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?
#2002944
Lesenswert?

Sven M. schrieb:

>
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
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?
Gast #2002959
Lesenswert?

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

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren