Assembler Code V26

; *******************************************************************
; Programm PATermV2.6.asm
; Dieses PA-Terminalprogrammes: Es beinhaltet einen 8 stelligen (4 Byte)
; Dekadischen Zähler zum zählen der Hübe eines Pressluftantriebes. Nach 
; dem Aufzählen wird der BCD Stelleninhalt für die Siebensegmentanzeige
; codiert und anschliessend seriell an die Anzeige versandt.
; Das PA-Terminal ist Teilnehmer eines halbduplex RS485-Buses. An diesem
; ist es in der Lage mit einem Master seriell zu über km-Distanzen zu 
; kommunizieren. Implementiert sind Befehle zur Hubzählauslese bzw. 
; Korrektur, Seriennummernauslese und Korrektur, sowie Fehlerstandauslese
; und Löschung dessens.
; *******************************************************************
 
 
 
; Seriennummer Antrieb:
SN		equ	d'00000137' 	; Terminal Nr. 1
 
 
 
; Register
; Namen-Registeradressen (Festwert):
; Bank 0:			; Bank 1:
INDF		equ 0x00	; <-
TMR0		equ 0x01	; Option Register
PLC		equ 0x02	; <- 
STATUS		equ 0x03	; <-
FSR		equ 0x04	; <-
PORTA		set 0x05	; TRISA
PORTB		set 0x06	; TRISB
EEDATA		equ 0x08	; ECON1
EEADR		equ 0x09	; ECON2
PCLATH		equ 0x0A	; <-
INTCON		equ 0x0B	; <-
 
 
; Bank 1:
TRISA		set 0x05
TRISB		set 0x06
EECON1		equ 0x08
EECON2		equ 0x09
 
; Variablen
 
ByteNr		set 0x0C
Anzeige		set 0x0D
Anzeigewert	set 0x0E
Testwert	set 0x0F
 
B3		set 0x10	; Höchste Doppelstelle Anzeige: Mio. und Zehnmio.
B2		set 0x11	; dritte Doppelstelle Anzeige: Zehntausender und Hundertaus.
B1		set 0x12	; zweite Doppelstelle Anzeige: Hunderter und Tausender
B0		set 0x13	; niedrigstes Doppelstelle Anzeige: Einer und Zehner
 
B3?		set 0x14	; Redundanzstellen
B2?		set 0x15	
B1?		set 0x16	
B0?		set 0x17	
 
B3??		set 0x18	
B2??		set 0x19	
B1??		set 0x1A	
B0??		set 0x1B	
 
ESpeicherA	set 0x1C
PWMa		set 0x1D
Buffer		set 0x1E	; Speichert schon gesendet Status
PWMs		set 0x1F
 
A0		set 0x20	; Adressspeicher MSB (ID PA-Terminal)
A1		set 0x21	; Adressspeicher LSB
F0		set 0x22	; Fehlerbyte MSB
F1		set 0x23	; Fehlerbyte  LSB
 
A0?		set 0x24	; Redundanzstellen
A1?		set 0x25	; 
F0?		set 0x26	; 
F1?		set 0x27	; 
 
A0??		set 0x28	; 
A1??		set 0x29	; 
F0??		set 0x2A	; 
F1??		set 0x2B	; 			
 
Schleife1	set 0x2C
Schleife2	set 0x2D
Schleife3	set 0x2E
Schleife4	set 0x2F
 
B3???		set 0x30	
B2???		set 0x31
B1???		set 0x32	
B0???		set 0x33
Telnr		set 0x34
SERBUF		set 0x35
Bitindex	set 0x36
 
Schleife5	set 0x3C	
Schleife6	set 0x3D
RAM1		set 0x3E
RAM2		set 0x3F
 
Steuer		set 0x40
Adresse0	set 0x41
Adresse1	set 0x42
D1		set 0x43
D2		set 0x44
D3		set 0x45
D4		set 0x46
identisch	set 0x47
Fehler		set 0x48
Fehlkont	set 0x49	; Fehlerkontrollbyte
korrekt		set 0x4A
TS		set 0x4B
Sprung		set 0x4C
RAM		set 0x4D
Vorgabe		set 0x4E	;
Vergleich	set 0x4F        ; 
 
 
 
; Konstanten
 
PWMF		equ 0x50   ; Pulsweitenschwelle ( <an, > aus)
PWMm		equ 0x7F   ; Pulsweitenzyklusmaximalwert
uSchwelle	equ D'16'  ; 
oSchwelle	equ D'111' ;
 
 
 
;Bitnamen
c		equ 0	; (STATUS)
z		equ 2	; (STATUS)
RP0		equ 5	; (STATUS)
RP1		equ 6	; (STATUS)
IRP 		equ 7	; (STATUS)
 
GIE		equ 7	; (INTCON)
RBIF		equ 0	; (INTCON)
INTE		equ 4	; (INTCON)
 
WR		equ 1	; (EECON1)
WREN		equ 2	; (EECON1)
RD		equ 0	; (EECON1)
EEIF		equ 4	; (EECON1)
 
;           PORTA
ClockLED	equ 2	; Pin1: Anzeige Clock (Bit 2 Port A)
serLED		equ 3	; Pin2: Serielle Daten zur Anzeige (Bit 3 Port A)
Strobe		equ 4	; Pin3: Strobe zur Anzeige Übernahme (Bit 4 Port A)
OutEnabl	equ 1	; Pin18: Anzeige an/aus (Bit 1 Port A)
 
 
 
;           PortB	
Moved		equ 0	; Pin6:  Moved (inside) Signal
			; Hardware (Jumper) Sperre Nullung Zählerstand: 
ZeroReset	equ 1	; Pin07: Low = Nullsetzen gesperrt,
			;        high Nullsetzen möglich
ReportTrans	equ 2	; PIN08: Serielle Daten Ausgabe
Direction	equ 3	; Pin09: Richtung der Halbduplex RS485:
			;	low = receive,
			;	high = send
iniDataSave	equ 4	; Pin10: veranlassse Datensicherung :
			;	high = on power, 
			; 	low = Datensicherung ausführen!
Commands	equ 5	; Pin11: Received Remote Commands
Program		equ 6	; Pin12: In Curcuit Programm Data
ProClock	equ 7	; Pin13: Inserie-Programmierclock
 
; Makrodefinitionen
bank0		macro
		bcf	STATUS, RP0
		endm
 
 
bank1		macro
		bsf	STATUS, RP0
		endm
 
		org	0x00	
 
		goto 	main
 
; hier potetielle Interrups
 
 
main
		NOP	; (Wg. Einsprung Interlock an h'04'!)
		NOP	
		goto	Start
 
 
; Interruptrutine DATASAVE an H'04'
		; vvvvv  hier Interrupt-Einsprungpunkt vvvv
		Call	Interrupt 
		; ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
		; 	Bei Powerdown: Stop in Interrupetrutine
		; 	Bei Fernbefehlsempfang: mache nun weiter!
		goto	Zyklus		; springe an Anfang Konsistenztest
		return
 
