Hallo,
ich habe folgende Schaltung aufgebaut und möchte diese nun in Betrieb
nehmen...
http://www.klaus-leidinger.de/mp/Mikrocontroller/7Segment/7Segment.html#oben
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)
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?
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:
1
;**** Includes ****
2
3
.include "m8def.inc"
4
5
;***** Pin definitions
6
7
.equ SSeg = PORTB ;Ausgabe Port
8
.equ SSegdr = DDRB ;Ausgabe Richtungsregister
9
.equ punkt = 7 ;'Punkt-Bit'
10
11
;***** Global register variables
12
13
.def temp = R16 ;Register zum Zwischenspeichern
14
.def zahl = R17 ;Zahl die ausgegeben werden soll
15
16
17
18
19
ausgabe:
20
ldi ZH,high(ziffer<<1) ;Z-Pointer mit Adresse
21
ldi ZL,low(ziffer<<1) ; der Tabelle laden
22
adc ZL, zahl ;Auszugebende Zahl mit Z-Pointer (LOW) addieren
23
brcc nc ;Testen ob Carry-Flag gesetzt ansonsten springen
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.
"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.
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
(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?
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?"
"...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
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.