www.mikrocontroller.net

Dec_T15.asm

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    
webmaster@mikrocontroller.net – Impressum – Werbung auf Mikrocontroller.net