Atmega8515 programmieren?

Hallo Michael!

Ich habe heute Abend mal selber versucht, Port`s abzufragen, und das auf einen anderen Port aus zugeben.

Code:
in portd,rega
out porta,rega
geht das so? oder gibt es da "feinere" Lösungen für ?
Das geht so nicht, zumindest dann nicht, wenn du die logischen Zustände der Pins eines Ports abfragen möchtest.
Ein Port hat ein Register (DDRx) mit dem du die Richtung (Direction) des Ports oder einzelner Pins eines Ports festlegst und ein Datenregister Register (PORTx). Mit dem Datenregister PORTx kannst du Daten am Port ausgeben, wenn der Port als Ausgang geschaltet ist oder die Funktion Tristate/Pullup einstellen, wenn der Port als Eingang geschaltet ist.

Wenn du PORTx ausliest, liest du nicht die logischen Zustände der Pins des Ports, sondern den Registerinhalt von PORTx.

Möchtest Du den logischen Zustand von Pins einlesen, musst du den entsprechenden Portpin mit DDRx als Eingang schalten, mit PORTx definierst du entweder Tristate (hochohmig) oder Pullup.

Einlesen kannst du nun den Zustand über PINx, Beispiel:
Code:
sbic PINA, PA0   ; skip, wenn PA0 logisch 0 ist
sbis PINA, PA0   ; skip, wenn PA0 logisch 1 ist
in RegA, PINA    ; alle logischen Zustände der Pins in RegA
Verzweigung, wenn PortD-Pin0 Low, bzw wenn Portd-Pin1 Low ist?
Zum Beispiel so (Pins vorher als Eingang mit Pullup beschalten):
Code:
sbis PIND, PD0
rjmp taste_pin0_gedrueckt
sbis PIND, PD1
rjmp taste_pin1_gedrueckt
Wenn ich nun Addition / Subtration mit dem "Rega" anstellen will (also + bzw - 1), was mach ich da ? Mit "add" berechne ich gleich 2 Byte, oder?
Code:
; 8bit Addition
add RegA, RegB     ; RegA = RegA + RegB (Bei Überlauf ist Bit c = 1)


; 16Bit Addition
ldi RegA, low(1000)   ; erste Zahl
ldi RegB, high(1000)
ldi RegC, low(3500)   ; zweite Zahl
ldi RegD, high(3500)

add RegA, RegC        ; erst niederwertige Bytes addieren
adc RegB, RegD        ; dann höherwertige Bytes addieren und Überlauf C berücksichtigen

; Bei Subtraktion funktioniert das äquivalent.

; Nun noch mit Konstanten subtrahieren:
subi RegA, 20     ; RegA = RegA-20

; Addieren mit Konstanten über subi
subi RegA, -20   ; RegA = RegA+20

; Addition von 1 (inkrementieren)
inc RegA

; Subtraktion von 1 (dekrementieren)
dec RegA
 
Klasse Dirk, habe ich mir gleich ausgedruckt!

Aber noch habe ich irgendwo einen Denkfehler:

Code:
abfrage:   ;so lange bis eine taste gedrückt wird
sbic pind,pd0
rjmp abfrage

Addi:
inc rege  ;einen dazu
out porta,rege  ; RegE auf PortA
rjmp pause  ; zur pausenroutine
rjmp abfrage ;zurück zur tastenabfrage

Pause:
   wdr                            ; Watchdog-Timer reset
   
   ldi RegA, 175
pause100_loop1: ldi RegB, 200 ; Schleife 3 : t3= (3+t2)*TempReg1
pause100_loop2: ldi RegC, 10  ; Schleife 2 : t2=(3+t1)*TempReg2
pause100_loop3: dec RegC      ; Schleife 1 : t1=2*TempReg1
   brne pause100_loop3 
   dec RegB           
   brne pause100_loop2            ; t3 = (3+(3+2*TempReg1)*TempReg2)*TempReg1
   wdr                            ; Watchdog-Timer reset unberuecksichtigt,
                                  ; kann hier jedoch vernachlaessigt werden!!!
   dec RegA                    
   brne pause100_loop1                
ret

In der Hoffnung dass nach jedem drücken der Taste ein aufsteigener Binärwert von RegE auf PortA ausgegen wird .........
Jedenfalls den ersten Tastendruck zeigt er auch an, jedoch nach der Pause geht die 1er LED wieder aus :confused:
(RegE = r23 , wird auch nicht weiter benutzt)


Wo ist mein Denkfehler??? Muss irgendwas mit der Pause zutun haben, denn ohne den Sprug zur Pause gehts ...

Die länge der Sprungmarken: ist das "egal" wie lang die Wörter sind, oder wird im fertigen Programm auch pro Buchstabe ein Byte verbraucht?
Also ob "abfr" und "abfrage" die selbe Anzahl von Bytes im Speicher belegen!?
 
Hallo Michael,
habe gerade leider nicht viel Zeit, ich kuck später nocheinmal ins Forum, was mir aber aufgefallen ist:

Code:
Addi:
inc rege  ;einen dazu
out porta,rege  ; RegE auf PortA
rjmp pause  ; zur pausenroutine
rjmp abfrage ;zurück zur tastenabfrage
Du macht einen rjmp zur Pause, und Pause wird mit ret (return) beendet. Du musst Pause mit "rcall Pause" aufrufen.

Bis dann
Dirk
 
Jawoll, das war der Fehler! Wär ich nie drauf gekommen. Habe bisher noch keinen Unterschied zwischen "irgendwo hin springen" und "Unterprogramm aufrufen" gesehen.

Ok, denn werd` ich mal noch ein wenig "Blödsinn" zusammen stellen (Nur so lernt man), die nächsten Fragen kommen bestimmt :eek:
 
