Hallo zusammen,
ich hatte mal einen simplen DCC Generator programmiert, weil ein Kumpel auch seine Decoder testen wollte.
Falls es hier also nicht nur um die Treiberstufe geht, sondern auch um ein solches Programm, dann kannst du dies ja vielleicht als Ausgangspunkt für deine spezielle Anforderung nehmen.
Im Moment wird dort eine an- und abschwellende PWM ausgegeben.
CodeBox BascomAVR
'(
Tool, zur Ausgabe von DCC Protokollen nach OpenDCC Beschreibung
Format eines Telegramms ist
kurz: 111111111111110AAAAAAAA0BBBBBBBB0CCCCCCCC
lang: 111111111111110AAAAAAAA0BBBBBBBB0EEEEEEEE0CCCCCCCC
Anzahl Praeambel Bits (immer 1) kann scheinbar zwischen 10 und 16 variieren (ist daher unten als Konstante angegeben)
Trennbits zwischen Adresse (A), Befehl (B), Erweiterung (E) und Checksumme (C) sind immer 0
eine 1 ist 58µs high und 58µs low, eine 0 ist 116µs high und 116µs low
Zwischen den einzelnen Telegrammen ist eine Pause 1000µs (siehe Konstante Zwischen_pause)
Nachdem alle Telegramme übertragen wurden, kommt eine Pause von 10000µs (siehe Konstante Ende_pause)
Telegramme können per UART an das Programm übergeben werden.
Format ist hierbei
kurz: {A,B}
lang: {A,B,E}
A,B und E dürfen maximal den Wert 255 haben.
Es wird keine Kontrolle auf Korrektheit nach dem DCC Protokoll durchgeführt.
Dies muss vom übergebenden Programm erfolgen
Wenn ein korrektes Telegramm erkannt wurde, wird es auf dem UART ausgeben.
Format ist hierbei
kurz: A,B,C
lang: A,B,E,C
C wird aus A XOR B bzw A XOR B XOR E berechnet
Falls ein Wert > 255 ist, wird ein Fehler zurückgegeben
Erweiterte Programmierbefehle des OpenDCC Protokolls werden zur Zeit nicht unterstützt
')
$regfile = "m1284pdef.dat"
$crystal = 20000000 'Minimum ist etwa 1MHz
$hwstack = 40
$swstack = 40
$framesize = 100
$baud = 115200 'kann auch kleiner sein
Config Timer1 = Timer , Prescale = 1024 , Compare_a = Toggle , Clear_timer = 1
Const _print_out = 0
Const _use_timer = 1 'Timer1 oder Timer2 kann verwendet werden (Timer muss Fast-PWM mit OCRnA als TOP Wert können)
Const _mit_rauschen = 0
Config Timer2 = Pwm , Prescale = 64 , Compare_b_pwm = Clear_up
Config Timer0 = Timer , Prescale = 256
#if _use_timer = 1
Const Timer_prescale = 1
Tccr1a = Bits(wgm11 , Wgm10) 'fast_PWM (Mode 15), Ausgang = B, Prescale = 1)
Tccr1b = Bits(cs10 , Wgm13 , Wgm12) 'Top = OCR1A, Compare = OCR1B
#elseif _use_timer = 2
#if _xtal > 8000000 'da timer2 nur 8-bit hat, müssen Werte größer 255 durch geeignete Wahl des Prescalers vermieden werden
Const Timer_prescale = 32
Tccr2a = Bits(wgm21 , Wgm20) 'fast_PWM (mode 7), Ausgang = B, Prescale = 32)
Tccr2b = Bits(cs21 , Cs20 , Wgm22) 'Top = OCR2A, Compare = OCR2B
#else
Const Timer_prescale = 8
Tccr2a = Bits(wgm21 , Wgm20) 'fast_PWM mode 7), Ausgang = B, Prescale = 8)
Tccr2b = Bits(cs21 , Wgm22) 'Top = OCR2A, Compare = OCR2B
#endif
#endif
Const Eins_high = 58
Const Null_high = 116
Const Eins_gesamt = Int(_xtal * Eins_high * 2 / Timer_prescale / 1000000) - 1 '58
Const Eins = Int(eins_gesamt / 2 )
Const Null_gesamt = Int(_xtal * Null_high * 2 / Timer_prescale / 1000000) - 1
Const Null = Int(null_gesamt / 2 )
Const Zwischen_pause = 1000 '1000µs Pause zwischen zwei Telegrammen
Const Ende_pause = 2000 '10000µs Pause nach Übertragung aller Telegramme, danach wieder von vorne
Const Praeambel_bits = 16 'Festlegung der Anzahl der Synchronisierungsbits
Const Praeambel_start = 1 'Dies sind die Bitnummern in Abhängigkeit von der Anzahl Praeambel Bits und evtl. Erweiterungsbyte
Const Praeambel_end = Praeambel_bits
Const Trenn_null_1 = Praeambel_end + 1
Const Adress_start = Trenn_null_1 + 1
Const Adress_end = Adress_start + 7
Const Trenn_null_2 = Adress_end + 1
Const Befehl_start = Trenn_null_2 + 1
Const Befehl_end = Befehl_start + 7
Const Trenn_null_3 = Befehl_end + 1
Const Erweiterung_start = Trenn_null_3 + 1
Const Erweiterung_end = Erweiterung_start + 7
Const Trenn_null_4 = Erweiterung_end + 1
Const Checksumme_start = Trenn_null_4 + 1
Const Checksumme_end = Checksumme_start + 7
Const Telegram_end1 = Erweiterung_end + 2
Const Telegram_end2 = Checksumme_end + 2
Const Max_telegram_count = 100 'max 100 Telegramme können erzeugt werden
Dim Adresse(max_telegram_count) As Byte
Dim Befehl(max_telegram_count) As Byte
Dim Erweiterung(max_telegram_count) As Byte
Dim Neue_adresse As Word
Dim Neuer_befehl As Word
Dim Neue_erweiterung As Word
Dim Neue_checksumme As Byte
Dim Checksumme As Byte
Dim Dcc_bit_no As Byte
Dim Bit_no As Byte
Dim Next_bit As Byte
Dim Current_bit As Byte
Dim Invld_flag As Byte
Dim Telegram_no As Byte
Dim Telegram_count As Byte
Dim Byte_cnt As Byte
Dim Byte_rcvd As Byte
Dim Peak As Byte
Dim Pwm_up As Bit
Dim Pwm_0 As Byte
Telegram_count = 1
Adresse(1) = 99
Befehl(1) = 100
Erweiterung(1) = 6
Adresse(2) = 3
Befehl(2) = 5
'Adresse(3) = 2
'Befehl(3) = 7
'Erweiterung(3) = 5
'Adresse(4) = 2
'Befehl(4) = 7
Config Portd.5 = Output
#if _mit_rauschen = 1
Const Max_rnd = 2000 'dies ist das absolute maximum, kleinere Werte erzeugen mehr peaks
Config Timer3 = Timer , Prescale = 1 , Clear_timer = 1
Ocr3a = Rnd(max_rnd) + 500
On Compare3a Cmp3_isr
Enable Compare3a
#endif
#if _use_timer = 1
On Compare1b Cmp_isr Nosave 'dadurch ist die ISR nur 45 Takte lang, damit geht auch 1MHz Clock
Enable Compare1b 'beim Compare Match werden die neuen Werte für OCRnA und OCRnB entsprechend des Bits geladen.
Ocr1a = Eins_gesamt 'Beim Erreichen des Top Wertes werden sie dann in die Register übernommen
Ocr1b = Eins - 1
#if _chip = 62 'M88P
Config Portb.2 = Output 'Ausgabe Pin für Timer1 Kanal B
#elseif _chip = 103 'M1284P
Config Portd.4 = Output 'Ausgabe Pin für Timer1 Kanal B
#endif
#elseif _use_timer = 2
On Compare2b Cmp_isr Nosave
Enable Compare2b
Ocr2a = Eins_gesamt
Ocr2b = Eins - 1
#if _chip = 62
Config Portd.3 = Output 'Ausgabe Pin für Timer2 Kanal B
#elseif _chip = 103
Config Portd.6 = Output 'Ausgabe Pin für Timer2 Kanal B
#endif
#endif
On Urxc Urxc_isr
Enable Urxc
Enable Interrupts
Do
If Tifr0.tov0 = 1 Then
Tifr0.tov0 = 1
If Pwm_up = 1 Then
If Pwm_0 < 255 Then
Incr Pwm_0
Else
Pwm_up = 0
End If
Else
If Pwm_0 > 0 Then
Decr Pwm_0
Else
Pwm_up = 1
End If
End If
End If
If Dcc_bit_no < Befehl_start Then
Befehl(1) = Pwm_0
Ocr2b = Pwm_0
End If
If Telegram_count > 0 Then
If Next_bit = 1 Then
Next_bit = 0
Incr Dcc_bit_no
If Dcc_bit_no = Telegram_end1 And Erweiterung(telegram_no ) = 0 Or Dcc_bit_no = Telegram_end2 Then
Dcc_bit_no = 0
Incr Telegram_no
#if _use_timer = 1
Reset Tccr1a.com1b1 'Ausgang B ausschalten für die Pausen
#elseif _use_timer = 2
Reset Tccr2a.com2b1 'Ausgang B ausschalten
#endif
Reset Portd.5
If Telegram_no > Telegram_count Then
Telegram_no = 1
Waitus Ende_pause
Else
Waitus Zwischen_pause
End If
Set Portd.5
#if _use_timer = 1
Tcnt1 = 0 'Ausgang B ausschalten
#elseif _use_timer = 2
Tcnt2 = 0 'Ausgang B ausschalten
#endif
If Telegram_count > 0 Then
#if _use_timer = 1
Set Tccr1a.com1b1 'Ausgang B ausschalten
#elseif _use_timer = 2
Set Tccr2a.com2b1 'Ausgang B ausschalten
#endif
End If
Else
Select Case Dcc_bit_no
Case Praeambel_start To Praeambel_end: 'Praeambel Bits erzeugen
Current_bit = 1
Case Trenn_null_1: 'erste 0 nach Praeambel
Current_bit = 0
Case Adress_start To Adress_end 'Adress-Bits erzeugen
Bit_no = Adress_end - Dcc_bit_no
Current_bit = Adresse(telegram_no).bit_no
Case Trenn_null_2: 'zweite 0 nach Adress
Current_bit = 0
Case Befehl_start To Befehl_end 'Befehl-Bits erzeugen
Bit_no = Befehl_end - Dcc_bit_no
Current_bit = Befehl(telegram_no).bit_no
Case Trenn_null_3: 'dritte 0 nach Befehl
Current_bit = 0
Case Erweiterung_start To Erweiterung_end: 'Erweiterung-Bits erzeugen falls notwendig
Bit_no = Erweiterung_end - Dcc_bit_no
If Erweiterung(telegram_no) = 0 Then
Checksumme = Adresse(telegram_no) Xor Befehl(telegram_no )
Current_bit = Checksumme.bit_no
Else
Current_bit = Erweiterung(telegram_no).bit_no
End If
Case Trenn_null_4: 'vierte 0 nach Erweiterung falls notwendig
Current_bit = 0
Case Checksumme_start To Checksumme_end: 'Checksummen Bits erzeugen
Bit_no = Checksumme_end - Dcc_bit_no
Checksumme = Adresse(telegram_no) Xor Befehl(telegram_no )
Checksumme = Checksumme Xor Erweiterung(telegram_no )
Current_bit = Checksumme.bit_no
End Select
End If
End If
End If
Loop
Cmp_isr: 'beim Match (also mitten im Bit) werden die neuen Werte fürs nächste Bit gesetzt.
!PUSH R24
!IN r24, SREG
!PUSH R24
!PUSH R25
!PUSH R16
#if _use_timer = 1
If Current_bit = 0 Then
Ocr1a = Null_gesamt
Ocr1b = Null - 1
Else
Ocr1a = Eins_gesamt
Ocr1b = Eins - 1
End If
#elseif _use_timer = 2
If Current_bit = 0 Then
Ocr2a = Null_gesamt
Ocr2b = Null - 1
Else
Ocr2a = Eins_gesamt
Ocr2b = Eins - 1
End If
#endif
Next_bit = 1 'jetzt kann die MainLoop das nächste Bit holen
!POP R16
!POP R25
!POP R24
!Out Sreg , R24
!POP R24
Return
Urxc_isr:
Byte_rcvd = Udr
Select Case Byte_rcvd
Case "{":
If Byte_cnt = 0 Then Byte_cnt = 1 Else Byte_cnt = 0
Case ",":
If Byte_cnt = 2 Or Byte_cnt = 4 Then Incr Byte_cnt Else Byte_cnt = 0
Case "}":
If Byte_cnt = 4 Or Byte_cnt = 6 Then
If Telegram_count < Max_telegram_count Then
Invld_flag = 0
If Neue_adresse > 255 Then
Print "Adr nio"
Invld_flag = 1
End If
If Neuer_befehl > 255 Then
Print "Bef nio"
Invld_flag = 1
End If
If Neue_erweiterung > 255 Then
Print "Erw nio"
Invld_flag = 1
End If
If Invld_flag = 0 Then
Adresse(telegram_count + 1) = Neue_adresse
Befehl(telegram_count + 1) = Neuer_befehl
Neue_checksumme = Neue_adresse Xor Neuer_befehl
Print Neue_adresse ; "," ; Neuer_befehl ;
If Byte_cnt = 6 Then
Erweiterung(telegram_count + 1) = Neue_erweiterung
Neue_checksumme = Neue_checksumme Xor Neue_erweiterung
Print "," ; Neue_erweiterung ;
End If
Print "," ; Neue_checksumme
Incr Telegram_count
End If
End If
End If
Byte_cnt = 0
Case 48 To 57: 'es sind nur Ziffern erlaubt
Byte_rcvd = Byte_rcvd - 48 'ASCII Wert der 0 abziehen
Select Case Byte_cnt
Case 1: 'Start des Adressbyte
Neue_adresse = Byte_rcvd
Byte_cnt = 2
Case 2: 'Fortsetzung des Adressbyte
Neue_adresse = Neue_adresse * 10
Neue_adresse = Neue_adresse + Byte_rcvd
Case 3: 'Start des Befehlsbyte
Neuer_befehl = Byte_rcvd
Byte_cnt = 4
Case 4: 'Fortsetzung des Befehlsbyte
Neuer_befehl = Neuer_befehl * 10
Neuer_befehl = Neuer_befehl + Byte_rcvd
Case 5: 'Start des Erweiterungsbyte
Neue_erweiterung = Byte_rcvd
Byte_cnt = 6
Case 6: 'Fortsetzung des Erweiterungsbyte
Neue_erweiterung = Neue_erweiterung * 10
Neue_erweiterung = Neue_erweiterung + Byte_rcvd
End Select
End Select
Return
#if _mit_rauschen = 1
Cmp3_isr:
Ocr3a = Rnd(max_rnd) + 500
Toggle Tccr1a.com1b1
Peak = Rnd(10) + 1
Waitus Peak
Toggle Tccr1a.com1b1
Return
#endif