Forum: Mikrocontroller und Digitale Elektronik Tabellen in Assembler für Atmega 16


von kuku (Gast)


Lesenswert?

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

von Otto (Gast)


Lesenswert?

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

von Otto (Gast)


Lesenswert?

geht natürlich auch mit Zahlen:

.db  0x00,0x01,0x0A,0xFF  ; Dummy - Daten

Otto

von kuku (Gast)


Lesenswert?

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

von Falk (Gast)


Lesenswert?

@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

von Jörg X. (Gast)


Lesenswert?

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 ? 
;)

von Otto (Gast)


Lesenswert?

>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

von kuku (Gast)


Lesenswert?

@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

von Hannes L. (hannes)


Lesenswert?

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...

...

von Falk (Gast)


Lesenswert?

@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

von kuku (Gast)


Lesenswert?

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

von Falk (Gast)


Lesenswert?

@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

von kuku (Gast)


Angehängte Dateien:

Lesenswert?

Hallo Falk.
Hier ist das Quellcode.
Für jede Verbesserung bin ich dankbar.

kuku

von Karl H. (kbuchegg)


Lesenswert?

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.
1
  mov   temp,r0         ;in R0
2
3
;*******************************************************
4
;Ausgabe am Port B
5
  out portb, temp
6
7
;*******************************************************    
8
;Testtabelle:
9
;7-Segment anzeige mit gemeinsamen Kathode
10
;      
11
;        a
12
;      -----
13
;     f| g |b
14
;      -----
15
;     e| d |c  *
16
;      -----
17
;        abcdefg*
18
tab:  .db 0b11111100  ;0
19
      .db 0b01100010  ;1
20
      .db 0b11011010  ;2
21
      .db 0b11110010  ;3

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...

von Falk (Gast)


Angehängte Dateien:

Lesenswert?

Siehe Anhang.

MFG
Falk

von Falk (Gast)


Lesenswert?

Mist, eine Minute zu langsam! ;-)

MFG
Falk

von Karl H. (kbuchegg)


Lesenswert?

Dafür hab ich den 'ret' am Ende übersehen :-)

von kuku (Gast)


Lesenswert?

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.

von Karl H. (kbuchegg)


Lesenswert?

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_t Digits[] = { 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
int main()
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.


von Falk (Gast)


Lesenswert?

@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


von Karl H. (kbuchegg)


Lesenswert?

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.

von Hannes L. (hannes)


Lesenswert?

@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.

...

von Falk (Gast)


Lesenswert?

@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

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
Noch kein Account? Hier anmelden.