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 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 ecran call OutLcdDaten movlw 'c' ; simbolul pe ecran call OutLcdDaten movlw ')' ; simbolul pe ecran call OutLcdDaten movlw ' ' ; call OutLcdDaten movlw 'D' ; simbolul pe ecran call OutLcdDaten movlw '.' ; simbolul pe ecran call OutLcdDaten movlw 'O' ; simbolul pe ecran call OutLcdDaten movlw 'l' ; simbolul pe ecran call OutLcdDaten movlw 't' ; simbolul pe ecran call OutLcdDaten movlw 'e' ; simbolul pe ecran 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 ecran call OutLcdDaten movlw ' ' ; call OutLcdDaten movlw '=' ; 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' ; simobolul µ 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