'(------------------------------------------------------------------------------
Bonze's K-Bus -> NEC Transciever
--------------------------------------------------------------------------------
MCU: ATtiny2313
Takt: 8MHz intern
--K-Bus--> TH3122 --UART--> Tiny2313 --PWM--> NEC
--------------------------------------------------------------------------------
verwendete Hardware:
-Timer1 im frequenzkorrektem Fast-PWM
-ICU1 legt Frequenz fest
-OCU1A als PWM-Output, IRQ modifiziert ICR1 (genau genommen PPM)
-UART1
-RxD für K-Bus-Empfang (IRQ-basiert)
-TXD für Debugging (ggf später K-Bus-senden)
-Timer0
-Überlauf(IRQ) detektiert neues Telegramm, durch reload in RxD unterdrückt
TH3122 ATtiny2313
+------------+ +-----------------------+
| Sense|--->| ??? Reset(A2)|<------Reset
| Reset|--->| ??? MOSI(B5)|<---+ |
| SEN/STA|<-->| ??? MISO(B6)|--->+---ISP
<-->|Bus RxD|--->|RxD(D0) SCK(B7)|<---+
| TxD|<---|TxD(D1) OC1A(B3)|--->PWM--->NEC
+------------+ +-----------------------+
freie Pins (PortB=PC-Ints):
A0=XTAL0 ???
A1=XTAL1 ???
B0=AIN0
B1=AIN1
B2=(OC0A)
B4=(OC1B)
D2=INT0
D3=INT1
D4=(T0)
D5=(OC0B)
D6=ICP1 (InputCaptureUnit durch frequenzkorrekten PWM belegt)
--------------------------------------------------------------------------------
')
'derzeit wird der UART-Transmitter fürs debugging verwendet, Fehlerbytes:
Const Nec_transmitter_overrun = &H01
Const Nec_crc_error = &H02
$crystal = 8000000
$regfile = "attiny2313.dat"
$hwstack = 25
$swstack = 25
$framesize = 20
Const Debugmode = 1 '1=debugmode, 0=normal mode
'****Interruptvektoren****
On Oc1a Oc1a_isr Nosave 'Hi->Lo-Flanke vom NEC, Pulslänge wird angepaßt
On Oc0a K_bus_timeout_isr Nosave 'Timeout für UART
On Urxc Uart_recieved_isr Nosave 'byte empfangen, ggf CRC, BIP, IGN, CRC_OK für main
'****globale Variablen****
'für NEC-Sender
Dim Bitzaehler As Byte 'Zählt über NEC gesendete Bits
Dim Adress As Byte 'NEC-Empfängeradresse
Dim Kommando As Byte 'NEC-Kommando
'für K-Bus-Empfänger
Dim Bytezaehler As Byte ' (restliche) Bytes des Telegrammes
Dim K_rec_buff As Byte 'RxD-ISR übergibt Byte hier
Dim Nec_tree_ptr As Byte 'zeigt auf aktuellen Knoten im Eeprom
Dim Xnor As Byte 'führt CRC-Byte mit
'GPIOR0 wird als universellesFlagRegister verwendet (default alle Bits=0)
Bip Alias Gpior0.0 'neues Byte im Puffer
Ign Alias Gpior0.1 'Rest-Telegramm ignorieren!
Crc_ok Alias Gpior0.2 'CRC-Check war ok
Nec_busy Alias Gpior0.3 'der sendet noch
'****************Subs***************
Declare Sub Initnec(byval Zieladresse As Byte)
Declare Sub Sendnec(byval Kommandobyte As Byte)
Declare Sub Initkbus()
Call Initnec(&B10011101) 'NEC-Interface mit Adresse initialisieren
Call Initkbus() 'K-Bus-Interface initialisieren
Enable Interrupts 'Interrupts freigeben
Dim Temp As Byte
Dim Temp2 As Byte
'***********Hauptschleife***********
Do
'Bip pollen, und Bytes im Eeprom suchen, bei CRC_OK korrespondierenden NEC senden********************
If Bip = 1 Then 'neues relevantes Byte?
Bip = 0
Readeeprom Temp , Nec_tree_ptr 'NEC-Code laden
If Crc_ok = 1 Then 'CRC_ok?
Call Sendnec(temp) 'NEC senden
Else
Do
Incr Nec_tree_ptr
Readeeprom Temp2 , Nec_tree_ptr 'Knotenwert laden
Incr Nec_tree_ptr 'zeigt auf Adresse
If Temp2 = Temp Then
Exit Do
End If
Decr Temp
If Temp = 0 Then 'nicht gefunden
Ign = 1 'Ignore-Flag
Exit Do
End If
Loop
End If
End If
Loop
'*****************Subroutinen*******
Sub Initnec(zieladresse As Byte)
Tccr1a = 2 'für normale I/O und WGM=14
Ocr1a = 17999
Icr1 = 17999
Ddrb.3 = 1 'PortB.3 (OC1A) ist Ausgang
Bitzaehler = 38
Adress = Zieladresse
Enable Oc1a
End Sub
Sub Sendnec(kommandobyte As Byte)
If Nec_busy = 1 Then
#if Debugmode = 1
Udr = Nec_transmitter_overrun 'Fehlercode senden(UART)
#endif
Else
Kommando = Kommandobyte 'zu sendendes CMD übernommen
Tccr1b = 25 'Timer läuft (->IRQs)
SBI PORTB, PORTB3 'Startburst
#if Debugmode = 1
Udr = Kommando 'NEC-Code (Byte) über UART gesendet
#endif
Nec_busy = 1
End If
End Sub
Sub Initkbus()
Bytezaehler = 255 'beginn eines Telegrammes
Nec_tree_ptr = 0 '->Wurzel
Xnor = 0
'Timer0 ->CTC mit IRQ und 1,696ms (OCR0A)
Ocr0a = 52
Tccr0a = &B00000010 'CTC Mode
Tccr0b = &B00000100 'Timer0 mit Prescaler 256 gestarted
Enable Oc0a 'IRQ aktivieren (TIMSK)
'UART vorbereiten 9600 Baut ,8DB, 1SB, gerade Parität
sbi UCSRC,upm1 'gerade Parität, der Rest ist default
Ubrrl = 51 '9600baud bei 8MHz, U2X=0 Error:0,16%
#if Debugmode = 0
Ucsrb = &B10010000 'Reciever mit IRQ aktiv
#else
Ucsrb = &B10011000 'Reciever mit IRQ aktiv, Transmitter ohne
#endif
End Sub
'*****Interrupt Service Routinen****
K_bus_timeout_isr:
$asm 'bei Timeout (1,7ms) auf init zurücksetzen
push r16 'R16->Stack
LDI r16, 255
STS {Bytezaehler}, R16 'Bytezaehler = 255
LDI r16, 0
STS {nec_tree_ptr}, r16 'nec_tree-Ptr = 0
STS {xnor}, r16 'XNOR = 0
CBI GPIOR0, 1 'IGN-Flag gelöscht
pop r16 'R16<-Stack
$end Asm
Return
Uart_recieved_isr:
$asm 'empfangenes Byte abholen, auswerten, ggf CRC, Flags für main setzen
push R16 'R16->Stack
LDI R16, 0
Out Tcnt0 , R16 'Timer reset
in r16, UDR 'Empfangenes Byte->R16
SBIC UCSRA, UPE
SBI GPIOR0, 1 'Paritätsfehler -> setze IGN-Flag
SBIC GPIOR0, 1 'IGN gesetzt?
RJMP rx_isr_restore_R16 'dann ignoriere Byte
PUSH R17 'R17->Stack
IN R17, SREG
PUSH R17 'SREG->Stack
LDS R17, {Bytezaehler}
PUSH R18 'R18 ->Stack
LDS R18, {Xnor}
DEC R17 'decr Bytezaehler
STS {Bytezaehler}, R17
BRNE notCRC 'nur bei Zaehler=0...
CP R16, R18 'CRCcheck
#if Debugmode = 0
BRNE Restore_r18_sreg_r17 'CRC-ERROR->nix zu tun
#else
brne crcerror
#endif
SBI GPIOR0, 0 'setze BIP
SBI GPIOR0, 2 'setze CRC_OK
RJMP Restore_r18_sreg_r17
#if Debugmode = 1
Crcerror:
ldi R16,Nec_crc_error
Out Udr , R16 'Fehlercode senden
RJMP Restore_r18_sreg_r17
#endif
Notcrc: '...sonst
CPI R17, 253 'wenn Längenbyte empfangen
BRNE notlength 'dann
STS {Bytezaehler}, R16 'Bytezaehler=neues Byte
RJMP calccrc
Notlength:
BRCC calccrc 'wenn Bytezaehler>253 überspringe, sonst...
STS {K_rec_buff}, R16 'neues Byte->Puffer
STS {Bytezaehler}, R17 'Bytezaehler abgespeichert
SBI GPIOR0, 0 'BIP gesetzt
Calccrc:
EOR R18, R16 'xnor=xnor EOR neues Byte
STS {Xnor}, R18 'XNOR abgespeichert
Restore_r18_sreg_r17: 'R18, SREG, R17 zurückholen
POP R18
POP R17
Out Sreg , R17
pop R17
Rx_isr_restore_r16: 'R16 zurückholen
pop R16
$end Asm
Return
Oc1a_isr: 'PWM-Frequenz anpassen (PPM)
$asm 'Assemblerblockanfang
PUSH XH
PUSH XL
PUSH R16
IN R16, SREG
PUSH R16 'Register und SREG gesichert
Loadadr Bitzaehler , X 'X Enthält Bitzaehler -speicheradresse
LD R16, X 'R16=Bitzähler
DEC R16 'R16 dekrementiert
ST X+, R16 'Bitzähler zurückgespeichert, X enthält Adress-Adresse
BREQ naechstesVorbereiten 'final wurde gesendet, Sprung (nächstes vorbereiten)
CPI R16, 34 'Z=1 <==> Bitzaehler (jetzt)= 34
BREQ burstAbschalten 'dann springe burstAbschalten
cpi R16, 33 'Z=1<==>Bitzaehler=33
BREQ pauseEnde 'dann -> Pause Ende
BRSH dasWars '>33->dasWars (0,33,34 wurden bereits behandelt, bleiben die 32 Bits)
CPI R16, 17 'Carry bei den letzten 17 als einem Endburst (R16=0) plus 16 Bits(R16=16..1)
BRCC AdresseStimmt 'sonst überspringe
inc XL 'X =Kommandoadresse
Adressestimmt:
LD R16, X
LSL R16 'einmal nach links schieben, MSB wandert ins Carry
BRCS EinsSenden 'bei 1 springe, bei 0 bleibe
INC R16 'links wurde ne 0 rausgeschoben, deswegen wird die 0 hinten zur 1 invertiert
ST X, R16 'Byte zurückgespeichert
LDI R16, hbyte(8999)
Out Icr1h , R16
LDI R16, lbyte(8999)
Out Icr1l , R16 'Icr Angepaßt
RJMP dasWars 'Fall 0 erledigt
Einssenden:
ST X, R16 'die hinten eingeschobene 0 ist bereits invers zur 1 - Byte zurückgespeichert
LDI R16, hbyte(17999 )
Out Icr1h , R16
LDI R16, lbyte(17999 )
Out Icr1l , R16 'Icr Angepaßt
RJMP dasWars 'Fall 1 erledigt
Pauseende:
LDI R16, hbyte(4499)
Out Ocr1ah , R16
LDI R16, lbyte(4499) 'Ocr wieder Auf 562,5 µs
Out Ocr1al , R16 'wird erst nach dem nächsten TOV aktiv
LDI R16, 130
Out Tccr1a , R16 'B3 wird PWM (lo->hi beim nächsten TOV)
RJMP dasWars '->dasWars
Burstabschalten:
CBI PORTB, PORTB3 'B3 -> lo
RJMP dasWars '->dasWars
Naechstesvorbereiten:
LDI R16 , 24
Out Tccr1b , R16 'Timer Steht
LDI R16, hbyte(17999)
Out Ocr1ah , R16
Out Icr1h , R16
LDI R16, lbyte(17999)
Out Ocr1al , R16
Out Icr1l , R16 'Ocr1a Und Icr1 Für Nächsten Start Vorbereitet
LDI R16, 38
STS {Bitzaehler},R16 'Bitzäehler reinitialisiert (38)
LDI R16,0
Out Tcnt1h , R16
Out Tcnt1l , R16 'Timer = 0 (Reload, ggf anpassen)
LDI R16, 2
Out Tccr1a , R16 'B3 ist wieder I/O
Daswars:
POP R16
Out Sreg , R16
POP R16
POP XL
POP XH 'SREG und Register (R16, XH, XL) wiederhergestellt
$end Asm
Nec_busy = 0
Return