Hallo Michael.
Habe bisher noch keinen Unterschied zwischen "irgendwo hin springen" und "Unterprogramm aufrufen" gesehen.
Mit "rjmp Label" springst du direkt zu dem label "Label:", das Programm wird an dieser Stelle fortgesetzt.

Mit "rcall Label" springst du ebenfalls zu dem label, es wird sich aber zusätzlich die Adresse von dem Befehl nach "rcall Label" gemerkt. Am Schluss der Routine "Label:" kommt dann ein "ret" (return), es wird in der Befehlsfolge wieder zurück zu dem Befehl nach "rcall Label" gesprungen und das Programm dort fortgesetzt.

Dann gibt es noch bedingte Sprünge, also zum Beispiel "sbis (skip bit io set), sbic (skip bit io clear), brcs (branch if carry set) usw...
 
Ich glaub wir sind schon mitten in einem Assemblerkurs für Anänger :rolleyes:

Ich habe nun eine Pin-Abfrage mit "sbic pind,p0" gemacht, gleich darauf mit "rjmp" zur Zählroutine.
Nun ist das Viech aber so schnell ....... oder ich vieeeeeeeeeel zu langsam!

Gibt es noch eine andere "simple" Möglichkeit, dass wenn ich die Taste gedrückt habe, er nicht sofort weiter zählt, als ein Sprung in eine Warteschleife?


Jedenfalls mache ich schon (kleine) Fortschritte, dank deiner super guten Erklärungen hier im Forum so wie auch in deinen Prgrammbeispielen!
Basic, also Bascom, habe ich seit Tagen nicht mehr angerührt, Assembler tuts "genau so gut", muss ich mich eben nur mehr rein knien :)
 
Hallo Michael.
Code:
 Ich habe nun eine Pin-Abfrage mit "sbic pind,p0" gemacht, gleich darauf mit "rjmp" zur Zählroutine.
