list p=16F84,r=dec include "p16F84.INC" __idlocs 0501h __config _XT_OSC & _WDT_ON & _PWRTE_ON ;Bit-Belegung PortA DMX equ 0 AFEED equ 1 BUSY equ 2 STROBE equ 3 SELIN equ 4 ;zum RAM rücklesen ;Variablen magic equ 0Ch ;Schalter für's EEPROM-Auslesen (RAM-vor-EEPROM) ;unused mem equ 0Dh ;unused pointer equ 0Eh counter equ 0Fh ;64 Kanäle (auch im EEPROM) chfirst equ 10h chlast equ 4Fh MNOP macro count local a=0 while a88 µs movlw 27+1 ;also 27*3+4=85 µs movwf counter ;Schleifen-Init: 2 µs wait_88us decfsz counter,f ;Schleifen-Inneres: 3 µs goto wait_88us ;Schleifen-Ausbruch: 2 µs nop ;1 Ausgleichs-NOP für 86 µs (+2 für Folgebefehle) bcf INTCON,GIE ;TIME_CRITICAL bsf PORTA,0 ;Mark 8µs MNOP 7 bcf PORTA,0 ;Startbit (Null) movlw 10+1 ;also 10*3+4=34 µs movwf counter wait_36us decfsz counter,f goto wait_36us nop ;1 Ausgleichs-NOP für 35 µs (+1 für Folgebefehl) bsf PORTA,0 ;Stoppbits (>=8 µs) bsf INTCON,GIE call init_pointer ;dauert mit Aufruf 8 µs; ggf. Makro einsetzen chanel bcf INTCON,GIE ;TIME_CRITICAL bcf PORTA,0 ;Startbit (4 µs) LOCAL a=0 WHILE a<8 movfw INDF ;RAM-Speicherzelle laden rrf INDF,f ;Speicherzelle rotieren iorlw 0FEh ;BUSY=high belassen movwf PORTA ;Bit 0 ausgeben (alle anderen sind Eingabe!) a+=1 ENDW rrf INDF,f ;noch einmal, um CY einzuschieben MNOP 2 bsf PORTA,0 ;Stoppbits (>=8 µs) bsf INTCON,GIE nop incf FSR,f ;nächste Speicherzelle decfsz counter,f goto chanel clrwdt goto go ;zum Anfang EERead: ;EEPROM lesen (lästige Bankumschaltung) BANKSEL 80h bsf EECON1,RD ;Lesen auslösen eerw: btfsc EECON1,RD ;dauert nicht lange goto eerw BANKSEL 0 return EEWrite: ; Diese Routine vergleicht den EEPROM- mit dem RAM-Inhalt. ; Sind diese verschieden, wird _eine_ Speicherzelle gebrannt. ; Bei gesetztem Brenn-Bit (Bit 1, "WR") wird nichts getan ; In den EEPROM kommen NEGIERTE Datenbits wegen Default=0 ; Wenn alle Bytes stimmen, wird das RAM-vor-EEPROM-Byte gelöscht BANKSEL 80h movlw 1< Raus! call init_pointer_EE suche: call EERead movfw INDF xorlw 0FFh ;Komplement bilden xorwf EEDATA,f ;gleich? (W bleibt) SKPZ goto burn ;ungleich - brennen! incf FSR,f incf EEADR,f SKPNZ ;falls nur 6 Bits, wird's Null (Notnagel) return ;alle Speicherzellen verglichen btfss EEADR,6 ;falls 8 Bits, Bit 6 testen goto suche clrf magic return ;raus wenn =64 burn: movwf EEDATA ;Ungleich? - Neues Datum eintragen BANKSEL 80h bsf EECON1,WREN ;Bit 2: Schreibfreigabe movlw 55h movwf EECON2 movlw 0AAh movwf EECON2 ;Kennung zun "Brennen" bsf EECON1,WR ;Brennung auslösen BANKSEL 0 return init_pointer_EE: clrf EEADR init_pointer: clrf FSR bsf FSR,4 ;macht 10h = chfirst clrf counter bsf counter,6 return ;Unterprogramm: Daten zum PC auslesen lesen: call init_pointer BANKSEL 80h clrf TRISB BANKSEL 0 read_lpt_data: movfw INDF ;Datenbyte holen movwf PORTB ;Datenbyte ausgeben ;diese beiden (bei PC-Absturz) Endlosschleifen ;werden durch den Watchdog-Timer nach ca. 18 ms abgewürgt; ;die Initialisierungsroutine setzt BUSY auf HIGH... bcf PORTA,BUSY ;Bereit zur Daten-Ausgabe read_wait_for_low btfsc PORTA,STROBE ;Strobe endlich LOW? goto read_wait_for_low bsf PORTA,BUSY ;Bestätigung read_wait_for_high btfss PORTA,STROBE ;Strobe endlich HIGH? goto read_wait_for_high incf FSR,f ;nächste Speicherzelle clrwdt decfsz counter,f goto read_lpt_data ;nächstes Byte BANKSEL 80h decf TRISB,f ;0FFh, also wieder Eingabe BANKSEL 0 return end