DCC Dekoder mit AtTiny45

#4905738
Lesenswert?

Da es nun doch schon über nen Monat her is mach ich dazu mal nen neuen 
Thread auf...

Dann frisch ans Werk
Ich will die Schaltung im Anhang als Weichen/Signaldekoder verwenden
(Eigentlich benutze ich einen AtTiny45 aber den gabs in Eagle nicht)
Dabei ist PB2 ein Eingang mit eingeschaltetem Pull-Up Widerstand, wobei 
der Externe Interrupt bei fallenden Flanken triggert.

Momentan soll der Dekoder bei Empfang eines vollständigen DCC-Telegramms 
(Präambel, LowAdresse, HighAdresse, Checksum) die LED an PORTB3 
einschalten.

Das ganze, falls ich es ans Gleis anschließes funktioniert auch 
grundsätzlich, allerdings muss ich in meiner CS2 bisweilen eine 
DCC-Weiche 8 mal umschalten bis der Dekoder ein vollständiges Telegramm 
erhält und die LED einschaltet.

Nun meine Frage an alle die sich auf dem Gebiet auskennen.
Könnt ihr mir irgendwelche Verbesserungen vorschlagen (Sowohl in 
Elektronik als auch Programm), damit der Dekoder bestenfalls besser 
läuft?

Zum auswerten benutze ich folgenden Code
(Ich hoffe ihr nehmt mir die fehlende Kommentierung nicht all zu übel, 
für den der sich in DCC auskennt sollten die jump-ziele eigentlich 
Kommentierung genug sein)
1
; Mikrocontroller: ATtiny45
2
;            -------------
3
;(RESET)PB5 =|           |= VCC
4
;            |           |
5
;    (O)PB3 =|           |= PB2(INT0)
6
;            |           |
7
;       PB4 =|           |= PB1
8
;            |           |
9
;       GND =|           |= PB0
10
;            -------------
11
;
12
; Taktgeber: Interner Oszillator
13
; Taktfrequenz: 8 MHz
14
; Zykluszeit: 125ns
15
;
16
; Brown-out Detection: 2,7V
17

18
.set PR  = 7    ; präambel-Flag
19
.set AL  = 6    ; adresseLow-Flag
20
.set AH  = 5    ; adresseHigh-Flag
21
.set CS  = 4    ; checksum-Flag
22

23
.def adresseLow = r0
24
.def adresseHigh = r1
25
.def checksum = r2
26
.def bitCounter = r19
27
.def DCCREG = r20
28

29
.include "tn45def.inc"  ; Definitionsdatei für den AtTiny45 einbinden
30

31
.CSEG
32
;------------------------------- Interruptvektortabelle --------------------------------
33
.org 0x0
34
    rjmp RESET      ; Address 0x0000
35
    rjmp INT0_ISR    ; Address 0x0001 (External Interrupt Request 0)
36
    reti        ; Address 0x0002 (Pin Change Interrupt Request 0)
37
    reti        ; Address 0x0003 (Timer/Counter1 Compare Match A)
38
    reti        ; Address 0x0004 (Timer/Counter1 Overflow)
39
    reti        ; Address 0x0005 (Timer/Counter0 Overflow)
40
    reti        ; Address 0x0006 (EEPROM Ready)
41
    reti        ; Address 0x0007 (Analog Comparator)
42
    reti        ; Address 0x0008 (ADC Conversion Complete)
43
    reti        ; Address 0x0009 (Timer/Counter1 Compare Match B)
44
    rjmp TC0A_ISR    ; Address 0x000A (Timer/Counter0 Compare Match A)
45
    reti        ; Address 0x000B (Timer/Counter0 Compare Match B)
46
    reti        ; Address 0x000C (Watchdog Time-out)
47
    reti        ; Address 0x000D (USI START)
48
    reti        ; Address 0x000E (USI Overflow)
49

50

51
;------------------------------------ Hauptprogramm ------------------------------------
52
; Einstiegspunkt
53
RESET:
54
    ; Stackpointer initialisieren
55
    ldi r16, HIGH(RAMEND)
56
    out SPH, r16
57

58
    ldi r16, LOW(RAMEND)
59
    out SPL, r16
60

61
    ; I/O Konfiguration
62
    ldi r16, (1 << DDB3)
63
    ldi r17, (1 << PB0) | (1 << PB1) | (1 << PB2) | (1 << PB4)
64

65
    out DDRB, r16    ; PINB3 => Ausgang
66
    out PORTB, r17    ; Pull-Up Widerstände an allen Eingängen
67

68
    nop          ; Synchronisation
69

70
    ; External Interrupt Konfiguration
71
    ldi r16, (1 << ISC01)
72
    out MCUCR, r16    ; Fallende Flanke an INT0 löst Interrupt aus
73

74
    ldi r16, (1 << INT0)
75
    out GIMSK, r16    ; Aktiviere External Interrupts
76

77
    nop          ; Synchronisation
78

79
    ; Timer/Counter0 Konfiguration
80
    ldi r16, (1 << TSM) | (1 << PSR0) 
81
    out GTCCR, r16    ; Timer/Counter0 Reset
82

83
    ldi r16, (1 << WGM01)
84
    out TCCR0A, r16    ; Timer/Counter0 CTC-Modus
85

86
    ldi r16, (1 << CS01)
87
    out TCCR0B, r16    ; Timer/Counter0 Prescaler 8
88

89
    ldi r16, 87
90
    out OCR0A, r16
91

92
    ldi r16, (1 << OCIE0A)
93
    out TIMSK, r16    ; Aktiviere Timer/Counter0 Output Compare Match A Interrupts
94