Nun ist das Viech aber so schnell ....... oder ich vieeeeeeeeeel zu langsam!
Man könnte es folgendermaßen lösen: Je Taste verwendet man zwei Flags (Bits), ich nenne diese mal BitAKey und BitBWait. Wird die Taste gedrückt wird immer BitBWait gesetzt. BitAKey wird nur dann gesetzt, wenn BitBWait zuvor gelsöscht war. BitBWait wird dann gelöscht, wenn die Taste losgelassen wird.
Irgendwo im Programm kann nun irgendeine Routine auf das Tastensignal BitAKey reagieren und bestätigt durch löschen dieses Flags.
Das hört sich vielleicht kompliziert an, ist es aber eigentlich gar nicht. Komplizierter wird es dann, wenn man noch Verzögerung und Tastenwiederholung "einbaut".

Ich kann dir ja mal ein Beispiel schreiben, aber heute schaffe ich es nicht mehr.

Code:
 Basic, also Bascom, habe ich seit Tagen nicht mehr angerührt, Assembler tuts "genau so gut"
Naja, das Basic hat auch bestimmt Vorteile, es kommt immer darauf an, was man programmieren möchte und wie groß das Projekt ist, an dem man arbeitet. Ich programmiere Assembler, C und Pascal. Pascal mag ich, weil es strukturierter ist als C, das ist natürlich Geschmacksache, viele schwören auf C. Der Vorteil an C, es ist eher verbreitet und es gibt bereits viele fertige Programmteile, die man nutzen kann. Je nachdem, wie man Assembler programmiert, kann der Programmcode sehr effektiv sein. Bei Assembler hat man den höchsmöglichen Einfluß auf den "tatsächlichen" Programmablauf. Ich finde, wenn man mit Assembler anfängt, lernt man eher den Mikrocontroller kennen, als bei Hochsprachen.
 
Ja, ich glaub ich bleibe erstmal bei Assembler, die meisten Befehle kann man doch recht gut von der Funktion ableiten.
Aber ums lesen und lernen komme ich nicht dran vorbei :rolleyes:

Wenn du Lust hast, darfst du mir gerne noch dein Tastenabfrage-Beispiel zeigen. Ich habe es jetzt zwar so weit mit einer Pausenroutine hin bekommen, aber es gibt sicherlich elegantere Möglichkeiten. Denn wenn ich jetzt die Taste drücke, und der AVR gerade in der Warteschleife ist, habe ich Pech gehabt ...

Nochmal ganz Kurz zur externen Frequenz:
Ich muss dem AVR Mitteilen, dass er von außen die Frequenz bekommt, und ich muss ihm sagen wie hoch die Frequenz ist. Wie waren die Befehle dafür?

Und zu "Data-Zeilen":
Kann ich x-belibig viele Data-Zeilen einsetzen, die ich einfach durch ein Label auseinander halte?
(Im Basic gab es nur ein Data-Bereich, und auch den Vektor konnte ich nicht "verbiegen"?!)

Schönes Wochenende

Michael

Nachtrag:
Den ersten AVR habe ich so eben in die ewigen Jagdgründe geschickt: 8V DC verträgt er einfach nicht :(
 
Hallo Michael,

ich hoffe du hast meine Private Nachricht (PN) erhalten, den Inhalt von deinem Postfach für Private Nachrichten siehst du beim Anmelden oben rechts.

Ja, ich glaub ich bleibe erstmal bei Assembler, die meisten Befehle kann man doch recht gut von der Funktion ableiten.
Aber ums lesen und lernen komme ich nicht dran vorbei
Assembler ist vielleicht ein bisschen schwerer als Hochsprachen, da ja Assembler hier auch AVR-spezifisch ist, Hochsprachen sind erste einmal plattformunabhängig, aber lernen muss man überall. :)
Mal ein Tipp, programmiere Assembler mudulartig, packe funktionierende Programmteile in Routinen und schreibe über die Routine kurze Bemerkungen, welche Eingangsvariablen benötigt werden und welche Ausgangsvariablen vorhanden sind, dann kannst Du die Routinen später einmal in anderen Projekten schnell einbauen.

