www.mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik LED Multiplex ansteuern


Autor: Sven Scholz (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

ich habe folgende Schaltung aufgebaut und möchte diese nun in Betrieb
nehmen...

http://www.klaus-leidinger.de/mp/Mikrocontroller/7...

Ich benutze zur Ansteuerung den ATmega8 und verwende AVRStudio4 von
Atmel.
Da ich absoluter MC-Neuling bing, bräuchte ich etwas Unterstützung
hinsichtlich der Assembler-Programmierung.

Zunächst einmal möchte ich einen Zähler programmieren, der von 0000 bis
9999 hochzählt.
Hat vielleicht jemand einen passenden Quellcode hierfür oder eine
Hex-Datei, damit ich die Funktion der Schaltung überprüfen kann?

Für die Ansteuerung der einzelnen Segmente verwende ich den Port B.
Für das An- und Abschalten der 7-Segment-Anzeige habe ich den Port D
vorgesehen...


Vielen Dank schon mal.
(hoffentlich kann mir geholfen werden)

Autor: Sven Scholz (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hat denn noch niemand von euch so etwas programmiert? Ich dachte, dass
ich einen passenden Quellcode dafür, wie "Sand am Meer" finden würde
im Internet. Scheint doch wohl nicht so einfach zu sein wie?

Autor: Marco K. (Gast)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Servus Sven,
es ist nicht so das keiner 7-Seg. benutzt, aber die meisten benutzen
zum ansteuern noch ein Extra IC (I2C oder 4-Bit) um Pin's am
µ-Controller, Leitungen, Programmieraufwand und natürlich Rechenzeit zu
sparen. Da ich aber weiß wie schwer der Einstieg ins µ-Controller
programmieren ist geb ich dir hier mal ein paar Ansätze wie du dein
Programm schreiben könntest:
;**** Includes ****

.include "m8def.inc"

;***** Pin definitions

.equ  SSeg  = PORTB      ;Ausgabe Port
.equ  SSegdr  = DDRB      ;Ausgabe Richtungsregister
.equ  punkt  = 7        ;'Punkt-Bit'

;***** Global register variables

.def  temp  = R16      ;Register zum Zwischenspeichern
.def  zahl  = R17      ;Zahl die ausgegeben werden soll




ausgabe:
  ldi   ZH,high(ziffer<<1)  ;Z-Pointer mit Adresse 
  ldi   ZL,low(ziffer<<1)  ;  der Tabelle laden
  adc    ZL, zahl      ;Auszugebende Zahl mit Z-Pointer (LOW) addieren
  brcc  nc          ;Testen ob Carry-Flag gesetzt ansonsten springen
  inc    ZH          ;Z-Pointer (HIGH) Inkrementieren
nc:  lpm    temp, Z        ;Daten aus Tabelle laden
  out    SSeg, temp      ;Zahl auf 7-Segment ausgeben

  cbi    SSeg, punkt      ;Schaltet Punkt ein
  sbi    SSeg, punkt      ;Schaltet Punkt aus
  ret

ziffer:
  .db $81, $B7, $C2, $92, $B4, $B4, $98, $88, $B3, $80, $90 ;Tabelle mit
Ziffern von 0-9
Das wäre ein Unterprogramm um auf einer 7-Segment-Anzeige eine Zahl zu
bringen. Mit Tabellen zu arbeiten sieht am Anfang oft kompliziert aus,
ist aber extrem praktisch. Um die Befehle besser zu Verstehen zu können
hab ich dir noch das ATMEL Instruction-Set mit angehängt, da sind alle
Befehle der AVR's beschrieben.

Autor: Tobias Schneider (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Seit wann gibts denn hier source highlighting?

Gruss Tobias

Autor: Marco K. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hab ich Forum gelesen, und mußte des hier gleich mal ausprobier. ;-)

Gruß Marco

Autor: Marco K. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Servus Sven,

Ich hab auch noch ne Routine für dich gefunden die dir eine 16-Bit Zahl
in BCD umwandelt. Die BCD Zahlen kannst du dann auf deine 7-Segment
Anzeige ausgeben:

http://www.avr-asm-tutorial.net/avr_de/rechnen/kon...

Autor: Peter Dannegger (peda)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
"Hat denn noch niemand von euch so etwas programmiert?"

Doch, schon.

Aber als Anfänger sollte man lieber schrittweise vorgehen (LED an, aus,
blinken, Timerinterrupt usw.).


Fremde Quelltexte zu verstehen, fällt selbst alten Programmierhasen
schwer. Daher bezweifle ich stark, daß Dir ein fertiges Progamm was
nützt. Trotzdem hab ich mal eine einfache ADC-Anwendung rangehängt.

Fürs einfachere Layout haben Digit 0 und 2 bzw. Digit 1 und 3
unterschiedliche Pinbelegung, deshalb 2 7-Segmentkodetabellen.

Noch ein Trick dabei ist, daß der Timerinterrupt den ADC startet und
erst nach der Wandlung das nächste Digit eingeschaltet wird. Ansonsten
bewirkt nämlich der Stromverbrauch der LEDs kleine
Spannungsschwankungen und der Meßwert zappelt ständig.

Anders gesagt, ohne ADC macht man die Digitausgabe einfach direkt im
Timerinterrupt.


Aber wie gesagt, ohne Grundlagenkenntnisse, wird der Code wohl mehr
Fragen aufwerfen anstatt beantworten. Obwohls nur ein sehr kleines
Programm ist (sind ja nur 89 Words).


Peter


P.S.:
Man kriegt hier auch viel leichter Hilfe, wenn man seine eigenen
Lösungsschritte darstellt und konkrete Fragen hat, anstatt nach einer
Fixundfertig-Lösung zu schreien.

Autor: Sven Scholz (Gast)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Also ich habe jetzt meine ersten Gehversuche hinter mir und mein erstes
Ziel mehr oder weniger umgesetzt. Ist eine ganz schön Arbeit, das Ganze
richtig zeitlich hinzubekommen.

Habe den Quellcode als Anhang beigefügt. Vielleicht könnt ihr da ja mal
reinschauen und einige Bemerkungen dazu machen.

Mein nächstes Ziel ist es jetzt, unterschiedliche Ziffern für das
jeweilige Display auszugeben. Bis jetzt kann ich halt nur eine Ziffer
an alle 4 Displays schicken, die dann gleichzeitig angezeigt wird.
(z.B. 6666, 8888, 4444)

Bin aber jetzt ganz zuversichtig, dass ich das noch irgendwann mal
hinkriegen werde. Wenn man bedenkt, dass ich mich jetzt erst seit 8
Tagen mit dem Thema beschäftige.

Danach wäre eine Realisierung eines richtigen Counters angesagt, der
von 0000 bis 9999 in einer Schritten hochzählt.

Also, wenn ihr produktive Ideen oder Quellcodeschnipsel für mich habt,
dann bitte her damit...

Danke schon mal für die brauchbaren Tipps!

MfG,

Sven

Autor: Sven Scholz (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
(siehe Anhang vom Beitrag zuvor)

init:ldi r21,0x00 ;      hier steht sozusagen mein offset



main:

  ldi   ZH,high(zahlen<<1)  ;Z-Pointer mit Adresse
  ldi   ZL,low(zahlen<<1)  ;  der Tabelle laden
  adc    ZL, r21      ;Auszugebende Zahl mit Z-Pointer (LOW) addieren
  lpm zahl1, Z ; Load constant from Program
  lpm zahl2, Z;
  lpm zahl3, Z;
  lpm zahl4, Z;
  inc    ZH          ;Z-Pointer (HIGH) Inkrementieren

  cpi r21,10
  breq init          ; Sprung wenn Vergleich stimmt
    inc r21           ;für nächste Ziffer


  RCALL ausgabe
  rjmp main







Wie schaffe ich es nun, zahl2 immer dann um eins zu erhöhen, wenn zahl1
die 0 erreicht?

Ich brauche irgendwie mehr Zeiger, die meine "Zahlen-Tabelle" lang
wandern. Gibt es dafür irgendwie eine elegante Methode?

Autor: Sven Scholz (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
das ist ja so kompliziert...

also bin jetzt soweit, dass ich von 0000 bis 0099 hochzählen kann, doch
wird es jetzt zunehmend komplizierter, so dass ich mich langsam selbst
nicht mehr in meinem eigenen Quellcode zurechtfinde.

Brauche Unterstützung bei der Sache.
Ist da draußen nicht irgendwo ein "Assembler-Gott?"

Autor: Peter Dannegger (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
"...doch wird es jetzt zunehmend komplizierter..."


Es ist immer am einfachsten, die CPU in ihren Hausformat rechnen zu
lassen, also im Binärsystem.
Mit 2 Bytes kann man dann bis 65535 zählen.
Und erst zur Anzeige wandelt man in das Dezimalsystem um.
Für den Anfang ist es aber sinnvoll, erstmal nur ein Byte zu zählen und
anzuzeigen, also von 0 ... 255. Und wenn man das verstanden hat, weiter
zu gehen.

Wichtig ist es, alles in kleine Teilaufgaben zu zerlegen und nicht
gleich alles zusammen machen zu wollen.


Schau Dir mal in meinem Beispiel die Routine "decout" an.

Die macht nichts anderes, als eine 16Bit-Zahl in ihre 5 Digits zu
zerlegen.
Das 1. Digit wird weggeschmissen, da ich nur 4-stellig anzeige.
Und die anderen 4 Digits werden per LPM in den 7-Segmentcode gewandelt
und in den Anzeigeregistern abgelegt, von wo sie dann per
Timerinterrupt zyklisch ausgegeben werden.

Die Binär nach Dezimal Wandlung selber geschieht nach dem
Subtraktionsprinzip, d.h. man zählt einfach mit, wie oft 10000, 1000,
100 und 10 ohne Unterlauf abgezogen werden können.
Die Routine ist dann noch optimiert, indem absichtlich immer über den
Unterlauf bzw. Überlauf hinaus gezählt wird.


Peter

Autor: Marco K. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Servus Sven,

Respekt, für den den Anfang nicht schlecht.
Das mit dem riesigen unübersichtlichen Code ist typisch für Assembler,
da muss man wirklich sauber Programmieren und alles Aufteilen damit
sich später noch zurecht findet. Ein kleiner Tipp: Soviel wie möglich
mit Kommentaren versehen, sonst weiß man 2 Wochen später selbst nicht
mehr was welcher Befehl bewirken soll. Und mit der Zeit findest du auch
deinen eigenen Stil.
Zu deinem Programm:

An deiner Stelle würde ich wie Peter schon sagte zwei Register zum
Zählen nehmen und die vor jeder ausgabe in 4 BCD Zahlen umwandeln
lassen.
Zum Rückwärtszählen hät ich dir ein kleines Beispiel, dass mit dem
Y-Register (16 Bit) arbeitet.
init:
ldi   YL, $10      ;9999 in Y-Register laden
ldi   YH, $27

start:
rcall   ausgabe    ;Springe zum Ausgabe UP

sbiw  YH:YL,1      ;Y-Register dekrementieren
brne  init         ;Teste, ob Y = 0
rcall delay_loop   ;kurze Pause
jmp   start        ;Nächste Zahl

Gruß Marco

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.