Atmega8515 programmieren?

Ja, du müsstest mit rcall die Routine Scan aufrufen.

Wenn du programmierst, versuche möglichst bestimmte Aufgaben in Routinen zu programmieren...
Code:
Scan:
   ; hier der Programmcode der Routine
ret
... damit wird das Programm, besonders wenn es größer ist, übersichtlicher. Außerdem kannst du die Routinen schneller in anderen Programmen einbauen. Beispiel ist meine TaskManager oder mein KeyboardManager. Den KeyboardManager habe ich in vereinfachter Form aus einem größeren Asm-Projekt von mir verwendet.

Das erste Programm, was ich dir gepostet habe, war ein Grundgerüst, dieses kann man nun mit seinem eigenen Programm erweitern.

Der Aufbau ist eigentlich folgender (dieses Grundgerüst nutze ich bei Assembler-Programmen immer, es ist nur ein Vorschlag, man kann es auch anders machen):
  1. Include der Definitionsdatei
  2. Interrupteinsprungadressen mit Interruptroutinen verlinken (ab Adresse 0x00, .org 0x00 rjmp SystemInit usw...)
  3. Register definieren (r0 ... r31)
  4. Macros definieren (kann man auch weglassen)
  5. Variablen im SRAM definieren (.sreg)
  6. SystemInit (Anfang des Codesegments .cseg, hier wird nach Reset hingesprungen, hier erfolgt einmalig die Initialisierung von Variablen, Registern, Ports)
  7. SystemLoop (dies ist die Endlosschleife)
  8. Zum Schluss Include von Includefiles (ausgelagerter Code) und vielleicht die Definition von Speicherstellen im EEPROM (.eseg)
In der Routine SystemLoop läuft dein Programm. Der TaskManager setzt zeitabhängig bestimmte Bits. Man kann diese im Systemloop permanent abfragen und darauf reagieren. Das mache ich in den Routinen Task5ms, Task20ms und Task250ms. Rufst Du in diesen Routinen eine Routine auf, wird diese mit der entsprechenden Periodendauer aufgerufen, zum Beispiel die Routine KeyboardManager in der Routine Task20ms alle 20ms.

Variablen definieren:
Ab flexibelsten kannst du mit den Registern r16 bis r31 arbeiten. Die Register kannst du mit .def r16 MeinRegister16 einfach benennen, du kannst aber auch mit r16 arbeiten.
Diese Register kannst du bitadressieren
Code:
[COLOR=DarkSlateBlue]sbr r16, 1<<5
sbrs r16, 5[/COLOR]
Die Register r0 bis r15 sind nicht ganz so flexibel, Bitadressierung geht hier nicht und du kannst nicht direkt Werte reinladen:
Code:
ldi r5, 20 ;geht nicht!
; Umweg:
ldi r16, 20
mov r5, r16
Bestimmte Register haben oft bestimmte Aufgaben:
Der InstructionCode mul legt das 16 Bit Ergebnis in r0 und r1 ab.
Der InstructionCode lpm (kennst du schon von der Tabellenadressierung) legt das Ergebnis in r0 ab.
Die Register x (r26, r27), y (r28, r29) und z (r30, r31) werden oft zur Adressierung verwendet.
Mit Registervariablen (r0 ... r31) läßt sich rechnen, add, adc, sub, sbc, inc, dec usw.

Nicht so flexibel sind die SRAM-Variablen, dafür hat man da viel mehr Speicherplatz. Wenn du mit SRAM-Variablen rechnen möchtest, oder diese irgenwie weiter vearbeiten möchtest, kopierst du den Inhalt zuerst in ein Register, machst irgendwas damit und kopierst sie wieder zurück:
Code:
lds r16, MeineSRAMVariable
inc r16
sts MeineSRAMVariable, r16
Durch indirekte Adressierung kann man auch schnell größere Speicherbereiche verarbeiten.
Achso, SRAM-Variablen definierst du nach .dseg (Datensegment)
Code:
MeineSRAMVariable:    .byte 1
; oder auch
VariableABC:    .byte 3