Start
		; Initialisierung
		bank1			; Disable Interupts !
		BCF	INTCON, GIE
 
		; IO-Port Einrichtung
		bank0	; adressiere Bank0
		CLRF	PORTA
 
		bank1	; adressiere Bank1
		MOVLW	B'00000000'	; 8x Ausgang
		MOVWF 	TRISA		; Setze Richtung
 
		bank0	; adressiere Bank0
		CLRF	PORTB
 
		bank1	; adressiere Bank1
		; Datasave 4-vv-3	Direction
		; Command 5-v  v-2	SerData
		; Pro1	 6-v	v-1	ZeroReset
		; Pro2	7-v	 v-0	frei
		MOVLW	B'00110011'		; 4x Ausgang, 4x Eingang
		MOVWF 	TRISB			; Setze Richtung
 
		bank0				; adressiere Bank0
		BCF	PORTB, Direction	; Initialisiere auf Empfang
		BCF	PORTB, ReportTrans	; Ini. ausgabe Null
		BCF	PORTB, 6		; Ini Programmmierport Null
		BCF	PORTB, 7		; Ini. Programmierport Null
 
 
		MOVLW	H'00'
		MOVWF	ESpeicherA	; Lade EEpromstartwert
 
		MOVLW	D'1'	; "Moved"-Spikebuffer
		MOVWF	Buffer
		CLRF	Fehler
 
		; Ini. Pulsweitenmodulation: PWMm >>>>>>>>>>>> PWMa >>>> PWMs >>> 0
		MOVLW	PWMm	; (In der "Delay"-Rutine ist die Wiederholfrequenz hoch!
		MOVWF	PWMa	; wird in aktuellen Laufwert geladen.
		MOVLW	h'40'	; Starte bei Powerup mit Anzeige an!
		MOVWF	PWMs	; wenn diese Schwelle erreicht, dann schalte ein,
				; hier Daueraus, da PWMa nie gleich 0, da PWMA wieder orher wieder 
				; auf PWMm gesetzt wird! Normalschwelle sonst gleich 1 und somit
				; PWM-Faktor gleich : 1/PWMm= 64/127 = 0,5
 
 
 
 
 
		; **************************
 
 
		BTFSS	PORTB, 1	; Wenn Inijumper offen:  ZeroReset = H (EE-> Null),
		goto	LeseEE		; sonst, wenn gesetzt:   ZeroReset = L: EEprom>RAM
 
		Call	Nullsetzen	; Nullsetzen EEPROM 1,3ms
		; goto 	SCHLUSS
		; hier evtl. warten auf Traffic zur SN-Erstvergabe
 
LeseEE		Call	HoleEE		; hole Zählerstand (4Byte=8Stellen), SN(2Byte=4Stellen)
					; sowie Fehlerstand (2Byte=4Stellen)
					; Dauer: 0,9 ms (-> 2,4ms)
 
		; Anzeige Seriennummer 
		; (Missbraucht Zählerstandstellen, aber Konsistenz korigiert das!)
		MOVF	B3, 0		; Temporäre Auslagerung
		MOVWF	B3???
		MOVF	B2, 0
		MOVWF	B2???
		MOVF	B1, 0
		MOVWF	B1???
		MOVF	B0, 0
		MOVWF	B0???
 
		; **** Anzeige 1x Start **** 
 
		; Anzeige "Start  !"
		MOVLW	H'DE'	; " !" 	
		MOVWF	B0
		MOVLW	H'BD'  	; "t "-120
		MOVWF	B1
		MOVLW	H'AC'	; "ar"-
		MOVWF	B2
		MOVLW	H'5B'   ; "St"-80
		MOVWF	B3
		Call	IniStream
		Call	STREAM		; Zeige "Start  !"
 
		Call	Delay		; ca. 1,5s Verzögerung (incl. PWM !).
 
		MOVF	A0, 0		; lade LSB Adresse = Seriennummer (Dekadisch)
		MOVWF	B0
		MOVF	A1, 0		; lade MSB Adresse
		MOVWF	B1
		MOVF	Fehler, 0	; Zeichen "  " (Test EESCHreibfehler)
		MOVWF	B3
		MOVLW	H'5F'   	; Zeichen "Sn"
		MOVWF	B2
 
 					; Sn#-Anzeige
		Call	IniStream
		Call	STREAM		; Zeige "Sn  xxxx"
 
		Call	Delay		; ca. 1,5s Verzögerung.
 
 
		MOVF	B3???, 0	; Rückverlagerung
		MOVWF	B3
		MOVF	B2???, 0
		MOVWF	B2
		MOVF	B1???, 0
		MOVWF	B1
		MOVF	B0???, 0
		MOVWF	B0
 
		Call	IniStream
		Call	STREAM		; Zeige Hubzählerstand
 
		Call	Delay		; ca. 1,5s Verzögerung.
; Achtung: Delayrutine nutzt Zähler, deswegen Zählwert wiederherstellung danach:
		MOVF	B3???, 0	; Rückverlagerung ..
		MOVWF	B3		; in drei Redundanzstellen ...
		MOVWF	B3?
		MOVWF	B3??
 
		MOVF	B2???, 0
		MOVWF	B2
		MOVWF	B2?
		MOVWF	B2??
 
		MOVF	B1???, 0
		MOVWF	B1
		MOVWF	B1?
		MOVWF	B1??
 
		MOVF	B0???, 0
		MOVWF	B0
		MOVWF	B0?
		MOVWF	B0??
 
Frei		; Freigabe der Interlocks !!!
		BSF	STATUS, RP0	; Bank1
		;	  v- Global Interlock
		;	     v- RB0  (B3): "Moved" (alt V1: RA0, neu V2: an RB0)
		;	      v- RB4-7 (B4): z.B. Commannds
		MOVLW	B'10001000'	; Enable (B0) global interlock,
					; and special: RB0 (B3), RB4-7 (B4)
		MOVWF	INTCON		; Schreibe ins Inerlockkontrollregister
		BCF	STATUS, RP0	; Bank0
 
		; Ini. Pulsweitenmodulation für Normalzyklus (geringer Frequenz wg. Konsist.)
				;            an      |->           aus
				; PWMm >>>>>>>>>>>> PWMa >>>> PWMs >>> 0
		MOVLW	PWMm	; (In der "Delay"-Rutine ist die Wiederholfrequenz hoch!
		MOVWF	PWMa	; wird in aktuellen Laufwert geladen.
		MOVLW	h'0'	; Starte mit Anzeige aus!
		MOVWF	PWMs	; wenn diese Schwelle unterschritten, dann schalte ein,
				; hier Daueraus, da PWMa nie gleich Null, da PWMA vorher wieder
				; auf PWMm gesetztwird! Normalschwelle sonst gleich 1 und somit
				; PWM-Faktor gleich : 1/PWMm= 1/16.
 
		MOVLW	D'1'		; Clear des Filterbuffers!
		MOVWF	Buffer		; ab dort wieder 16 High zum Senden nötig!
 
; **************************************************************************************
; ****************************** Der Zyklus ********************************************
Zyklus
		MOVF	PORTB, 0	; Signal "Moved" 
		MOVWF	B3???		; PORTB	Sicherung (gg.f. Vergleich mit Vorzustand)
		Call	Konsistenz	; 0,6 ms ->1,8 ms (1,2 ms)
 
; Eingefahren: zählen und senden
 
		BTFSS	PORTB, Moved	; wenn Moved high wird und ...
		goto 	NSenden
BUF		;Ausgef.:	       ,->127----------/------127
		;                   uS(16)         oS(111)
		;Eingef.:   1-------/-------------<1-'	
		MOVlW	d'127'
		SUBWF	Buffer, 0	; wenn voll (127), dann...
		BTFSS	STATUS, z	; ... nicht erhöhen.
		INCF	Buffer,	1	; sonst erhöhe Spikepuffer
		MOVLW	uSchwelle
		SUBWF	Buffer, 0	; wenn untere Schwelle überschritten
		BTFSS	STATUS, z	; Nach 16x High gesehen: latsche (1. Schwellwert)
 
		goto	hatschon
				; genau einmal nach 16 Highs
 
Latchzaehlen    ; 11111111111111111111111111111111111111111111111
		CALL	IniByte
		CALL	EinByte		; Springe in dek. Aufzählrutine
senden
		CALL	IniStream	; Initialisierung Straeming
		CAll	STREAM		; Acht Byte an Anzeige shiften
		MOVF	B3, 0		; neuen Zählerstand ...		
		MOVWF	B3?		; in restliche Redundanzstellen ...
		MOVWF	B3??
 
		MOVF	B2, 0
		MOVWF	B2?
		MOVWF	B2??
 
		MOVF	B1, 0
		MOVWF	B1?
		MOVWF	B1??
 
		MOVF	B0, 0
		MOVWF	B0?
		MOVWF	B0??
 
		MOVLW	D'127'		
		MOVWF	Buffer		;  ansonsten wenn bereits gefahren,
		goto	hatschon	;  halte gesendet und mach weiter
NSenden		; 22222222222222222222222222222222222222222222222
 
		DECF	Buffer, 0	; Test dekrementieren in W
		BTFSC	STATUS, z	; wenn schon 1 nicht weiter dekrementieren!
		goto	hatschon	; noch im Bereich < uSchwelle
 
		MOVF	Buffer, 0	; z.B d'112'
		SUBLW	oSchwelle	; Teste auf Erreichen oSchwelle 
		BTFSS	STATUS, z	; Rücksetzen, wenn Schwelle (z.B. D'111')
		goto 	w4		; unterschritten!
		MOVLW	D'1'		; Clear des Sendebuffers!
		MOVWF	Buffer		; ab dort wieder 16 High zum Senden nötig!
		goto	hatschon
w4
		DECF	Buffer, 	; reduziere Spikebuffer (bei Low-INSIDE) 
					; 
 
 
 
hatschon
 
		;Call	Pulsweitenmodulation 
		; (nun im Konsistenztest intergriert wg. höherer Frequenz)
 
		MOVLW	H'99'		; Bei 99 Mio ist ganz Schluss
		SUBWF	B3, 0		; Subtrahiere ByteNr-4
		BTFSS	STATUS, z	; Checke ob am Ende
		goto	Zyklus		; Bei 99 Mio. beginne bei Null!
 
 
		goto 	SCHLUSS
 
; **************************************************************************************
; **************************************************************************************
 
Interrupt	;	!!!!!!! an   PORTB,4 (iniDatasave, kann Prellen)   !!!!!!!!
	  	;	!!!!!!! oder PORTB,5 (Command line changed)        !!!!!!!!
	 	;	!!!!!!! tritt eine Änderung auf                    !!!!!!!!
 
		BSF		PORTB, 7 	; Triggertestpunkt
 
		MOVF	Buffer, 0	; Prellfilter "Move"-Signal
		MOVWF	B2???		; Sichere Filterbuffer für "Move" zwischen.
		MOVLW	d'1'		; Startwert Filterbuffer "inidatasave"
		MOVWF	Buffer
StartBit?	; war es nur ein Startbit ? (RS485 ist vorgespannt stabil) 
		BTFSS	PORTB, Commands	; Polle auf Startbit(L) ...
		goto 	NurBefehl
 
 
 
 
 
 
 
BUF2	; ******** Entprellfilter ********************************************
		; Wenn Interrupt nicht durch Remote Befehl (Start= Low),
		; dann Entprellen vor Datensicherung!
		; AUS:	        ,->127-----------/------127
		;             uS(16)         oS(111)
		; AN:  1-----/------------1<--'
 
		BTFSC	PORTB, iniDataSave	; wenn iniDataSave low ist erhöhe Zähler, ...
		goto	AN		; ... sonst wenn wieder high: Trigger abwärts, reduziere Zähler
aufwärtsZ	COMF	Buffer, 0	; wenn voll (255), dann nicht erhöhen:...
		BTFSC	STATUS, z	; ... voll?
		goto	BUF2		; nächste Prellprüfung.
		INCF	Buffer,	1	; .. nicht voll: Zähler erhöhen!
		MOVLW	uSchwelle
		SUBWF	Buffer, 0	; wenn untere Schwelle überschritten
		BTFSS	STATUS, z	
		goto	BUF2		; nächste Prellprüfung.
 
AUS ;(Zustand): Nach 16x Low: Daten sichern (1.Schwellwert) -> AUS!
		Call 	SchreibeEE	; 0-> Shut down, Datensicherung!
		GOTO	SCHLUSS		; Da gibt's kein Zurück!
 
AN  ;(Zustand): noch weiter an falls nur Prellensolange 
		MOVLW	D'1'
		SUBWF	Buffer, 0	; zunächst nur testweise in W dekrementieren	
		BTFSC	STATUS, z	; wenn schon 1 raus aus Filter und Interrupt!
		goto	w7
		MOVF	B2???, 0	; hole zwischengespeicherten Filterbuffer "Move"
		MOVWF	Buffer		; übernehme wieder Filterbuffer "Mov" (im Zyklus relevant!)
		BCF	PORTB, 7	; Nur f. Test: Lösche Interuped-status
		bcf	INTCON, 0	; lösche RBchange-Interuppt (Spike IniDatasave)
					; Global Interuped wird by Return gelöscht
		retfie			; war nur Stöhrung: Ausgang aus Interrupt ...
 
w7		MOVLW	oSchwelle	; Buffer weiter reduzieren
		SUBWF	Buffer, 0	; Teste auf Erreichen oSchwelle
		BTFSS	STATUS, z	; Rücksetzen, wenn Schwelle (d'127' h'80') unterschritten
		goto 	reduziere
		MOVLW	D'2'		; Clear des Filterbuffers!
		MOVWF	Buffer		; ab dort wieder 16 High zum Senden nötig!
reduziere
		DECF	Buffer, 1	; reduziere Buffer, aber weiter im Filter!
		goto	BUF2
 
NurBefehl	; 22222222222222222222222222222222222222222222
 
		Call	traffic		; 1-> Power da, aber Befehleingang!
 
		BCF	PORTB, 7	; Nur f. Test: Lösche Interuped-status
		bcf	INTCON, 0	; lösche RBchange-Interupped (Datenverker)
							; Global Interuped wird by Return gelöscht
		BCF	PORTB, 3	; Ändere Halfduplex-Richtung: Mache RS485-
							; Sender wieder zum Empfänger!
	   	MOVLW	d'1'		; Totzeit nach aktuellem Befehl für neue Befehle:
		MOVWF	Schleife3	; (gibt externem Master Zeit zum Rückschalten von
Totzeit	
		Call 	ByteZeit	; Empfang auf Senden, Umschaltprozess kann sonst
		Decfsz	Schleife3, 1	; erneut Interupped auslösen!
		goto	Totzeit		; Sperrzeit f. Master
 
 
		retfie				; Beende Interupt 
		; (nur nach Remotebefehl Abarbeitung)
 
 
 ;*************** Schreibe Datensicherung (Power down) RAM -> EEPROM  ************
SchreibeEE						
		BSF	PORTB, 6	; Test: Zeige Schreiben an RB6 an!
		MOVLW	h'2'		; 1->0 zwei Zeilen
		MOVWF	Schleife1	; Zeilenindex (vom EEPROM aus)	
SS1		; Start Schleife 1
 
		MOVLW	h'0C'		; 0B->....->0 (12x)
		MOVWF	Schleife2	; Spaltenindex 		
SS2		; Start Schleife2
 
 
Schreiben	;  *** Bestimme Ursprung (RAM) und Zieladresse (EESpeicher) ***
 
		MOVF	Schleife1, 0	; Lade Zeilenwert in W
		MOVWF	ESpeicherA	; Füge Zeilenwert in ESpeicherA ein
		DECF	ESpeicherA, 1	; (muss um eins kleiner sein als Schleife)
		SWAPF	ESpeicherA, 1	; Übernehme Wert in höheres Nibble: Zeilenindex
		MOVF	Schleife2, 0	; Lade Spaltenwert in W
		ADDLW	h'FF'		; -1 ! (Muss um eins kleiner sein als Schleife)
		ADDWF	ESpeicherA, 0	; Addiere Spaltenwert zur Zeile in W
		MOVWF	ESpeicherA	; Füge komplette Ursprungsadresse in ESpeicherA
		MOVLW	h'10'		; 
		ADDWF	ESpeicherA, 0	; W: Erhöhe Zielbereich RAM um eine Zeile 
					; gegenüber EEPROM!    RAM = ESpeicherA + h'10'
		MOVWF	FSR		; Pointer auf RAM-Adresse
		MOVF	INDF, 0		; Rufe gepointeten Inhalt ab!
		MOVWF	EEDATA		; Übergebe RAM-Wert an EE-Übergabeadresse
 
		MOVF	ESpeicherA, 0	; Ziel ins EEPROM
		MOVWF	EEADR		; Ziele auf EE_Adresse Ziel
 
		; ************ Einschreiberutine ************
		BSF	STATUS, RP0	; Wahl Bank1
		BSF	EECON1, WREN	; Enable Write Bit
		MOVLW	h'55'
		MOVWF	EECON2
		MOVLW	h'AA'
		MOVWF	EECON2
		BSF	EECON1, WR
KontrolleSi	BTFSS	EECON1, EEIF	; warte auf Flag Schreiberfolg!
		goto	KontrolleSi
		BCF	EECON1, EEIF	; Flag f. erfolgreiches EE-Schreiben rücksetzten
 		BCF	STATUS, RP0	; wieder Bank0 wählen
		; >>> Verrify: <<<<
		MOVF	EEDATA, 0	; Hole letzten Schreibwert in W!
		BSF	STATUS, RP0	; Wahl Bank1
		BSF	EECON1, RD	; Lese eingeschriebenes Byte
		BCF	STATUS, RP0	; wieder Bank0 wählen
		SUBWF	EEDATA, 0	;
		BTFSS	STATUS, z	; Wenn Soll und ist gleich weiter ...
		INCF	Fehler, 1	; sonst Schreibfehler erhöhen!	
		DECFSZ 	ESpeicherA, 1	; zeige auf nächstes Byte
		BCF	EECON1, WREN	; disable Write Bit
 
		; ************ Ende Einschreiberutine ***********
 
		DECFSZ	Schleife2, 1		; Spalten abgearbeitet?
		goto 	SS2
 
ESchleifeSS1	DECFSZ	Schleife1, 1 		; Zeilen abgearbeitet?
		goto 	SS1
 
		BCF	PORTB, 6	; Test: Zeige Fertig Schreiben!
 
		RETURN			; To Befehl9 oder Interrupt und dann zum SCHLUSS mit
					; Warten auf Powerdown.
 
 
 
; ********************* Remote-commands and Respond **************************************
; Das PA-Terminal soll im Augenblick sechs Fernbefehle erkennen und gegebenfalls richtig 
; beantworten. ; Dazu wird über einen RS485-Feldbus im Halpduplexbetrieb ein 7 Byte langes 
; Mastertelegramm verschickt. ; Nach dem Versenden der sieben Byte geht der Master für eine 
; gewisse Zeit auf Empfang um ebenfalls ; bis zu sieben Byte vom angesprochenen PA-Terminal 
; zu erhalten. Da die Signalübertragung auf einem Bus, ; also mit mehreren Teilnehmern 
; statt findet, sehen auch nich angesprochene Terminals sowohl Mastertelegramm wie auch ggf.
; die Antwort. Ein fälschliche Reaktion von anderen Teilnehmern darauf muss vermieden 
; werden, ; da zu einem Zeitpunkt nur jeweils ein Sender auf dem Bus aktiv sein darf!
; Es gibt Adrressierte und Unadressierte Befehle (Mastertelegramme)
; *****************************************************************************************
 
traffic
		BTFSC	PORTB, 3	; Empfange Fernbefehle ...		
		Return
		movlw	h'7'
		movwf	Schleife1	;
		BCF	PORTB, ReportTrans	; Bereite Ruhezustandsausgabe vor:
					; bestimmt Pegel sobald auf Senden umgestell wird!
 
 
Zeichenein	; *****************************************************************
		; Synchronisation auf Startbit (0)
		BTFSC 	PORTB, 5	; übergehe bei Startbit erstes Mal gleich 0!
		goto 	Zeichenein	; suche weiter Startbit
		call 	half_Baud	; 14µS vorher bis hier: nun Warte halbe Baudrate
 
		btfsc	PORTB, 5	; 1µs (2µS) Wenn weiteres mal gleich Null: 
					; synchronisiert mit eingehendem Telegram!
		goto    Zeichenein	; 2µS warte weiter wenn Startbit immer noch nicht da
					; (Erstes war Spike)!
 
 	; einmal synchronisiert werden sieben Zeichen genommen, ob die da sind nicht!
	; Startadresse vom Mastertelegramm ( Steuerbyte als Erstes: 40,41,...,47)
		movlw	h'3F'		; 1µS
		movwf	Telnr		; 1µS Zieladresse Telegram -1
Tele7		; (10 µS Summe Befehle um Einlese SUB)
		movlw	8		; 1 µS Beginne serielle Eingangssequenz	
		movwf	Schleife6	; 1 µS erfasse 8 Datenbits
		clrf	SERBUF		; 1 µS Lösche Buffer!
 
		incf	Telnr, 0	; 1 µS erhöhe Zieladresse und ...
		movwf	Telnr		; 1 µS speichere in Variable zurück ...
		movwf	FSR		; 1 µS wie auch in Pointer
 
		Call	inch_n1		; empfange einen Rahmen 104 µS 
					; (Start-Bit, 8x Daten-Bit, Stop-Bit)
		movwf	INDF		; 1 µS Speichere Zeichen in Telegrammstellen!
 
		DECFSZ	Schleife1, 1	; 1µs (2µS) 
		goto	Tele7		; 2µS erfasse sieben Zeichen
wasnun
 
		; 	 Unadressierter Befehle
 
Befehl5?	; 	 Unadressierter Befehle
		movlw	5 		; Befehl Display einschalten 
					; (an allen PA-Terminal)
		subwf	Steuer, 0	; Vergleiche mit Steuerbyte
		BTFSS	STATUS, z	; 
		goto	Befehl10?
		; Display EINSCHALTEN
 
		movlw   PWMF		; lade konstanten Schwellwert ...
		movwf	PWMs		; in Schwellwertvariable ! 
		goto 	fertigT		; Schwellwertvariable
 
Befehl10?	; 	 Unadressierter Befehle
		movlw	d'10' 		; Befehl Display einschalten 
					; (an allen PA-Terminal)
		subwf	Steuer, 0	; Vergleiche mit Steuerbyte
		BTFSS	STATUS, z	; 
		goto	Befehl7?
		; Display AUSSCHALTEN
 
		movlw   0		; lade konstanten Schwellwert ...
		movwf	PWMs		; in Schwellwertvariable ! 
		goto 	fertigT		; Schwellwertvariable
 
Befehl7?	; >>> Befehl Fehler nullsetzen (an allen PA-Terminal)
		movlw	7 		
		subwf	Steuer, 0	; Vergleiche mit Steuerbyte
		BTFSS	STATUS, z
		goto	aBefehle
 
		clrf	F1		; Setze Fehlerzähler Konsistenz auf Null
		clrf	F1?
		clrf    F1??
		clrf	F0
		clrf	F0?
		clrf	F0??
 
		goto 	fertigT
 
aBefehle	; Identifizierung, bin ich angesprochen?
 
		clrf	Vergleich	; Bereite Adressvergleich vor
		movf	Adresse0, 0 	; Lade Adresswert aus Telegram in W
		subwf	A0, 0		; Vergleiche mit LSB RAM-Adresse (reduntant)
		BTFSC	STATUS, z	
		INCF	Vergleich, 1
		movf	Adresse1, 0 	; Lade Adresswert aus Telegram in W
		subwf	A1, 0		; Vergleiche mit MSB RAM-Adresse (reduntant)
		BTFSC	STATUS, z	
		INCF	Vergleich, 1
		BTFSS	Vergleich, 1 	; Wenn beide Adressbytes übereinstimmen...
		goto	fertigT
					; ***************************************
		BSF	PORTB, 3	; Ändere Halfduplex-Richtung: 
					; Mache RS485 Transmitter Slave zum Sender!
 
		;MOVLW	h'FF'		; 2xh'FF' kommt weder in Daten noch in Adress- bzw. 
					; Steuerkode vor!
		;MOVWF	identisch	; Schreibe erstes Endzeichen in erw. Ausgabestelle.
		;MOVWF	Fehler		; Schreibe zweite Endzeichen in erw. Ausgabestelle.
		;Call	ByteZeit	; Gibt Zeit f. Umstellung Empfang/Senden		
 
Befehl1?	; >>> Befehl: "Request Counter value"
		movlw	1 		; Befehl Display einschalten (an allen PA-Terminal)
		subwf	Steuer, 0	; Vergleiche mit Steuerbyte
		BTFSS	STATUS, z
		goto	Befehl2?
		MOVF	B3, 0		; Schreibe Zählerstand in Transferregister: 
		MOVWF	D1		; höchstwertiges zuerst!
		MOVF	B2, 0		; ( Adresse steht bei korrekter Identifizierung
		MOVWF	D2		;  schon drin)
		MOVF	B1, 0
		MOVWF	D3
		MOVF	B0, 0
		MOVWF	D4
		Call	Datenaus	; Gibt sieben Byte aus: h40-47
		goto 	fertigT		; Transmitter als Slave wieder empfangsbereit!
 
Befehl2?	; >>> Befehl: Set Countervalue: Kopiere Zählerstand in drei
		; Sicherungsstellen!
		movlw	2 		; Befehl Display einschalten (an allen PA-Terminal)
		subwf	Steuer, 0	; Vergleiche mit Steuerbyte
		BTFSS	STATUS, z
		goto	Befehl3?
 
		MOVF	D4, 0		; Schreibe MSB in Stelle ganz "links"
		MOVWF	B0
		MOVWF	B0?
		MOVWF	B0??
		MOVF	D3, 0		; Schreibe Zweithöchstes Byte in Stelle ganz 
		MOVWF	B1		; "halb links"
		MOVWF	B1?
		MOVWF	B1??
		MOVF	D2, 0		; Schreibe dritthöchstes Byte in Stelle 
		MOVWF	B2		; "halb rechts"!
		MOVWF	B2?
		MOVWF	B2??
		MOVF	D1, 0		; Schreibe letztes Byte in Stelle ganz "rechts"
		MOVWF	B3
		MOVWF	B3?
		MOVWF	B3??
		Call	IniStream
		Call	STREAM		; Zeige gesetzten Hubzählerstand!
		Call	Datenaus	; Gibt sieben Byte aus: h40-47
		goto 	fertigT		;  Slave zum Sender!
 
Befehl3?  	; >>> Befehl: Request SN#
		movlw	3
		subwf	Steuer, 0	; Vergleiche mit Steuerbyte
		BTFSS	STATUS, z
		goto	Befehl4?
 
		MOVF	Adresse0, 0	; Kopiere Adresse zusätzlich zu Byte1,2 
		MOVWF	D1		; (A0,A1) noch in Datenstellen (D1,D2).
		MOVF	Adresse1, 0
		MOVWF	D2
		CLRF	D3
		CLRF	D4		
		Call	Datenaus	; Gibt sieben Byte aus: h40-47
		goto 	fertigT		;  Slave wieder empfangsbereit!
 
Befehl4?	; >>> Befehl: "Set Serial Number": Kopiere SN in drei Sicherungsstellen
		; falls Strahlungsereignisszähler korrumpiert hat.
		movlw	4 			
		subwf	Steuer, 0	; Vergleiche mit Steuerbyte
		BTFSS	STATUS, z
		goto	Befehl6?
 
		MOVF	D1, 0
		MOVWF	A0
		MOVWF	A0?
		MOVWF	A0??
		MOVF	D2, 0
		MOVWF	A1
		MOVWF	A1?
		MOVWF	A1?
		Call	Datenaus	; Gibt sieben Byte aus: h40-47
		goto 	fertigT		;  Slave wieder empfangsbereit!
 
Befehl6? 	; >>> Befehl: Request number of consistency failures
		movlw	6
		subwf	Steuer, 0	; Vergleiche mit Steuerbyte
		BTFSS	STATUS, z
		goto	Befehl8?
 
		MOVF	F0, 0		; Übergebe zwei Stellen Fehlerzähler mit LSB zuerst!
		MOVWF	D1
		MOVF	F1, 0
		MOVWF	D2
		CLRF	D3
		CLRF	D4		
		Call	Datenaus	; Gibt sieben Byte aus: h40-47
		goto 	fertigT		;  empfangsbereit!
 
Befehl8? 	; >>> Befehl: Stream out EE-Bytes (24x)
		movlw	8
		subwf	Steuer, 0	; Vergleiche mit Steuerbyte
		BTFSS	STATUS, z
		goto	Befehl9?
 
		Call	HoleEE		; liest EEProm und gibt es an Remote
							; aus da Steuer=8 ist !
		goto	fertigT
 
Befehl9? 	; >>> Befehl: Write willingly to EE-Bytes (24x)
		movlw	9
		subwf	Steuer, 0	; Vergleiche mit Steuerbyte
		BTFSS	STATUS, z
		goto	fertigT
 
		Call	SchreibeEE	; Nur für Test: Ins EE-Schreiben
					; (sonst nur automatisch bei Power-Down!)
 
fertigT
		return 
 
; ********************* Schreibe Nullen ein ->EEPROM (->RAM) *************************
Nullsetzen
 
		MOVLW	h'40'			; ...sonst Nullen ins EEPROM
		MOVWF	ESpeicherA		; Lösche von hinten
		; Interlock vorher schon disabled !
 
nullen		; Begin ESpeicherA-Schleife
 
		MOVF	ESpeicherA, 0	; Ziel in W
		ADDLW	H'FF'		; -1: h40 Werte (d64): von 3F..00 
		MOVWF	EEADR		; Ziele auf EE_Adresse Ziel
		MOVLW	h'00'		; Lade Nullwert
		; Test gebe Adresse in Data (obere auskommentieren!)	
		MOVWF	EEDATA		; Übergebe Nullwert an Übergabeadresse
 
		; ************ Einschreiberutine ************
		BSF	STATUS, RP0	; Wahl Bank1
		; Interlock vorher schon disabled !
		BSF	EECON1, WREN	; Enable Write Bit
		MOVLW	h'55'
		MOVWF	EECON2
		MOVLW	h'AA'
		MOVWF	EECON2
		BSF	EECON1, WR
		; BCF	EECON1, WREN	; Disable Write Bit
		; BCF	EECON1, WR	; (soll eigentlich HW machen)
Kontrolle	BTFSS	EECON1, EEIF	; warte auf Flag Schreiberfolg!
		goto	Kontrolle
		BCF	EECON1, EEIF	; Flag f. erfolgreiches EE-Schreiben rücksetzten
 		BCF	STATUS, RP0	; wieder Bank0 wählen
		; >>> Verrify: <<<<
		MOVF	EEDATA, 0	; Hole letzten Schreibwert in W!
		BSF	STATUS, RP0	; Wahl Bank1
		BSF	EECON1, RD	; Lese eingeschriebenes Byte
		BCF	STATUS, RP0	; wieder Bank0 wählen
		SUBWF	EEDATA, 0	;
		BTFSS	STATUS, z	; Wenn Soll und ist gleich weiter ...
		INCF	Fehler, 1	; sonst Schreibfehler erhöhen!	
		DECFSZ 	ESpeicherA, 1	; zeige auf nächstes Byte
		goto 	nullen
 
		; ************ Ende Einschreiberutine ***********
		BSF	STATUS, RP0	; Wahl Bank1
		BCF	EECON1, WREN	; Disable Write Bit
 		BCF	STATUS, RP0	; wieder Bank0 wählen
		; Interlocks später aktiviert!		
		RETURN			; Fertig mit Nullsetzen!
 
 ;********************* Lese EEPROM und kopiere in das RAM ***************************
 
HoleEE		; EEPROM auslesen und in den Arbeitsspeicher
 
		;BSF	PORTB, 7	; Zu Testzwecken mache High wärend EE-lesen
		; Ini. S1
		MOVLW	h'2'		; 2->1->0: Durchlaufzahl + 1
		MOVWF	Schleife1	; = Zeilenindex + 1 (sonst 0 nicht mehr ausgeführt!)
 
S1		; Start Schleife1	
		; Ini für S2		
		MOVLW	h'0C'		; ->0B->....->1 (12x)
		MOVWF	Schleife2	; = Spaltenindex + 1 
					; (sonst 0 nicht mehr ausgeführt!)
 
S2		
		;  *** Bestimme Ursprung (ESpeicherA) und Zieladresse (RAM) ***
		DECF	Schleife1, 0	; Schleife1 -1 = Zeilenwert
		MOVWF	ESpeicherA		; Lade korr. Zeilenwert in W
		SWAPF	ESpeicherA, 1	; Übernehme Wert in höheres Nibble: Zeilenindex
		MOVLW	h'1'
		SUBWF	Schleife2, 0	; Schleifenwert2 - 1 = Spaltenwert => W (Bytestelle)
		ADDWF	ESpeicherA, 1	; Addiere Bytestelle zur Zeile
		MOVLW	h'10'			; erhöhe Zielbereich RAM 
		ADDWF	ESpeicherA, 0	; um eine Zeile gegeüber EEPROM
		MOVWF	RAM				; RAM = ESpeicherA + h'10'
 
		; ***********  Begin Leserutine EEPROM->RAM (Zählerstand, SN, Fehler) 
		MOVF	RAM, 0
		MOVWF	FSR
		BCF		STATUS, RP0			
		MOVF	ESpeicherA, 0
		MOVWF	EEADR
		BSF	STATUS, RP0	; wähle Bank 1
		BSF	EECON1, RD	; Lese EEprom aus (zurück per HW)
		BCF	STATUS, RP0	; zurück Bank 0
		MOVF	EEDATA, 0	; übernehme EE-Datum
		MOVWF	INDF		; schreibe EEprom-Datum in
					; RAM-Adresse durch FSR gepointed.
		; *********** Ende Leserutine
 
 
 
	    ; Versende an Remote-Master (LANTRONIX)
		MOVLW	h'8'		; 
		XORWF	Steuer, 0	;
		BTFSS	STATUS, z	; wenn Ausgabeorder...
		goto	go_on		; ... sonst weiter!
 
		MOVF	EEDATA, 0	; ...lade aktuell geholten EE-Wert
		Call	outch_n		; gib Wert auf Sender!
		Call	baud		; gebe länger Zeit f. Synchronisierung
		MOVF	EEDATA, 0	; ...lade aktuell geholten EE-Wert nochmal!	
		BTFSC	D1, 0		; Wenn  in Datum1 = 1, dann auch >> Display!
		Call 	EEtoDisplay	; ggf. EE-Lesekontrolle		
 
 
 
go_on	
		DECFSZ	Schleife2, 1; dekrementiere Spalte
		goto	S2			; weiter in Schleife 2...
 
		DECFSZ	Schleife1, 1; dekrementiere Zeile wenn nicht Null!
		goto	S1 			; Weiter in Schleife1...
 
		;BCF	PORTB, 7		; Zu Testzwecken: rücksetzen!
 
		RETURN  ; Ende HoleEE >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
 
 
 
 
Konsistenz	; ********** Konsistenztest **********************************
 
		MOVF	PORTB, 0	; 
		XORLW	b'10000000'	; wenn 0 mach 1 sonst wenn 1 mach 0
		MOVWF	PORTB		; toggle Testsignal für Konsistenzintervall
 
		MOVLW	h'3'			
		MOVWF	Schleife3	; Untersuchungssache (Zeile 1->0)
		MOVLW	h'C'
		MOVWF	TS		; Untersuchungsstelle
		MOVLW	h'FC'		; entspricht -4
		MOVWF	Sprung
		MOVLW   h'0'
		MOVWF	identisch	; ini. Gleich
		MOVWF	Fehler		; ini. Fehler
 
		; je drei Sicherungsstellen für Zählerwert, Seriennummer und Fehler
		; h0x: 1xxx.2xxx.3xxx (Zähler)   x = Bytestelle
		; h1x: 1xxx.2xxx.3xxx (2SN/2F#)
 
S3		MOVLW	h'05'			; Ini Schleife 4
		MOVWF	Schleife4		; Untersuchungsstelle Byte 1-4 (<- B,A,9,8)
		DECFSZ	Schleife3, 1	; Zeilenschleife
		goto	S4
		goto	hinterS3
 
S4		MOVLW	h'06'
		ADDWF	Schleife4, 0	; Teststelle aus Schleife4: 4,3,2,1 -> B,A,9,8
		MOVWF	TS
		MOVLW	h'3'		; IniSchleife 5 & 6
		MOVWF	Schleife5	; Index Teststelle, innerhalb einer Zeile
		MOVLW	h'3'
		MOVWF	Schleife6	; Index Vergleichstelle (erst zwei stufen, dann nur eine)			
		DECFSZ	Schleife4, 1	; Byteschleife
		goto	S5				
		goto	hinterS4				
 
S5		DECFSZ	Schleife5, 1	; reduziere solange Schleife1 2>1>0 nicht schon Null
		goto	S6
		goto	hinterS5
 
S6		DECFSZ	Schleife6, 1
		goto	EEPROMRAM
		goto	hinterS6
 
EEPROMRAM	
		MOVF	Schleife3, 0	; 
		MOVWF	RAM1		; Lade Zeile in RAM1
		SWAPF	RAM1, 1		; Übernehme Wert in höheres Nibble: Zeilenindex
		MOVF	TS, 0		; Lade Teststelle in W (Bytestelle)
		ADDWF	RAM1, 0		; Addiere Bytestelle zur Zeile
		MOVWF	RAM1
		MOVWF	RAM2	
		MOVF	Sprung, 0			
		ADDWF	RAM2, 0		; reduziere auf Redundanzstelle vier darunter: RAM2 = RAM1 - 4
		MOVWF	RAM2
 
		MOVWF	FSR
		MOVF	INDF, 0		; Erfasse Wert an RAM1
		MOVWF	Vergleich	; Lade Wert in "Vergleich"
		MOVF	RAM1, 0
		MOVWF	FSR
		MOVF	INDF, 0		; Erfasse Wert an RAM2
		MOVWF	Vorgabe		; Lade Wert an Stelle Vorgabe
 
		XORWF	Vergleich, 0	; Checke ob "Vergleich" und "Vorgabe" (in W) 
		BTFSS	STATUS, z		; identisch sind.
		goto	ungleich
gleich			
		INCF	identisch, 1
		MOVF	Vorgabe, 0
		MOVWF	korrekt		; Setze Korrekt = Vorgabewert
		goto	naechste
ungleich	BSF	Fehlkont, 7	; Setze Fehlerflag für Stelle!
		INCF	Fehler, 1	; erhöhe Fehlerzähler
		MOVF	identisch, 1	; wenn identisch gleich Null,
		BTFSS	STATUS, z	; also drei Vergleichswerte verschieden ...
		goto	naechste
		MOVF 	Vorgabe, 0		
		MOVWF	korrekt		; ... nehme letzten Vorgabewert!
 
 
naechste
		MOVLW	h'FC'		; entspricht -4
		ADDWF	Sprung, 1	; Subtrahiere Sprung -4 -> -8
		Call	Pulsweitenmodulation	
		goto	S6		; Ende Schleife6
 
hinterS6
		MOVLW	h'2'
		MOVWF	Schleife6
		MOVLW	h'FC'		; entspricht -4
		MOVWF	Sprung
		ADDWF	TS, 1		; Reduziere Teststelle um vier Positionen
		goto	S5		; Ende Schleife5
 
hinterS5
		MOVLW	h'3'		; Index Vergleichstelle (erst zwei Stufen,
		MOVWF	Schleife6	; dann nur eine!)
		BTFSS	Fehlkont, 7	; Fehlerkorrektur wenn es Fehler gab.
		goto	S4		; Ende Schleife4
 
		; Drei RAMwerte korrigieren:			
		BCF	Fehlkont, 7	; Setze Fehlerflag zurück
		MOVLW	h'4'
		MOVWF	Fehlkont
Skorrekt	DECFSZ	Fehlkont, 1
		goto	KorrW
		goto	S4
KorrW		MOVF	RAM2, 0
		MOVWF	FSR
		MOVF	korrekt, 0	; Lade Korrekturwert...
		MOVWF	INDF		; ...in erste Korrekturstelle
		MOVLW	h'4'
		ADDWF	RAM2, 1
		goto	Skorrekt
 
hinterS4	goto	S3		; Ende Schleife3
 
hinterS3	RETURN
 
 
 
inch_n1		; Aufsynchronisation erfolgt!
		call	baud		; nach 1/2 Baut übergehe Startbit -> 1 1/2 Baud
		bcf	STATUS, c	; Lösche Übertragsbit
		rrf	SERBUF, 1	; Rotiere MSB nach rechts!
		btfsc	PORTB, 5	; Datum eine 0?
		bsf	SERBUF, 7	; wenn ja übergehe, sonst setze MSB = 1!
		bsf	PORTB, 6	; Tastpunktausgabe (nur Simulationszwecke)
		bcf	PORTB, 6
		decfsz	Schleife6, 1	; Acht Bits abgearbeitet?
		goto 	inch_n1		; nein: hole noch ein Bit
		call 	baud		; zeige auf  Stopbit (1)
		call	baud		; zeige auf Startbit (0)
		movf	SERBUF, 0	; Lege Zeichen ins Arbeitsregister
		return
 
outch_n		; 
		movwf	SERBUF		; Schreib in W übergebenes Byte in SERBUF
		movlw	8
		movwf	Schleife6	
		bcf	PORTB, 2	; erzeuge  Start-Bit (L) 
		call 	baud		; Schiebe auf erstes Byte	
outch_n1
		rrf 	SERBUF, 1	; rotiere erstes Bit ins Carrybit
		BTFSS	STATUS, c	; Teste Carrybit
		bcf	PORTB, 2	; wenn 0 gebe auch 0 aus!
		btfsc	STATUS, c 	; Teste nochmal Carrybit
		bsf	PORTB, 2	; wenn 1 gebe auch 1 aus!
		bsf	PORTB, 6	; nur zu Simulationszwecken
		bcf	PORTB, 6
		call 	baud		; verögere eine Baudperiode
		decfsz	Schleife6, 1	; wenn alle Bits durch, sende noch Stopbit...
		goto 	outch_n1	; sonst nächstes Zeichen
 
		rrf	SERBUF, 1	; MSB aus Carry zurück ins bit7!
		bsf	PORTB, 2	; Setze Stopbit (1)
		call 	baud		; lasse dies eine Baudperiode stehen
 
		retlw	0
 
 
; **********************************************************
; BAUD Routine @4 Mhz
; Baut Rate:		Konstante:
;    1200 Baud		
;    2400 Baud		
;    4800 Baud		
;    9600 Baud		104,15 µS
;   19200 Baud		
; variables used: 	Reg 'Schleife2'
; ***********************************************************
baud		; Intervall Baudrate	Vorlauf 10µS
		movlw 	D'30'		; Ein Takt: 1µS
		movwf	Schleife4	; ein Takt: 1µs
baud1
		decfsz	Schleife4, 1	; 1 µs (+1 µs mehr bei Null)
		goto	baud1		; 2 µS
 
		retlw	0		; 2 µS , weiter nach 10+2+3x30+2 µS = 104µS
 
half_Baud	; Intervall halbe Baudrate (3µs Vorlauf)
		movlw	D'11'		; 1µS
		movwf	Schleife4	; 1µS
hbaud1
		decfsz	Schleife4, 1	; 1 µs (+1 µs mehr bei Null)
		goto 	hbaud1		; 2 µS
		nop			; 1 µS
		retlw	0	 	; nach weiteren	3+2+3x14+2+2 µS = 52 µS
 
ByteZeit	; Definiert Zeit eines Byterahmens (10Bit) f. Umschalten Empfangen/Senden
		movlw	D'10'		; 1µS
		movwf	Schleife5
ByteZeitS	
		Call 	baud
		decfsz	Schleife5, 1
		goto	ByteZeitS	
		retlw	0	 		 		
 
Datenaus	
		movlw	h'3F'
		movwf	Telnr	
		movlw	h'7'		; Steuerbyte als Erstes: 40,41,...,47,48 EOF, 49 EOF
		movwf	Schleife1	; 7-7x->0
SSSS1
		incf	Telnr, 0
		movwf	Telnr
		movwf	FSR
		movf	INDF, 0		; Hole Telegrammstellen ins W zur Übergabe!
 
		Call	outch_n		; sende einen Rahmen 104 µS mit LSB voraus 
					; (Start-Bit, 8x Daten-Bit, Stop-Bit)
 
 
		DECFSZ	Schleife1, 1	; erfasse sieben Zeichen
		goto	SSSS1	
 
		Return			; verlasse "traffic"
 
STREAM				;  8 stellige Anzeige seriell streamen (Clearschleife ???)
				;  Reihenfolge der Abarbeitung der vier Zählstellen bestimmt
				;  Ausgabe auf die acht Stellen: LSB zuerst ->
 
Traillingzero			; Führende Nullen nicht anzeigen...
 
	MOVlW	B'11111111'	; Stellen mit 1 werden später angezeigt, 0 nicht!
	MOVWF	Vorgabe 	; temporär Speicher für vorangende Nullen
	MOVLW	d'8'		; ini. Bitzaehler beim Streamen
	MOVWF	Bitindex
	BCF	STATUS, c	; Leere Carrybit
 
	MOVF	B3, 0		; MS-Nibble noch Null? 
	ADDLW	H'F0'		; h'F0'+ B3 > h'FF'? => Carry = 1
	BTFSC	STATUS, c	; ja: carry = (Nibble genutzt)=shiftend / nein= weiter
	GOTO	shiftend	; Nibble belegt = nicht Null: ab hier anzeigen!
	RLF	Vorgabe, 1	; 
	DECF	Bitindex, 1
	MOVF	B3, 1
	BTFSS	STATUS, z	; LS-Nibble auch noch Null
	GOTO	shiftend	; Nibble belegt = nicht Null: ab hier anzeigen!
	BCF	STATUS, c	; Leere Carrybit
	RLF	Vorgabe, 1	; Schiebe c-Ergebniss (Stelle genutzt) in LSBit
	DECF	Bitindex, 1
 
	MOVF	B2, 0		; MS-Nibble noch Null?
	ADDLW	H'F0'		; h'F0'+ B3 > h'FF'? => Carry = 1	
	BTFSC	STATUS, c	; ja= (Nibble genutzt)=shiftend / nein= weiter
	GOTO	shiftend	; Nibble belegt = nicht Null: ab hier anzeigen!
	RLF	Vorgabe, 1	; Schiebe c-Ergebniss (Stelle genutzt) in LSBit
	DECF	Bitindex, 1
	MOVF	B2, 1
	BTFSS	STATUS, z	; LS-Nibble auch noch Null
	GOTO	shiftend	; Nibble belegt = nicht Null: ab hier anzeigen!
	BCF	STATUS, c	; Leere Carrybit
	RLF	Vorgabe, 1	; Schiebe c-Ergebniss (Stelle genutzt) in LSBit
	DECF	Bitindex, 1
 
	MOVF	B1, 0		; MS-Nibble noch Null?
	ADDLW	H'F0'		; h'F0'+ B3 > h'FF'? => Carry = 1
	BTFSC	STATUS, c	; ja= (Nibble genutzt)=shiftend / nein= weiter
	GOTO	shiftend	; Nibble belegt = nicht Null: ab hier anzeigen!
	RLF	Vorgabe, 1	; Schiebe c-Ergebniss (Stelle genutzt) in LSBit
	DECF	Bitindex, 1
	MOVF	B1, 1
	BTFSS	STATUS, z	; LS-Nibble auch noch Null
	GOTO	shiftend	; Nibble belegt = nicht Null: ab hier anzeigen!
	BCF	STATUS, c	; Leere Carrybit
	RLF	Vorgabe, 1	; Schiebe c-Ergebniss (Stelle genutzt) in LSBit
	DECF	Bitindex, 1
 
	MOVF	B0, 0		; MS-Nibble noch Null?
	ADDLW	H'F0'		; h'F0'+ B3 > h'FF'? => Carry = 1
	BTFSC	STATUS, c	; ja= (Nibble genutzt)=shiftend / nein= weiter
	GOTO	shiftend	; Nibble belegt = nicht Null: ab hier anzeigen!
	RLF	Vorgabe, 1	; Schiebe c-Ergebniss (Stelle genutzt) in LSBit
	DECF	Bitindex, 1
	MOVF	B0, 1
	; letzte Stelle bleibt angezeigt!
	RLF	Vorgabe, 1	; Schiebe c-Ergebniss (Stelle genutzt) in LSBit
	DECF	Bitindex, 1
	goto	komplett
 
shiftend
	RLF	Vorgabe, 1	; rotiere in Ausgangsposition (vorher höchstwertige = akut
	DECFSZ	Bitindex, 1	; reduziere Bitnummer
	goto	shiftend
 
 
komplett
	;RLF	Vorgabe,1	; letztes Rotieren stellt "Vorgabe" wieder richtig
 
 
 
StartStream
NB_un				; ***** Streame Anzeigewert für unteres Nibble (8Bit) ***
	MOVLW	B'00001111'	; Maske oberes Nibble, greife unteres	
	ANDWF	INDF, 0		; Maskiere 2. Nibble
	MOVWF	Anzeige		; Halte Unteres Nibble
	MOVWF	Testwert	; aktueller Testwert
	CALL	Kodierung	; Kodierung auf Byte zur Anzeige
	MOVLW	d'8'		; ini. Bitzaehler beim Streamen
	MOVWF	Bitindex
Los_un
	RLF	Anzeigewert, 1	; rotiere links
	BTFSC	STATUS, c
	GOTO	Ge2
Ng2	BCF	PORTA, serLED	; setze SerialBit 0
	GOTO	w2
Ge2	BSF	PORTA, serLED	; setze SerialBit 1
w2	BSF	PORTA, ClockLED	; setze Clock
 	BCF	PORTA, ClockLED	; nulle Clock
	DECFSZ	Bitindex, 1	; reduziere Bitnummer
	goto	Los_un
 
 
NB_ob				; ***** Streame Anzeigewert für obere Nibble (8Bit) ****
	MOVLW	H'F0'		; Maskiere unteres Nibble, greife oberes	
	ANDWF	INDF, 0		; Nehme oberes Nibble
	MOVWF	Anzeige		; Halte Obereres Nibble
	MOVWF	Testwert	; aktueller Testwert
	SWAPF	Testwert, 1	; reduziere Wert höheres Nibble auf einfaches Nibble
	CALL	Kodierung	; Kodierung auf Byte zur Anzeige
	MOVLW	d'8'		; ini. Bitzaehler beim Streamen
	MOVWF	Bitindex
Los_ob
	RLF		Anzeigewert, 1	; rotiere links
	BTFSC	STATUS, c
	GOTO	Ge1
Ng1	BCF	PORTA, serLED	; lösche SerialBit 0
	GOTO	w1	
Ge1	BSF	PORTA, serLED	; setze SerialBit 1
w1	BSF	PORTA, ClockLED	; setze Clock	
 	BCF	PORTA, ClockLED	; nulle Clock
	DECFSZ	Bitindex, 1	; reduziere Bitnummer
	goto	Los_ob
 
;	nächstes Byte (2 Stellen)
	DECF	FSR, 1		; erhöhe Pointer auf Stelle
	INCF	ByteNr, 1
 
	MOVLW	D'4'
	SUBWF	ByteNr, 0
	BTFSS	STATUS, z	;
	goto	StartStream
	BSF	PORTA, Strobe	; Überneme nach vier Byte (8 Stellen)
 	BCF	PORTA, Strobe	; nulle Strobe
	MOVLW	0
	MOVWF	ByteNr
	Return
 
 
 
 
 
EinByte
	INCF	INDF, 1		; Inc. Zähler
	MOVLW	B'00001111'	; Maske oberes Nibble	
	ANDWF	INDF, 0		; Maskiere 2. Nibble
	ADDLW	D'246'		; Führe Überlauf herbei wenn Bx =9
	BTFSS	STATUS, c	; Überlauf erreicht?
	RETURN			; wenn kein Überlauf erhöhe um 1...
	MOVLW	B'11110000'	; Maske unteres Nibble
	ANDWF	INDF, 1		; setze unteres Nibble 0 (nulle halb)
	MOVLW	B'00010000'
	ADDWF	INDF, 1		; Übertrag zu 2.tem Nibble, 2.Stelle um 1 erhöht...
 
NIBBLE2				; nach 99 (1001.1001) kommt 160 (1010.0000)
	MOVF	INDF, 0		; Hole aktualisierten Zählerstand ins W
	ADDLW	d'96'		; Führe Überlauf herbei wenn 100 (100 -> 160 A0)
	BTFSS	STATUS, c	; 99 voll?
	RETURN			; wenn NOR voll zurück...
	MOVLW	0
	MOVWF	INDF		; Lösche ganz: Ein Byte, zwei Stellen
	DECF 	FSR,1		; erhöhe Pointer auf Hunderterstelle
	INCF	ByteNr, 1	; Erhöhe Bytezähler (Werttigkeit)
	Call	EinByte
	INCF	FSR, 1		; zurück Stelle tiefer...
	DECF	ByteNr, 1	; Reduziere Bytezähler (Werttigkeit)
	RETURN
	goto 	Zyklus
 
 
Kodierung	; (->Anzeigewert) Kodierung zur Siebensegmentanzeige
Eins		; 0->15 Anzeige-> Testwert -> Anzeigewert
	DECFSZ	Testwert, 1	; Reduziere Anzeige und übergehe wenn Null
	goto 	Zwei
	MOVLW	d'6'		; Eins-Anzeige h'06'
	goto	Uebernahme
 
Zwei		; 2->1
	DECFSZ	Testwert, 1	; Reduziere Anzeige und übergehe wenn Null
	goto 	Drei
	MOVLW	d'91'		; Zwei-Anzeige h'5B'
	goto	Uebernahme
 
Drei        ; 3->2
	DECFSZ	Testwert, 1	; Reduziere Anzeige und übergehe wenn Null
	goto 	Vier
	MOVLW	d'79'		; Drei-Anzeige h'4F'
	goto	Uebernahme
 
Vier		; 4->3
	DECFSZ	Testwert, 1	; Reduziere Anzeige und übergehe wenn Null
	goto 	Fuenf
	MOVLW	d'102'		; Vier-Anzeige h'66'
	goto	Uebernahme
 
Fuenf		; 5->4
	DECFSZ	Testwert, 1	; Reduziere Anzeige und übergehe wenn Null
	goto 	Sechs
	MOVLW	d'109'		; Fuenf-Anzeige h'6D'
	goto	Uebernahme
 
Sechs		; 6->5
	DECFSZ	Testwert, 1	; Reduziere Anzeige und übergehe wenn Null
	goto 	Sieben
	MOVLW	d'125'		; Sechs-Anzeige h'7D'
	goto	Uebernahme
 
Sieben		; 7->6
	DECFSZ	Testwert, 1	; Reduziere Anzeige und übergehe wenn Null
	goto 	Acht
	MOVLW	d'7'		; Sieben-Anzeige h'07'
	goto	Uebernahme
 
Acht		; 8->7
	DECFSZ	Testwert, 1	; Reduziere Anzeige und übergehe wenn Null
	goto 	Neun
	MOVLW	d'127'		; Acht-Anzeige h'7F'
	goto	Uebernahme
 
Neun		; 9->8
	DECFSZ	Testwert, 1	; Reduziere Anzeige und übergehe wenn Null
	goto 	Dasa
	MOVLW	d'111'		; Neun-Anzeige h'6F'
	goto	Uebernahme
 
Dasa		; 10(A)->9
	DECFSZ	Testwert, 1	; Reduziere Anzeige und übergehe wenn Null
	goto 	Dast
	MOVLW	d'220'		; "a"-Anzeige h'DC'
	goto	Uebernahme
 
Dast		; 11(B)->10
	DECFSZ	Testwert, 1	; Reduziere Anzeige und übergehe wenn Null
	goto 	Dasr
	MOVLW	d'120'		; "t"-Anzeige h'78'
	goto	Uebernahme
 
Dasr		; 12(C)->11
	DECFSZ	Testwert, 1	; Reduziere Anzeige und übergehe wenn Null
	goto 	Leer
	MOVLW	d'80'		; "r"-Anzeige h'50'
	goto	Uebernahme
 
Leer		; 13(D)->12
	DECFSZ	Testwert, 1	; Reduziere Anzeige und übergehe wenn Null
	goto 	Ausruf
	MOVLW	d'0'		; " "-Anzeige h'00'
	goto	Uebernahme
 
Ausruf		;14(E)->13
	DECFSZ	Testwert, 1	; Reduziere Anzeige und übergehe wenn Null
	goto 	Dasn
	MOVLW	d'134'		; "!"-Anzeige h'86'
	goto	Uebernahme
 
Dasn		;15(F)->14
	DECFSZ	Testwert, 1	; Reduziere Anzeige und übergehe wenn Null
	goto 	Null
	MOVLW	d'84'		; Null-Anzeige h'54'
	goto	Uebernahme
 
Null		; (0)->15
	MOVLW	d'0'		
	BTFSC	Vorgabe, 0	; "0" nicht anzeigen wenn führende Null (LS-Bit = akut)
	MOVLW	d'63'		; Null-Anzeige h'3F'
	goto	Uebernahme
 
Uebernahme
	RRF	Vorgabe	, 1	; Schieben auf nächste Stelle
	MOVWF	Anzeigewert	; Wert für Anzeigeelement
	Return
				;           aus            |->       an
Pulsweitenmodulation		; PWMm >>>>>>>>>>>> PWMa >>>> PWMs >>>> 0	
 
	DECFSZ	PWMa, 1		; Dekrementiere aktuellen PMW-Laeufer
	goto	w3
	MOVLW	PWMm		; PWM-Maximalwert
	MOVWF	PWMa		; Setzte zurück auf Zyklusvollwert.
 
w3	MOVF	PWMs, 0		; komplementiere Schwellwert in W
	SUBWF	PWMa, 0		; addiere neg. Schwellwert vom aktuellen Wert
	BTFSS	STATUS, c	; wenn noch über Schwellwert (C=1) ...
	BSF	PORTA,	OutEnabl	; ... setze Anzeige an!
	BTFSC	STATUS, c		; wenn überm Schwellwert... 
	BCF	PORTA,	OutEnabl	; ... setzte Anzeige aus!
	Return
 
Zaehlnull			; nur für lange Delayrutine 
	MOVLW	D'0'		; ini. Stellenzähler
	MOVWF	B0
	MOVWF	B1
	MOVWF	B2
	MOVWF	B3
	Return	
 
IniByte
	MOVLW	H'13'		; erstes Byte
	MOVWF	FSR		; Lade Pointer auf erstes Byte
	MOVLW	D'0'		; ini. Stellenzähler
	MOVWF	ByteNr		; Lade Schleifenzähler mit 0
	Return
 
IniStream
	MOVLW	H'13'		; Initialisiere Streamen
  	MOVWF	FSR			; Zeige auf höchste Stelle
	MOVLW	D'0'
	MOVWF	ByteNr		; Lade Schleifenzähler mit 0
	Return
 
Delay
	Call	IniByte		; Initialisierung für Byte-Rutinennutzung
	Call	Zaehlnull	; Zähler mit Null laden	
Schleife
	CALL	EinByte		; zähle für Delay dekadisch aufwärts (Ca. 5µS/call)
	Call 	Pulsweitenmodulation
	MOVLW	H'10'		; Bei 1 Mio ist Schluss
	SUBWF	B2, 0		; Subtrahiere 1 Mio.
	BTFSS	STATUS, z	; Checke ob am Ende
	goto	Schleife
	Return
 
EEtoDisplay	; W-> Diese Prozedur gibt die vom EEProm eingelesenen
		; Stellen zu Kontrollzwecken auf dem Display in der 
		; Form: 	Ausleseadresse	Auslesewert
		; z.B. Hex:            "S_1B I_1B"	
 
					; W wird übergeben!
		MOVWF	B0		; Ausgabe in Stelle B0 (HEX)
 
		MOVLW	h'1D'		; "I_" in B1
		MOVWF	B1
 
		MOVF	EEADR, 0	; Anzeige akt. Adresse
		MOVWF	B2
 
w6		MOVLW	h'5D'		; "S_"
		MOVWF	B3		; 
 
		Call	IniStream
		Call	STREAM		; Zeige Hubzählerstand
		MOVLW	PWMF		; mach an
		MOVWF	PWMs	
		Call	Delay		; ca. 1,5s Verzögerung.
		MOVLW	1		; mach aus
		MOVWF	PWMs		;
		Return	
 
SCHLUSS		; Durch Einschalten aller LED-Elemente soll nach der Datensicherung
		; die kondensatorspannung möglichst schnell herunter gefahren
		; werden, um Korruption des EE-Speichers zu vermeiden !!!
 
		MOVLW	h'88'	; "88" 	
		MOVWF	B0
		MOVLW	h'88'  ;  "88"
		MOVWF	B1
		MOVLW	h'88'	; "88"
		MOVWF	B2
		MOVLW	h'88'	; Fehler beim EESchreiben zeigen!
		MOVWF	B3
		Call	IniStream
		Call	STREAM		; Zeige "88888888"
		BSF	PORTA, OutEnabl
		goto	$		; Programm bleibt hier stehen !!!
 
		end