kann mir jemand helfen, wie man die tabelle im Assembler programmiert
und die liest. hab folgendes vor. ich will ein wert durch
tastendrücken, wie bei einer uhr einlesen und über 7 segment anzeige
anzeigen lassen. hat jemand ideen, wie man sowas macht.
danke im voraus
Hallo kuku,
ein Beispiel für eine Tabelle:
Laden der Tabellenwerte:
========================
ldi ZH,high(t_text<<1) ;test - text
ldi ZL,low(t_text<<1) ;
lpm ;load program memory
mov temp,S ;in R0(=S)
Positionieren auf das nächste Element:
======================================
inc ZL
Tabelle:
========
t_text:
.db "Dies sind Deine Daten!"
Gruss Otto
Hallo Otto, danke für dein Antwort.
Ich habe die Tabelle in Quellcode implimentiert. Kann alle Werte der
Tabelle auslesen und auf das Port ausgeben.
Weitere Frage, wenn ich einen bestimmten Wert der Tabelle auslesen will,
wie soll ich hier vorgehen.
In deinem Beispiel wird nur ZL inkrementiert, und was ist mit dem ZH,
warum wird ZH nicht verändert.
Gruss kuku
@kuku
>Weitere Frage, wenn ich einen bestimmten Wert der Tabelle auslesen will,>wie soll ich hier vorgehen.
ldi zl, low(t_text+offset)
ldi zh, high(t_text+offset)
lpm
>In deinem Beispiel wird nur ZL inkrementiert, und was ist mit dem ZH,>warum wird ZH nicht verändert.
Schlechte Programmierung. Normalerweise muss es immer eine 16 Bit
Operation sein.
ldi r16,low(increment)
add zl,r16
ldi r16,high(increment)
adc zh,r16
(4 Worte, 4 Takte)
oder wenn man nur um 1 erhöhen will, einfach einen Dummyzugriff mit
Postincrement machen, spart Speicher und ist schneller
ld r16,z+
(1 wort, 2 Takte)
MFG
Falk
es gibt noch "adiw" und "sbiw", auch jeweils 1 Word, 2 Takte, aber eine
Konstante 0-63,
@kuku (Gast): aber warum schau ich ins "instruction Set" und nicht du ?
;)
>Schlechte Programmierung. Normalerweise muss es>immer eine 16 Bit Operation sein.
Wenn die Tabelle die richtige Basisadresse hat
und auf maximal 256 Elemente zugegriffen wird ?
Es war:
>ein Beispiel für eine Tabelle:
Otto
@Jörg X. (Gast):"instruction Set" ist auf Englisch, und ich habe
gewaltige Probleme damit.
Wenn jemand mir einen Link geben würde, wo man das alles in deutsche
Sprache nachlesen kann. Das wäre super.
kuku
kuku wrote:
> @Jörg X. (Gast):"instruction Set" ist auf Englisch, und ich habe> gewaltige Probleme damit.
Ohne Englisch wird es nix werden. Ich hatte auch nie
Englisch-Unterricht. Ich habe mich mittels Wörterbuch durch die
Datenblätter gewühlt. Inzwischen brauche ich das Wörterbuch immer
seltener.
> Wenn jemand mir einen Link geben würde, wo man das alles in deutsche> Sprache nachlesen kann. Das wäre super.
Befehlssatz auf Deutsch gibt's bei ELEKTOR. Das Buch
"AVR-Mikrocontroller-Praxis" von Volpe ist nichts Anderes als eine
(fehlerhafte) Übersetzung des Befehlssatzes. Kostet etwa 40 Euro. Falls
Du mein (gebrauchtes und korregiertes) haben willst, wird es geringfügig
billiger.
Nun zum Thema:
Meine Routine, die im Multiplex die Bitmuster in das Display schreibt,
sieht so aus:
1
setseg: ;UP, setzt Segmente am Display
2
ldi zl,low(bimu*2) ;Z-Pointer auf Anfang
3
ldi zh,high(bimu*2) ;der Tabelle mit Bitmustern
4
add zl,wl ;Zahlenwert addieren
5
adc zh,null ;evtl. Übertrag auch
6
lpm wl,z ;Bitmuster aus Flash holen
7
out segport,wl ;und an Segment-Port ausgeben
8
ret ;zurück...
9
10
11
bimu: ;Bitmuster für Display-Segmente
12
.db 0b01000001,0b01011111 ;0, 1
13
.db 0b00110001,0b00010101 ;2, 3
14
.db 0b00001111,0b10000101 ;4, 5
15
.db 0b10000001,0b01011101 ;6, 7
16
.db 0b00000001,0b00000101 ;8, 9
Der Zahlenwert wird dem Unterprogramm im Register "wl" übergeben. Das
Unterprogramm richtet den Zeiger auf das benötigte Element der Tabelle
(bimu) ein, holt das Bitmuster und gibt es an dem Port (segport) aus, an
dem die Segmente angeschlossen sind.
Man hole sich also den benötigten Zahlenwert (der jeweiligen
Anzeigestelle), achte dabei darauf, dass er nicht kleiner als 0 und
größer als 9 sein kann, und rufe diese Routine auf. Fertig...
...
@Otto
>>Schlechte Programmierung. Normalerweise muss es>>immer eine 16 Bit Operation sein.>Wenn die Tabelle die richtige Basisadresse hat>und auf maximal 256 Elemente zugegriffen wird ?
Das stand da aber nirgendwo.
>Es war:>>ein Beispiel für eine Tabelle:
Ja, ein schlechtes, oder zumindest unvollständiges. Dutzende Anfänger
machen das 1:1 nach und schreien dann hier rumm wenns klemmt. -> Nicht
gut.
MfG
Falk
Hab die Routine mit Offset von Falk ausprobiert, kann die Werte
einlesen, in richtigen reinfolge, aber nicht die, die ich eingentlich
haben will. In hex-Datei liegen die Werte der Tabelle am Ende,
eingelesen wird irgenwo von der mitte. Wieso, hab noch nicht
rausgefunden. Es könnte vielleicht am meinem Quellcode liegen.
Die Routine von Hannes Lux funktioniert einwandfrei.
Ich bedanke mich bei Otto, Falk, Jörg X. und Hannes Lux, die mir bei
Lösung des Problems geholfen haben. Hoffentlich hab ich keinen
vergessen.
MfG kuku
@kuku
>eingelesen wird irgenwo von der mitte. Wieso, hab noch nicht>rausgefunden. Es könnte vielleicht am meinem Quellcode liegen.
Dann lass mal sehen. Aber möglichst als Anhang.
MFG
Falk
Dein µC hält nicht einfach an, nur weil den Source
Code zu Ende ist. Der macht weiter und interpretiert
jedes Byte das ihm im Flash unterkommt als Befehl.
Insbesondere macht der µC nach
out portb, temp
weiter und holt sich den nächsten Befehl. Der Binärcode dieses
Befehls lautet 0b11111100 und mit dem Instruction Set könnte
man jetzt auch rauskriegen, was dieser Befehl machet. Egal.
Wenn dieser Befehl abgearbeitet ist, kommt der nächste drann.
Sein Binärcode lautet 0b01100010. Wieder: Mit dem Instruction
Set könnte man rauskriegen was das für ein Befehl ist.
Wenn dein Programm soweit abgearbeitet ist, dass es
für den µC nichts mehr zu tun gibt, musst du ihn trotzdem
beschäftigen. Und wenn es nur eine Endlosschleife ist,
in der du ihn gefangen hälst.
Zum Thema Tabelle:
ldi ZH,high(tab+1)
ldi ZL,low(tab+1)
Du hast nicht richtig acht gegeben. Sonst wär dir aufgefallen,
dass die Adressangabe bei den gezeigten Beispielen immer
verdoppelt wird (also einen Faktor *2 enthält).
setseg: ;UP, setzt Segmente am Display
ldi zl,low(bimu*2) ;Z-Pointer auf Anfang
ldi zh,high(bimu*2) ;der Tabelle mit Bitmustern
add zl,wl ;Zahlenwert addieren
adc zh,null ;evtl. Übertrag auch
lpm wl,z ;Bitmuster aus Flash holen
out segport,wl ;und an Segment-Port ausgeben
ret ;zurück...
kuku wrote:
> Danke, hab Verbessert. Funktioniert.> ich bin halt Anfänger. ich wußte, daß das so kompliziert ist, aber wie> es aussieht, ist es noch schlimmer.
Wenn dir das kompliziert vorkommt:
Warum tust du dir dann Assembler an?
Nicht falsch verstehen: Ich bin ein starker Verfechter
der Fraktion, die einen Einstieg mit Assembler befürwortet.
Aber ansonsten nehm ich für sowas C. Da kümmert sich der
Compiler um all die kleinen Details
1
#include<avr/io.h>
2
#include<stdtypes.h>
3
4
uint8_tDigits[]={0b11111100,// 0
5
0b01100010,// 1
6
0b11011010,// 2
7
0b11110010,// 3
8
0b01100110,// 4
9
0b10110110,// 5
10
0b10111110,// 6
11
0b11100000,// 7
12
0b11111110,// 8
13
0b11110110,// 9
14
0b11101110,// A
15
0b00111110,// b
16
0b10011100,// C
17
0b01111010,// d
18
0b10011110,// E
19
0b10001110,// F
20
0b00100000,// i
21
0b00101010,// n
22
0b00101110,// h
23
};
24
25
intmain()
26
{
27
DDRB=0b11111111;
28
29
PORTB=Digits[0];
30
31
while(1){
32
}
33
}
Kein Problem mit der Größe der Interrupt Tabelle, den
Tabellenzugriff macht dir der Compiler korrekt und wenn
du die Endlos-while Schleife vergisst, dann fängt dich
das gcc-C-System auf und ergänzt die auch noch für dich.
Ganz abgesehen davon, dass du den Eiertanz um die Register-
belegung los bist.
@Karl heinz Buchegger
>Wenn dir das kompliziert vorkommt:>Warum tust du dir dann Assembler an?>Aber ansonsten nehm ich für sowas C. Da kümmert sich der>Compiler um all die kleinen Details
Naja, aber gerade auch in C gibt es MEHR als genug Möglichkeiten, sich
als Anfänger in den Fuss zu schiessen.
Als ich damals mit C angefangen habe konnte ich bereits sehr gut
programmieren, in Pascal, Basic, Assembler.
Was ich geflucht habe . . . 8-0
Teufel und Belzebub.
MfG
Falk
Falk wrote:
>> Naja, aber gerade auch in C gibt es MEHR als genug Möglichkeiten, sich> als Anfänger in den Fuss zu schiessen.
Ja klar. Das ist ja das schöne daran :-)
Aber in C musst du wenigstens noch 'den Abzug betätigen', in
Assembler reicht es schon wenn man einmal kurz wegschaut :-)
> Als ich damals mit C angefangen habe konnte ich bereits sehr gut> programmieren, in Pascal, Basic, Assembler.> Was ich geflucht habe . . . 8-0
Fluchen ist die Sprache die alle Programmierer beherrschen.
>> Teufel und Belzebub.
Drum ist ein Bund Knoblach am Monitor nie verkehrt.
@kuku:
Ein wichtiger Hinweis noch:
Bitte in einer Tabelle im Flash darauf achten, dass jede Zeile eine
gerade (durch zwei teilbare) Anzahl von Bytes enthält. Beachtet man das
nicht, fügt der Assembler von sich aus Nullbytes ein. Der Grund dafür
ist, dass der Flash wordorentiert adressiert ist (ein Word sind zwei
Bytes, also 16 Bit), der LPM-Zugriff aber byteorientiert erfolgt
(derhalb wird die Adresse ja auch verdoppelt, siehe Beschreibung des
Befehls LPM).
Achja, Z-Pointer muss auf Adresse * 2 (Adresse mal 2),
nicht auf Adresse mal 2 plus 1, das geht daneben.
...
@Hannes Lux
>Achja, Z-Pointer muss auf Adresse * 2 (Adresse mal 2),>nicht auf Adresse mal 2 plus 1, das geht daneben.
Das +1 ist doch Absicht, er will auf die einzelnen Elemente zugreifen.
MFG
Falk