Wenn du Lust hast, darfst du mir gerne noch dein Tastenabfrage-Beispiel zeigen. Ich habe es jetzt zwar so weit mit einer Pausenroutine hin bekommen, aber es gibt sicherlich elegantere Möglichkeiten. Denn wenn ich jetzt die Taste drücke, und der AVR gerade in der Warteschleife ist, habe ich Pech gehabt ...
Ja, da werde ich dir etwas schreiben.

Kann ich x-belibig viele Data-Zeilen einsetzen, die ich einfach durch ein Label auseinander halte?
Du kannst so viele Daten definieren, bis der Flash-Speicher voll ist, da hast du einiges zu tippen ;)
Code:
LabelName:
.db 20
.db 39
.db 40, 50, 0x60    ; hier fügt der Assembler ein Byte ein, da nur 3 Bytes
                          ; in dieser Zeile, es müssen aber wegen  
                          ; Word-Adressierung AVR immer geradzahlige Bytes sein.
.dw 0x3578, 2478  ; hier mir DefineWord, gleich 16Bit Zahl (2 Bytes) definieren
Nachdem im Programm die Register und die SRAM-Variablen definiert wurden, kommt die Assembler-Direktive .cseg (Code-Segment). Ab hier folgt alles was ins Flash kommen soll, also Programmcode und die Tabelle(n), wenn die Tabelle ins EEPROM soll, muss vor die Tabelle .eseg (EEPROM-Segment), aber jetzt nicht irritieren lassen, deine Tabelle muss ins Flash.

Nochmal ganz Kurz zur externen Frequenz:
Ich muss dem AVR Mitteilen, dass er von außen die Frequenz bekommt, und ich muss ihm sagen wie hoch die Frequenz ist. Wie waren die Befehle dafür?
Das musst Du vor dem Programmiervorgang im Dialog Fuses der Programmiersoftware einstellen. Was nutzt du denn als Taktquelle, 10MHz Quarz?
 
Hallo Dirk!

So wie ich gelesen habe, kann man sich den AVR mit falschen Fusbits auch ganz arg tot legen?!
Als Quarz dachte ich gleich an 16Mhz (verarbeitet er meine willkürlichen Sprünge im Prgramm schneller *lach).
Wenn 16Mhz aber zu hoch oder zu ungeschickt gewählt ist.... ich habe so einiges an Quarzen da. Nur meine Quarzoszilatoren fangen erst bei 20Mhz an, also unbrauchbar für den 8515.

Ahhh, .db und .dw , ich hätt wohl umständlich 2 regsiter zum auslesen eines Word benutzt....

Aber ich merke gerade, ich will schon wieder alles auf einmal, sollte mich erst noch ein wenig mit den Grundlagen beschäftigen :eek:
 
Hallo Michael!

So wie ich gelesen habe, kann man sich den AVR mit falschen Fusbits auch ganz arg tot legen?!
Wenn man zum Beispiel das Fusebit SPI-Enable abschaltet, kann man den den Mikrocontroller nur noch per JTAG oder parallel programmieren. Schlecht ist es dann, wenn man nicht die Möglichkeit hat, den Mikrocontroller so zu programmieren.
Programmiert man zum Beispiel die Fusebits so, dass der AVR einen externen Taktgenerator benötigt (interner Oszillator ist abgeschaltet) und man hat nur einen Quarz aber keinen externen Taktgenerator, hat man sich ebenfalls eine "Sackgasse" gebaut.

Wenn 16Mhz aber zu hoch oder zu ungeschickt gewählt ist.... ich habe so einiges an Quarzen da.
16MHz sind schon in Ordnung, man möchte ja gerne einen schnellen AVR ;)
 
So, habe dann AVR-Studio veranlasst, die Fusebits auf Extern zu setzen... und es läuft so ca 16 mal schneller :D