; Im Programmteil (.cseg) kopierst du die Inhalte der SRAM-Variablen dann zum Beispiel folgendermaßen in Register:

lds RegA, MeineSRAMVariable

lds RegB, VariableABC+0  ; Niederwertigsten Byte
lds RegC, VariableABC+1
lds RegD, VariableABC+2 ; Höchstwertiges Byte
Argumente bei Routinen:
Wenn du Routinen schreibst, die Argumente erwarten und Ergebnisse liefern, verwende möglichst immer die selben Register zur Übergabe der Variablen, zum Beispiel RegA (r16), RegB (r17) ... dann bleibt alles übersichtlicher, und du kannst deine Routinen schneller irgendwoanders "einbauen".

Am Wochenende finde ich eventuell etwas Zeit, dir bei deinem Programm zu helfen, wenn du das möchtest.

Gruß
Dirk
 
... und wie ich das möchte :p

Mir ist aufgefallen, dass du grundsätzlich "RegA" für alle möglichen Aufgaben benutzt.
Wäre es nicht Übersichtlicher, verschiedene Register für verschiedene Aufgaben zu verwenden?
Ich finde es (noch) recht unübersichtlich, den Wert des Registers zu sichern, andere Operationen auszuführen, und dann den Wert wieder zu retten?!
 
Mir ist aufgefallen, dass du grundsätzlich "RegA" für alle möglichen Aufgaben benutzt.
RegA steht ja in deinem Fall für das Register r16. Du kannst das auch anders nennen oder du benennst das Register nicht und schreibst gleich r16. Der Grund warum ich das für alle möglichen Aufgaben nutze ist folgender: Das Register r16 ist das erste Register des oberen Bereichs des Registerblocks (r16 bis r31). Die Register im oberen Bereich sind flexibler als die im unteren Bereich. In meinen Programmen nutze ich die Register ab r16 immer für Operationen und zur Parameterübergabe mit Routinen. Der Vorteil ist, man erreicht dadurch einen besseren Programmierstil, Programmteile lassen sich so einfacher austauschen, erweitern oder verbessern. Wenn man größere Programme schreibt und diese ggf. noch dokumentieren und vailidieren muß, hat das natürlich erhebliche Vorteile, da man bereits funktionierende Programmteile nicht neu analysieren und testen muß, naja zumindest nicht so aufwendig.

Wäre es nicht Übersichtlicher, verschiedene Register für verschiedene Aufgaben zu verwenden?
Das kannst du natürlich machen, bei kleineren Programmen macht es durchaus Sinn, die Register mit bestimmten Aufgaben zu belegen. Bei größeren Programmen ist es ja in der Regel so, dass die Register nicht für alle Variablen ausreichen, so dass man Variablen in das SRAM verlagern muß.

Ich finde es (noch) recht unübersichtlich, den Wert des Registers zu sichern, andere Operationen auszuführen, und dann den Wert wieder zu retten?!
Wenn du alle Variablen in Registerbank (r0 bis r31) unterbringen kannst, fällt das natürlich weg. Du mußt nicht unbedingt SRAM nutzen. Ich habe SRAM-Variablen in deinem Programm verwendet, damit du siehst, wie man damit umgeht.
Wenn du dir mal das Blockdiagramm eines AVR ansiehst, wirst du verstehen, warum keine Operationen mit SRAM-Variablen möglich sind, und warum deshalb der Umweg über die Register notwendig ist. Nur die Register sind mit der Arithmetic Logic Unit (ALU) verbunden. Das ist eigentlich typisch für Mikrocontroller. Bei älteren Mikrocontrollerkernen, zum Beispiel bei Intel 8051 kast du nur ein Register, der Accu, mit dem du Operationen ausführen kannst.
 

Ü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)