list p=16f883 ;***************************************************** ;* Pinbelegung ;* ---------------------------------- ;* PORTA: 0 < Spannung U vom ELKO ;* 1 < vom Messgleichrichter 1 mVAC = 80 mVDC ;* 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 > 1: entladen des Elko via 25 Ohm ;* 2 > 0: laden des ELKO via 25 Ohm ;* 3 - ;* 4 < Switch_Cal ;* 5 < Switch_Z ;* 6 - ;* 7 - ;* ;***************************************************** ; ; sprut (zero) Bredendiek 01/2004..09/2011 ; www.sprut.de ; ; ELKO-Messgerät mit LCD ; ; Prozessor 16F883 ; ; Prozessor-Takt 8 MHz intern ; ; LCD am PortB ;***************************************************** ; Includedatei für den 16F883 einbinden #include ERRORLEVEL -302 ;SUPPRESS BANK SELECTION MESSAGES ; Configuration festlegen: ; 8 MHz intern, CLKOUT function on RA6 __CONFIG _CONFIG1, _PWRTE_ON & _WDT_OFF & _INTOSC & _MCLRE_ON & _CP_OFF & _CPD_OFF & _BOR_OFF & _LVP_OFF & _FCMEN_OFF & _IESO_OFF ; 8 MHz intern, no CLKOUT ;__CONFIG _CONFIG1, _PWRTE_ON & _WDT_OFF & _INTOSCIO & _MCLRE_ON & _CP_OFF & _CPD_OFF & _BOR_OFF & _LVP_OFF & _FCMEN_OFF & _IESO_OFF __CONFIG _CONFIG2, _WRT_OFF & _BOR40V ;***************************************************** ; Variablen festlegen ; 16F883 ; 0x 20 .. 0x 7F ; 0x A0 .. 0x EF ; 0x120 .. 0x16F ;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 g0 equ 0x32 ; Rechenregister für Division g1 equ 0x33 ; Temp equ 0x34 ; für Stringausgabe count equ 0x35 ; Zähler für ADC-Eingangsumschaltwartezeit Rp0 equ 0x36 Rp1 equ 0x37 ESR0 equ 0x38 ESR1 equ 0x39 ff0 equ 0x3A ; puffer fuer f ff1 equ 0x3B 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 neunteStelle B'10001001' ; #define achteStelle2 B'11001000' ; #define neunteStelle2 B'11001001' ; #define zehnteStelle2 B'11001010' ; #define R250 PORTC, 0 ; Pin mit 250-Ohm zum ELKO #define Switch_Cal PORTC, 4 ; Kalibriermode, 1-nein, 0-ja #define Switch_Z PORTC, 5 ; Z von RP abziehen? 1-ja, 0-nein #define Fehler Flags,0 #define Leading0 Flags,1 ;***************************************************** org 0 goto Init ;***************************************************** Txt00 dt "Hallo ",' '+80h Txt01 dt "o.k. ",' '+80h Txt10 dt "MesseC",' '+80h Txt11 dt "Entlad",' '+80h Txt12 dt "Lade ",' '+80h Txt13 dt "K:20mA",' '+80h Txt14 dt "K:mOhm",' '+80h ;***************************************************** ; Das Programm beginnt mit der Initialisierung Init ; Takt einstellen bei INTOSC bsf STATUS, RP0 ; Bank 1 bsf OSCCON, IRCF2 ; 8 MHz bsf OSCCON, IRCF1 bsf OSCCON, IRCF0 bcf STATUS, RP0 ; Bank 0 ; Ports clrf PORTB bsf STATUS, RP0 ; Bank 1 movlw Ini_opt ; pull-up on, wird in Kapazitaet ueberschrieben movwf OPTION_REG clrf TRISB ; PortB alle outputs fuer LCD bsf STATUS, RP1 ; Bank 3 clrf ANSELH bcf STATUS, RP1 ; Bank 0 bcf STATUS, RP0 ; Bank 0 clrf PORTB clrf PORTC bsf PORTC,2 ; Ladetransistor aus bcf PORTC,1 bsf PORTC,2 bsf STATUS, RP0 ; Bank 1 bcf TRISC,1 ; RC1 output bcf TRISC,2 ; RC2 output bcf STATUS, RP0 ; Bank 0 clrf INTCON ;Display initialisieren call InitLcd movlw Txt00 ; 'Hallo' zum Display call Write call WAIT250ms call WAIT250ms ; ADC initialisieren ;ADC-Eingang AN0 auswählen clrf ADCON0 ; ADC speed für 5 ... 20 MHz einstellen, 8MHz/32 = 250 kHz BSF ADCON0, ADCS1 ; ADCS1=1 ; Daten rechtsbündig BSF STATUS, RP0 ; Bank1 clrf ADCON1 ; Referenz Vdd&Vss BSF ADCON1, ADFM ; ADFM=1, Daten rechtsbündig ;AN0 und AN1 bsf TRISA, 0 bsf TRISA, 1 BSF STATUS, RP1 ; Bank3 bsf ANSEL, ANS0 bsf ANSEL, ANS1 BCF STATUS, RP1 ; Bank0 BCF STATUS, RP0 ; ADC einschalten BSF ADCON0, ADON ; ADON=1 Mainloop btfss Switch_Cal call Kalibrierung call Kapazitaet ; Messung der Kapazität -> C movfw C0 ; C -> f movwf f0 movfw C1 movwf f1 call B2D ; Wandlung von f in dezimal nach SZT,ST,SH,SH,SE call Ausgabe_uF ; Kapazität anzeigen am LCD 1.Zeile vorn call Rp ; Messung des ESR movfw ESR0 ; ESR -> f movwf f0 movfw ESR1 movwf f1 call B2D ; Wandlung von f in dezimal nach SZT,ST,SH,SH,SE call Ausgabe_ESR ; ESR anzeigen am LCD 2.Zeile vorn call Leckstrom call B2D ; Wandlung von f in dezimal nach SZT,ST,SH,SH,SE call Ausgabe_IR ; f anzeigen am LCD 1.Zeile hinten movlw Txt01 ; 'o.k.' zum Display call Write call WAIT250ms call WAIT250ms call WAIT250ms call WAIT250ms goto Mainloop ;***************************************************** ; Kalibrierung des Ladestroms und des Messgleichrichters ; Switch_Z gesteckt : Messgleichrichter kalibrieren (1 mOhm = 1) ; Switch_Z offen : Ladestrom kalibrieren (20mA bzw. 250 Ohm) Kalibrierung btfss Switch_Z goto Kal_Acdc Kal_I ; Switch_Z offen movlw Txt13 ; 'K:20mA' zum Display call Write ; ELKO laden ueber 250 Ohm ; ; Variante 1 ; Milliamperemeter anstelle des Test-ELKOs anschließen ; Strom auf 20mA einstellen an R22 ; ; Variante 2 ; 100 Ohm widerstand anschließen anstelle des ELKOs ; am display 1,43V einstellen mit R22 bsf R250 bsf STATUS, RP0 ; Bank 1 bcf TRISC,0 ; RC0 (das 250-Ohm-Pin) output bcf STATUS, RP0 ; Bank 0 bsf R250 Kal_I_Loop call ADC ; AN0 nach f1,f0, braucht etwa 50 us call mV ; wandeln in Millivolt -> f call B2D ; Wandlung von f in dezimal nach SZT,ST,SH,SH,SE call Ausgabe_mV call WAIT250ms goto Kal_I_Loop Kal_Acdc ; Switch_Z gesteckt movlw Txt14 ; 'K:mOhm' zum Display call Write ; ohmschen Widerstand anstelle des ELKOs anschließen z.B. 470mOhm ; am Display den Widerstandswert einstellen mit R23 bsf ADCON0,CHS0 ; ADC vorbereiten: Umschalten auf AN1 Kal_Acdc_Loop call WAIT250ms call ADC ; Messe den Nullpunktfehler des Messgeichrichters -> f = NPE movfw f0 ; f -> xw movwf xw0 movfw f1 movwf xw1 ; NPE nach xw call On100kHz ; Test-Rechteck 0,65536 Sekunden BSF ADCON0, GO ; ADC starten call On100kHz ; Test-Rechteck 0,65536 Sekunden call ADCloop ; Messwert in f call Sub16 ; f:= f-xw = Rp-NPE call B2D ; Wandlung von f in dezimal nach SZT,ST,SH,SH,SE call Ausgabe_ESR ; ESR anzeigen am LCD 2.Zeile vorn goto Kal_Acdc_Loop ;***************************************************** ; Kapazität bestimmen ; Ergebnis nach C1, C0 [µF] ; am Ende ist der Kondensator auf 2,5V geladen Kapazitaet call Entladen ; ELKO entladen movlw Txt10 ; 'Messe C' zum Display call Write clrf C0 ; Kapazitätsregister löschen clrf C1 ; 8 MHz/5770Hz = 1386 = 4 x 2 x 173 ; Vorteiler 2:1 ; 173 Zähltakte 256-173=83 movlw B'10000000' ; pull-up aus, Timer0 interner Takt 2:1 bsf STATUS, RP0 ; Bank 1 movwf OPTION_REG bcf STATUS, RP0 ; Bank 0 ; ELKO laden ueber 250 Ohm bsf R250 bsf STATUS, RP0 ; Bank 1 bcf TRISC,0 ; RC0 (das 250-Ohm-Pin) output bcf STATUS, RP0 ; Bank 0 bsf R250 Kap_loop movlw D'83' ; bei 8 MHz movwf TMR0 bcf INTCON, T0IF call ADC ; AN0 nach f1,f0, braucht etwa 50 us 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 ; warten bis 0.172 ms vorbei sind goto Kap_loop ; Kap_Ende Kap_ERROR bsf STATUS, RP0 ; Bank 1 bsf TRISC,0 ; RC0 (das 250-Ohm-Pin) input bcf STATUS, RP0 ; Bank 0 return ;***************************************************** ; ELKO entladen auf 40 mV über 25 Ohm Entladen ; ELKO entladen movlw Txt11 ; 'Entlade' zum Display call Write bcf R250 ; steht ohnehin auf input bsf PORTC,1 ; Entladetransistor an Entladen_loop call ADC ; AN0 nach f1,f0 ;call Ausgabe_f1f0 ; Wandlung von f in dezimal und anzeigen am LCD DEBUG 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 bcf PORTC,1 ; Entladetransistor aus return ;***************************************************** ; ELKO auf Vdd aufladen Laden5V ; ELKO laden movlw Txt12 ; 'Lade' zum Display call Write bcf PORTC,2 ; Ladetransistor an Laden_loop call ADC ; AN0 nach f1,f0 ;call Ausgabe_f1f0 ; Wandlung von f in dezimal und anzeigen am LCD DEBUG movlw B'11111100' iorwf f1, w ; muss '00000011' = 0x03 sein xorlw 0xFF btfss STATUS,Z ; >0x0300 >3,75V ? goto Laden_loop ; nein movlw B'00000111' iorwf f0,w xorlw 0xFF btfss STATUS,Z ; >0x03F8 (< 4,965V) goto Laden_loop ; nein bsf PORTC,2 ; Ladetransistor aus return ;***************************************************** ; Leckstrom bei 5V messen ; 220 kOhm Messwiderstand ; 1 uA -> 0.22V -> ADC:45 ; maxinal möglicher Wert ist (1024 -0) / 45 = 23 Leckstrom call Laden5V ; elko auf Vdd aufladen ; f1,f0 sichern movfw f0 movwf ff0 movfw f1 movwf ff1 call WAIT50ms call ADC movfw f0 movwf xw0 movfw f1 movwf xw1 movfw ff0 movwf f0 movfw ff1 movwf f1 ; I[uA] = (f-xw)/45 call Sub16 ; f = f-xw bei Überlauf (neg. Ergebnis) ist C gesetzt ; weiter nur bei positivem Ergebnis bc LeckNegativ clrf xw1 movlw D'45' movwf xw0 call Div16 return LeckNegativ clrf f1 clrf f0 return ;***************************************************** ; Scheinwiderstand in mOhm bei 100kHz berechnen ; Z = 1/(2 x PI x f x C) ; Z = 1591 / µF ; 10 uF -> 159 mO ; 100 uF -> 15 mO ; 1000 uF -> 1 mO ; Ergebnis in f ; falls jumper Switch_Z gesteckt ist, dann 0 zurückgeben Rschein clrf f1 clrf f0 btfss Switch_Z return ; 1591 = 06 37 movlw 0x06 ; 1591 -> f movwf f1 movlw 0x37 movwf f0 movwf C0 ; C -> xw movwf xw0 movfw C1 movwf xw1 call Div16 ; f:= f / xw = 1591 / C return ;***************************************************** ; Spannung mit ADC messen ; Ergebnis nach f1,f0 ADC BSF ADCON0, GO ; ADC starten ADCloop BTFSC ADCON0, GO ; 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 ;***************************************************** ; Spannung an AN1 messen ; Ergebnis nach f1,f0 ADC1 bsf ADCON0, CHS0 ; Umschalten auf AN1 movlw D'200' ; 200 Zyklen sind 100 µs movwf count ; 40µs Pause sind 80 Zyklen ADC1_aqui1 DECFSZ count, f goto ADC1_aqui1 call ADC bcf ADCON0, CHS0 ; zurückschalten auf AN0 movlw D'200' ; 200 Zyklen sind 100 µs movwf count ; 40µs Pause sind 80 Zyklen ADC1_aqui0 DECFSZ count, f goto ADC1_aqui0 return ;***************************************************** ; 100kHz einschalten für 0,65536 Sekunden ; 200 000 Flanken/s, 10 Befehle pro Halbwelle bei 8 MHz On100kHz clrf loops2 ; 256 Schleifen = 0,655 s clrf loops ; 256 Perioden = 2,56 ms On100a bsf PORTC,2 ; laden stoppen bsf PORTC,1 ; entladen nop nop nop nop nop nop nop nop bcf PORTC,1 bcf PORTC,2 ; laden nop nop nop nop nop decfsz loops,f goto On100a decfsz loops2,f goto On100a bsf PORTC,2 ; laden stoppen return ;***************************************************** ; Rp messen ; C muß auf 2,5V geladen sein ; dann 100kHz einschalten ; danach AN1 messen Rp call Rschein ; Z -> f (Scheinwiderstand in mOhm bei 100kHz berechnen) movfw f0 ; f -> xw movwf xw0 movfw f1 movwf xw1 ; Z nach xw ; ADC vorbereiten bsf ADCON0,CHS0 ; vorbereiten: Umschalten auf AN1 call WAIT250ms call ADC ; Messe den Nullpunktfehler des Messgeichrichters -> f = NPE call Add16 ; f = NPE + Z movfw f0 ; f -> xw movwf xw0 movfw f1 movwf xw1 ; NPE+Z nach xw call On100kHz ; Test-Rechteck 0,65536 Sekunden BSF ADCON0, GO ; ADC starten call On100kHz ; Test-Rechteck 0,65536 Sekunden call ADCloop ; Messwert in f bcf ADCON0,CHS0 ; zurückschalten auf AN0 ; 1 mVAC = 80 mVDC ; bei 2,5V / 25 Ohm = 0,1A ; 1 mOhm = 0,1 mVAC = 8 mVDC ; ADC-Auflösung = 4,88 mV = 0,61 mOhm ; vorläufig: Auflösung = 1 mOhm movfw f0 ; f -> Rp movwf Rp0 movfw f1 movwf Rp1 ; Rp sichern call Sub16 ; f:= f-xw = Rp-Z-NPE movfw f0 ; f -> ESR movwf ESR0 movfw f1 movwf ESR1 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 ;***************************************************** ;primitive 16 bit Division f:= f / xw ; ohne Rest und ohne Runden Div16 clrf g0 decf g0, f clrf g1 decf g1, f Div16Loop incf g0, f btfsc STATUS, Z incf g1, f call Sub16 ; btfss STATUS, C ;Überlauf goto Div16Loop ;Stelle 1 mehr movfw g0 movwf f0 movfw g1 movwf f1 return ;***************************************************** ; Division durch 2 wird w-mal ausgeführt ; die zu dividierende Zahl steht in xw Div2 movwf counter ; Anzahl der Divisionen speichern Div2a ; 16 bit xw:=xw/2 bcf STATUS, C ; carry löschen rrf xw1, f rrf xw0, f decfsz counter, f ; fertig? goto Div2a ; nein: noch mal return ;***************************************************** ; Wandlung des ADC-Wert in Millivolt (binär) ; Der ADC-Wert steht in f1,f0 ; Ergebnis steht in f1,f0 mV ; zunächst die Multiplikation mal 5 movfw f0 movwf xw0 movfw f1 movwf xw1 call Add16 ; f := 2xADC call Add16 ; f := 3xADC call Add16 ; f := 4xADC call Add16 ; f := 5xADC ; ADC * 5 nach xw kopieren movfw f0 movwf xw0 movfw f1 movwf xw1 ; xw := 5xADC ; xw durch 64 dividieren (6 mal durch 2) ; dann ist xw = 5xADC/64 movlw 6 call Div2 call Sub16 ; f := 5xADC - 5xADC/64 ; xw auf 5xADC/128 verringern movlw 1 call Div2 call Sub16 ; f := 5xADC - 5xADC/64 - 5xADC/128 return ; fertig ;***************************************************** ; 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 von f1-f0 als Dezimalzahl in der Form '12 345' ; Unterdrückung führender Nullen Ausgabe_f1f0 ; f1,f0 sichern movfw f0 movwf ff0 movfw f1 movwf ff1 ; Wandlung von f in dezimal nach SZT,ST,SH,SH,SE call B2D ;movlw B'10000000' ; 1. Zeile movlw neunteStelle ; 1. Zeile 9. stelle call OutLcdControl call OutLcdControl 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 ; gesicherte f1,f0 zurückholen movfw ff0 movwf f0 movfw ff1 movwf f1 return ;***************************************************** ;Anzeige der ADC-Spannung in mV '12 345 mV' ;Unterdrückung führender Nullen Ausgabe_mV movlw B'10000000' ; 1. Zeile call OutLcdControl 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 ' ' ; Lücke call OutLcdDaten movlw 'm' call OutLcdDaten movlw 'V' call OutLcdDaten 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 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 ' ' ; Lücke call OutLcdDaten 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 ;***************************************************** ;Anzeige der Dezimalzahl am LCD in der Form '12 345 mOhm' ;Unterdrückung führender Nullen Ausgabe_ESR movlw B'11000000' ; 2. Zeile call OutLcdControl 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 ' ' ; Lücke call OutLcdDaten movlw 'm' call OutLcdDaten movlw B'11110100' ; Ohm call OutLcdDaten return ;***************************************************** ;Anzeige der Dezimalzahl am LCD in der Form ' 22 µA' ; maxinal möglicher Wert ist (1024 -0) / 45 = 23 ;Unterdrückung führender Nullen Ausgabe_IR movlw neunteStelle ; 1. Zeile 9. stelle call OutLcdControl movlw ' ' ; Lücke call OutLcdDaten bsf Leading0 movfw SH call AusLed movfw SZ call AusLed bcf Leading0 movfw SE call AusLed movlw ' ' ; Lücke call OutLcdDaten movlw B'11100100' ; µ call OutLcdDaten movlw 'A' 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 ;movlw neunteStelle2 ; 2. Zeile 9. stelle movlw zehnteStelle2 ; 2. Zeile 10. 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 call WAIT250ms movlw B'00110000' ; 1 movwf LcdPort bsf LcdE nop bcf LcdE call WAIT50ms ; 50 ms Pause 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 bcf LcdRw bcf LcdRs 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 bcf LcdRw bcf LcdRs 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 ;***************************************************** ; 100 ms Wartezeit WAIT100ms movlw D'100' ; 100 ms Pause movwf loops goto WAIT ;***************************************************** ; 50 ms Wartezeit WAIT50ms movlw D'50' ; 50 ms Pause movwf loops goto WAIT ;***************************************************** ; 250 ms Wartezeit WAIT250ms movlw D'250' ; 250 ms Pause movwf loops goto WAIT ;***************************************************** ;Zeitverzögerung um loops * 1 ms ; 8 MHz Takt bedeutet 2 MHz interner Zyklus ; also dauert 1 ms genau 2000 Befehle ; 200 Schleifen a 10 Befehle sind 2000 Befehle = 1 ms WAIT top movlw .200 ; 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