	list p=16f876
;*****************************************************
;*  	Pinbelegung
;*	----------------------------------	
;*	PORTA: 	0 < Spannung U vom ELKO
;*		1 -
;*		2 -
;*		3 -
;*		4 -
;*		5 -
;*		6 -
;*		7 -
;*
;*	PORTB:	0 LCD Display E
;*		1 -
;*		2 LCD Display RS
;*		3 LCD Display R/W
;*		4 LCD Display D4
;*		5 LCD Display D5
;*		6 LCD Display D6
;*		7 LCD Display D7
;*	
;*	PORTC:	0 > 250 Ohm zum ELKO (70 + 180)
;*		1 -
;*		2 -
;*		3 -
;*		4 -
;*		5 -
;*		6 -    
;*		7 -
;*	
;*****************************************************
;
;sprut (zero) Bredendiek 01/2004
;
; ELKO-Messgerät mit LCD
; Messung der Kapazität in µF
; Auflösung:      1 µF
; C maximal: 65 000 µF
;
; Prozessor 16F876 
;
; Prozessor-Takt 10 MHz
;
; LCD am PortB
;*****************************************************
; Includedatei für den 16F876 einbinden

	#include <P16f876.INC>

	ERRORLEVEL      -302    	;SUPPRESS BANK SELECTION MESSAGES

; Configuration festlegen:
; Power on Timer, kein Watchdog, HS-Oscillator, kein Brown out, kein LV-programming
	__CONFIG	_PWRTE_ON & _WDT_OFF & _HS_OSC & _BODEN_OFF & _LVP_OFF

;*****************************************************
; Variablen festlegen

;16 Bit Rechenregister
xw0		equ	0x21	; Rechenregister
xw1		equ	0x22	; 
f0		equ	0x23	; Rechenregister
f1		equ	0x24	; 
counter		equ	0x25	; 
Flags		equ	0x26	; 
SZT		equ	0x27	; BCD-Register
ST		equ	0x28	; 
SZ		equ	0x29	; 
SH		equ	0x2A	; 
SE		equ	0x2B	; 
loops		equ	0x2C	; timer für wait
loops2		equ	0x2D	; timer für wait
LcdStatus	equ	0x2E	;
LcdDaten	equ	0x2F	;
C0		equ	0x30	; Kapazitätsregister in µF
C1		equ	0x31
Temp		equ	0x32

Ini_con		Equ	B'00000000'	; TMR0 -> Interupt disable
Ini_opt		Equ	B'00000010'	; pull-up

; für LCD-Pins
#define	LcdE		PORTB,0		; enable Lcd
#define	LcdRw		PORTB,3		; read Lcd
#define	LcdRs		PORTB,2		; Daten Lcd (nicht control)	
#define LcdPort		PORTB		; Datenbus des LCD (obere 4 Bit)
#define achteStelle	B'10001000'	; 
#define achteStelle2	B'11001000'	; 

#define	R250		PORTC, 0	; Pin mit 250-Ohm zum ELKO

#define	Fehler		Flags,0
#define	Leading0	Flags,1
;*****************************************************

	org	0
	goto	Init

Txt00	dt	"Capacimetru",' '+80h
Txt01	dt	"o.k.       ",' '+80h
Txt10	dt	"C scurt    ",' '+80h
Txt11	dt	"Descarca   ",' '+80h


; Das Programm beginnt mit der Initialisierung

Init	bsf     STATUS, RP0	; Bank 1
	movlw   Ini_opt     	; pull-up on
	movwf   OPTION_REG 
	movlw	B'00000000'	; PortB alle outputs 
	movwf	TRISB
	bcf     STATUS, RP0	; Bank 0
	clrf	PORTB
	movlw   Ini_con     	; Interupt disable
	movwf   INTCON   

