Ja, du müsstest mit rcall die Routine Scan aufrufen.
Wenn du programmierst, versuche möglichst bestimmte Aufgaben in Routinen zu programmieren...
... 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):
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
Die Register r0 bis r15 sind nicht ganz so flexibel, Bitadressierung geht hier nicht und du kannst nicht direkt Werte reinladen:
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:
Durch indirekte Adressierung kann man auch schnell größere Speicherbereiche verarbeiten.
Achso, SRAM-Variablen definierst du nach .dseg (Datensegment)
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
Wenn du programmierst, versuche möglichst bestimmte Aufgaben in Routinen zu programmieren...
Code:
Scan:
; hier der Programmcode der Routine
ret
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):
- Include der Definitionsdatei
- Interrupteinsprungadressen mit Interruptroutinen verlinken (ab Adresse 0x00, .org 0x00 rjmp SystemInit usw...)
- Register definieren (r0 ... r31)
- Macros definieren (kann man auch weglassen)
- Variablen im SRAM definieren (.sreg)
- SystemInit (Anfang des Codesegments .cseg, hier wird nach Reset hingesprungen, hier erfolgt einmalig die Initialisierung von Variablen, Registern, Ports)
- SystemLoop (dies ist die Endlosschleife)
- Zum Schluss Include von Includefiles (ausgelagerter Code) und vielleicht die Definition von Speicherstellen im EEPROM (.eseg)
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]
Code:
ldi r5, 20 ;geht nicht!
; Umweg:
ldi r16, 20
mov r5, r16
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
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
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