/********************************************************************************
* DCC Wagen Decoder Software V1.0 *
* Copyright 2011 Toralf Wilhelm *
* *
* private Nutzung erwünscht, gewerbliche Nutzung erfordert zwingend meine Zustimmung! *
* Datei: interrupt.S *
* Kontakt: toralfwilhelm@web.de *
* Webseite: www.toralfwilhelm.de *
* Version: 01/2011 Version 1 Start *
* Beschreibung: enthält die Interruptschleifen der DCC Lichtdecoder Software *
********************************************************************************/
/***************************
* Register und Konstanten *
***************************/
; intsreg
; DCCport
; DCCpin
; Lowpegel
; Highpegel
; DCCreg
; analog_sw
; analog_sw_zeit
; w
; flag
; EmpPos
; Bitzaehler
; DCC_xor
; ByteA-ByteF
; Zaehler_10us
; U_LED
#include "definitionen.h"
.text
/***********************
* Timer_0/2_interrupt *
***********************
bei tiny44/45 Timer0 bei mega8 Timer2
wird alle 10us ausgelöst und liest dann bit von int0/d2 (auch jeder andere pin möglich) ein
dazu teiler auf1 (8tackte=1us) -> bis 80 zählen lassen und einen Compare interrupt auslösen
zw 26 und 34 cpu tackte -> 25-30% cpu leistung werden hier verbraucht!
es werden die register intsreg,lowpegel,highpegel belegt
das ergebnis wird mit dem flag neuerBefehl angezeigt und in ByteA-F zurückgegeben
*/
#ifdef __AVR_ATmega8__
TIM2_COMP:
#elif defined (__AVR_ATtiny44__) || defined(__AVR_ATtiny45__)
TIM0_COMPA:
#endif
in intsreg,SREG // sreg sichern bewußt nicht im fifo abgelegt, da so schneller
sbic DCCport,DCCpin // wenn aktueller Pegel=0 1x springen
rjmp DCC_PIN_HIGH
inc Lowpegel // Lowpegel inc
brne DCC_BIT_SET // wenn beim inc kein Überlauf (z=0) weiter mit..
rjmp KEIN_DCC_SETZTEN // sonst zu..
DCC_PIN_HIGH:
inc Highpegel // Highpegel inc
brne DCC_BIT_SET // wenn beim inc kein Überlauf (z=0) weiter mit..
KEIN_DCC_SETZTEN:
ldi Lowpegel,11 // wenn Überlauf war, Lowpegel auf min für Lowbit setzen
sbrs DCCreg,analog // wenn analog erlaubt 1x springen
rjmp DCC_BIT_SET // sonst fertig gleich weiter mit
push w // Arbeitsregister sichern (nur machen wenn kein DCC Signal verhanden
// dadurch verlängert sich die interruptschleife)
lds w,analog_sw
inc w // analog_sw erhöhen (Umschaltverzögerung)
cpi w,analog_sw_zeit // analog_zw_zeit*255*10us= ca 100ms auf DCC Pulse warten (bei analog_zw_zeit=40)
brlo KEIN_DCC_SETZTEN_END // dann auf analog umschalten
clr w
sbr DCCreg,1<<keinDCC
pop w
rjmp DCC_BIT_SET
KEIN_DCC_SETZTEN_END:
sts analog_sw,w
pop w
DCC_BIT_SET:
cpi Lowpegel,3 // wenn mindestens 3x Low eingetroffen
brne 1f // dann 1x springen
clr Highpegel // sonst erst Highpegel löschen
1: cpi Highpegel,3 // ist jetzt Highpegel = 3
brne ZU_TIM2_COMP_ENDE // wenn ungleich, dann zu
cbr flag,(1<<bit) // neues bit löschen
cpi Lowpegel,7 // ist Lowpegel kleiner 7
brsh 1f // wenn größer/gleich 1x springen
sbr flag,(1<<bit) // neues bit setzen
1: clr Lowpegel // Lowpegel wieder löschen
inc Highpegel // zur sicherheit 1x erhöhen, damit nicht noch ein Byte erkannt wird
DCC_SCHLEIFE: // DCC Bits zu Befehl zusammensetzten
cpi EmpPos,Preamble // auf Empfangsposition Preamble testen
brne LESE_BYTE_A
sbrs flag,bit // wenn das neue Bit = 1 dann erhöhe Zähler
rjmp PRE_END // ansonsten Signal für Präambel Ende
inc bitzaehler //
ZU_TIM2_COMP_ENDE: // (Sprungverlängerungslabel)
rjmp TIM2_COMP_ENDE // erst einmal fertig
PRE_END:
cpi bitzaehler,10 // wenn Bitzähler kleiner 10
brlo PRE_FEHLER // dann Fehler
clr bitzaehler // lösche Zähler
ldi EmpPos,ByteA_lesen
rjmp TIM2_COMP_ENDE // erst einmal fertig
PRE_FEHLER:
rjmp DCC_NEUSTART // Endlosschleife
LESE_BYTE_A:
cpi EmpPos,ByteA_lesen // auf Empfangsposition Byte A testen
brne LESE_BYTE_B
sbrc flag,neuerBefehl // nur neuen Befehl einlesen, wenn letzter abgearbeitet
rjmp DCC_NEUSTART // sonst DCC Neustart machen
cpi bitzaehler,8 // vergleiche mit Bytelänge
breq BYTE_A_END // und springe wenn Byte eingelesen
sec // setzte Carry
sbrs flag,bit // wenn empfangenes Bit=1 1x springen
clc // lösche Carry
rol byteA // schiebe Carry von rechts in das Register
inc bitzaehler // erhöhe Zähler
rjmp TIM2_COMP_ENDE // erst einmal fertig
BYTE_A_END:
mov DCC_xor,byteA // sichere Byte
sbrc flag,bit // springe 1x wenn empfangenes Bit=0
rjmp DCC_NEUSTART // sonst Byte nicht korrekt abgeschlossen
clr bitzaehler // lösche Zähler
ldi EmpPos,ByteB_lesen
rjmp TIM2_COMP_ENDE // erst einmal fertig
LESE_BYTE_B:
cpi EmpPos,ByteB_lesen // auf Empfangsposition Byte B testen
brne LESE_BYTE_C
cpi bitzaehler,8 // vergleiche mit Bytelänge
breq BYTE_B_END // und springe wenn Byte eingelesen
sec // setzte Carry
sbrs flag,bit // wenn empfangenes Bit=1 1x springen
clc // lösche Carry
rol byteB // schiebe Carry von rechts in das Register
inc bitzaehler // erhöhe Zähler
rjmp TIM2_COMP_ENDE // erst einmal fertig
BYTE_B_END:
eor DCC_xor,byteB // bilde XOR
sbrc flag,bit // springe 1x wenn empfangenes Bit=0
rjmp DCC_NEUSTART // sonst Byte nicht korrekt abgeschlossen
clr bitzaehler // lösche Zähler
ldi EmpPos,ByteC_lesen
rjmp TIM2_COMP_ENDE // erst einmal fertig
LESE_BYTE_C:
cpi EmpPos,ByteC_lesen // auf Empfangsposition Byte C testen
brne LESE_BYTE_D
cpi bitzaehler,8 // vergleiche mit Bytelänge
breq BYTE_C_END // und springe wenn Byte eingelesen
sec // setzte Carry
sbrs flag,bit // wenn empfangenes Bit=1 1x springen
clc // lösche Carry
rol byteC // schiebe Carry von rechts in das Register
inc bitzaehler // erhöhe Zähler
rjmp TIM2_COMP_ENDE // erst einmal fertig
BYTE_C_END:
eor DCC_xor,byteC // bilde XOR
sbrc flag,bit // springe 1x wenn empfangenes Bit=0
rjmp DATENPRUEFEN // ansonsten Telegrammende
clr bitzaehler // lösche Zähler
ldi EmpPos,ByteD_lesen
rjmp TIM2_COMP_ENDE // erst einmal fertig
LESE_BYTE_D:
cpi EmpPos,ByteD_lesen // auf Empfangsposition Byte D testen
brne LESE_BYTE_E
cpi bitzaehler,8 // vergleiche mit Bytelänge
breq BYTE_D_END // und springe wenn Byte eingelesen
sec // setzte Carry
sbrs flag,bit // wenn empfangenes Bit=1 1x springen
clc // lösche Carry
rol byteD // schiebe Carry von rechts in das Register
inc bitzaehler // erhöhe Zähler
rjmp TIM2_COMP_ENDE // erst einmal fertig
BYTE_D_END:
eor DCC_xor,byteD // bilde XOR
sbrc flag,bit // springe 1x wenn empfangenes Bit=0
rjmp DATENPRUEFEN // ansonsten Telegrammende
clr bitzaehler // lösche Zähler
ldi EmpPos,ByteE_lesen
rjmp TIM2_COMP_ENDE // erst einmal fertig
LESE_BYTE_E:
cpi EmpPos,ByteE_lesen // auf Empfangsposition Byte E testen
brne LESE_BYTE_F
cpi bitzaehler,8 // vergleiche mit Bytelänge
breq BYTE_E_END // und springe wenn Byte eingelesen
sec // setzte Carry
sbrs flag,bit // wenn empfangenes Bit=1 1x springen
clc // lösche Carry
rol byteE // schiebe Carry von rechts in das Register
inc bitzaehler // erhöhe Zähler
rjmp TIM2_COMP_ENDE // erst einmal fertig
BYTE_E_END:
eor DCC_xor,byteE // bilde XOR
sbrc flag,bit // springe 1x wenn empfangenes Bit=0
rjmp DATENPRUEFEN // ansonsten Telegrammende
clr bitzaehler // lösche Zähler
ldi EmpPos,ByteF_lesen
rjmp TIM2_COMP_ENDE // erst einmal fertig
LESE_BYTE_F:
cpi EmpPos,ByteF_lesen // auf Empfangsposition Byte F testen
brne DCC_NEUSTART
cpi bitzaehler,8 // vergleiche mit Bytelänge
breq BYTE_F_END // und springe wenn Byte eingelesen
sec // setzte Carry
sbrs flag,bit // wenn empfangenes Bit=1 1x springen
clc // lösche Carry
rol byteF // schiebe Carry von rechts in das Register
inc bitzaehler // erhöhe Zähler
rjmp TIM2_COMP_ENDE // erst einmal fertig
BYTE_F_END:
eor DCC_xor,byteF // bilde XOR
sbrc flag,bit // springe 1x wenn empfangenes Bit=0
rjmp DATENPRUEFEN // ansonsten Telegrammende
rjmp DCC_NEUSTART // wenn nicht DCC_NEUSTART
DATENPRUEFEN: // Datenprüfung und Übergabe
tst DCC_xor // prüfe DCC_xor auf 0
brne DCC_NEUSTART // wenn nicht 0 dann Fehler
// wenn byteA = 0 oder byteA = eigene Adresse oder RESET Flag gesetzt
// Bit für neue daten setzen alle anderen Telegramme gleich verwerfen
tst byteA // wenn 0 = Broadcast an alle
breq 2f // dann ok
cp byteA,Adresse // wenn eigene Adresse
breq 2f // dann OK
sbrc flag,resetbit // wenn 1 war reset
rjmp 2f // dann auch ok
rjmp DCC_NEUSTART // alles andere gleich verwerfen und DCC Neustart
2:
sbrc DCCreg,(keinDCC)
rjmp Reset // wenn vorher im analog Modus, dann jetzt Neustart im DCC Modus
sbr flag,(1<<neuerBefehl) // neuer DCC Befehl eingetroffen
cbr DCCreg,(1<<analog) // wenn 1x DCC, dann analog Modus sperren
rjmp TIM2_COMP_ENDE // fertig
DCC_NEUSTART:
clr bitzaehler // loesche den BitCounter wieder
clr EmpPos // EmpPos auf Preamble
TIM2_COMP_ENDE:
inc Zaehler_10us // Zaehler register alle 10us inc
out SREG,intsreg // sreg wiederherstellen
reti // und fertig
/****************************
* ADC Wert einlesen fertig *
****************************/
ADC_Complete:
in intsreg,SREG // sreg sichern bewußt nicht im fifo abgelegt, da so schneller
push w // Arbeitsregister sichern
ADC_WERTE_EINLESEN:
in w, ADCL // immer zuerst LOW Byte lesen
in w, ADCH // danach das mittlerweile gesperrte High Byte
// beides in w einlesen, da nur 8 bit nötig
cp w,U_LED
brlo U_LED_ZU_KLEIN
U_LED_ZU_GROSS:
in w,OCR1AL
tst w
breq ADC_ende
dec w
out OCR1AL,w
rjmp ADC_ende
U_LED_ZU_KLEIN:
in w,OCR1AL
inc w
tst w
breq ADC_ende
out OCR1AL,w
ADC_ende:
pop w // w wiederherstellen
out SREG,intsreg // sreg wiederherstellen
reti
Detected encoding: UTF-8 | 0
|