; ADC initialisieren
	; ADC einschalten
	BSF	ADCON0, 0	; ADON=1
	; ADC-Eingang AN0 auswählen
	BCF	ADCON0, 5	; ADCHS2=0
	BCF	ADCON0, 4	; ADCHS1=0
	BCF	ADCON0, 3	; ADCHS0=0
	; ADC speed für 5 ... 20 MHz einstellen
	; 44,8µs = 22,3 kHz max
	BSF	ADCON0, 7	; ADCS1=1
	BCF	ADCON0, 6	; ADCS0=0
	; Daten rechtsbündig
	BSF	STATUS,RP0	; Bank1
	clrf	ADCON1		; RA0,1,2,3,5 aktiv; Referenz Vdd&Vss
	BSF	ADCON1, 7	; ADFM=1, Daten rechtsbündig
	BCF	STATUS,RP0	; Bank0

;Display initialisieren
	call	InitLcd
        movlw	B'10000000'	; 1. Zeile
	call	OutLcdControl
	
        movlw	'('   ;  simbolul    pe display
        call	OutLcdDaten
	movlw	'c'   ;  simbolul    pe display
        call	OutLcdDaten
	movlw	')'   ;  simbolul    pe display
        call	OutLcdDaten
        movlw	' '   ;
	call	OutLcdDaten 
	movlw	'D'   ;  simbolul    pe display
        call	OutLcdDaten
	movlw	'.'   ;  simbolul    pe display
        call	OutLcdDaten
	movlw	'O'   ;  simbolul    pe display
        call	OutLcdDaten
	movlw	'l'   ;  simbolul    pe display
        call	OutLcdDaten
	movlw	't'   ;  simbolul    pe display
        call	OutLcdDaten
	movlw	'e'   ;  simbolul    pe display
        call	OutLcdDaten
	movlw	'a'   ;
	call	OutLcdDaten 
	movlw	'n'   ;
	call	OutLcdDaten
	movlw	'u'   ;
	call	OutLcdDaten
	movlw	Txt00		; 'txt 00' zum Display
	call	Write
        movlw	D'255'		; 255 ms Pause 
	movwf	loops	        
        call	WAIT		; 
	movlw	D'255'		; 255 ms Pause 
	movwf	loops	        
        call	WAIT		; 
	movlw	D'255'		; 255 ms Pause 
	movwf	loops	        
        call	WAIT		; 
	movlw	D'255'		; 255 ms Pause 
	movwf	loops	        
        call	WAIT		; 
	movlw	D'255'		; 255 ms Pause 
	movwf	loops	        
        call	WAIT		; 
	movlw	D'255'		; 255 ms Pause 
	movwf	loops	        
        call	WAIT		; 
	movlw	D'255'		; 255 ms Pause 
	movwf	loops	        
        call	WAIT		; 
	movlw	D'255'		; 255 ms Pause 
	movwf	loops	        
        call	WAIT		; 
	call	InitLcd
	goto	Mainloop

Mainloop
        

	call	Kapazitaet	; Messung der Kapazität
	movfw	C0
	movwf	f0
	movfw	C1
	movwf	f1
	call	B2D		; Wandlung in dezimal nach SZT,ST,SH,SH,SE
	call	Ausgabe_uF	; Kapazität anzeigen am LCD 1.Zeile vorn

	movlw	Txt01		; 'o.k.' zum Display
	call	Write

	movlw	D'255'		; 255 ms Pause 
	movwf	loops	
	call	WAIT		; 
	movlw	D'255'		; 255 ms Pause 
	movwf	loops	
	call	WAIT		; 
	movlw	D'255'		; 255 ms Pause 
	movwf	loops	
	call	WAIT		; 
	movlw	D'255'		; 255 ms Pause 
	movwf	loops	
	call	WAIT		; 
	goto	Mainloop

;*****************************************************
; Kapazität bestimmen
; Ergebnis nach C1, C0 [µF]
Kapazitaet
	call	Entladen	; ELKO entladen
	movlw	Txt10		; 'Messe C' zum Display	
	call	Write
	clrf	C0		; Kapazitätsregister löschen
	clrf	C1
	; Timer0 auf 0,1733 ms einstellen (5770 Hz); 
	; 10MHz/5770Hz = 1733 = 4 x 2 x 217
	; Vorteiler 2:1
	; 217 Zähltakte 256-217=39
	movlw	B'10000000'
	bsf     STATUS, RP0	; Bank 1
	movwf	OPTION_REG
	bcf     STATUS, RP0	; Bank 0
	; ELKO laden
	bsf	R250
	bsf     STATUS, RP0	; Bank 1
	bcf	TRISC,0		; RC0 output
	bcf     STATUS, RP0	; Bank 0
	bsf	R250
