Dec_T15.asm
; ***************************************************************
; * Copyright by mad.dax@t-online.de *
; * DCC-Decoder Testversion *
; * 14 / 28 und 126 Fahrstufen ( Fahrstufe 14 = 27 ) *
; * Übergänge Stufenlos *
; * PWM mit 6125 HZ, internes Timing mit CV6 trimmbar *
; * kurze und lange Adressierung ( 7 und 14 Bit je nach CV ) *
; * F1 / F2 als Ausgänge, F3 als Rangiergang *
; * Mehrfachtraktion ( Consist ) noch nicht getestet *
; * Programming on the Track mit DDW-Server V 0.6.7 und *
; * Java DCC Railroad Network Client V 4.11 getestet *
; * Bedienung auch mit GPlan V 0.60 getestet *
; * Version: 06.04 *
; ***************************************************************
;
; Hardware Anforderungen:
;
; Standard Belegung
;
; Tiny 15 PDIP/SOIC
;
;(RESET/ADC0) PB5 = 1 8 = VCC
;(ADC3) PB4 = 2 7 = PB2 (ADC1/SCK/T0/INT0)
;(ADC2) PB3 = 3 6 = PB1 (AIN1/MISO/OC1A)
; GND = 4 5 = PB0 (AIN0/AREF/MOSI)
;
; DCC Decoder
;
;RESET PB5 = 1 8 = VCC
;Funktion 2 PB4 = 2 7 = PB2 DCC Eingang
;Funktion 1 PB3 = 3 6 = PB1 Ausgang Rückwärts
; GND = 4 5 = PB0 Ausgang Vorwärts
;NB: NMRA-DCC Basisprotokoll (abs. FRU, 7-bit-Adr., 14 FS)
;N1: NMRA-DCC erweitert (abs. FRU, 7-bit-Adr., 5 Funkt., 28 FS)
;N2: NMRA-DCC erweitert (abs. FRU, 7-bit-Adr., 5 Funkt., 128 FS)
;N3: NMRA-DCC erweitert (abs. FRU, 14-bit-Adr., 5 Funkt., 28 FS)
;N4: NMRA-DCC erweitert (abs. FRU, 14-bit-Adr., 5 Funkt., 128 FS)
;
; Software Funktionen:
;
.NOLIST
.INCLUDE "tn15def.inc"
;
; Konstanten FlagReg
;
.equ CONREV = 4 ;Consist Reverse Direction bei 1
.equ SERVMODE = 3 ;Programmiermodus
.equ BitNew =2 ;Flag Neues Bit eingetroffen
.equ LoTiF =1 ;Long Time Flag
.equ Bit =0 ;Bit Wert
; Konstanten DCCReg
;
.equ LongADR = 7 ;Lange Adresse bei 1
.equ RevDir = 6 ;Fahrtrichtung reversiert bei 1
.equ DIR =5 ;Fahrtrichtung 1=vorwärts, 0=rückwärts
.equ FL =4 ;FL nicht benutzt
.equ F4 =3 ;F4 nicht benutzt
.equ F3 =2 ;F3 Rangiergang bei 1-Signal
.equ F2 =1 ;F2
.equ F1 =0 ;F1
.equ SampleTime = 255 - 105 ;139- ca. 30 Befehlszyklen 75% der High-Signal Periodendauer = 87us ohne Precaler
.equ WaitTime = 255 - 200 ;250? maximale Bitlänge = 10000us bei Prescaler 64
.equ EEAdresse = 0 ;Speicherplatz eigene Adresse im EEPROM
.equ EEStart = 1 ;Speicherplatz Start-Speed nicht benutzt
.equ EEIncrease = 2 ;Speicherplatz Beschleunigungskonstante im EEPROM
.equ EEDecrease = 3 ;Speicherplatz Verzögerungskonstante im EEPROM
.equ EEMaxSpeed = 4 ;Speicherplatz Höchstgeschwindigkeit im EEPROM
.equ EEOSCCAL = 5 ;Speicherplatz OSCCAL im EEPROM
.equ EELongADR = 28 ;Speicherplatz Lange Adresse gesetzt im EEPROM
.equ EELongADRHI =16 ;Speicherplatz Lange Adresse EEPROM
.equ EELongADRLO = 17 ;Speicherplatz Lange Adresse EEPROM
.equ EECONAdr = 18 ;Speicherplatz Consist Adresse EEPROM
.equ ACKTime = 63 ;5 ms bei Timer 1 = CK/128
.equ RESTime = 250 ;20 ms bei Timer 1 = CK/128
;
; Benutzte Register
;
.def Adresse = R0 ;eigene Adresse
.def ISTSpeed = R1 ;berechnete Geschwindigkeit
.def SOLLSpeed = R2 ;Soll Geschwindigkeit
.def IncCnt = R3 ;Beschleunigungszähler/Bremszähler
.def IncVAL = R4 ;Beschleunigungkonstante
.def IncCnt1 = R5 ;Beschleunigungszähler/Bremszähler
.def DecVAL = R6 ;Bremskonstante
.def MaxSpeed = R7 ;Höchstgeschwindigkeit
.def ByteA = R8 ;Empfangenes Byte
.def ByteB = R9 ;Empfangenes Byte
.def ByteC = R10 ;Empfangenes Byte
.def ByteD = R11 ;Empfangenes Byte
.def ByteE = R12 ;Empfangenes Byte
.def ByteF = R13 ;Empfangenes Byte
.def HIAdresse = R14 ;eigene Adresse HI-Byte für lange Adresse
.def LoAdresse = R15 ;eigene Adresse Lo-Byte für lange Adresse
.def TEMPS = R16 ;SREG Sicherungsregister
.def TEMPI = R17 ;TEMP Register für Initialisierung und Interupt-Schmierregister
.def TEMP1 = R18 ;TEMP Register für Hauptprogramm und Initialisierung
.def TEMP2 = R19 ;TEMP Register für Hauptprogramm
.def TEMP3 = R20 ;TEMP Register für Hauptprogramm
.def CONAdr = R21 ;Consist-Adresse ( Mehrfachtraktion )
;def FREI = R22
.def FlagReg = R23 ;Flag Register
.def DCCReg = R24 ;DCC Register für Funktionen und Fahrtrichtung
.def ByteCNT = R25 ;Bytezähler für Datenhandling
.def BitCNT = R26 ;Bitzähler für Datenhandling
.def PRGCHECK = R27 ;Checkbyte für CV Schreiben
;def FREI = R28
;def FREI = R29
;def Reserviert = R30
;def Reserviert = R31
;
;
; Code beginnt hier
;
.CSEG
.ORG $0000
;
; Reset- und Interrupt-Vektoren
rjmp RESET ; Reset handler
rjmp EXT_INT0 ; IRQ0 handler
reti ;PIN_CHANGE ; Pin change handler
reti ;TIM1_CMP ; Timer1 compare match
rjmp TIM1_OVF ; Timer1 overflow handler
rjmp TIM0_OVF ; Timer0 overflow handler
reti ;EE_RDY ; EEPROM Ready handler
reti ;ANA_COMP ; Analog Comparator handler
reti ;ADC ; ADC Conversion Handler
;
;
; **************** Ende der Interrupt Service Routinen *********************
;
;
; 8x8 Bit Unsigned Multiplication von ATMEL
;def TEMP1 =r16 ;multiplicand
;def TEMP2 =r17 ;multiplier
;def TEMP2 =r17 ;result Low byte
;def TEMP3 =r18 ;result High byte
MUL8X8: clr TEMP3 ;clear result High byte
ldi ByteCNT,8 ;init loop counter
lsr TEMP2 ;rotate multiplier
MULSTART:
brcc MULMORE ;carry set
add TEMP3,TEMP1 ;add multiplicand to result High byte
MULMORE:
ror TEMP3 ;rotate right result High byte
ror TEMP2 ;rotate right result L byte and multiplier
dec ByteCNT ;decrement loop counter
brne MULSTART ;if not done, loop more
ret
writeEEPROM:
sbic EECR,EEWE ; wird momentan noch geschrieben ?
rjmp PC-1 ; Schleife
out EEAR,TEMP1 ; Erfasse EEProm Schreibadresse
out EEDR,TEMP2 ; Erfasse EEProm Schreibdaten
cli ; alle Interrupts ausschalten
sbi EECR,EEMWE ; Setze EEProm Master-Schreibbit
sbi EECR,EEWE ; Setze EEProm Schreib-Befehl
sbic EECR,EEWE ; wird momentan noch geschrieben ?
rjmp PC-1 ; Schleife
sei ; alle Interrupts wieder einschalten
ret ; Rücksprung
readEEPROM:
sbic EECR, EEWE ; wird noch geschrieben ?
rjmp PC-1 ; Schleife
out EEAR, TEMP1 ; Erfasse EEProm-Leseadresse
sbi EECR, EERE ; Setze EEProm-Lesebefehl
in TEMP2, EEDR ; Lese EEprom-Daten
ret ; Rücksprung
EXT_INT0: ;Flankenwechsel von Low auf High
in TEMPS,SREG ; SREG sichern
clr TEMPI ; Timer anhalten
out TCCR0,TEMPI ; Prescaler steht auf STOP-Counter mit 000
in TEMPI,TIFR ; lösche Timer 0 Interrupt Flag
andi TEMPI,0b00000010 ; das eventuell während dieses Interuptaufrufes
out TIFR,TEMPI ; gesetzt worden ist
cbr FlagReg, (1<<LoTiF)+(1<<BitNew); lösche Long Time Flag für Zeitüberschreitung
; lösche indikator für neues Bit
ldi TEMPI, SampleTime; lade das Timer/Counter0
out TCNT0,TEMPI ; mit der Zeit fuer 'Abtasten
ldi TEMPI,0b00000001 ; 0 0 0 Stop, the Timer/Counter0 is stopped.
out TCCR0,TEMPI ; 0 0 1 CK
; 0 1 0 CK/8
; 0 1 1 CK/64
; 1 0 0 CK/256
; 1 0 1 CK/1024
; 1 1 0 External Pin T0, falling edge
; 1 1 1 External Pin T0, rising edge
out SREG,TEMPS ; SREG rücksichern
reti ; Rücksprung und Interupts wieder einschalten
TIM1_OVF: ;Beschleunigungs/Verzögerungszähler
;bei Timer 1 = 1,6 MHz wird der
;Interupt wid demnach alle 6250 Hz ausgelöst
;die kürzeste Rampen-Zeit ist 0,12 Sec für den Sprung von 0 auf 252 bei IncVAL = 0
;die längste Rampen-Zeit ist 31,3 sec für den Sprung von 0 auf 252 bei IncVAL = 255
ldi TEMPI, 3 ; Verzögerungsfaktor
inc IncCNT1 ; erhöhe Zähler
cp IncCNT1, TEMPI
brne OVF1
clr IncCNT1 ; lösche Beschleunigungszähler
inc IncCNT
cp ISTSpeed, SOLLSpeed; vergleiche IST <> SOLL
breq Gleich ; wenn Wert nicht gleich
brsh DECSpeed ; wenn Wert größer gleich
brlo INCSpeed ; wenn Wert kleiner
Gleich: clr IncCNT ; lösche Beschleunigungszähler
clr IncCNT1 ; lösche Beschleunigungszähler
reti ; Rücksprung und Interupts wieder einschalten
INCSpeed: cp IncCNT, IncVAL ; vergleiche Beschleunigungszähler
brne OVF1 ; Springe wenn kleiner
clr IncCNT ; lösche Beschleunigungszähler
clr IncCNT1 ; lösche Beschleunigungszähler
inc ISTSpeed ; erhöhe Speed
rjmp PWMOut ; weiter
DECSpeed: cp IncCNT, DECVAL ; vergleiche Beschleunigungszähler
brne OVF1 ; Springe wenn kleiner
clr IncCNT ; lösche Beschleunigungszähler
clr IncCNT1 ; lösche Beschleunigungszähler
dec ISTSpeed ; verringere Speed
PWMOut: tst ISTSpeed ; ist Speed 0
brne OUT ; dann 0 ansonsten Out
ldi TEMPI,0b01000101 ; Timer/Counter1 PWM vom
out TCCR1,TEMPI ; Ausgang trennen
cbi PortB, PB0 ; alles auf Null
reti ; Rücksprung und Interupts wieder einschalten
OUT: sbrs DCCReg, DIR ; wenn Fahrtrichtung vorwärts
rjmp REV ; überspringe setzen Ausgang rückwärts
cbi PORTB, PB0 ; setze Ausgang für vorwärts
out OCR1A, ISTSpeed ; Wert für Speed nach Timer 1 Compare
ldi TEMPI,0b01100101 ; Timer/Counter1 PWM
out TCCR1,TEMPI ; Ausgang direkt
reti ; Rücksprung und Interupts wieder einschalten
REV: sbi PORTB, PB0 ; setze Ausgang für rückwärts
out OCR1A, ISTSpeed ; Wert für Speed nach Timer 1 Compare
ldi TEMPI,0b01110101 ; Timer/Counter1 PWM
out TCCR1,TEMPI ; Ausgang indirekt
OVF1: reti ; Rücksprung und Interupts wieder einschalten
TIM0_OVF:
in TEMPS,SREG ; SREG sichern
clr TEMPI ; Timer anhalten
out TCCR0,TEMPI ; Prescaler steht auf STOP-Counter mit 000
sbrs FlagReg,LoTiF ; ist der Interrupt wegen der Sample-Zeit ausgeloest worden
rjmp SAMPLE ; ja, dann sample das Bit
clr BitCnt ; nein, dann loesche den BitCounter wieder
clr ByteA
clr ByteB
clr ByteC
clr ByteD
clr ByteE
clr ByteF
cbr FlagReg, (1<<LoTiF)+(1<<BitNew); lösche Long Time Flag für Zeitüberschreitung
; lösche indikator für neues Bit
out SREG,TEMPS ; SREG rücksichern
reti ; Rücksprung und Interupts wieder einschalten
SAMPLE: in TEMPI, PINB ; hole PORT B
com TEMPI ; drehe PORT B
bst TEMPI, PB2 ; hole Eingangswert
bld FlagReg, Bit ; nach Merker
sbr FlagReg, (1<<BitNew)+(1<<LoTiF); und signalisiere neues Bit angekommen
; setze Long Time Flag für Zeitüberschreitung
ldi TEMPI,WaitTime ; lade das Timer/Counter0
out TCNT0,TEMPI ; mit der Zeit fuer Warten
ldi TEMPI,0b00000011 ; 0 0 0 Stop, the Timer/Counter0 is stopped.
out TCCR0,TEMPI ; 0 0 1 CK
; 0 1 0 CK/8
; 0 1 1 CK/64
; 1 0 0 CK/256
; 1 0 1 CK/1024
; 1 1 0 External Pin T0, falling edge
; 1 1 1 External Pin T0, rising edge
out SREG,TEMPS ; SREG rücksichern
reti ; Rücksprung und Interupts wieder einschalten
;BITFILTER:;Bitfilter
;clr BitCnt ;
;clr Temp1 ;
;sec ; setzte Carry
;rol Temp1 ; schiebe Carry von rechts in das Register
;BITFIL: cp BitCnt, Temp3 ; vergleiche mit Bitposition
;breq BITFILEND ; und springe wenn Bit auf Position
;rol Temp1 ; schiebe Carry von rechts in das Register
;inc BitCnt ; erhöhe Zähler
;rjmp BITFIL ; Schleife
;BITFILEND:ret ; Rücksprung
;BITSETZEN:;Bit-Wert holen
;clr BitCnt ;
;clr Temp1 ;
;sec ; setzte Carry
;sbrs ByteC, 3 ; wenn empfangenes Bit=1
;clc ; sonst lösche Carry
;rol Temp1 ; schiebe Carry von rechts in das Register
;BITSET: cp BitCnt, Temp3 ; vergleiche mit Bitposition
;breq BITSETEND ; und springe wenn Bit auf Position
;rol Temp1 ; schiebe Carry von rechts in das Register
;inc BitCnt ; erhöhe Zähler
;rjmp BITSET ; Schleife
;BITSETEND:ret ; Rücksprung
RUN: ; Timer und Interupts mit RUN-Werten laden
ldi TEMP1,0b00000110 ;Timer 0/1 Overflow enable
out TIMSK,TEMP1
ldi TEMP1,0b11111100 ; Timer/Counter1 PWM
out OCR1B,TEMP1 ; OCR1B mit 252
ldi TEMP1,0b01000101 ; 0 0 0 0 Timer/Counter1 is stopped.
out TCCR1,TEMP1 ; 0 0 0 1 CK*16 (=PCK)
; 0 0 1 0 CK*8 (=PCK/2)
; 0 0 1 1 CK*4 (=PCK/4)
; 0 1 0 0 CK*2 (=PCK/8)
; 0 1 0 1 CK für PWM mit 6125 Hz
; 0 1 1 0 CK/2
; 0 1 1 1 CK/4
; 1 0 0 0 CK/8
; 1 0 0 1 CK/16
; 1 0 1 0 CK/32
; 1 0 1 1 CK/64
; 1 1 0 0 CK/128
; 1 1 0 1 CK/256
; 1 1 1 0 CK/512
; 1 1 1 1 CK/1024
clr TEMP1
out TCNT1,TEMP1 ; lösche Timer 1
ldi TEMP1,0b00000110 ; lösche Timer Interupts
out TIFR,TEMP1
cbr Flagreg, (1<<SERVMODE); beende Servicemode
rjmp MAIN ; Endlosschleife
RESET: ; Programm Kaltstart
cli ; alle Interrupts ausschalten
ldi TEMP1,0b01000011 ;Interupt auf Rise-Flanke, Pull-Up Disabble
out MCUCR,TEMP1
ldi TEMP1,0b01000000 ;Interupt 0 enable
out GIMSK,TEMP1
ldi TEMP1,0b00000010 ;Timer 0 Overflow enable
out TIMSK,TEMP1
ldi TEMP1,0b00011011 ;PB0/1/3/4 als Ausgang, PB2/5 als Eingang
out DDRB,TEMP1
ldi TEMP1, EEOSCCAL ;hole Oszillator Calibrierung
rcall readEEProm
out OSCCAL, Temp2
ldi TEMP1, EEAdresse ;hole Adresse
rcall readEEProm
mov Adresse, Temp2
ldi TEMP1, EEIncrease ;hole Beschleunigung
rcall readEEProm
mov IncVAL, Temp2
ldi TEMP1, EEDecrease ;hole Verzögerung
rcall readEEProm
mov DecVAL, Temp2
ldi TEMP1, EEMaxSpeed ;hole Höchstgeschwindigkeit
rcall readEEProm
mov MaxSpeed, Temp2
ldi TEMP1, EELongADR ; Bit für Lange Adresse
rcall readEEProm
bst Temp2, 5
bld DCCReg, LongADR
bst Temp2, 0 ; Reversierbetrieb
bld DCCReg, RevDir
ldi TEMP1, EELongADRHI; Lange Adresse
rcall readEEProm
mov HIAdresse, Temp2
ldi TEMP1, EELongADRLO; Lange Adresse
rcall readEEProm
mov LOAdresse, Temp2
ldi TEMP1, EECONAdr ; Consist Adresse
rcall readEEProm
mov CONAdr, Temp2
bst CONAdr, 7 ; hole Consist Richtung
bld FlagReg, CONREV
andi CONAdr, 0b01111111; blende Richtung in Adresse aus
ldi TEMP1,0b00001100 ; 0 0 0 0 Timer/Counter1 is stopped.
out TCCR1,TEMP1 ; 0 0 0 1 CK*16 (=PCK)
; 0 0 1 0 CK*8 (=PCK/2)
; 0 0 1 1 CK*4 (=PCK/4)
; 0 1 0 0 CK*2 (=PCK/8)
; 0 1 0 1 CK
; 0 1 1 0 CK/2
; 0 1 1 1 CK/4
; 1 0 0 0 CK/8
; 1 0 0 1 CK/16
; 1 0 1 0 CK/32
; 1 0 1 1 CK/64
; 1 1 0 0 CK/128 für Resetzeit und ACK
; 1 1 0 1 CK/256
; 1 1 1 0 CK/512
; 1 1 1 1 CK/1024
ldi TEMP1, RESTime ; lade das Timer/Counter1
out TCNT1, TEMP1 ; mit der Zeit fuer Reset
ldi TEMP1,0b01000000 ; lösche externen Interupt 0
out GIFR,TEMP1
ldi TEMP1,0b00000110 ; lösche Timer Interupts
out TIFR,TEMP1
; bereinige alle benötigten Register
clr ISTSpeed
clr SOLLSpeed
clr IncCnt
clr IncCnt1
andi DCCReg, 0b11000000
clr TEMP1
out PortB, TEMP1
sbr Flagreg, (1<<SERVMODE) ; setze Service
sei ; aktiviere alle gesetzten Interupts
Main: ;hier beginnt das Hauptprogramm
clr BitCnt ; nein, dann loesche den BitCounter wieder
clr ByteA ; loesche die Empfangsregister wieder
clr ByteB
clr ByteC
clr ByteD
clr ByteE
clr ByteF
cbr FlagReg, (1<<BitNew)+(1<<Bit)+(1<<LoTif)
PREAMBLE: ; Prüfe Präambel nach NMRA-DCC
sbrs FlagReg, BitNew ; wenn kein neues Bit dann
rjmp PC-1 ; Schleife
cbr FlagReg,(1<<BitNew); lösche indikator für neues Bit
sbrs FlagReg, Bit ; wenn Bit = 1 dann erhöhe Zähler
rjmp PreEND ; ansonsten Signal für Präambel Ende
inc BitCnt ;
rjmp PREAMBLE ; Schleife
PreEND: cpi BitCnt, 10 ; wenn Bitzähler kleiner 10
brlo PreFehl ; dann Fehler
clr BitCnt ; lösche Zähler
rjmp GetByteA ; hole Adresse (kurze NMRA-Adresse )
PreFehl: rjmp MAIN ; Endlosschleife
GetByteA: ; hole erstes von bis zu sechs Bytes
sbrs FlagReg, BitNew ; wenn kein neues Bit dann
rjmp PC-1 ; Schleife
cbr FlagReg,(1<<BitNew); lösche indikator für neues Bit
cpi BitCnt, 8 ; vergleiche mit Bytelänge ;
breq ByteAENDE ; und springe wenn Byte eingelesen
sec ; setzte Carry
sbrs FlagReg, Bit ; wenn empfangenes Bit=1
clc ; lösche Carry
rol ByteA ; schiebe Carry von rechts in das Register
inc BitCnt ; erhöhe Zähler
rjmp GetByteA ; Schleife
ByteAENDE:mov Temp1, ByteA ; sichere Byte
sbrc FlagReg, Bit ; wenn empfangenes Bit=1
rjmp MAIN ; dann Byte nicht korrekt abgeschlossen
clr BitCnt ; lösche Zähler
GetByteB: ; hole zweites von bis zu sechs Bytes
sbrs FlagReg, BitNew ; wenn kein neues Bit dann
rjmp PC-1 ; Schleife
cbr FlagReg,(1<<BitNew); lösche indikator für neues Bit
cpi BitCnt, 8 ; vergleiche mit Bytelänge ;
breq ByteBENDE ; und springe wenn Byte eingelesen
sec ; setzte Carry
sbrs FlagReg, Bit ; wenn empfangenes Bit=1
clc ; lösche Carry
rol ByteB ; schiebe Carry von rechts in das Register
inc BitCnt ; erhöhe Zähler
rjmp GetByteB ; Schleife
ByteBENDE:eor TEMP1, ByteB ; bilde XOR
sbrc FlagReg, Bit ; wenn empfangenes Bit=1
rjmp MAIN ; dann Byte nicht korrekt abgeschlossen
clr BitCnt ; lösche Zähler
GetByteC: ; hole drittes von bis zu sechs Bytes
sbrs FlagReg, BitNew ; wenn kein neues Bit dann
rjmp PC-1 ; Schleife
cbr FlagReg,(1<<BitNew); lösche indikator für neues Bit
cpi BitCnt, 8 ; vergleiche mit Bytelänge ;
breq ByteCENDE ; und springe wenn Byte eingelesen
sec ; setzte Carry
sbrs FlagReg, Bit ; wenn empfangenes Bit=1
clc ; lösche Carry
rol ByteC ; schiebe Carry von rechts in das Register
inc BitCnt ; erhöhe Zähler
rjmp GetByteC ; Schleife
ByteCENDE:eor TEMP1, ByteC ; bilde XOR
sbrc FlagReg, Bit ; wenn empfangenes Bit=1
rjmp Check ; dann Telegrammende
clr BitCnt ; lösche Zähler
GetByteD: ; hole viertes von bis zu sechs Bytes
sbrs FlagReg, BitNew ; wenn kein neues Bit dann
rjmp PC-1 ; Schleife
cbr FlagReg,(1<<BitNew); lösche indikator für neues Bit
cpi BitCnt, 8 ; vergleiche mit Bytelänge ;
breq ByteDENDE ; und springe wenn Byte eingelesen
sec ; setzte Carry
sbrs FlagReg, Bit ; wenn empfangenes Bit=1
clc ; lösche Carry
rol ByteD ; schiebe Carry von rechts in das Register
inc BitCnt ; erhöhe Zähler
rjmp GetByteD ; Schleife
ByteDENDE:eor TEMP1, ByteD ; bilde XOR
sbrc FlagReg, Bit ; wenn empfangenes Bit=1
rjmp Check ; dann Telegrammende
clr BitCnt ; lösche Zähler
GetByteE: ; hole fünftes von bis zu sechs Bytes
sbrs FlagReg, BitNew ; wenn kein neues Bit dann
rjmp PC-1 ; Schleife
cbr FlagReg,(1<<BitNew); lösche indikator für neues Bit
cpi BitCnt, 8 ; vergleiche mit Bytelänge ;
breq ByteEENDE ; und springe wenn Byte eingelesen
sec ; setzte Carry
sbrs FlagReg, Bit ; wenn empfangenes Bit=1
clc ; lösche Carry
rol ByteE ; schiebe Carry von rechts in das Register
inc BitCnt ; erhöhe Zähler
rjmp GetByteE ; Schleife
ByteEENDE:eor TEMP1, ByteE ; bilde XOR
sbrc FlagReg, Bit ; wenn empfangenes Bit=1
rjmp Check ; dann Telegrammende
clr BitCnt ; lösche Zähler
GetByteF: ; hole sechstes Byte
sbrs FlagReg, BitNew ; wenn kein neues Bit dann
rjmp PC-1 ; Schleife
cbr FlagReg,(1<<BitNew); lösche indikator für neues Bit
cpi BitCnt, 8 ; vergleiche mit Bytelänge ;
breq ByteFENDE ; und springe wenn Byte eingelesen
sec ; setzte Carry
sbrs FlagReg, Bit ; wenn empfangenes Bit=1
clc ; lösche Carry
rol ByteF ; schiebe Carry von rechts in das Register
inc BitCnt ; erhöhe Zähler
rjmp GetByteF ; Schleife
ByteFENDE:eor TEMP1, ByteF ; bilde XOR
sbrs FlagReg, Bit ; wenn empfangenes Bit=0
rjmp MAIN ; dann Byte nicht korrekt abgeschlossen
Check: ; Datenprüfung und Übergabe
tst TEMP1 ; prüfe auf 0
brne CHECKFehl ; wenn nicht 0 dann Fehler
sbrc Flagreg, SERVMODE
rjmp Servicemode; Programmiermodus CV-Lesen, Schreiben, Bitmanipulation
ldi TEMP1, 0 ; prüfe Adresse
cp ByteA, TEMP1 ; wenn 0 dann
breq CHECKALL ; Broadcast an alle
ldi TEMP1, 255 ; prüfe Adresse
cp ByteA, TEMP1 ; wenn 255 dann
breq CHECKIDLE ; IDLE an alle
tst CONAdr ; prüfe Consist-Adresse ( Mehrfachtraktion ) auf NULL
brne CONCHECK ; und springe wenn gesetzt
sbrc DCCReg, LongADR ; wenn Bit gesetzt
rjmp CHECKLONG ; lange Adresse
cp Adresse, ByteA ; wenn eigene Adresse
breq CHECKEND ; dann Check OK
CHECKIDLE:; alle Decoder sind IDLE
CHECKFehl:;Prüfsummenfehler
rjmp MAIN ; Endlosschleife
CONCHECK: ;Prüfung auf Consistadresse
mov TEMP1, ByteA ; sichere Daten
andi TEMP1, 0b01111111; blende Bit 7 aus
cp CONAdr, TEMP1 ; wenn eigene Consist-Adresse
breq CHECKEND ; dann Check OK
rjmp MAIN ; Endlosschleife
CHECKLONG:;lange Adresse
mov TEMP1, ByteA ; prüfe Adresse
andi Temp1, 0b11000000; auf lange Adresse
cpi Temp1, 0b11000000; wenn nicht gleich dann
brne CHECKFehl ; sind wir nicht gemeint
mov TEMP1, ByteA
cp HIAdresse, TEMP1 ; prüfe HI-Adresse
brne CHECKFehl
mov TEMP1, ByteB
cp LOAdresse, TEMP1 ; prüfe LO-Adresse
brne CHECKFehl
mov ByteB, ByteC ; schiebe Bytes
mov ByteC, ByteD
mov ByteD, ByteE
mov ByteE, ByteF
CHECKALL: ; alle Decoder sind angesprochen
CHECKEND: ;Adresse und Prüfsumme OK
;Funktionen
mov TEMP1, ByteB ;Daten sichern
andi TEMP1,0b11100000 ;Datenbits ausblenden
cpi TEMP1, 0b00000000 ;Vergleiche mit Consist Control
breq Consist
cpi TEMP1, 0b00100000 ;Vergleiche mit Advanced Operation
breq Advanced
cpi TEMP1, 0b01000000 ;Vergleiche mit Speed Rückwärts
breq SpeedCalc
cpi TEMP1, 0b01100000 ;Vergleiche mit Speed Vorwärts
breq SpeedCalc
cpi TEMP1, 0b10000000 ;Vergleiche mit Funktionsgruppe F1-F4
breq FGroup1
; cpi TEMP1, 0b10100000 ;Vergleiche mit Funktionsgruppe F5-F8
; cpi TEMP1, 0b11000000 ;Vergleiche mit Future Expansion
; cpi TEMP1, 0b11100000 ;Vergleiche mit CV Access
; breq CVAccess
rjmp MAIN ;Endlosschleife
Consist: rjmp CONCTRL
Advanced: rjmp ADVCTRL
;CVAccess: rjmp CVACC
SpeedCalc:;Speed Berechnung 14 und 28 Fahrstufen
tst ISTSpeed ; schreibe Richtung nur
brne Speed28 ; wenn Speed 0
mov TEMP2, ByteB ; Daten sichern
sbrc DCCReg, RevDir ; wenn Fahrrichtung nicht reversiert
com ByteB ; dann wird Byte nicht gedreht
sbrc FlagReg, CONREV ; wenn Fahrrichtung in Consist nicht reversiert
com ByteB ; dann wird Byte nicht gedreht
bst ByteB, 5 ; hole Richtungsbit
bld DCCReg, DIR ; nach DCC Register
Speed28: clc ;
sbrc TEMP2, 4 ;
sec ;
andi TEMP2, 0b00001111;
rol TEMP2 ;
cpi TEMP2, 0b00000010 ;
brlo STOP ; Stop
cpi TEMP2, 0b00000100 ;
brlo ESTOP ; ESD
subi TEMP2,0b00000011 ;
sbrc DCCReg, F3 ; Rangiergang
rjmp Rangier ;
ldi TEMP1, 9 ; Max-Speed 28*9 = 252
rcall MUL8X8 ;
cp TEMP2, MaxSpeed ;
brsh Limit ;
mov SOLLSpeed, TEMP2 ;
rjmp MAIN ; Endlosschleife
Rangier: ;Rangiergang 14 und 28 Fahrstufen
ldi TEMP1, 3 ; Max-Speed 28*3 = 84
rcall MUL8X8 ;
mov SOLLSpeed, TEMP2 ;
rjmp MAIN ; Endlosschleife
LongSpeed:;Speed Berechnung 128 Fahrstufen
tst ISTSpeed ; schreibe Richtung nur
brne Speed126 ; wenn Speed 0
mov TEMP2, ByteC ; Daten sichern
sbrc DCCReg, RevDir ; wenn Fahrrichtung nicht reversiert
com ByteC ; dann wird Byte nicht gedreht
sbrc FlagReg, CONREV ; wenn Fahrrichtung in Consist nicht reversiert
com ByteC ; dann wird Byte nicht gedreht
bst ByteC, 7 ; hole Richtungsbit
bld DCCReg, DIR ; nach DCC Register
Speed126: andi TEMP2, 0b01111111; blende Richtung aus
cpi TEMP2, 0b00000000;
breq STOP ; Stop
cpi TEMP2, 0b00000001;
breq ESTOP ; ESD
subi TEMP2, 0b00000001; 128 - 1 macht 127 Fahrstufen
sbrc DCCReg, F3 ; Rangiergang
rjmp RangLong ; hier Speed durch 2
ldi TEMP1, 2 ; Max-Speed 126*2 = 252
rcall MUL8X8 ;
RangLong: cp TEMP2, MaxSpeed ;
brsh Limit ;
mov SOLLSpeed, TEMP2 ;
rjmp MAIN ; Endlosschleife
FGroup1: ;Funktionsgruppe 1
mov TEMP2, ByteB ; Daten sichern
andi DCCReg,0b11100000; Funktionen ausblenden
andi TEMP2, 0b00011111; Richtung ausblenden
or DCCReg, TEMP2 ; neue Funktionen speichern
in TEMP1, PortB ;
bst DCCReg, F1 ;
bld TEMP1, PB3 ;
bst DCCReg, F2 ;
bld TEMP1, PB4 ;
out PORTB, TEMP1 ;
rjmp MAIN ; Endlosschleife
Limit: mov SOLLSpeed, MaxSpeed
rjmp MAIN ; Endlosschleife
STOP: clr SOLLSpeed ;
rjmp MAIN ; Endlosschleife
ESTOP: clr SOLLSpeed ;
clr ISTSpeed ;
ldi TEMP1,0b01000101 ; Timer/Counter1 PWM vom
out TCCR1,TEMP1 ; Ausgang trennen
cbi PortB, PB0 ; alles auf Null
rjmp MAIN ; Endlosschleife
CONCTRL: ;Consist Control
mov TEMP1, ByteC ;Daten sichern
andi TEMP1, 0b11110000;LO-Nibble ausblenden
cpi TEMP1, 0b00000000;vergleiche mit Decoder Control
breq DECCON
cpi TEMP1, 0b00010000;vergleiche mit Consist Control
breq CONCON
rjmp MAIN ; Endlosschleife
DECCON: ;Decoder Control
mov TEMP1, ByteC ;Daten sichern
andi TEMP1,0b00001111 ;Hi-Nibble ausblenden
cpi TEMP1, 0b00000000 ;vergleiche mit Reset
breq DECCONReset
cpi TEMP1, 0b00000001 ;vergleiche mit Hard-Reset
breq DECCONHardReset
cpi TEMP1, 0b00001111 ;vergleiche mit Acknowledgement Request
breq DECCONAcc
lsr TEMP1 ;schiebe Bit 0 raus
; cpi TEMP1, 0b00000001 ;vergleiche mit Factory Test
; cpi TEMP1, 0b00000010 ;vergleiche mit Future Use
; cpi TEMP1, 0b00000011 ;vergleiche mit Advanced Acknowledgement
; cpi TEMP1, 0b00000100 ;vergleiche mit Future Use
cpi TEMP1, 0b00000101 ;vergleiche mit Advanced Adressing
breq DECCONAdr
; cpi TEMP1, 0b00000110 ;vergleiche mit Future Use
rjmp MAIN ;Endlosschleife
DECCONReset: rjmp Reset
DECCONHardReset: wdr
DECCONAcc: rjmp PRGACK
DECCONAdr: bst ByteC, 0
bld DCCReg, LongADR
rjmp MAIN ;Endlosschleife
CONCON: ;Consist Control
ldi TEMP3, EECONAdr ; setzte Schreib-Adresse
mov TEMP2, ByteD ; hole Daten
mov TEMP1, ByteC ; Daten sichern
cpi TEMP1, 0b00010010 ; vergleiche mit Consist normal Direction
breq CONDIR
cpi TEMP1, 0b00010011 ; vergleiche mit Consist reverse Direction
breq CONINV
rjmp MAIN ; Endlosschleife
CONDIR: andi TEMP2, 0b01111111; setze Richtung auf Direct
rcall writeEEPROM ; und schreibe ins EEPROM
rjmp Reset ; Decoder Reset für neue Datenübernahme
CONINV: ori TEMP2, 0b10000000; setze Richtung auf Reverse
rcall writeEEPROM ; und schreibe ins EEPROM
rjmp Reset ; Decoder Reset für neue Datenübernahme
ADVCTRL: ;Advanced Control
mov TEMP1, ByteB ;Daten sichern
andi TEMP1,0b00011111 ;Hi-Nibble ausblenden
cpi TEMP1, 0b00011111 ;128 Speed Step
breq Speed128
cpi TEMP1, 0b00011110 ;Restricted Speed Step
rjmp MAIN ;Endlosschleife
Speed128: rjmp LongSpeed ;Speed Berechnung 128 Fahrstufen
;CVACC: ;CV Access Instuction ( kurze Form )
; mov TEMP1, ByteB ;Daten sichern
; cpi TEMP1, 0b11110010 ;2. Beschleunigungsvariable
; cpi TEMP1, 0b11110011 ;2. Bremsvariable
;CVACCEND: rjmp MAIN ;Endlosschleife
Servicemode:; Programmiermodus CV-Lesen, Schreiben, Bitmanipulation
ldi TEMP1, 0b01111000 ; prüfe Funktionscode
cp ByteA, TEMP1 ; auf CV Bitmanpulation
breq PRGBITMAN ; Bitmanipulation wird nicht unterstützt
ldi TEMP1, 0b01110100 ; prüfe Funktionscode
cp ByteA, TEMP1 ; auf CV Verify Byte
breq PRGVERIFY ; Verifizierung
ldi TEMP1, 0b01111100 ; prüfe Funktionscode
cp ByteA, TEMP1 ; auf CV Write Byte
breq PRGWRITE ; Schreiben
;Prüfung auf Reset
in TEMP1, TIFR ; hole Timer Interuptflag
sbrs TEMP1, TOV1 ; wenn Resetzeit abgelaufen und kein Programmierbefehl
rjmp MAIN ;
rjmp RUN ; setze Timer auf RUN-Werte
PRGBITMAN:;Bitmanipulation
rjmp main
;ldi Temp1, 0b00010000; Bit-Filter für Write (1) und Verify (0)
;and TEMP1, ByteC ; UND mit Datenbyte
;tst Temp1 ; prüfe auf 0
;brne BITWRITE ;
;BITVERIFY:;Bitverify
;ldi Temp3, 0b00000111; Bit-Filter für Byteposition
;and Temp3, ByteC ; mit Datenbyte
;rcall BITFILTER
;mov Temp3, Temp1 ; sichere Bitfilter
;mov Temp1, ByteB ; hole Adresse
;rcall readEEPROM ; lese CV
;and Temp2, Temp3 ; Bits ausblenden
;ldi Temp3, 0b00000111; Bit-Filter für Byteposition
;and Temp3, ByteC ; mit Datenbyte
;;rcall BITSETZEN
;cpse Temp1, Temp2 ; Teste ob gleich
;rjmp Main
;rjmp PRGACK ; Acknowlege
;BITWRITE:;BITWRITE
;cpi ByteCNT, 2 ; prüfe Checkzähler
;brlo BITWRITEEND ; ob Daten mehr als zweimal gleich empfangen
;ldi Temp3, 0b00000111 ; Bit-Filter für Byteposition
;and Temp3, ByteC ; mit Datenbyte
;rcall BITFILTER
;mov Temp3, Temp1 ; sichere Bitfilter
;mov Temp1, ByteB ; hole Adresse
;rcall readEEPROM ; lese CV
;com TEMP3 ; drehe Bitmuster
;and Temp2, Temp3 ; Bit ausblenden
;ldi Temp3, 0b00000111 ; Bit-Filter für Byteposition
;and Temp3, ByteC ; mit Datenbyte
;rcall BITSETZEN
;or Temp2,Temp1 ; Bit mit altem Bitmuster verodern
;mov Temp1, ByteB ; hole Adresse
;rcall writeEEPROM ; Schreibe CV
;clr ByteCNT ; lösche Checkzähler
;rjmp PRGACK ; Acknowlege
;BITWRITEEND:rjmp main
PRGVERIFY:mov TEMP1, ByteB ; setze Lese-Adresse
rcall readEEPROM ; lies
cpse TEMP2, ByteC ; und vergleiche
rjmp main ; wenn gleich dann
sbi PortB, PB0 ; setze einen Motorausgang
rjmp PRGACK ; ACK
PRGWRITE: cp PRGCHECK, ByteD ; vergleiche mit vorherigen Daten (XOR-Byte)
brne PRGWRACK ; springe wenn ungleich
mov TEMP1, ByteB ; setzte Schreib-Adresse
mov TEMP2, ByteC ; hole Daten
rcall writeEEPROM ; und schreibe ins EEPROM
PRGWRACK: mov PRGCHECK, ByteD ; Datencheck
sbi PortB, PB1 ; setze einen Motorausgang
PRGACK: ; Acknowledge
cli ; alle Interrupts ausschalten
ldi TEMP1, ACKTime ; lade den Timer/Counter1
ldi TEMP1,0b00001100 ; 1 1 0 0 CK/128 für Resetzeit und ACK
out TCCR1,TEMP1 ;
out TCNT1, TEMP1 ; setze Zeit für Acknowlege
in TEMP1, TIFR ; hole Timer Interuptflag
sbrs TEMP1, TOV1 ; wenn Ackzeit abgelaufen
rjmp PC-2 ; Schleife
ldi TEMP1, 0b00000110; lösche Timer Interupts
out TIFR, TEMP1
clr TEMP1
out PortB, TEMP1 ; lösche Motorausgang
sei ; alle Interrupts wieder einschalten
rjmp MAIN ; Endlosschleife
;** hier beginnt das EEProm **
.ESEG
.ORG $0000
.db 0x01, 0x00 ; Adresse und StartSpeed
.db 0x80, 0x80 ; IncVAL und DecVal
.db 0x80, 0x71 ; MaxSpeed und OSCCAL
.db 0xFF, 0xFF ; Frei und Frei
.db 0xFF, 0xFF ; Frei und Frei
.db 0xFF, 0xFF ; Frei und Frei
.db 0xFF, 0xFF ; Frei und Frei
.db 0xFF, 0xFF ; Frei und Frei
.db 0xC0, 0x01 ; HI-Byte und LO-Byte
.db 0x00, 0xFF ; Consist und Frei
.db 0xFF, 0xFF ; Frei und Frei
.db 0xFF, 0xFF ; Frei und Frei
.db 0xFF, 0xFF ; Frei und Frei
.db 0xFF, 0xFF ; Frei und Frei
.db 0x00, 0xFF ; Configuration Data und Frei