Forum: Mikrocontroller und Digitale Elektronik DCC Dekoder mit AtTiny45


von Michael E. (mieb)


Angehängte Dateien:

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

von Thomas E. (thomase)


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.

von Michael E. (mieb)


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

von Thomas E. (thomase)


Angehängte Dateien:

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.

: Bearbeitet durch User
von Michael E. (mieb)


Lesenswert?

Hab es zwar nicht auf Wikipedia gelesen aber ist gut zu wissen

Bin auf 75 µs runter und die Abfrage bei 0 hatte ich ja im Code oben 
sowieso schon drin.

Werde da jetzt mal weiter probieren. Danke

Michael

von Roman (Gast)


Lesenswert?

Hallo Michael,

warum das Rad immer wieder neu erfinden. Nehme den Decoder von Toralf 
wilhelm und gut ist. Da kannst Du im Sourcecode einiges lernen. Außerdem 
gibt es fertige Platinen.
Gruß
Roman

von Thomas E. (thomase)


Lesenswert?

Roman schrieb:
> warum das Rad immer wieder neu erfinden

Weil man es kann oder es lernen möchte, um dann zu sagen, daß man es 
kann.

: Bearbeitet durch User
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.