Kap_loop
	movlw	D'39'
	movwf	TMR0
	bcf	INTCON,T0IF

	call	ADC		; AN0 nach f1,f0
	btfsc	f1,1		; > 511 ?
	goto	Kap_Ende	; nein: U>2,5V

	incf	C0,f
	btfsc	STATUS,Z
	incf	C1,f
	btfsc	STATUS,Z
	goto	Kap_ERROR	; C > 65 000 µF  Anzeige 00 000µF

Kap_loop2
	btfss	INTCON,T0IF
	goto	Kap_loop2
	goto	Kap_loop	; 
Kap_Ende
Kap_ERROR
	bsf     STATUS, RP0	; Bank 1
	bsf	TRISC,0		; RC0 input
	bcf     STATUS, RP0	; Bank 0
	return

;*****************************************************
; ELKO entladen auf 40 mV
Entladen
	; ELKO entladen
	movlw	Txt11		; 'Entlade' zum Display
	call	Write
	bcf	R250
	bsf     STATUS, RP0	; Bank 1
	bcf	TRISC,0		; RC0 output
	bcf     STATUS, RP0	; Bank 0
	bcf	R250
Entladen_loop
	call	ADC		; AN0 nach f1,f0
	movfw	f1
	btfss	STATUS,Z	; < 256 ? (< 1,28V)
	goto	Entladen_loop	; nein
	movlw	B'11111000'
	andwf	f0,w
	btfss	STATUS,Z	; < 8 ? (< 0,04V)
	goto	Entladen_loop	; nein

	bsf     STATUS, RP0	; Bank 1
	bsf	TRISC,0		; RC0 input
	bcf     STATUS, RP0	; Bank 0
	return

;*****************************************************
; Spannung mit ADC messen
; Ergebnis nach f1,f0
ADC
	BSF	ADCON0, 2	; ADC starten
ADCloop
	BTFSC	ADCON0, 2	; ist der ADC fertig?
	GOTO	ADCloop		; nein, weiter warten
	movfw	ADRESH		; obere  2 Bit auslesen
	movwf	f1		; obere  2-Bit nach U1H
	bsf	STATUS,RP0	; Bank1
	movfw	ADRESL		; untere 8 Bit auslesen
	bcf	STATUS,RP0	; Bank0
	movwf	f0		; untere 8-Bit nach U1L
	return

;*****************************************************
;16 bit Adition, C-Flag bei Überlauf gesetzt
Add16                           ; 16-bit add: f := f + xw
         movf    xw0,W           ; xw0 nach W
         addwf   f0,F            ; f0 := f0 + xw0

         movf    xw1,W           ; xw1 nach W
         btfsc   STATUS,C        ; fall ein Überlauf auftrat:
         incfsz  xw1,W           ;   xw1+1 nach W
         addwf   f1,F            ; f1 := f1 + xw1

         return                  ; fertig

;*****************************************************
; 16 Bit Subtraktion, bei Überlauf (neg. Ergebnis) ist C gesetzt
Sub16				; 16 bit f:=f-xw 
	bcf	Fehler		; extraflags löschen 

	movf	xw0, w		; f0:=f0-xw0
	subwf	f0, f

	btfsc	STATUS,C
	goto 	Sub16a
	movlw	0x01		; borgen von f1
	subwf	f1, f

	btfss 	STATUS,C
	bsf	Fehler		; Unterlauf

Sub16a
	movf	xw1,w		; f1:=f1-xw1
	subwf	f1    ,f

	btfss	STATUS,C
	bsf	Fehler 		; Unterlauf

	bcf	STATUS, C 	; C-Flag invertieren
	btfsc	Fehler
	bsf	STATUS, C
	return