Mit den "Data`s" komme ich nun auch noch gar nicht klar:
Für den Anfang würde mir ein Bit reichen, brauche ich also kein HIGH und LOW Bit?!
Wenn ich nun Auslese, wird die erste Stelle ausgelesen.
Soweit so gut. Aber was hab ich zutun, wenn ich zB die 12. Stelle auslesen möchte?!
Wenn ich dein Programmbeispiel sehe, finde ich ich nirgends einen Zähler oder Zeiger, der sagt welche Stelle gelesen werden soll :confused:
Sicherlich gibt es für 1Byte auslesen auch einen ganz einfachen Weg ?!

Also ich steh da nun komplett vor einem Berg, sehe den Wald vor Bäumen nicht mehr .... HILFEEEEEEEE :rolleyes:

So, nun schon wieder Ich!
Um die 0 in der Zehnerstelle ganz aus zu schalten, also das erst das 10er Display bei 1 statt mit 0 beginnt, hatte ich mir folgendes gedacht:
mit "sbis" das Register abfragen, ist in dem Register der Wert für 0, soll auf dem Displaly 00000000 ausgegeben werden....
Geht aber nicht ?! Oder geht doch, und ich hab falsch gedacht?
Ja Klar, gibt es auch eine elegantere Lösung für, aber ich komm noch nicht drauf *lachhhhhh
 
Ich weiß jetzt nicht genau wie du das meinst...
Aber was hab ich zutun, wenn ich zB die 12. Stelle auslesen möchte?!
Möchtest du eine 12stellige 7Segmentanzeige oder meinst du den 12. Eintrag in einer Datentabelle der Einträge für die Portausgabe (PLL)?
Die Zählvariable heißt "DisplayNumber". Für die Anzeigenausgabe prüfe ich erst einmal wieviele 100er, 10er und 1er vorhanden sind. Die 100er brauchst du ja nicht, weil du nicht über 99 kommst. Es werden dann die 10er und danach die 1er über eine Tabelle in die entsprechenden Segmentbits (a-g) gewandelt, die dann ausgegeben werden.
Möchtest Du nun DisplayNumber in einen Wert wandeln (Byte->PLL), adressierst du die Einträge der Tabelle direkt über den Wert DisplayNumber. DisplayNumber entspricht hier also einem Offset zur Tabellenadresse. Ist DisplayNumber = 0, wird der erste Eintrag (Byte) adressiert, ist DisplayNumber = 12, wird der 13. Eintrag adressiert. Wenn du für den PLL mehr Auflösung benötigst, also zum Beispiel 2Byte (Word), musst du die Tabelleneinträge ein bisschen anders adressieren, da möchte ich dich aber jetzt nicht durcheinander bringen.

Um die 0 in der Zehnerstelle ganz aus zu schalten, also das erst das 10er Display bei 1 statt mit 0 beginnt...
Du meinst damit, die 10er Stelle unterdrücken, wenn ein Wert < 10 angezeigt wird? Da die 10er Stelle die höchstwertige Stelle ist, kann man die leicht unterdrücken, ein bisschen aufwendiger wird es, wenn man mehrere Dezimalstellen hat und du Stellen mittendrin unterdrücken möchtest, die dürfen ja nicht nur dann unterdrückt werden wenn sie "0" sind, da ja höherwertige Stellen dann nicht unbedingt "0" sind.
10er Stelle Unterdrücken kannst du zum Beispiel so lösen:

In der Routine LEDDisplay ...
Code:
   ;********************************************
   ;*** 10er Stelle  ausgeben ***********************
   
   lds RegA, Result+1        ; das sind die 10er
   [COLOR=DarkRed]cpi RegA, 0                 ; Vergleich mit "0"
   breq keine_10er_stelle  ; ist "0", also am Port 0b00000000 ausgeben (Anzeige aus)

