www.mikrocontroller.net

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


Autor: kuku (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Otto (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Otto (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
geht natürlich auch mit Zahlen:

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

Otto

Autor: kuku (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Falk (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Jörg X. (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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 ? 
;)

Autor: Otto (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: kuku (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Hannes Lux (hannes)
Datum:

Bewertung
0 lesenswert
nicht 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:
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...


bimu:                   ;Bitmuster für Display-Segmente
.db 0b01000001,0b01011111   ;0, 1
.db 0b00110001,0b00010101   ;2, 3
.db 0b00001111,0b10000101   ;4, 5
.db 0b10000001,0b01011101   ;6, 7
.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...

...

Autor: Falk (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: kuku (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Falk (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: kuku (Gast)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Falk.
Hier ist das Quellcode.
Für jede Verbesserung bin ich dankbar.

kuku

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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.
  mov   temp,r0         ;in R0

;*******************************************************
;Ausgabe am Port B
  out portb, temp

;*******************************************************    
;Testtabelle:
;7-Segment anzeige mit gemeinsamen Kathode
;      
;        a
;      -----
;     f| g |b
;      -----
;     e| d |c  *
;      -----
;        abcdefg*
tab:  .db 0b11111100  ;0
      .db 0b01100010  ;1
      .db 0b11011010  ;2
      .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...

Autor: Falk (Gast)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Siehe Anhang.

MFG
Falk

Autor: Falk (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Mist, eine Minute zu langsam! ;-)

MFG
Falk

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Dafür hab ich den 'ret' am Ende übersehen :-)

Autor: kuku (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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

#include <avr/io.h>
#include <stdtypes.h>

uint8_t Digits[] = { 0b11111100,    // 0
                     0b01100010,    // 1
                     0b11011010,    // 2
                     0b11110010,    // 3
                     0b01100110,    // 4
                     0b10110110,    // 5
                     0b10111110,    // 6
                     0b11100000,    // 7
                     0b11111110,    // 8
                     0b11110110,    // 9
                     0b11101110,    // A
                     0b00111110,    // b
                     0b10011100,    // C
                     0b01111010,    // d
                     0b10011110,    // E
                     0b10001110,    // F
                     0b00100000,    // i
                     0b00101010,    // n
                     0b00101110,    // h
                   };

int main()
{
  DDRB = 0b11111111;

  PORTB = Digits[0];

  while( 1 ) {
  }
}

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.


Autor: Falk (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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


Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Hannes Lux (hannes)
Datum:

Bewertung
0 lesenswert
nicht 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.

...

Autor: Falk (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.