;*****************************************************
; Wandlung einer Binärzahl (< 100 000) in eine 5-stellige Dezimalzahl
; Die Binärzahl steht in f1,f0
; die Dezimalstellen werden in SZT (zehntausender), ST (tausender), SH (hunderter),
;    SZ (zehner) und SE (einer) gespeichert.
B2D
	; Test auf zehntausender 10 000d = 0x2710
	movlw	0x27
	movwf	xw1
	movlw	0x10
	movwf	xw0
	call	B2Da
	movwf	SZT
	; Test auf tausender 1000d = 0x03E8
	movlw	0x03
	movwf	xw1
	movlw	0xE8
	movwf	xw0
	call	B2Da
	movwf	ST
	; Test auf hunderter 100d = 0x0064
	clrf	xw1
	movlw	0x64
	movwf	xw0
	call	B2Da
	movwf	SH
	; Test auf zehner 10d = 0x000A
	clrf	xw1
	movlw	0x0A
	movwf	xw0
	call	B2Da
	movwf	SZ
	movfw	f0
	movwf	SE
	return

B2Da
	clrf	counter
B2Sb	incf	counter, f	; wie oft abgezogen?
	call	Sub16		; f:=f-xw	
	btfss	STATUS, C	; zu oft abgezogen?
	goto	B2Sb		; nein: noch einmal
	call	Add16		; f:=f+xw
	decf	counter, w
	return

;*****************************************************
;Anzeige der Dezimalzahl am LCD in der Form '12 345µF'
;Unterdrückung führender Nullen
Ausgabe_uF
	movlw	B'10000000'	; 1. Zeile
	call	OutLcdControl
	
        movlw	'C'   ;  litera  C pe display
        call	OutLcdDaten
        movlw	' '   ;
	call	OutLcdDaten 
	movlw	'='   ;  simbolul = pe display
	call	OutLcdDaten
	bsf	Leading0
	movfw	SZT
	call	AusLed
	movfw	ST
	call	AusLed

	movlw	' '		; Lücke
	call	OutLcdDaten

	movfw	SH
	call	AusLed
	movfw	SZ
	call	AusLed
	bcf	Leading0
	movfw	SE
	call	AusLed

	movlw	B'11100100'	; µ
	call	OutLcdDaten
	movlw	'F'
	call	OutLcdDaten
	return

AusLed
	btfss	STATUS,Z
	bcf	Leading0
	iorlw	'0'		;wandeln in ASCCI
	btfsc	Leading0
	movlw	' '		;führende 0
	call	OutLcdDaten
	return
	
;*****************************************************
;* Write
;* Ausgabe eines Strings der ab W im Speicher steht
;* Note: Endekennzeichen ist Zeichen mit Bit 7 = 1
;* Input : W zeigt auf String	 (RETLWs)
Write 
	movwf	Temp		; Temp = Pointer
	movlw	achteStelle2	; 2. Zeile 8. stelle
	call	OutLcdControl	
	decf	Temp,f
GoWrite	
	call	PclSub2		; Pointer erhöhen und nächstes Zeichen lesen
	addlw	80h		; ist Bit 7 gesetzt? EOT
	btfsc	STATUS,C
	goto	OutLcdDaten	; letztes Zeichen
	andlw	7fh		; zeichen wieder herstellen
	call	OutLcdDaten	; Ausgabe
	goto	GoWrite	

PclSub2
	incf	Temp, F		; Pointer auf nächstes Zeichen
	movf	Temp, W		; Pointer nach W
	movwf	PCL		; Sprung zur Addresse auf die PCLATH,W zeigt

;*****************************************************
;+++LCD-Routinen**************************************
;*****************************************************
;LCD initialisieren, Begrüßung ausgeben

InitLcd
	movlw	D'255'		; 250 ms Pause nach dem Einschalten
	movwf	loops	
	call	WAIT		

	movlw	B'00110000'	; 1
	movwf	LcdPort
	bsf	LcdE
	nop	
	bcf	LcdE
	
	movlw	D'50'		; 50 ms Pause
	movwf	loops
	call	WAIT
	
	movlw	B'00110000'	; 2
	call	Control8Bit
	movlw	B'00110000'	; 3
	call 	Control8Bit
	movlw	B'00100000'	; 4
	call 	Control8Bit

	movlw	B'00000001'	; löschen und cusor home
	call	OutLcdControl	
	movlw	B'00101000'	; 5 function set, 4-bit  2-zeilig,  5x7
	call	OutLcdControl	
	movlw	B'00001000'	; 6 display off
	call	OutLcdControl
	movlw	B'00000110'	; 7 entry mode, increment, disable display-shift
	call	OutLcdControl
	movlw	B'00000011'	; 8 cursor home, cursor home
	call	OutLcdControl
	movlw	B'00001100'	; 9 display on, Kursor aus , Blinken aus
	call	OutLcdControl
	return

;*****************************************************
; ein Steuerbyte 8-bittig übertragen
Control8Bit
	movwf	LcdPort
	bsf	LcdE
	nop
	bcf	LcdE
	movlw	D'10'
	movwf	loops
	call 	WAIT
	return

;*****************************************************
; darauf warten, daß das Display bereit zur Datenannahme ist
LcdBusy
        bsf     STATUS, RP0	; make Port B4..7 input
	movlw	B'11110000'
	iorwf   TRISB, f 
        bcf     STATUS, RP0
BusyLoop		
	bcf	LcdRs
	bsf	LcdRw		; Lesen
	bsf	LcdE
	nop
	movf	LcdPort, w
	movwf	LcdStatus
	bcf	LcdE
	nop
	bsf	LcdE		; Enable
	nop
	bcf	LcdE
	btfsc	LcdStatus, 7	; teste bit 7
	goto	BusyLoop
	bcf	LcdRw
        bsf     STATUS, RP0	; make Port B4..7 output
	movlw	B'00001111'
	andwf   TRISB, f    
        bcf     STATUS, RP0
	return	

;*****************************************************
; aus W ein Byte mit Steuerdaten zum Display übertragen
OutLcdControl
	movwf	LcdDaten
	call	LcdBusy
	movf	LcdDaten, w
	andlw	H'F0'
	movwf	LcdPort		; Hi-teil Daten schreiben
	bsf	LcdE
	nop
	bcf	LcdE		; Disable LcdBus
	swapf	LcdDaten, w
	andlw	H'F0'
	movwf	LcdPort		; Lo-teil Daten schreiben
	bsf	LcdE
	nop
	bcf	LcdE		; Disable LcdBus
	return

;*****************************************************
; aus W ein Datenbyte zum Display übertragen
OutLcdDaten
	movwf	LcdDaten
	call	LcdBusy
	movf	LcdDaten, w
	andlw	H'F0'
	movwf	LcdPort		; Hi-teil Daten schreiben
	bsf	LcdRs		; Daten
	bsf	LcdE		; Enable LcdBus
	nop
	bcf	LcdE		; Disable LcdBus	
	swapf	LcdDaten, w
	andlw	H'F0'
	movwf	LcdPort		; Lo-teil Daten schreiben
	bsf	LcdRs		; Daten
	bsf	LcdE
	nop
	bcf	LcdE		; Disable LcdBus	
	bcf	LcdRs		;
	return

;*****************************************************
;Zeitverzögerung um loops * 1 ms
; 10 MHz externer Takt bedeutet 2,5 MHz interner Takt
; also dauert 1 ms genau 2500 Befehle
; 250 Schleifen a 10 Befehle sind 2500 Befehle = 1 ms

WAIT
top     movlw   .250           ; timing adjustment variable (1ms)
        movwf   loops2
top2    nop                    ; sit and wait
        nop
        nop
        nop
	nop
        nop
        nop
        decfsz  loops2, F      ; inner loops complete?
        goto    top2           ; no, go again
                               ;
        decfsz  loops, F       ; outer loops complete?
        goto    top            ; no, go again
        retlw   0              ; yes, return from subWAIT

;*****************************************************

	end