95
    nop          ; Synchronisation
96

97
    ; Speicherkonfiguration
98
    clr adresseLow
99
    clr adresseHigh
100
    clr checksum
101
    clr bitCounter
102
    clr DCCREG
103

104
    ldi DCCREG, (1 << PR) ; DCC Status => Präambel
105

106
    nop          ; Synchronisation
107

108
    sei          ; Interrupts Global aktivieren
109

110
  loop:
111
    rjmp loop
112

113
INT0_ISR:
114
    ldi r16, 0
115
    out GTCCR, r16    ; Timer/Counter0 start
116
    reti
117
 
118
TC0A_ISR:
119
    ldi r16, (1 << TSM) | (1 << PSR0) 
120
    out GTCCR, r16    ; Timer/Counter0 Reset
121

122
    sbic PINB, PINB2  ; if (PINB2 == 1)
123
    rjmp eins      ; then
124
    rjmp null      ; else
125

126
  eins:
127
    sbrc DCCREG, PR
128
    rjmp praeambel1
129

130
    sbrc DCCREG, AL
131
    rjmp alow1
132

133
    sbrc DCCREG, AH
134
    rjmp ahigh1
135

136
    sbrc DCCREG, CS
137
    rjmp checksum1
138

139
   praeambel1:
140
    inc bitCounter
141

142
    cpi bitCounter, 15
143
    brcc dccreset
144
    reti
145

146
   alow1:
147
    inc bitCounter
148
    cpi bitCounter, 9
149
    breq dccreset
150
    sec
151
    rol adresseLow
152
    reti
153

154
   ahigh1:
155
      inc bitCounter
156
    cpi bitCounter, 9
157
    breq dccreset
158
    sec
159
    rol adresseHigh
160
    reti
161

162
   checksum1:
163
    inc bitCounter
164
    cpi bitCounter, 9
165
    breq auswertung
166

167
    sec
168
    rol checksum
169
    reti
170

171
  null:
172
    sbrc DCCREG, PR
173
    rjmp praeambel0
174

175
    sbrc DCCREG, AL
176
    rjmp alow0
177

178
    sbrc DCCREG, AH
179
    rjmp ahigh0
180

181
    sbrc DCCREG, CS
182
    rjmp checksum0
183

184
   praeambel0:
185
    cpi bitCounter, 10
186
    brcs dccreset
187
    
188
    ldi DCCREG, (1 << AL)
189
    clr bitCounter
190
    reti
191

192
   alow0:
193
    inc bitCounter
194
    cpi bitCounter, 9
195
    breq lth
196
    lsl adresseLow
197
    reti
198

199
    lth:
200
    ldi DCCREG, (1 << AH)
201
    clr bitCounter
202
    reti
203

204
   ahigh0:
205
    inc bitCounter
206
    cpi bitCounter, 9
207
    breq htc
208
    lsl adresseHigh
209
    reti
210

211
    htc:
212
    ldi DCCREG, (1 << CS)
213
    clr bitCounter
214
    reti
215

216
   checksum0:
217
    inc bitCounter
218
    cpi bitCounter, 9
219
    breq dccreset
220
    lsl checksum
221
    reti
222

223
  auswertung:
224
    sbi PORTB, PORTB3
225
  dccreset:
226
    ldi DCCREG, (1 << PR)
227
    clr bitCounter
228
    reti

Viele Grüße
Michael
Angehängte Dateien:
#4905874
Lesenswert?

Michael E. schrieb:
> praeambel1:
>     inc bitCounter
>
>     cpi bitCounter, 15
>     brcc dccreset
>     reti

Wie kommst du auf die 15?

Minimum für Sync sind 10 Bits, Norm für Zentralen sind >=16 Bits.
<10 Bits darf er nicht, >=12 muß der Dekoder erkennen. Aber 15?


Michael E. schrieb:
> ldi r16, 87
>     out OCR0A, r16

88µs könnten zu lang sein. Wenn nämlich die Timer-ISR noch läuft und die 
Flanke vom nächsten Bit schon ansteht, kommt die INT0-ISR entsprechend 
später. Und mit jedem weiteren 1-Bit wird es noch knapper. Die Toleranz 
des RC-Oszillators tut evtl. noch ihr Übriges dazu.
#4905886
Lesenswert?

Puh dachte schon es meldet sich gar niemand mehr :D

Hab auf einer Seite gelesen dass es maximal 14 1en in der Präambel sein 
dürfen
und da es dementsprechend 14 sein dürfen wird die carry-flag, die ich 
danach ja abfrage, erst gecleart wenn es 15 werden.

Dann war wohl die Telegramm beschreibung der Seite falsch.

Zum zweiten
Da hatte ich auch schon drüber nachgedacht. Was denkst du welchen Wert 
ich benutzen sollte?

Michael
#4905960
Lesenswert?

Michael E. schrieb:
> Hab auf einer Seite gelesen dass es maximal 14 1en in der Präambel sein
> dürfen

Ja, das steht auf Wikipedia. Das war wohl auch mal Usus. Aber die Norm 
sagt 16. Da er 10 Syncs als richtige Präambel erkennen soll, solltest du 
auf >=10 nach dem Empfang einer 0 testen. Wenn du während des Empfangs 
immer die 1-Bits mitzählst und bei einem 0-Bit den Zähler testest, hast 
du immer ein Sync empfangen wenn der Zähler >=10 ist. Natürlich muß der 
Zähler nach dem Empfang einer 0 immer gelöscht werden.

Michael E. schrieb:
> Was denkst du welchen Wert
> ich benutzen sollte?

Ich frage nach 75µs ab.
Angehängte Dateien:

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren