
Viele Grüße,
Kalle
Code: Alles auswählen
r16= rot
r17= rotgelb
...
ldi rot, 0b00000001
ldi rotgelb, 0b00000011
ldi gruen, 0x0b00000100
...
und so weiter
Code: Alles auswählen
...
out portb, rot ;Rot ausgeben
rcall Zeit_lang ;lange Zeitschleife
...
Code: Alles auswählen
...
.DSEG ;Beginn des Datensegments
rot: .BYTE 1 ;Variable "rot" mit 1 Byte festlegen
rotgruen: .BYTE 1 ;Variable "Rotgruen" mit 1 Byte festlegen
gruen: .BYTE 1 ;Variable "Gruen" mit 1 Byte festlegen
gelb: .BYTE 1 ;Variable "Gelb" mit 1 Byte festlegen
Code: Alles auswählen
ldi r16, 0x01 ;Bitmuster für "rot" in r16 schreiben
Code: Alles auswählen
sts rot, r16
Code: Alles auswählen
ldi r16, 0x01 ;Bit0 für rote Lampe setzen
sts rot, r16 ;Bitmuster nach "rot" speichern
ldi r16, 0x03 ;Bit0 und Bit1 für rote und gelbe Lampe setzen
sts rotgelb, r16 ;Bitmuster nach "rotgelb" speichern
ldi r16, 0x04 ;Bit2 für grüne Lampe setzen
sts gruen, r16 ;Bitmuster nach "gruen" speichern
ldi r16, 0x02 ;Bit1 für gelbe Lampe setzen
sts gelb, r16 ;Bitmuster nach "gelb" speichern
Code: Alles auswählen
lds r16, rotgelb ;Bitmuster für rotgelb nach r16 laden
out Portb, r16 ;r16 an PortB ausgeben
Code: Alles auswählen
; automatische, vereinfachte Verkehrsampel
.include "m8def.inc" ; Damit weis der Compiler, auf welchen Proz er compilieren muss
.def Time1 = r16
.def Time2 = r17
.def Time3 = r18
.def Temp = r19
.org 0x0000
rjmp Init ; Springe nach einem Reset zum Label "Init"
Init: ; Hier beginnt die Initialisierung
; Setzen des Stackpointers
ldi r16, LOW(RAMEND) ; unteres Byte der hächstmöglichen Adresse holen
out SPL, r16 ; Unteres Byte des SP beschreiben
ldi r16, HIGH(RAMEND) ; oberes Byte der höchstmnöglichen Adresse holen
out SPH, r16 ; oberes Byte des SP beschreiben
; Initialisieren der Eingänge
ldi r16, 0x00 ; alle Bits in r16 auf 0 setzen
out ddrd, r16 ; Alle Pins von Port C sind Eingang
ldi r16, 0xFF ; Bit 2 und Bit 3 setzen
out portd, r16 ; PC2 und PC3 bekommen PullUp-Widerstände
ldi r16, 0xFF ; alle Bits in r16 auf 1 setzen
out ddrb, r16 ; Alle Pins von Port B sind Ausgang
ldi r16, 0x00 ; Alle Bits in r16 löschen
out portb, r16 ; Alle LEDs aus
;Ampelfarben definieren
ldi r16, 0x01 ; Bitmuster für "Rot"
sts Rot, r16 ; Bitmuster in SRAM ablegen
ldi r16, 0x03 ; Bitmuster für "RotGelb"
sts RotGelb, r16 ; Bitmuster in SRAM ablegen
ldi r16, 0x04 ; Bitmuster für "Gruen"
sts Gruen, r16 ; Bitmuster in SRAM ablegen
ldi r16, 0x02 ; Bitmuster für "Gelb"
sts Gelb, r16 ; Bitmuster in SRAM ablegen
Hauptprogramm:
lds Temp, Rot ; Bitmuster für Rot laden
out PortB, Temp ; Ausgabe Bitmuster
rcall Lang ; Lange Zeitschleife
lds Temp, RotGelb ; Bitmuster für Rot/Gelb laden
out PortB, Temp ; Ausgabe Bitmuster
rcall Kurz ; Kurze Zeitschleife
lds Temp, Gruen ; Bitmuster für Gruen laden
out PortB, Temp ; Ausgabe Bitmuster
rcall Lang ; Lange Zeitschleife
lds Temp, Gelb ; Bitmuster für Gelb laden
out PortB, Temp ; Ausgabe Bitmuster
rcall Kurz ; Kurze Zeitschleife
rjmp Hauptprogramm ; Zurück zum Anfang
;Unterprogramme:
Kurz:
inc Time1 ; Time1 um 1 erhöhen
cpi Time1, 0xFF ; Ist der Wert 255 erreicht?
brne Kurz ; Wenn nein, dann Schleifenanfang
inc Time2 ; Time2 um 1 erhöhen
cpi Time2, 0xFF ; Ist der Wert 255 erreicht?
brne Kurz ; Wenn nein, dann Schleifenanfang
inc Time3 ; Time3 um 1 erhöhen
cpi Time3, 0x30 ; Ist der Wert 0x30 erreicht?
brne Kurz ; Wenn nein, dann Schleifenanfang
ldi Time3, 0x00 ; Time3 zurücksetzen
ret ; Zurück
Lang:
inc Time1 ; Time1 um 1 erhöhen
cpi Time1, 0xFF ; Ist der Wert 255 erreicht?
brne Lang ; Wenn nein, dann Schleifenanfang
inc Time2 ; Time2 um 1 erhöhen
cpi Time2, 0xFF ; Ist der Wert 255 erreicht?
brne Lang ; Wenn nein, dann Schleifenanfang
inc Time3 ; Time3 um 1 erhöhen
cpi Time3, 0xA0 ; Ist der Wert 0xA0 erreicht?
brne Lang ; Wenn nein, dann Schleifenanfang
ldi Time3, 0x00 ; Zeitvariable löschen!
ret ; Zurück
; Datensegment
.DSEG
Rot: .BYTE 1
RotGelb: .BYTE 1
Gruen: .BYTE 1
Gelb: .BYTE 1
Code: Alles auswählen
;in Register r16 steht die auszulesende Detektoradresse, die darin enthaltene Lokadresse soll nach r17 geholt werden
Abfrage1:
cpi r16, 0x01 ;soll Detektor1 ausgelesen werden?
brne Abfrage2 ;wenn nein, weiter mit Abfrage 2
lds r17, Detektor1 ;Detektor1 einlesen
rjmp Abfrage_ende ;keine weitere Abfrage
Abfrage2:
cpi r16, 0x02 ;soll Detektor2 ausgelesen werden?
brne Abfrage2 ;wenn nein, weiter mit Abfrage 3
lds r17, Detektor2 ;Detektor2 einlesen
rjmp Abfrage_ende ;keine weitere Abfrage
Abfrage3:
...
Abfrage24:
...
Code: Alles auswählen
ldi r30, 0x00 ;Lower Byte in Z-Pointer schreiben
ldi r31, 0x02 ;Higher Byte in Z-Pointer schreiben
Code: Alles auswählen
ld r17, Z
Code: Alles auswählen
mov r30, r16 ;Detektornummer in Z-Pointer kopieren
ld r17, Z ;Inhalt von durch Z-Pointer adressierte Speicherstelle nach r17 laden
Code: Alles auswählen
ldi r30, 0x00 ;Startwert in Z-Pointer LowerByte schreiben
Zaehlschleife
inc r30 ;Z-Pointer inkrementieren
ld r17, Z ;Inhalt von SDRAM nach r17
out Portb, r17 ;Ausgabe an Port
cpi r30, 0x18 ;Sind die 24 Speicherstellen durchgezählt?
brne Zaehlschleife ;wenn nein, dann weiterzählen
Code: Alles auswählen
sd y, r17 ;Speichern von r17 an das im Y-Pointer adressiere Byte im SDRAM
Code: Alles auswählen
Schleife:
ldi r30, 0x01 ;0x201 ist Bitmuster rot
rcall Ausgabe ;Ausgabe
rcall Zeit_lang ; lange Zeitschleife
inc r30 ;0x202 ist Bitmuster rot/gelb
rcall Ausgabe ;Ausgabe
rcall Zeit_kurz ;kurze Zeitschleife
inc r30 ;0x203 ist Bitmuster grün
rcall Ausgabe ;Ausgabe
rcall Zeit_lang ;lange Zeitschleife
inc r30 ;0x204 ist Bitmuster gelb
rcall Ausgabe ;Ausgabe
rcall Zeit_kurz ;kurze Zeitschleife
rjmp Schleife ;Zurück zum Anfang
Ausgabe: ;Unterprogramm zur Ausgabe
ld r16, Z ;Durch Z-Register adressiertes Byte nach r16 laden
out PortB, r16 ;Bitmuster ausgeben
ret ;Ende Unterprogramm
Code: Alles auswählen
; Lichteffekte
.include "m8def.inc" ; Damit weis der Compiler, auf welchen Proz er compilieren muss
.def Temp = r16
.def Time = r17
.org 0x0000
rjmp Init ; Springe nach einem Reset zum Label "Init"
.org 0x0009
rjmp Timer_ISR ; Interruptvektor für Overflow Timer0
Init: ; Hier beginnt die Initialisierung
; Setzen des Stackpointers
ldi r16, LOW(RAMEND) ; unteres Byte der hächstmöglichen Adresse holen
out SPL, r16 ; Unteres Byte des SP beschreiben
ldi r16, HIGH(RAMEND) ; oberes Byte der höchstmnöglichen Adresse holen
out SPH, r16 ; oberes Byte des SP beschreiben
; Initialisieren der Eingänge
ldi r16, 0x00 ; alle Bits in r16 auf 0 setzen
out ddrd, r16 ; Alle Pins von Port C sind Eingang
ldi r16, 0xFF ; Bit 2 und Bit 3 setzen
out portd, r16 ; PC2 und PC3 bekommen PullUp-Widerstände
; Initialisieren der Ausgänge
ldi r16, 0xFF ; alle Bits in r16 auf 1 setzen
out ddrb, r16 ; Alle Pins von Port B sind Ausgang
ldi r16, 0x00 ; Alle Bits in r16 löschen
out portb, r16 ; Alle LEDs aus
; Initialisieren von Timer0
ldi r16, 0b00000101 ; Prescaler 1024
out tccr0, r16 ; Prescaler in Timerregister schreiben
ldi r16, 0b00000001 ; TimerOverflow 0 einschalten
out TIMSK, r16
ldi Time, 0xFF ; Zaehler zurücksetzen
; Initialisieren der Lichteffekte
ldi r31, 0x02 ; HigherByte in Z-Register laden
ldi r30, 0x00 ; LowerByte in Z-Register laden
;---Hier werden die Bitmuster für die Lichteffekte angelegt---
ldi temp, 0b00011000
st z, temp
inc r30
ldi temp, 0b00100100
st z, temp
inc r30
ldi temp, 0b01000010
st z, temp
inc r30
ldi temp, 0b10000001
st z, temp
inc r30
ldi temp, 0b11000011
st z, temp
inc r30
ldi temp, 0b01100110
st z, temp
inc r30
ldi temp, 0b00011000
st z, temp
inc r30
ldi temp, 0b00111100
st z, temp
inc r30
ldi temp, 0b01111110
st z, temp
;---Ende der Definition der Bitmuster---
ldi r30, 0x00 ; Z-Pointer zurücksetzen
sei ; Interrupts erlauben
Hauptprogramm:
rjmp Hauptprogramm ; Das Hauptprogramm ist nur eine Endlosschleife
Timer_ISR:
inc Time ; Time 1 hochzählen
cpi Time, 0x04 ; Wurde die ISR 10mal aufgerufen?
brne ISR_Ende ; Wenn nein, dann springe zum Ende
ldi Time, 0x00 ; Time1 zurücksetzen
Effekt:
ld Temp, z ; Bitmuster aus SRAM laden
out portb, temp ; Bitmuster ausgeben
inc r30 ; Z-Pointer inkrementieren
cpi r30, 0x09 ; Hat r30 den Wert 9 erreicht?
brne ISR_Ende ; Wenn nein, dann ISR beenden
ldi r30, 0x00 ; Z-Pointer zurücksetzen
ISR_Ende:
reti ; Ende ISR
Da ist ein "D" zuviel, der Atmel hat SRAM (statisches RAM, siehe http://de.wikipedia.org/wiki/Static_Ran ... ess_Memory ) und kein SDRAM (synchrones dynamisches RAM, siehe http://de.wikipedia.org/wiki/SDRAM ).Muenchner Kindl hat geschrieben:Nun, wie wir ja wissen beinhaltet unser Mikrocontroller neben dem Prozessor auch einen Flash, einen EEProm, sowie ein schnelles SDRAM.
Hallo Rainer,Rainer Müller hat geschrieben:Hallo Thomas,
erlaubst Du einem außenstehenden Mitleser eine Korrektur?
...
Gruß
Rainer
Code: Alles auswählen
; Blitzlichteffekte mit kallibriertem Oszillator
; OSCCAL-Wert befindet sich im EEPROM unter 0x00FF
...
Code: Alles auswählen
Schreibe_EEProm: ; Unterprogramm zum Beschreiben des EEPROM
sbic EECR, EEWE ; ist der letzte Schreibvorgang beendet?
rjmp Schreibe_EEProm ; Wenn nein, dann nochmal prüfen
Code: Alles auswählen
ldi Temp, 0x00 ; Higher Byte ist 0x00
out EEARH, Temp ; Schreibe Higher Byte in Adressregister
ldi Temp, 0xFF ; Lower Byte ist 0xFF
out EEARL, Temp ; Schreibe Lower Byte in Adressregister
ldi Temp, 0x55 ; unser zu sicherndes Byte
out EEDR, Temp ; Schreibe das Datenbyte ins Datenregister
Code: Alles auswählen
cli ; Alle Interupts sperren, die folgenden beiden Befehle dürfen nicht unterbrochen werden!
sbi EECR, EEMWE ; Master Write Enable setzen
sbi EECR, EEWE ; Write Enable setzen und Schreibvorgang starten
sei ; Interupts erlauben
Code: Alles auswählen
Lese_EEProm: ; Unterprogramm zum Auslesen des EEPROM
sbic EECR, EEWE ; ist der letzte Schreibvorgang beendet?
rjmp Lese_EEProm ; Wenn nein, dann nochmal prüfen
Code: Alles auswählen
ldi Temp, 0x00 ; Higher Byte ist 0x00
out EEARH, Temp ; Schreibe Higher Byte in Adressregister
ldi Temp, 0xFF ; Lower Byte ist 0xFF
out EEARL, Temp ; Schreibe Lower Byte in Adressregister
Code: Alles auswählen
sbi EECR, EERE ; Lesevorgang einleiten
in Temp, EEDR ; Ausgelesenes Byte nach Temp schreiben
Code: Alles auswählen
; Lesen und Schreiben im EEPROM
; Unser Datenbyte liegt im EEPROM auf Adresse 0x0102
; T1 schaltet LEDs weiter
; T2 speichert aktuellen Zustand
.include "m8def.inc" ; Damit weis der Compiler, auf welchen Proz er compilieren muss
.def Temp = r19
.def Adresse_L = r20
.def Adresse_H = r21
.org 0x0000
rjmp Init ; Springe nach einem Reset zum Label "Init"
Init: ; Hier beginnt die Initialisierung
; Setzen des Stackpointers
ldi r16, LOW(RAMEND) ; unteres Byte der hächstmöglichen Adresse holen
out SPL, r16 ; Unteres Byte des SP beschreiben
ldi r16, HIGH(RAMEND) ; oberes Byte der höchstmnöglichen Adresse holen
out SPH, r16 ; oberes Byte des SP beschreiben
; Initialisieren der Eingänge
ldi r16, 0x00 ; alle Bits in r16 auf 0 setzen
out ddrd, r16 ; Alle Pins von Port C sind Eingang
ldi r16, 0xFF ; Bit 2 und Bit 3 setzen
out portd, r16 ; PC2 und PC3 bekommen PullUp-Widerstände
ldi r16, 0xFF ; alle Bits in r16 auf 1 setzen
out ddrb, r16 ; Alle Pins von Port B sind Ausgang
out portb, r16 ; Alle LEDs ein
ldi Adresse_H, 0x01 ; HigherByte der EEPROM-Adresse ablegen
ldi Adresse_L, 0x02 ; LowerByte der EEPROM-Adresse ablegen
; Laden des letzten Zustands
Lese_EEProm: ; Unterprogramm zum Auslesen des EEPROM
sbic EECR, EEWE ; ist der letzte Schreibvorgang beendet?
rjmp Lese_EEProm ; Wenn nein, dann nochmal prüfen
out EEARH, Adresse_H ; HigherByte in Register
out EEARL, Adresse_L ; LowerByte in Register
sbi EECR, EERE ; Lesevorgang einleiten
in Temp, EEDR ; Ausgelesenes Byte nach Temp schreiben
out portb, Temp ; gespeichertes Bitmuster ausgeben
Main: ; Hauptprogramm
sbis Pind, 2 ; Ist T1 betätigt?
rcall Bitmuster ; Wenn ja, verändere das Bitmuster
sbis Pind, 3 ; Ist T2 betätigt?
rcall Schreibe_EEPROM ; Wenn ja, dann schreibe EEPROM
rjmp Main ; Endlosschleife
Bitmuster: ; UP zum Verändern des Bitmusters
sbis Pind, 2 ; Ist T1 noch betätigt?
rjmp Bitmuster ; Wenn ja, nochmal abfragen
rol Temp ; Inhalt von Temp nach links schieben
out Portb, Temp ; Bitmuster ausgeben
ret ; Ende Unterprogramm
Schreibe_EEProm: ; Unterprogramm zum Beschreiben des EEPROM
sbis Pind, 3 ; Ist T2 betätigt?
rjmp Schreibe_EEProm ; Wenn ja, nochmal abfragen
sbic EECR, EEWE ; ist der letzte Schreibvorgang beendet?
rjmp Schreibe_EEProm ; Wenn nein, dann nochmal prüfen
out EEARH, Adresse_H ; HigherByte in Register
out EEARL, Adresse_L ; LowerByte in Register
out EEDR, Temp ; Schreibe das Datenbyte ins Datenregister
cli ; Alle Interupts sperren, die folgenden beiden Befehle dürfen nicht unterbrochen werden!
sbi EECR, EEMWE ; Master Write Enable setzen
sbi EECR, EEWE ; Write Enable setzen und Schreibvorgang starten
ret ; Ende Unterprogramm
Code: Alles auswählen
Main: ; Hauptprogramm
sbis Pind, 2 ; Ist T1 betätigt?
rcall Bitmuster ; Wenn ja, verändere das Bitmuster
sbis Pind, 3 ; Ist T2 betätigt?
rcall Schreibe_EEPROM ; Wenn ja, dann schreibe EEPROM
rjmp Main ; Endlosschleife
Code: Alles auswählen
Bitmuster: ; UP zum Verändern des Bitmusters
sbis Pind, 2 ; Ist T1 noch betätigt?
rjmp Bitmuster ; Wenn ja, nochmal abfragen
Es geht hier nicht um die Summenanzahl aller Schreibzyklen im EEPROM sondern um der Lösch- / Schreibzyklen für eine Zelle / Adresse. Unter dem Titel AVR101: High Endurance EEPROM Storage findet man bei Atmel eine Beschreibung, wie man bei Bedarf durch einen trickreichen Algorithmus und einige weitere Zellen im EEPROM diese Anzahl verlängern kann.Muenchner Kindl hat geschrieben:Das EEPROM kann beliebig oft ausgelesen, jedoch "nur" ca. 100.000 mal beschrieben werden.
Code: Alles auswählen
ldi r17, 0b01000000
out ADMUX, r17
Code: Alles auswählen
ldi r17, 0b11000110
out ADCSRA, r17
Code: Alles auswählen
in r17, ADCL ; Auslesen von ADCL, Ergebnis wird durch Überschreiben verworfen
in r17, ADCH ; Auslesen von ADCH zur weiteren Verwendung
Code: Alles auswählen
push r18 ; Sichern von r18
in r17, ADCL ; Einlesen von ADCL
in r18, ADCH ; Einlesen von ADCH, wird wieder verworfen
pop r18 ; Zurücksichern von r18 und Verwerfen von ADCH
Code: Alles auswählen
; ADC Test1
.include "m8def.inc" ; Damit weis der Compiler, auf welchen Proz er compilieren muss
.def Temp = r16
.def Ergebnis = r17
.org 0x0000
rjmp Init ; Springe nach einem Reset zum Label "Init"
Init: ; Hier beginnt die Initialisierung
; Setzen des Stackpointers
ldi r16, LOW(RAMEND) ; unteres Byte der hächstmöglichen Adresse holen
out SPL, r16 ; Unteres Byte des SP beschreiben
ldi r16, HIGH(RAMEND) ; oberes Byte der höchstmnöglichen Adresse holen
out SPH, r16 ; oberes Byte des SP beschreiben
; Initialisieren der Eingänge
ldi r16, 0x00 ; alle Bits in r16 auf 0 setzen
out ddrd, r16 ; Alle Pins von Port C sind Eingang
ldi r16, 0xFF ; Bit 2 und Bit 3 setzen
out portd, r16 ; PC2 und PC3 bekommen PullUp-Widerstände
; Initialisieren der Ausgänge
ldi r16, 0xFF ; alle Bits in r16 auf 1 setzen
out ddrb, r16 ; Alle Pins von Port B sind Ausgang
ldi r16, 0x00 ; Alle Bits in r16 löschen
out portb, r16 ; Alle LEDs aus
Main:
ldi temp, 0b01000000 ; ADC-Kanal0, int. Referenz, rechtsbündig
out ADMUX, temp ; Definition in ADMUX schreiben
Einlesen:
ldi temp, 0b11000111 ; ADC einschalten und Messung starten
out ADCSRA, Temp ; Steuerregister beschreiben
Warten:
sbis ADCSRA, ADIF ; Ist Messung abgeschlossen?
rjmp Warten ; Wenn nein, nochmal abfragen
in Ergebnis, ADCL ; ADCL nach Ergebnis einlesen
in temp, ADCH ; ADCH einlesen, wird nicht verarbeitet
out portb, Ergebnis ; Ergebnis nach PortB ausgeben
rjmp Einlesen ; Endlosschleife
Code: Alles auswählen
; ADC Test2
.include "m8def.inc" ; Damit weis der Compiler, auf welchen Proz er compilieren muss
.def Temp = r16
.def Ergebnis = r17
.org 0x0000
rjmp Init ; Springe nach einem Reset zum Label "Init"
Init: ; Hier beginnt die Initialisierung
; Setzen des Stackpointers
ldi r16, LOW(RAMEND) ; unteres Byte der hächstmöglichen Adresse holen
out SPL, r16 ; Unteres Byte des SP beschreiben
ldi r16, HIGH(RAMEND) ; oberes Byte der höchstmnöglichen Adresse holen
out SPH, r16 ; oberes Byte des SP beschreiben
; Initialisieren der Eingänge
ldi r16, 0x00 ; alle Bits in r16 auf 0 setzen
out ddrd, r16 ; Alle Pins von Port C sind Eingang
ldi r16, 0xFF ; Bit 2 und Bit 3 setzen
out portd, r16 ; PC2 und PC3 bekommen PullUp-Widerstände
; Initialisieren der Ausgänge
ldi r16, 0xFF ; alle Bits in r16 auf 1 setzen
out ddrb, r16 ; Alle Pins von Port B sind Ausgang
ldi r16, 0x00 ; Alle Bits in r16 löschen
out portb, r16 ; Alle LEDs aus
Main:
ldi temp, 0b01000000 ; ADC-Kanal0, int. Referenz, rechtsbündig
out ADMUX, temp ; Definition in ADMUX schreiben
ldi temp, 0b11100111 ; ADC einschalten und Messung FreeRunning starten
out ADCSRA, Temp ; Steuerregister beschreiben
Warten:
in Ergebnis, ADCL ; ADCL nach Ergebnis einlesen
in temp, ADCH ; ADCH einlesen, wird nicht verarbeitet
out portb, Ergebnis ; Ergebnis nach PortB ausgeben
rjmp Warten ; Endlosschleife
Code: Alles auswählen
; einstellbares Blinklicht mit Timer0
.include "m8def.inc" ; Damit weis der Compiler, auf welchen Proz er compilieren muss
.def Time1 = r16
.def Temp = r17
.org 0x0000
rjmp Init ; Springe nach einem Reset zum Label "Init"
.org 0x0009
rjmp Timer_ISR ; Interruptvektor für Overflow Timer0
Init: ; Hier beginnt die Initialisierung
; Setzen des Stackpointers
ldi r16, LOW(RAMEND) ; unteres Byte der hächstmöglichen Adresse holen
out SPL, r16 ; Unteres Byte des SP beschreiben
ldi r16, HIGH(RAMEND) ; oberes Byte der höchstmnöglichen Adresse holen
out SPH, r16 ; oberes Byte des SP beschreiben
; Initialisieren der Eingänge
ldi r16, 0x00 ; alle Bits in r16 auf 0 setzen
out ddrd, r16 ; Alle Pins von Port C sind Eingang
ldi r16, 0xFF ; Bit 2 und Bit 3 setzen
out portd, r16 ; PC2 und PC3 bekommen PullUp-Widerstände
; Initialisieren der Ausgänge
ldi r16, 0xFF ; alle Bits in r16 auf 1 setzen
out ddrb, r16 ; Alle Pins von Port B sind Ausgang
ldi r16, 0x00 ; Alle Bits in r16 löschen
out portb, r16 ; Alle LEDs aus
; Initialisieren von Timer0
ldi r16, 0b00000101 ; Prescaler 1024
out tccr0, r16 ; Prescaler in Timerregister schreiben
ldi r16, 0b00000001 ; TimerOverflow 0 einschalten
out TIMSK, r16
rcall ADC0_Lesen ; Ersten Zeitwert ermitteln
sei ; Interrupts erlauben
Hauptprogramm:
rjmp Hauptprogramm ; Das Hauptprogramm ist nur eine Endlosschleife
Timer_ISR:
inc Time1 ; Time 1 hochzählen
cpi Time1, 0x10 ; Wurde die ISR 30mal aufgerufen?
brne ISR_Ende ; Wenn nein, dann springe zum Ende
rcall ADC0_Lesen ; Poti einlesen
sbis PortB, 0 ; Ist LED1 ein?
rjmp LEDein ; Wenn nein, dann zum Einschalten springen
cbi PortB, 0 ; LED1 ausschalten
rjmp ISR_Ende ; Springe zum Ende
LEDein:
sbi PortB, 0 ; LED1 einschalten
ISR_Ende:
reti ; Ende ISR
ADC0_Lesen:
push temp ; Register Temp retten
ldi temp, 0b01100000 ; ADC-Kanal0, int. Referenz, linksbündig
out ADMUX, temp ; Definition in ADMUX schreiben
Einlesen:
ldi temp, 0b11000111 ; ADC einschalten und Messung starten
out ADCSRA, Temp ; Steuerregister beschreiben
Warten:
sbis ADCSRA, ADIF ; Ist Messung abgeschlossen?
rjmp Warten ; Wenn nein, nochmal abfragen
in Temp, ADCL ; ADCL nach Ergebnis einlesen
in Time1, ADCH ; ADCH einlesen, wird nicht verarbeitet
pop temp ; Register Temp zurückholen
ret ; Ende Unterprogramm
Hmmm... das sind ja drei Wünsche auf einmalKannst du bitte auch mal auf die Debug-Möglichkeiten des AVR Studios bei einem Beispiel mit einbinden ? Ein weiterer Traum wäre auch mal, das DCC Signal mit einem AVR zu "zerlegen" und auszuwerten, um mal sowas wie einen Funktionsdekoder oder Weichendekoder zu "bauen". Natürlich nur, wenn das andere auch wünschen.
Wir machen das zusammen und im Prinzip werden so gut wie alle bisher besprochenen Themen wiederholt und vertieft. Und... (ich bin auch noch nicht so weit)... tatsächlich gibt es von unserem Gesellenstück noch nicht mehr als hier zu lesen ist... wir machen das wirklich zusammenIch glaube ich bin auch noch nicht so weit
Code: Alles auswählen
; Workshop Projekt Ampel
; Autoren: Teilnehmer des Assemblerworkshops
; Version 1
; Vorgaben:
; EEPROM-Adresse für Statusbyte: 0x00FF
.include "m8def.inc" ; Damit weis der Compiler, auf welchen Proz er compilieren muss
.def Time1 = r16 ; Zeitvariable
.def Temp = r20 ; temporäre Variable
.def Status = r21 ; Statusbyte
.org 0x0000
rjmp Init ; Springe nach einem Reset zum Label "Init"
.org 0x0009
rjmp Timer_ISR ; Interruptvektor für Overflow Timer0
Init: ; Hier beginnt die Initialisierung
; Setzen des Stackpointers
ldi r16, LOW(RAMEND) ; unteres Byte der hächstmöglichen Adresse holen
out SPL, r16 ; Unteres Byte des SP beschreiben
ldi r16, HIGH(RAMEND) ; oberes Byte der höchstmnöglichen Adresse holen
out SPH, r16 ; oberes Byte des SP beschreiben
; Initialisieren der Eingänge
ldi Temp, 0x00 ; alle Bits in Temp auf 0 setzen
out ddrd, Temp ; Alle Pins von Port D sind Eingang
ldi Temp, 0xFF ; Alle Bits ind Temp auf 1 setzen
out portd, Temp ; PC2 und PC3 bekommen PullUp-Widerstände
; Initialisieren der Ausgänge
out ddrb, Temp ; Alle Pins von Port B sind Ausgang (Temp ist noch 0xFF)
ldi Temp, 0x00 ; Alle Bits in Temp löschen
out portb, Temp ; Alle LEDs aus
; Initialisieren von Timer0
ldi Temp, 0b00000101 ; Prescaler 1024
out tccr0, Temp ; Prescaler in Timerregister schreiben
ldi Temp, 0b00000001 ; TimerOverflow 0 einschalten
out TIMSK, Temp
Code: Alles auswählen
; Einlesen des Statusbytes
Lese_EEProm: ; Unterprogramm zum Auslesen des EEPROM
sbic EECR, EEWE ; ist der letzte Schreibvorgang beendet?
rjmp Lese_EEProm ; Wenn nein, dann nochmal prüfen
ldi Temp, 0x00 ; Higher Byte ist 0x00
out EEARH, Temp ; Schreibe Higher Byte in Adressregister
ldi Temp, 0xFF ; Lower Byte ist 0xFF
out EEARL, Temp ; Schreibe Lower Byte in Adressregister
sbi EECR, EERE ; Lesevorgang einleiten
in Status, EEDR ; Ausgelesenes Byte nach Status schreiben
andi Status, 0x01 ; Bit0 ist Statusbit, alle anderen löschen
sei ; Interrupts erlauben
Code: Alles auswählen
Hauptprogramm: ; Hier beginnt das Hauptprogramm
sbis Pind, 3 ; Ist T2 gedrückt
rcall Taste2 ; Wenn ja, dann Taste2 abarbeiten
rjmp Hauptprogramm ; Hauptprogramm ist Endlosschleife
Code: Alles auswählen
Taste2: ; Abarbeitung Taste2
sbis Pind, 3 ; Taste 2 losgelassen?
rjmp Taste2 ; Wenn nein, nochmal warten
cpi Status, 0x01 ; Ist Bit0 in Statusregister gesetzt?
brne Taste2_1 ; Wenn nein, springe zum Label Taste2_1
ldi Status, 0x00 ; Lösche Bit0 in Statusregister
rjmp Taste2_Ende ; Springe zum Ende
Taste2_1:
ldi Status, 0x01 ; Setze Bit0 in Statusregister
Taste2_Ende:
ret ; Ende UP
Code: Alles auswählen
Timer_ISR: ; Interuptserviceroutine des Timers
rcall Test1 ; Aufruf von Test1
reti ; Ende ISR
Code: Alles auswählen
Test1: ; Testroutine
out PortB, Status ; Ausgabe des Statusbytes
ret ; Ende UP
Code: Alles auswählen
; Workshop Projekt Ampel
; Autoren: Teilnehmer des Assemblerworkshops
; Version 1
; Vorgaben:
; EEPROM-Adresse für Statusbyte: 0x00FF
.include "m8def.inc" ; Damit weis der Compiler, auf welchen Proz er compilieren muss
.def Time1 = r16 ; Zeitvariable
.def Temp = r20 ; temporäre Variable
.def Status = r21 ; Statusbyte
.org 0x0000
rjmp Init ; Springe nach einem Reset zum Label "Init"
.org 0x0009
rjmp Timer_ISR ; Interruptvektor für Overflow Timer0
Init: ; Hier beginnt die Initialisierung
; Setzen des Stackpointers
ldi r16, LOW(RAMEND) ; unteres Byte der hächstmöglichen Adresse holen
out SPL, r16 ; Unteres Byte des SP beschreiben
ldi r16, HIGH(RAMEND) ; oberes Byte der höchstmnöglichen Adresse holen
out SPH, r16 ; oberes Byte des SP beschreiben
; Initialisieren der Eingänge
ldi Temp, 0x00 ; alle Bits in Temp auf 0 setzen
out ddrd, Temp ; Alle Pins von Port D sind Eingang
ldi Temp, 0xFF ; Alle Bits ind Temp auf 1 setzen
out portd, Temp ; PC2 und PC3 bekommen PullUp-Widerstände
; Initialisieren der Ausgänge
out ddrb, Temp ; Alle Pins von Port B sind Ausgang (Temp ist noch 0xFF)
ldi Temp, 0x00 ; Alle Bits in Temp löschen
out portb, Temp ; Alle LEDs aus
; Initialisieren von Timer0
ldi Temp, 0b00000101 ; Prescaler 1024
out tccr0, Temp ; Prescaler in Timerregister schreiben
ldi Temp, 0b00000001 ; TimerOverflow 0 einschalten
out TIMSK, Temp
; Einlesen des Statusbytes
Lese_EEProm: ; Unterprogramm zum Auslesen des EEPROM
sbic EECR, EEWE ; ist der letzte Schreibvorgang beendet?
rjmp Lese_EEProm ; Wenn nein, dann nochmal prüfen
ldi Temp, 0x00 ; Higher Byte ist 0x00
out EEARH, Temp ; Schreibe Higher Byte in Adressregister
ldi Temp, 0xFF ; Lower Byte ist 0xFF
out EEARL, Temp ; Schreibe Lower Byte in Adressregister
sbi EECR, EERE ; Lesevorgang einleiten
in Status, EEDR ; Ausgelesenes Byte nach Status schreiben
andi Status, 0x01 ; Bit0 ist Statusbit, alle anderen löschen
sei ; Interrupts erlauben
Hauptprogramm: ; Hier beginnt das Hauptprogramm
sbis Pind, 3 ; Ist T2 gedrückt
rcall Taste2 ; Wenn ja, dann Taste2 abarbeiten
rjmp Hauptprogramm ; Hauptprogramm ist Endlosschleife
Timer_ISR: ; Interuptserviceroutine des Timers
rcall Test1 ; Aufruf von Test1
reti ; Ende ISR
; Ab hier folgen die Unterprogramme
;------------------------------------------------------------------------------
Taste2: ; Abarbeitung Taste2
sbis Pind, 3 ; Taste 2 losgelassen?
rjmp Taste2 ; Wenn nein, nochmal warten
cpi Status, 0x01 ; Ist Bit0 in Statusregister gesetzt?
brne Taste2_1 ; Wenn nein, springe zum Label Taste2_1
ldi Status, 0x00 ; Lösche Bit0 in Statusregister
rjmp Taste2_Ende ; Springe zum Ende
Taste2_1:
ldi Status, 0x01 ; Setze Bit0 in Statusregister
Taste2_Ende:
ret ; Ende UP
;------------------------------------------------------------------------------
Test1: ; Testroutine
out PortB, Status ; Ausgabe des Statusbytes
ret ; Ende UP
Code: Alles auswählen
; Z-Pointer einrichten
.def ZH = r31
.def ZL = r30
Code: Alles auswählen
rcall Init_Datenbank ; Initialisierung der Datenbank
Code: Alles auswählen
Init_Datenbank:
; Ampelbilder Automatikampel
ldi ZH, 0x01 ; 0x01 in Higherbyte von Z-Pointer laden
ldi ZL, 0x00 ; 0x00 in Lowerbyte von Z-Pointer laden
ldi Temp, 0b10100001 ; Hauptstrasse grün, Nebenstrasse rot
st z, Temp ; Ampelbild ablegen
ldi ZL, 0x01 ; 0x01 in Lowerbyte von Z-Pointer laden
ldi Temp, 0b10110010 ; Hauptstrasse gelb, Nebenstrasse rot-gelb
st z, Temp ; Ampelbild ablegen
ldi ZL, 0x02 ; 0x02 in Lowerbyte von Z-Pointer laden
ldi Temp, 0b01001100 ; Hauptstrasse rot, Nebenstrasse grün
st z, Temp ; Ampelbild ablegen
ldi ZL, 0x03 ; 0x03 in Lowerbyte von Z-Pointer laden
ldi Temp, 0b10010110 ; Hauptstrasse rot-gelb, Nebenstrasse gelb
st z, Temp ; Ampelbild ablegen
; Ampelbilder Anforderungsampel
ldi ZH, 0x02 ; 0x02 in Higherbyte von Z-Pointer laden
ldi ZL, 0x00 ; 0x00 in Lowerbyte von Z-Pointer laden
ldi Temp, 0b10000001 ; Hauptstrasse grün, Fussgänger rot
st z, Temp ; Ampelbild ablegen
ldi ZL, 0x01 ; 0x01 in Lowerbyte von Z-Pointer laden
ldi Temp, 0b10000010 ; Hauptstrasse gelb, Fussgänger rot
st z, Temp ; Ampelbild ablegen
ldi ZL, 0x02 ; 0x02 in Lowerbyte von Z-Pointer laden
ldi Temp, 0b01000100 ; Hauptstrasse rot, Fussgänger grün
st z, Temp ; Ampelbild ablegen
ldi ZL, 0x03 ; 0x03 in Lowerbyte von Z-Pointer laden
ldi Temp, 0b10000110 ; Hauptstrasse rot-gelb, Fussgänger rot
st z, Temp ; Ampelbild ablegen
ret
Code: Alles auswählen
Timer_ISR: ; Interuptserviceroutine des Timers
sbrs Status, 0 ; Ist Bit0 in Register Status gesetzt?
rjmp Autoampel_aus ; Momentan wird mit S2 die Ampel ausgeschalten
Code: Alles auswählen
Autoampel_aus:
ldi Temp, 0b00010010 ; Haupt- und Nebenstrasse gelb
out Portb, Temp ; Ausgabe Ampelbild
reti ; Ende ISR
Code: Alles auswählen
Automatikampel:
ldi ZH, 0x01 ; Z-Pointer vorladen
Code: Alles auswählen
sbis portb, 1 ; Liegt momentan Gelb-Phase an?
rjmp Auto_lang
Code: Alles auswählen
Auto_kurz:
cpi Time1, 0x2F ; Timer abgelaufen?
brne Auto_kurz_ende ; Wenn nein, dann Kurztimer Ende
rjmp Automatikampel_s ; Wenn ja, dann zur Ampelsteuerung
Auto_kurz_ende:
inc Time1 ; Time1 hochzählen
reti ; Ende ISR
Das funktionsfähige Programm sieht damit so aus:Automatikampel_s:
ldi Time1, 0x00 ; Time zurücksetzen
inc ZL ; Z-Pointer um 1 erhöhen
cpi ZL, 0x04 ; Steht ZL auf 04?
brne Automatikampel_s1 ; Wenn nein, dann weiter
ldi ZL, 0x00 ; Wenn ja, ZL=00
Automatikampel_s1:
ld Temp, z ; Inhalt von Z nach Temp laden
out portb, Temp ; Ausgabe neues Ampelbild
reti ; Ende der ISR
Code: Alles auswählen
; Workshop Projekt Ampel
; Autoren: Teilnehmer des Assemblerworkshops
; Version 2
; Vorgaben:
; EEPROM-Adresse für Statusbyte: 0x00FF
.include "m8def.inc" ; Damit weis der Compiler, auf welchen Proz er compilieren muss
.def Time1 = r16 ; Zeitvariable
.def Temp = r20 ; temporäre Variable
.def Status = r21 ; Statusbyte
; Z-Pointer einrichten
.def ZH = r31
.def ZL = r30
.org 0x0000
rjmp Init ; Springe nach einem Reset zum Label "Init"
.org 0x0009
rjmp Timer_ISR ; Interruptvektor für Overflow Timer0
Init: ; Hier beginnt die Initialisierung
; Setzen des Stackpointers
ldi r16, LOW(RAMEND) ; unteres Byte der hächstmöglichen Adresse holen
out SPL, r16 ; Unteres Byte des SP beschreiben
ldi r16, HIGH(RAMEND) ; oberes Byte der höchstmnöglichen Adresse holen
out SPH, r16 ; oberes Byte des SP beschreiben
; Initialisieren der Eingänge
ldi Temp, 0x00 ; alle Bits in Temp auf 0 setzen
out ddrd, Temp ; Alle Pins von Port D sind Eingang
ldi Temp, 0xFF ; Alle Bits ind Temp auf 1 setzen
out portd, Temp ; PC2 und PC3 bekommen PullUp-Widerstände
; Initialisieren der Ausgänge
out ddrb, Temp ; Alle Pins von Port B sind Ausgang (Temp ist noch 0xFF)
ldi Temp, 0x00 ; Alle Bits in Temp löschen
out portb, Temp ; Alle LEDs aus
; Initialisieren von Timer0
ldi Temp, 0b00000101 ; Prescaler 1024
out tccr0, Temp ; Prescaler in Timerregister schreiben
ldi Temp, 0b00000001 ; TimerOverflow 0 einschalten
out TIMSK, Temp
; Einlesen des Statusbytes
Lese_EEProm: ; Unterprogramm zum Auslesen des EEPROM
sbic EECR, EEWE ; ist der letzte Schreibvorgang beendet?
rjmp Lese_EEProm ; Wenn nein, dann nochmal prüfen
ldi Temp, 0x00 ; Higher Byte ist 0x00
out EEARH, Temp ; Schreibe Higher Byte in Adressregister
ldi Temp, 0xFF ; Lower Byte ist 0xFF
out EEARL, Temp ; Schreibe Lower Byte in Adressregister
sbi EECR, EERE ; Lesevorgang einleiten
in Status, EEDR ; Ausgelesenes Byte nach Status schreiben
andi Status, 0x01 ; Bit0 ist Statusbit, alle anderen löschen
rcall Init_Datenbank ; Initialisierung der Datenbank
sei ; Interrupts erlauben
Hauptprogramm: ; Hier beginnt das Hauptprogramm
sbis Pind, 3 ; Ist T2 gedrückt
rcall Taste2 ; Wenn ja, dann Taste2 abarbeiten
rjmp Hauptprogramm ; Hauptprogramm ist Endlosschleife
;------------------------------------------------------------------------------
Timer_ISR: ; Interuptserviceroutine des Timers
sbrs Status, 0 ; Ist Bit0 in Register Status gesetzt?
rjmp Autoampel_aus ; Momentan wird mit S2 die Ampel ausgeschalten
Automatikampel:
ldi ZH, 0x01 ; Z-Pointer vorladen
sbis portb, 1 ; Liegt momentan Gelb-Phase an?
rjmp Auto_lang
Auto_kurz:
cpi Time1, 0x2F ; Timer abgelaufen?
brne Auto_kurz_ende ; Wenn nein, dann Kurztimer Ende
rjmp Automatikampel_s ; Wenn ja, dann zur Ampelsteuerung
Auto_kurz_ende:
inc Time1 ; Time1 hochzählen
reti ; Ende ISR
Auto_lang:
cpi Time1, 0xFF ; Timer abgelaufen?
brne Auto_lang_ende ; Wenn nein, dann Kurztimer Ende
rjmp Automatikampel_s ; Wenn ja, dann zur Ampelsteuerung
Auto_lang_ende:
inc Time1 ; Time1 hochzählen
reti ; Ende ISR
Automatikampel_s:
ldi Time1, 0x00 ; Time zurücksetzen
inc ZL ; Z-Pointer um 1 erhöhen
cpi ZL, 0x04 ; Steht ZL auf 04?
brne Automatikampel_s1 ; Wenn nein, dann weiter
ldi ZL, 0x00 ; Wenn ja, ZL=00
Automatikampel_s1:
ld Temp, z ; Inhalt von Z nach Temp laden
out portb, Temp ; Ausgabe neues Ampelbild
reti ; Ende der ISR
Autoampel_aus:
ldi Temp, 0b00010010 ; Haupt- und Nebenstrasse gelb
out Portb, Temp ; Ausgabe Ampelbild
reti ; Ende ISR
; Ab hier folgen die Unterprogramme
;------------------------------------------------------------------------------
Taste2: ; Abarbeitung Taste2
sbis Pind, 3 ; Taste 2 losgelassen?
rjmp Taste2 ; Wenn nein, nochmal warten
cpi Status, 0x01 ; Ist Bit0 in Statusregister gesetzt?
brne Taste2_1 ; Wenn nein, springe zum Label Taste2_1
ldi Status, 0x00 ; Lösche Bit0 in Statusregister
rjmp Taste2_Ende ; Springe zum Ende
Taste2_1:
ldi Status, 0x01 ; Setze Bit0 in Statusregister
Taste2_Ende:
ret ; Ende UP
;------------------------------------------------------------------------------
Test1: ; Testroutine
out PortB, Status ; Ausgabe des Statusbytes
ret ; Ende UP
;------------------------------------------------------------------------------
Init_Datenbank:
; Ampelbilder Automatikampel
ldi ZH, 0x01 ; 0x01 in Higherbyte von Z-Pointer laden
ldi ZL, 0x00 ; 0x00 in Lowerbyte von Z-Pointer laden
ldi Temp, 0b10100001 ; Hauptstrasse grün, Nebenstrasse rot
st z, Temp ; Ampelbild ablegen
ldi ZL, 0x01 ; 0x01 in Lowerbyte von Z-Pointer laden
ldi Temp, 0b10110010 ; Hauptstrasse gelb, Nebenstrasse rot-gelb
st z, Temp ; Ampelbild ablegen
ldi ZL, 0x02 ; 0x02 in Lowerbyte von Z-Pointer laden
ldi Temp, 0b01001100 ; Hauptstrasse rot, Nebenstrasse grün
st z, Temp ; Ampelbild ablegen
ldi ZL, 0x03 ; 0x03 in Lowerbyte von Z-Pointer laden
ldi Temp, 0b10010110 ; Hauptstrasse rot-gelb, Nebenstrasse gelb
st z, Temp ; Ampelbild ablegen
; Ampelbilder Anforderungsampel
ldi ZH, 0x02 ; 0x02 in Higherbyte von Z-Pointer laden
ldi ZL, 0x00 ; 0x00 in Lowerbyte von Z-Pointer laden
ldi Temp, 0b10000001 ; Hauptstrasse grün, Fussgänger rot
st z, Temp ; Ampelbild ablegen
ldi ZL, 0x01 ; 0x01 in Lowerbyte von Z-Pointer laden
ldi Temp, 0b10000010 ; Hauptstrasse gelb, Fussgänger rot
st z, Temp ; Ampelbild ablegen
ldi ZL, 0x02 ; 0x02 in Lowerbyte von Z-Pointer laden
ldi Temp, 0b01000100 ; Hauptstrasse rot, Fussgänger grün
st z, Temp ; Ampelbild ablegen
ldi ZL, 0x03 ; 0x03 in Lowerbyte von Z-Pointer laden
ldi Temp, 0b10000110 ; Hauptstrasse rot-gelb, Fussgänger rot
st z, Temp ; Ampelbild ablegen
ret
Code: Alles auswählen
.def Time2 = r17 ; zweite Zeitvariable
Code: Alles auswählen
; Initialisieren der Zähler
ldi Time1, 0x00 ; Time1 beginnt bei 00
ldi Time2, 0x0F ; Time2 beginnt bei 0x0F
Code: Alles auswählen
ldi Temp, 0b00010010 ; Fussgänger aus, Strassen gelb
out portb, Temp
Code: Alles auswählen
dec Time2 ; Time2 um 1 zurückzählen
cpi Time2, 0x00 ; Ist Time2 abgelaufen?
breq Auto_kurz_1 ; Wenn ja, dann nächste Zählschleife
reti ; Wenn nein, Ende ISR
Auto_kurz_1:
ldi Time2, 0x0F ; Time2 wieder vorladen
Code: Alles auswählen
Taste2: ; Abarbeitung Taste2
sbis Pind, 3 ; Taste 2 losgelassen?
rjmp Taste2 ; Wenn nein, nochmal warten
cli ; Interrupts sperren
ldi Time2, 0x0F ; Time2 neu initialisieren
ldi Time1, 0x00 ; Time1 neu initialisieren
cpi Status, 0x01 ; Ist Bit0 in Statusregister gesetzt?
brne Taste2_1 ; Wenn nein, springe zum Label Taste2_1
ldi Status, 0x00 ; Lösche Bit0 in Statusregister
rjmp Taste2_Ende ; Springe zum Ende
Taste2_1:
ldi Status, 0x01 ; Setze Bit0 in Statusregister
Taste2_Ende:
sei ; Interrupts erlauben
ret ; Ende UP
Code: Alles auswählen
; Workshop Projekt Ampel
; Autoren: Teilnehmer des Assemblerworkshops
; Version 2
; Vorgaben:
; EEPROM-Adresse für Statusbyte: 0x00FF
.include "m8def.inc" ; Damit weis der Compiler, auf welchen Proz er compilieren muss
.def Time1 = r16 ; Zeitvariable
.def Time2 = r17 ; zweite Zeitvariable
.def Temp = r20 ; temporäre Variable
.def Status = r21 ; Statusbyte
; Z-Pointer einrichten
.def ZH = r31
.def ZL = r30
.org 0x0000
rjmp Init ; Springe nach einem Reset zum Label "Init"
.org 0x0009
rjmp Timer_ISR ; Interruptvektor für Overflow Timer0
Init: ; Hier beginnt die Initialisierung
; Setzen des Stackpointers
ldi r16, LOW(RAMEND) ; unteres Byte der hächstmöglichen Adresse holen
out SPL, r16 ; Unteres Byte des SP beschreiben
ldi r16, HIGH(RAMEND) ; oberes Byte der höchstmnöglichen Adresse holen
out SPH, r16 ; oberes Byte des SP beschreiben
; Initialisieren der Eingänge
ldi Temp, 0x00 ; alle Bits in Temp auf 0 setzen
out ddrd, Temp ; Alle Pins von Port D sind Eingang
ldi Temp, 0xFF ; Alle Bits ind Temp auf 1 setzen
out portd, Temp ; PC2 und PC3 bekommen PullUp-Widerstände
; Initialisieren der Ausgänge
out ddrb, Temp ; Alle Pins von Port B sind Ausgang (Temp ist noch 0xFF)
ldi Temp, 0b00010010 ; Fussgänger aus, Strassen gelb
out portb, Temp
; Initialisieren von Timer0
ldi Temp, 0b00000101 ; Prescaler 1024
out tccr0, Temp ; Prescaler in Timerregister schreiben
ldi Temp, 0b00000001 ; TimerOverflow 0 einschalten
out TIMSK, Temp
; Einlesen des Statusbytes
Lese_EEProm: ; Unterprogramm zum Auslesen des EEPROM
sbic EECR, EEWE ; ist der letzte Schreibvorgang beendet?
rjmp Lese_EEProm ; Wenn nein, dann nochmal prüfen
ldi Temp, 0x00 ; Higher Byte ist 0x00
out EEARH, Temp ; Schreibe Higher Byte in Adressregister
ldi Temp, 0xFF ; Lower Byte ist 0xFF
out EEARL, Temp ; Schreibe Lower Byte in Adressregister
sbi EECR, EERE ; Lesevorgang einleiten
in Status, EEDR ; Ausgelesenes Byte nach Status schreiben
andi Status, 0x01 ; Bit0 ist Statusbit, alle anderen löschen
rcall Init_Datenbank ; Initialisierung der Datenbank
; Initialisieren der Zähler
ldi Time1, 0x00 ; Time1 beginnt bei 00
ldi Time2, 0x0F ; Time2 beginnt bei 0x0F
sei ; Interrupts erlauben
Hauptprogramm: ; Hier beginnt das Hauptprogramm
sbis Pind, 3 ; Ist T2 gedrückt
rcall Taste2 ; Wenn ja, dann Taste2 abarbeiten
rjmp Hauptprogramm ; Hauptprogramm ist Endlosschleife
;------------------------------------------------------------------------------
Timer_ISR: ; Interuptserviceroutine des Timers
sbrs Status, 0 ; Ist Bit0 in Register Status gesetzt?
rjmp Autoampel_aus ; Momentan wird mit S2 die Ampel ausgeschalten
Automatikampel:
ldi ZH, 0x01 ; Z-Pointer vorladen
sbis portb, 1 ; Liegt momentan Gelb-Phase an?
rjmp Auto_lang
Auto_kurz:
dec Time2 ; Time2 um 1 zurückzählen
cpi Time2, 0x00 ; Ist Time2 abgelaufen?
breq Auto_kurz_1 ; Wenn ja, dann nächste Zählschleife
reti ; Wenn nein, Ende ISR
Auto_kurz_1:
ldi Time2, 0x0F ; Time2 wieder vorladen
cpi Time1, 0x01 ; Time1 abgelaufen?
brne Auto_kurz_ende ; Wenn nein, dann Kurztimer Ende
rjmp Automatikampel_s ; Wenn ja, dann zur Ampelsteuerung
Auto_kurz_ende:
inc Time1 ; Time1 hochzählen
reti ; Ende ISR
Auto_lang:
dec Time2 ; Time2 um 1 zurückzählen
cpi Time2, 0x00 ; Ist Time2 abgelaufen?
breq Auto_lang_1 ; Wenn ja, dann nächste Zählschleife
reti ; Wenn nein, Ende ISR
Auto_lang_1:
ldi Time2, 0x0F ; Time2 wieder vorladen
cpi Time1, 0x1F ; Timer abgelaufen?
brne Auto_lang_ende ; Wenn nein, dann Kurztimer Ende
rjmp Automatikampel_s ; Wenn ja, dann zur Ampelsteuerung
Auto_lang_ende:
inc Time1 ; Time1 hochzählen
reti ; Ende ISR
Automatikampel_s:
ldi Time1, 0x00 ; Time zurücksetzen
inc ZL ; Z-Pointer um 1 erhöhen
cpi ZL, 0x04 ; Steht ZL auf 04?
brne Automatikampel_s1 ; Wenn nein, dann weiter
ldi ZL, 0x00 ; Wenn ja, ZL=00
Automatikampel_s1:
ld Temp, z ; Inhalt von Z nach Temp laden
out portb, Temp ; Ausgabe neues Ampelbild
reti ; Ende der ISR
Autoampel_aus:
ldi Temp, 0b00010010 ; Haupt- und Nebenstrasse gelb
out Portb, Temp ; Ausgabe Ampelbild
reti ; Ende ISR
; Ab hier folgen die Unterprogramme
;------------------------------------------------------------------------------
Taste2: ; Abarbeitung Taste2
sbis Pind, 3 ; Taste 2 losgelassen?
rjmp Taste2 ; Wenn nein, nochmal warten
cli ; Interrupts sperren
ldi Time2, 0x0F ; Time2 neu initialisieren
ldi Time1, 0x00 ; Time1 neu initialisieren
cpi Status, 0x01 ; Ist Bit0 in Statusregister gesetzt?
brne Taste2_1 ; Wenn nein, springe zum Label Taste2_1
ldi Status, 0x00 ; Lösche Bit0 in Statusregister
rjmp Taste2_Ende ; Springe zum Ende
Taste2_1:
ldi Status, 0x01 ; Setze Bit0 in Statusregister
Taste2_Ende:
sei ; Interrupts erlauben
ret ; Ende UP
;------------------------------------------------------------------------------
Test1: ; Testroutine
out PortB, Status ; Ausgabe des Statusbytes
ret ; Ende UP
;------------------------------------------------------------------------------
Init_Datenbank:
; Ampelbilder Automatikampel
ldi ZH, 0x01 ; 0x01 in Higherbyte von Z-Pointer laden
ldi ZL, 0x00 ; 0x00 in Lowerbyte von Z-Pointer laden
ldi Temp, 0b10100001 ; Hauptstrasse grün, Nebenstrasse rot
st z, Temp ; Ampelbild ablegen
ldi ZL, 0x01 ; 0x01 in Lowerbyte von Z-Pointer laden
ldi Temp, 0b10110010 ; Hauptstrasse gelb, Nebenstrasse rot-gelb
st z, Temp ; Ampelbild ablegen
ldi ZL, 0x02 ; 0x02 in Lowerbyte von Z-Pointer laden
ldi Temp, 0b01001100 ; Hauptstrasse rot, Nebenstrasse grün
st z, Temp ; Ampelbild ablegen
ldi ZL, 0x03 ; 0x03 in Lowerbyte von Z-Pointer laden
ldi Temp, 0b10010110 ; Hauptstrasse rot-gelb, Nebenstrasse gelb
st z, Temp ; Ampelbild ablegen
; Ampelbilder Anforderungsampel
ldi ZH, 0x02 ; 0x02 in Higherbyte von Z-Pointer laden
ldi ZL, 0x00 ; 0x00 in Lowerbyte von Z-Pointer laden
ldi Temp, 0b10000001 ; Hauptstrasse grün, Fussgänger rot
st z, Temp ; Ampelbild ablegen
ldi ZL, 0x01 ; 0x01 in Lowerbyte von Z-Pointer laden
ldi Temp, 0b10000010 ; Hauptstrasse gelb, Fussgänger rot
st z, Temp ; Ampelbild ablegen
ldi ZL, 0x02 ; 0x02 in Lowerbyte von Z-Pointer laden
ldi Temp, 0b01000100 ; Hauptstrasse rot, Fussgänger grün
st z, Temp ; Ampelbild ablegen
ldi ZL, 0x03 ; 0x03 in Lowerbyte von Z-Pointer laden
ldi Temp, 0b10000110 ; Hauptstrasse rot-gelb, Fussgänger rot
st z, Temp ; Ampelbild ablegen
ret
Code: Alles auswählen
in ZH, EEDR ; Ausgelesenes Byte in Z-Pointer übernehmen
cpi ZH, 0x03 ; Ist der Wert größer als 0x02?
brge Korrektur_ZH ; wenn ja, springe zur Korrektur
cpi ZH, 0x00 ; Ist der Wert 0?
breq Korrektur_ZH ; wenn ja, springe zur Korrektur
rjmp Init_Ende
Korrektur_ZH:
ldi ZH, 0x01
init_Ende:
Code: Alles auswählen
Taste2: ; Abarbeitung Taste2
sbis Pind, 3 ; Taste 2 losgelassen?
rjmp Taste2 ; Wenn nein, nochmal warten
cli ; Interrupts sperren
ldi Time2, 0x0F ; Time2 neu initialisieren
ldi Time1, 0x00 ; Time1 neu initialisieren
cpi ZH, 0x01 ; Ist Bit0 in Statusregister gesetzt?
brne Taste2_1 ; Wenn nein, springe zum Label Taste2_1
ldi ZH, 0x02 ; Lösche Bit0 in Statusregister
rjmp Taste2_Ende ; Springe zum Ende
Taste2_1:
ldi ZH, 0x01 ; Setze Bit0 in Statusregister
Taste2_Ende:
sei ; Interrupts erlauben
ret ; Ende UP
Code: Alles auswählen
Timer_ISR: ; Interuptserviceroutine des Timers
sbis portb, 1 ; Liegt momentan Gelb-Phase an?
rjmp Auto_lang
Code: Alles auswählen
; Workshop Projekt Ampel
; Autoren: Teilnehmer des Assemblerworkshops
; Version 3
; Vorgaben:
; EEPROM-Adresse für Statusbyte: 0x00FF
.include "m8def.inc" ; Damit weis der Compiler, auf welchen Proz er compilieren muss
.def Time1 = r16 ; Zeitvariable
.def Time2 = r17 ; zweite Zeitvariable
.def Temp = r20 ; temporäre Variable
;.def Status = r21 ; Statusbyte
; Z-Pointer einrichten
.def ZH = r31
.def ZL = r30
.org 0x0000
rjmp Init ; Springe nach einem Reset zum Label "Init"
.org 0x0009
rjmp Timer_ISR ; Interruptvektor für Overflow Timer0
Init: ; Hier beginnt die Initialisierung
; Setzen des Stackpointers
ldi r16, LOW(RAMEND) ; unteres Byte der hächstmöglichen Adresse holen
out SPL, r16 ; Unteres Byte des SP beschreiben
ldi r16, HIGH(RAMEND) ; oberes Byte der höchstmnöglichen Adresse holen
out SPH, r16 ; oberes Byte des SP beschreiben
; Initialisieren der Eingänge
ldi Temp, 0x00 ; alle Bits in Temp auf 0 setzen
out ddrd, Temp ; Alle Pins von Port D sind Eingang
ldi Temp, 0xFF ; Alle Bits ind Temp auf 1 setzen
out portd, Temp ; PC2 und PC3 bekommen PullUp-Widerstände
; Initialisieren der Ausgänge
out ddrb, Temp ; Alle Pins von Port B sind Ausgang (Temp ist noch 0xFF)
ldi Temp, 0b00010010 ; Fussgänger aus, Strassen gelb
out portb, Temp
; Initialisieren von Timer0
ldi Temp, 0b00000101 ; Prescaler 1024
out tccr0, Temp ; Prescaler in Timerregister schreiben
ldi Temp, 0b00000001 ; TimerOverflow 0 einschalten
out TIMSK, Temp
; Einlesen des Statusbytes
Lese_EEProm: ; Unterprogramm zum Auslesen des EEPROM
sbic EECR, EEWE ; ist der letzte Schreibvorgang beendet?
rjmp Lese_EEProm ; Wenn nein, dann nochmal prüfen
ldi Temp, 0x00 ; Higher Byte ist 0x00
out EEARH, Temp ; Schreibe Higher Byte in Adressregister
ldi Temp, 0xFF ; Lower Byte ist 0xFF
out EEARL, Temp ; Schreibe Lower Byte in Adressregister
sbi EECR, EERE ; Lesevorgang einleiten
in ZH, EEDR ; Ausgelesenes Byte in Z-Pointer übernehmen
cpi ZH, 0x03 ; Ist der Wert größer als 0x02?
brge Korrektur_ZH ; wenn ja, springe zur Korrektur
cpi ZH, 0x00 ; Ist der Wert 0?
breq Korrektur_ZH ; wenn ja, springe zur Korrektur
rjmp Init_Ende
Korrektur_ZH:
ldi ZH, 0x01
init_Ende:
rcall Init_Datenbank ; Initialisierung der Datenbank
; Initialisieren der Zähler
ldi Time1, 0x00 ; Time1 beginnt bei 00
ldi Time2, 0x0F ; Time2 beginnt bei 0x0F
sei ; Interrupts erlauben
Hauptprogramm: ; Hier beginnt das Hauptprogramm
sbis Pind, 3 ; Ist T2 gedrückt
rcall Taste2 ; Wenn ja, dann Taste2 abarbeiten
rjmp Hauptprogramm ; Hauptprogramm ist Endlosschleife
;------------------------------------------------------------------------------
Timer_ISR: ; Interuptserviceroutine des Timers
sbis portb, 1 ; Liegt momentan Gelb-Phase an?
rjmp Auto_lang
Auto_kurz:
dec Time2 ; Time2 um 1 zurückzählen
cpi Time2, 0x00 ; Ist Time2 abgelaufen?
breq Auto_kurz_1 ; Wenn ja, dann nächste Zählschleife
reti ; Wenn nein, Ende ISR
Auto_kurz_1:
ldi Time2, 0x0F ; Time2 wieder vorladen
cpi Time1, 0x01 ; Time1 abgelaufen?
brne Auto_kurz_ende ; Wenn nein, dann Kurztimer Ende
rjmp Automatikampel_s ; Wenn ja, dann zur Ampelsteuerung
Auto_kurz_ende:
inc Time1 ; Time1 hochzählen
reti ; Ende ISR
Auto_lang:
dec Time2 ; Time2 um 1 zurückzählen
cpi Time2, 0x00 ; Ist Time2 abgelaufen?
breq Auto_lang_1 ; Wenn ja, dann nächste Zählschleife
reti ; Wenn nein, Ende ISR
Auto_lang_1:
ldi Time2, 0x0F ; Time2 wieder vorladen
cpi Time1, 0x05 ; Timer abgelaufen?
brne Auto_lang_ende ; Wenn nein, dann Kurztimer Ende
rjmp Automatikampel_s ; Wenn ja, dann zur Ampelsteuerung
Auto_lang_ende:
inc Time1 ; Time1 hochzählen
reti ; Ende ISR
Automatikampel_s:
ldi Time1, 0x00 ; Time zurücksetzen
inc ZL ; Z-Pointer um 1 erhöhen
cpi ZL, 0x04 ; Steht ZL auf 04?
brne Automatikampel_s1 ; Wenn nein, dann weiter
ldi ZL, 0x00 ; Wenn ja, ZL=00
Automatikampel_s1:
ld Temp, z ; Inhalt von Z nach Temp laden
out portb, Temp ; Ausgabe neues Ampelbild
reti ; Ende der ISR
Autoampel_aus:
ldi Temp, 0b00010010 ; Haupt- und Nebenstrasse gelb
out Portb, Temp ; Ausgabe Ampelbild
reti ; Ende ISR
; Ab hier folgen die Unterprogramme
;------------------------------------------------------------------------------
Taste2: ; Abarbeitung Taste2
sbis Pind, 3 ; Taste 2 losgelassen?
rjmp Taste2 ; Wenn nein, nochmal warten
cli ; Interrupts sperren
ldi Time2, 0x0F ; Time2 neu initialisieren
ldi Time1, 0x00 ; Time1 neu initialisieren
cpi ZH, 0x01 ; Ist Bit0 in Statusregister gesetzt?
brne Taste2_1 ; Wenn nein, springe zum Label Taste2_1
ldi ZH, 0x02 ; Lösche Bit0 in Statusregister
rjmp Taste2_Ende ; Springe zum Ende
Taste2_1:
ldi ZH, 0x01 ; Setze Bit0 in Statusregister
Taste2_Ende:
sei ; Interrupts erlauben
ret ; Ende UP
;------------------------------------------------------------------------------
;------------------------------------------------------------------------------
Init_Datenbank:
; Ampelbilder Automatikampel
ldi ZH, 0x01 ; 0x01 in Higherbyte von Z-Pointer laden
ldi ZL, 0x00 ; 0x00 in Lowerbyte von Z-Pointer laden
ldi Temp, 0b10100001 ; Hauptstrasse grün, Nebenstrasse rot
st z, Temp ; Ampelbild ablegen
ldi ZL, 0x01 ; 0x01 in Lowerbyte von Z-Pointer laden
ldi Temp, 0b10110010 ; Hauptstrasse gelb, Nebenstrasse rot-gelb
st z, Temp ; Ampelbild ablegen
ldi ZL, 0x02 ; 0x02 in Lowerbyte von Z-Pointer laden
ldi Temp, 0b01001100 ; Hauptstrasse rot, Nebenstrasse grün
st z, Temp ; Ampelbild ablegen
ldi ZL, 0x03 ; 0x03 in Lowerbyte von Z-Pointer laden
ldi Temp, 0b10010110 ; Hauptstrasse rot-gelb, Nebenstrasse gelb
st z, Temp ; Ampelbild ablegen
; Ampelbilder Anforderungsampel
ldi ZH, 0x02 ; 0x02 in Higherbyte von Z-Pointer laden
ldi ZL, 0x00 ; 0x00 in Lowerbyte von Z-Pointer laden
ldi Temp, 0b10000001 ; Hauptstrasse grün, Fussgänger rot
st z, Temp ; Ampelbild ablegen
ldi ZL, 0x01 ; 0x01 in Lowerbyte von Z-Pointer laden
ldi Temp, 0b10000010 ; Hauptstrasse gelb, Fussgänger rot
st z, Temp ; Ampelbild ablegen
ldi ZL, 0x02 ; 0x02 in Lowerbyte von Z-Pointer laden
ldi Temp, 0b01000100 ; Hauptstrasse rot, Fussgänger grün
st z, Temp ; Ampelbild ablegen
ldi ZL, 0x03 ; 0x03 in Lowerbyte von Z-Pointer laden
ldi Temp, 0b10000110 ; Hauptstrasse rot-gelb, Fussgänger rot
st z, Temp ; Ampelbild ablegen
ret