[/COLOR]   rcall  LED_DecodeDigit1  [COLOR=DarkRed]; Nicht "0", also ausgeben[/COLOR]
   in RegB, PortB
   andi RegB, 0b10000000     ; das hier nur weil du  eventuell den Portpin7 anders
   or RegA, RegB             ; nutzt, damit das  Bit nicht geändert wird. 
   out PortB, RegA           ; ansonsten oberen 3  Zeilen weglassen
   [COLOR=DarkRed]rjmp weiter_mit_1er_stelle

keine_10er_stelle:
   ldi RegA, 0b00000000   ; alle Segmente aus
   out PortB, RegA[/COLOR]
[COLOR=DarkRed]
weiter_mit_1er_stelle:[/COLOR]
   ;************************************************
   ;*** 1er Stelle  ausgeben ************************
   lds RegA, Result+0        ; das sind die  1er
...
 
Ja, den 12. Eintrag in einer Datentabelle der Einträge für die Portausgabe meinte ich.

Das Zauberwort heisst ja "lpm", aber wie gehe ich damit um?
Wieso sind die Daten dann in r30/31 und plötzlich in r0 ?
Wenn ich nur je ein Byte auslesen möchte, kann ich doch auch jedes andere Register verwenden?

Ich muss ja:

- sagen wo die Data-Zeilen sind (Label)
- sagen welche Stelle der Data`s ich lesen möchte (zB 12. Stelle) (übernehme ich von "DisplayNumber")
- aus "dem" Regsiter das Byte in ein anderes übergeben
- das Byte auf PortC ausgeben

Also mit den Registern und mit welchem Befehl ich eben das gewünschte Byte auslese versteh ich noch garnicht.
Vielleicht könntest du da auch noch mal ein kurzes Beispiel zu geben?



Die Sache mit dem LEDDisplay und die Nullstelle leuchtet mir ein, ich hätte eben so anpacken wollen, dass wenn in PortB die Bits für die "0" gesetzt sind, dass ich dann die komplette 7-Segment aus schalte.
Daran dass RegA ja auch den Wert 0 in dem Moment beinhaltet, bin ich gar nicht erst gekommen.
 
Ich werde dir heute abend ein Beispiel schreiben, habe gerade wenig Zeit.
Das Zauberwort heisst ja "lpm", aber wie gehe ich damit um?
Wieso sind die Daten dann in r30/31 und plötzlich in r0 ?
Mit dem Befehl lpm (load program memory) lädt man aus dem Flash (program memory) ein Byte, welches sich an der Adresse befindet, die in den Registern r30 und r31 (zl, zh) steht, in das Register r0.
Das hört sich vielleicht jetzt kompliziert an, ist es aber nicht.

Du schreibst erst die Adresse in das Z-Register, das besteht aus 2Bytes, dem register zl (=r30, Lowbyte der Adresse) und zh (=r31, Highbyte der Adresse). Bei einer Tabellenadressierung addierst du den Offset zum Z-Register, danach lpm ausführen und das Ergebnis befindet sich immer in dem Register r0.
 
Also mit den Registern und mit welchem Befehl ich eben das gewünschte Byte auslese versteh ich noch garnicht.
Vielleicht könntest du da auch noch mal ein kurzes Beispiel zu geben?
Hier mal ein Beispiel einer Tabellenadressierung:

Code:
;*********************************************************************************
;* DecodePLLValue
;*
;* Description: 
;* Arguments  : RegA
;* Results    : RegA
;*
;*********************************************************************************
[B][COLOR=DarkSlateBlue] DecodePLLValue:[/COLOR][/B]

   ldi r30, LOW(2*PLLTable)  ; Anfangsadresse der Tabelle in das z-Register
   ldi r31, HIGH(2*PLLTable)

   add r30, RegA             ; hier den Offset addieren, also
   clr RegA                  ; z = z + RegA
   adc r31, RegA             ; jetzt zeigt z auf den Eintrag mit dem Offset RegA

   lpm                       ; load program memory (Byte aus Flash mit Adresse z lesen) 
                       
   mov RegA, r0              ; Ergebnis ist im Register r0, r0 nach RegA kopieren (muss
                             ; man nicht, aber es ist besser wenn man immer mit bestimmten
                             ; Registern arbeitet, um eine Struktur in seine Software zu bekommen)
[B][COLOR=DarkSlateBlue]ret[/COLOR][/B]

; Jetzt kommt die Tabelle, die muss nicht hinter der oberen Routine stehen,
; sie kann ganz woanders im Flash sein.
[B][COLOR=DarkSlateBlue]PLLTable[/COLOR][/B]:            
               ; RegA
.db 40, 42     ; 0, 1
.db 43, 44     ; 2, 3
.db 45, 47     ; 4, 5
.db 50, 51     ; 6, 7
.db 56, 57     ; 8, 9
.db 78, 80, 90, 100  ; 10, 11, 12, 13
; ... usw.

; hier machst du so viele Einträge, wie du benötigst,
; maximal sind es 256 Bytes, wenn du mehr benötigst, muss
; man für das InputArgument (hier RegA) zwei Byte verwenden
; und in der Routine DecodePLLValue eine 16Bit Addition 
; durchführen.

; Achte darauf, dass die Anzahl der Einträge in einer Zeile geradzahlig ist,
; der letzte Eintrag darf ungeradzahlig sein.

; Aufrufen kannst du die Routine zum Beispiel so:
[B][COLOR=DarkSlateBlue]MainLoop2[/COLOR][/B]:


   mov RegA, DisplayNumber    ; Deine Variable die du wandeln möchtest in RegA
   rcall DecodePLLValue       ; Hier die Routine mit der Tabellenadressierung
   out PortC, RegA            ; Das Ergebnis ist in RegA, zum Beispiel am PortC ausgeben.


rjmp mainloop2
 
Super Dirk, damit ist mir wirklich schon geholfen.

Was mich noch ein wenig verwirrt, warum werden 2 Regsiter benutzt, wenn ich nur ein Byte benötige?
Hat das etwas damit zutun dass r30 und r31 sowie r0 für diese speziellen Aufgaben vorgsehen sind? Oder würde das (theoretisch) auch mit jedem anderen Register funktionieren?
Und warum "(2*PLLTable)" ? Bedeutet dass PLLTable 2 Mal gelesen wird?

So, nun mal frisch ans Werk und mal sehen ob ich was zustande bekomme ;)
 
Hallo Michael,

es ist tatsächlich so, dass das Register z (also zl und zh bzw. r30 und r31) und r0 für den Befehl lpm benötigt werden. Kuck dir zum Beispiel mal den Befehl mul an, hier wird r0 und r1 mit dem 16Bit-Ergebnis geladen.
Das z-Register wird oft zum Adressieren verwendet. Die Register x, y, z, r0 und r1 haben bei manchen Befehlen besondere Aufgaben.

Und warum "2*PLLTable" ?
Das ist ein bisschen komplizierter zu erklären.
Der Programmspeicher der AVRs ist als Word (16Bit) organisiert, ein Word besteht aus einem HighByte und einem LowByte. Das z-Register adressiert aber eine Byteadresse. Das niederwertigste Bit des z-Registers adressiert entweder das LowByte oder das HighByte, alle anderen Bits adressieren die Wordadresse.
Mit der Assembleranweisung "2*PLLTable" (entspricht PLLTable<<1) bewirkst du ein Verschieben der Adressbits um ein Bit nach links, das Bit0 ist hier 0. Du kannst also mit dem z-Register (Pointer) 64kByte (32kWords) adressieren. Wenn der AVR mehr Flash-Speicher hat (zum Beispiel beim ATmega128), dann kannst du im Register RAMPZ das Z-Flag setzen, dann wird durch den Befehl ELPM der obere Speicherbereich, also die oberen 32kWords angesprochen. Da würde ich mich jetzt aber nicht durcheinander bringen lassen ;)
 
Hallo Dirk!
So, viele Stunden arbeit, aber ein noch nicht wirklich zufriedenstellendes Ergebnis.
Hier mal ein Ausschnitt :
Code:
Abfrage:
	sbis PIND, PD0
	rjmp taste_pin0_gedrueckt
	sbis PIND, PD1
	rjmp taste_pin1_gedrueckt
	rjmp Abfrage

taste_pin0_gedrueckt:
   wdr
   rcall LEDDisplay          
   rcall Pause100ms            
   rcall Pause100ms         
   rcall Pause100ms
   inc DisplayNumber
   cpi DisplayNumber, 80
   brlo abfrage               ; Nach oben begrenzt auf 80       
   ldi DisplayNumber, 1
   rjmp abfrage 

taste_pin1_gedrueckt:
   wdr
   rcall LEDDisplay          
   rcall Pause100ms           
   rcall Pause100ms        
   rcall Pause100ms
   dec DisplayNumber
   cpi DisplayNumber, 0
   brsh abfrage               ; solange DisplayNumber > 0          
   ldi DisplayNumber, 80   ; nach 1 kommt 80
   rjmp abfrage

Nach drücken der Taste p1 (Minus) kommt nach der 1 die 55 :confused:
Zusätlich nimmt er bei Taste p0 (Plus) erst noch ein Minus mit ?!

Ist für dich mein Fehler / Problem sofort offensichtlich?

Die PLLValue-Zeilen sind als nächstes dann dran :eek:

Viele Grüße
Michael
 
Hallo Michael,
ich kuck mir dein Programm heute abend nochmal genauer an, was mir im Moment auffällt ist, dass du nach Tastenbetätigung zuerst die Displayausgabe machst und dann die Variable DisplayNumber änderst.
Die "55" kommen bestimmt von einem Überlauf beim Dekrementieren der Variablen, die hat dann den Wert "255", die beiden niederwertigen Dezimalstellen werden angezeigt.
Code:
taste_pin1_gedrueckt:
   wdr
   rcall LEDDisplay          
   rcall Pause100ms           
   rcall Pause100ms        
   rcall Pause100ms
   dec DisplayNumber
   cpi DisplayNumber, [COLOR=Red][B]1              ; Vergleich mit 1[/B][/COLOR]
   brsh abfrage                      [COLOR=Red][B];[/B][/COLOR] [B][COLOR=Red]Solange >= 1[/COLOR][/B] (solange DisplayNumber > 0) 
   ldi DisplayNumber, 80        ; nach 1 kommt 80
   rjmp abfrage
Das mit den Pausen ist ungünstig, ich schreibe dir da mal eine elegantere Lösung für eine Tastenabfrage ... hatte ich dir ja versprochen.
 

Über uns

  • Makerconnect ist ein Forum, welches wir ausschließlich für einen Gedankenaustausch und als Diskussionsplattform für Interessierte bereitstellen, welche sich privat, durch das Studium oder beruflich mit Mikrocontroller- und Kleinstrechnersystemen beschäftigen wollen oder müssen ;-)
  • Dirk
  • Du bist noch kein Mitglied in unserer freundlichen Community? Werde Teil von uns und registriere dich in unserem Forum.
  •  Registriere dich

User Menu

 Kaffeezeit

  • Wir arbeiten hart daran sicherzustellen, dass unser Forum permanent online und schnell erreichbar ist, unsere Forensoftware auf dem aktuellsten Stand ist und der Server regelmäßig gewartet wird. Auch die Themen Datensicherheit und Datenschutz sind uns wichtig und hier sind wir auch ständig aktiv. Alles in allem, sorgen wir uns darum, dass alles Drumherum stimmt :-)

    Dir gefällt das Forum und unsere Arbeit und du möchtest uns unterstützen? Unterstütze uns durch deine Premium-Mitgliedschaft!
    Wir freuen uns auch über eine Spende für unsere Kaffeekasse :-)
    Vielen Dank! :ciao:


     Spende uns! (Paypal)