list p=16f876 ;************************************************************** ;* Pinbelegung ;* ---------------------------------- ;* PORTA: 0 < PTC-Spannung ;* 1 - ;* 2 - ;* 3 - ;* 4 - ;* 5 - ;* 6 - ;* 7 - ;* ;* PORTB: 0 Segment A AAAAA AAAAA AAAAA ;* 1 Segment F F B F B F B ;* 2 Segment E F B F B F B ;* 3 Segment D GGGGG GGGGG GGGGG ;* 4 Segment H E C E C E C ;* 5 Segment C E C E C E C ;* 6 Segment G DDDDD HH DDDDD HH DDDDD HH ;* 7 Segment B ;* ;* PORTC: 0 LED------------------------------------------------A ;* 1 LED--------------------------------A ;* 2 LED----------------A ;* 3 - ;* 4 - ;* 5 - ;* 6 - (> TX: RS-232-Ausgang zum Treiber) ;* 7 - (< RX: RS-232-Eingang vom Treiber) ;* ;************************************************************** ; ;sprut (zero) Bredendiek 06/2003 ; ; Termometer mit 16F876 und KTY81-110 ; ; Prozessor 16F876 / 16F673 ; ; Prozessor-Takt 4 MHz ; ; PTC-Spannung: ; Temp. Spannung ADC ; -20°C 1,0106 V 206 ; 0°C 1,1593 V 237 ; +20°C 1,3125 V 268 ; +40°C 1,4678 V 300 ; +100°C 1,9290 V 395 ; ; ; ;************************************************************** ; 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 & _XT_OSC & _BODEN_OFF & _LVP_OFF ;************************************************************** ; Variablen festlegen w_copy Equ 0x20 ; nur für INT s_copy Equ 0x21 ; nur für INT p_copy EQU 0x22 ; nur für INT Flags EQU 0x23 NrMessung EQU 0x24 ; zählt die 64 Temperaturmessungen Fehler equ 0x25 ; Fehlerregister für Mathematik count equ 0x26 ; universeller zähler loops equ 0x27 ; timer für wait loops2 equ 0x28 ; timer für wait ; Dezimalstellen Digit EQU 0x29 Ziffer1 EQU 0x2A Ziffer2 EQU 0x2B Ziffer3 EQU 0x2C HdH EQU 0x2D ;3 Hunderter HdZ EQU 0x2E ;2 Zehner HdE EQU 0x2F ;1 Einer HdX EQU 0x30 ; Puffer für eine Dezimalstelle ;16 Bit Rechenregister f0 equ 0x31 ; f1 equ 0x32 ; ;16 Bit Rechenregister xw0 equ 0x33 ; xw1 equ 0x34 ; ;16 Bit Rechenregister g0 equ 0x35 ; g1 equ 0x36 ; ; Konstanten festlegen #define Leading0 Flags,7 #define Negativ Flags,6 ; 1: Temperatur ist negativ ; der Wert offset dient zur Kalibrierung des Termometers ; der Standardwert ist 150 dezimal ; zeigt das Termometer eine um x° zu hohe Temperatur an, dann ; muss offset um x erhöht werden ; ; Beispiel: ; mit einem offset von 150 zeigt das Termometer eine um 4 °C ; zu hohe Temperatur an, dann ist offset auf 154 zu ändern. #define Offset D'250' ; Offset des PTC #define Toff1 D'30' #define Toff2 D'30' #define Ton1 D'38' #define Ton2 D'38' Ini_con Equ B'00000000' ; TMR0 -> Interupt disable Ini_opt Equ B'10000011' ; Timer0 int 16:1 ;************************************************************** org 0 goto Init ;************************************************************** ; die Interuptserviceroutine org 4 intvec movwf w_copy ; w retten swapf STATUS, w ; STATUS retten clrf STATUS movwf s_copy ; movf PCLATH, W movwf p_copy clrf PCLATH ; Bank 0 ; Intrupt servic routine Int_serv bsf PORTC, 2 ; Ziffer1 aus bsf PORTC, 1 ; Ziffer2 aus bsf PORTC, 0 ; Ziffer3 aus decf Digit,f ; Ziffernzähler verringern ;Digit=2: anzeigen Ziffer 3 1er ;Digit=1: anzeigen Ziffer 2 10er ;Digit=0: anzeigen Ziffer 1 100er btfsc STATUS, Z goto Int_0 ; Z-Flag=1 ergo Digit=0 decf Digit, w btfsc STATUS, Z goto Int_1 ; Digit=1 goto Int_2 ; Digit=2 Int_0 movfw Ziffer1 ; Wert der 1. Ziffer (100er) call Segmente movwf PORTB ; Segmente einschalten bcf PORTC, 2 ; 1. Ziffer einschalten movlw 3 movwf Digit goto Int_end Int_1 movfw Ziffer2 ; Wert der 2. Ziffer (10er) call Segmente movwf PORTB ; Segmente einschalten bcf PORTC, 1 ; 2. Ziffer einschalten goto Int_end Int_2 movfw Ziffer3 ; Wert der 3. Ziffer (1er) call Segmente movwf PORTB ; Segmente einschalten bcf PORTC, 0 ; 3. Ziffer einschalten goto Int_end Int_end movf p_copy, W movwf PCLATH swapf s_copy, w ; STATUS zurück movwf STATUS swapf w_copy, f ; w zurück mit flags swapf w_copy, w bcf INTCON, T0IF ; Interupt-Flag löschen retfie ;************************************************************** ; 7-Segment-Tabelle ;* PORTB: 0 Segment A AAAAA ;* 1 Segment F F B ;* 2 Segment E F B ;* 3 Segment D GGGGG ;* 4 Segment H E C ;* 5 Segment C E C ;* 6 Segment G DDDDD HH ;* 7 Segment B ; Segmente addwf PCL, f ; 76543210 ; BGCHDEFA retlw B'01010000' ; 0 retlw B'01011111' ; 1 retlw B'00110010' ; 2 retlw B'00010110' ; 3 retlw B'00011101' ; 4 retlw B'10010100' ; 5 retlw B'10010000' ; 6 retlw B'01011110' ; 7 retlw B'00010000' ; 8 retlw B'00010100' ; 9 retlw B'11111111' ; dunkel retlw B'10111111' ; - ;************************************************************** ;************************************************************** ; Das Programm beginnt mit der Initialisierung Init movlw B'11111111' movwf PORTB movwf PORTC ; LED aus bsf STATUS, RP0 ; Bank 1 movlw Ini_opt ; pull-up on movwf OPTION_REG movlw B'00000000' ; PortB & C alle outputs movwf TRISB movwf TRISC bcf STATUS, RP0 ; Bank 0 movlw B'00000000' movwf PORTB movwf PORTC ; LED aus movlw Ini_con ; Interupt disable movwf INTCON movlw 3 movwf Digit movlw D'1' movwf Ziffer1 movlw D'2' movwf Ziffer2 movlw D'3' movwf Ziffer3 ; Anzeige '321' ; 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 1,25 ... 5 MHz einstellen BCF ADCON0, 7 ; ADCS1=0 BSF ADCON0, 6 ; ADCS0=1 ; Daten rechtsbündig BSF STATUS,RP0 ; Bank1 clrf ADCON1 BSF ADCON1, 7 ; ADFM=1 BCF STATUS,RP0 ; Bank0 ; 244 Hz-Timer0-Interupt einstellen bsf STATUS, RP0 ; auf Bank 1 umschalten movlw B'10000011' ; internen Takt zählen, Vorteiler zum Timer0, 16:1 ; T0CS=0, PSA=0, PS=100, xx0x0100 movwf OPTION_REG movlw D'0' ; (1MHz : 16 ): 256= 244Hz bcf STATUS, RP0 ; auf Bank 0 zurückschalten movwf TMR0 bcf INTCON, T0IF bsf INTCON, T0IE ; Timer0 interupt erlauben bsf INTCON, GIE ; Interupt erlauben ; 1. Temperaturregister (16-Bit) auf 82 setzen (32+50) ; 2. 64 mal ADC abfragen, ADC-Wert jeweils zum Temperaturregister addieren (16 Bit Addition) ; 3. Temperaturregister durch 101 dividieren (16 Bit Division) ; 4. Vom Temperaturregister 150 subtrahieren (16 Bit Subtraktion) ; 5. Temperaturregister in BCD umrechen (3-stellig), Vorzeichen beachten mainloop ; Startwert für korrektes Runden clrf f1 movlw D'82' movwf f0 ; 64 Messungen movlw D'64' movwf NrMessung Messung call UMessen1 ; AN0 nach xw1,xw0 call Add16 ; 16-bit add: f = f + xw decfsz NrMessung, f goto Messung ; Division durch 101 movlw 0x00 ; 101 = 00 65 h movwf xw1 movlw 0x65 movwf xw0 call Div16 ; Division f:= f / xw ; 150°C Offset entfernen bcf Negativ ; angenommen: positive Temperatur clrf xw1 movlw Offset movwf xw0 call Sub16 ; 16 bit f:=f-xw calc=xw cnt=f; neg=C btfss STATUS, C goto Positiv bsf Negativ movfw f0 movwf xw0 movfw f1 movwf xw1 clrf f1 clrf f0 call Sub16 ; 16 bit f:=f-xw calc=xw cnt=f; neg=C Positiv call Luft2 call Luft1 call Hex2Dez8 ; Umrechnung in BCD call wait75ms goto mainloop ;************************************************************** ; Spannung wandeln nach xw1, xw0 UMessen1 clrf count aqui ; 0,3 ms ADC Aqusitionszeit nach Eingangswahl DECFSZ count, f goto aqui BSF ADCON0, 2 ; ADC starten loop BTFSC ADCON0, 2 ; ist der ADC fertig? GOTO loop ; nein, weiter warten movfw ADRESH ; obere 2 Bit auslesen movwf xw1 ; obere 2-Bit nach xw1 bsf STATUS,RP0 ; Bank1 movfw ADRESL ; untere 8 Bit auslesen bcf STATUS,RP0 ; Bank0 movwf xw0 ; untere 8-Bit nach xw0 clrf count ; Warten, damit der ADC sich erholen kann warten DECFSZ count, f goto warten return ;************************************************************** ;Warteroutinen verschiedener Länge **************************** ; 75 ms warten wait75ms movlw D'75' ; 75ms movwf loops goto WAIT ;************************************************************** ;Zeitverzögerung um loops * 1 ms ; 4 MHz externer Takt bedeutet 1 MHz interner Takt ; also dauert 1 ms genau 1000 Befehle ; 100 Schleifen a 10 Befehle sind 1000 Befehle = 1 ms WAIT top movlw .100 ; 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 ;************************************************************** ;+++Mathematik-Routinen *************************************** ;************************************************************** ; 16 Bit Subtraktion, bei Überlauf (neg. Ergebnis) ist C gesetzt Sub16 ; 16 bit f:=f-xw calc=xw cnt=f clrf 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, C ; unterlauf Sub16A movf xw1,w ; f1=f1-xw1 subwf f1 , f btfss STATUS, C bsf Fehler, C ; Unterlauf bcf STATUS, C btfsc Fehler, C bsf STATUS, C return ;************************************************************** ;16 bit Adition, C-Flag bei Überlauf gesetzt Add16 ; 16-bit add: f = f + xw movf xw0,W ; low byte addwf f0,F ; low byte add movf xw1,W ; next byte btfsc STATUS,C ; skip to simple add if C was reset incfsz xw1,W ; add C if it was set addwf f1,F ; high byte add if NZ return ; finished ;************************************************************** ;primitive 16 bit Division f:= f / xw 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 ;************************************************************** ; 8 Bit Wert w auf LED 3-stellig dezimal anzeigen ; 100 = 0064 h ; 10 = 000A h ; 1 = 0001 h Hex2Dez8 ; 8-bit (f1, f0) in 3-stellen BCD bsf Leading0 movlw 0x00 ; 100 = 00 64 h movwf xw1 movlw 0x64 movwf xw0 call Hex2Dez1 ; 100er movfw HdX btfsc Negativ movlw D'11' ;'-' movwf HdH movwf Ziffer1 movlw 0x00 ; 10 = 00 0A h movwf xw1 movlw 0x0A movwf xw0 call Hex2Dez1 ; 10er movfw HdX movwf HdZ movwf Ziffer2 movfw f0 movwf HdE movwf Ziffer3 return Hex2Dez1 clrf HdX decf HdX, f HdLoop incf HdX, f call Sub16 ; btfss STATUS, C ;Überlauf goto HdLoop ;Stelle 1 mehr call Add16 ; falls führende 0 dann Wert=D'10' movfw HdX btfss STATUS, Z bcf Leading0 btfss Leading0 return movlw D'10' movwf HdX return ;*********************************************************************** ; Lüfter ein/aus-schalten Luft1 ; prüfen ob TempTon MOVFW Ton1 subwf f0, w ; w:=f-38 = temp-Ton btfsc STATUS, C bsf PORTC,5 ; Lüfter an return Luft2 ; prüfen ob TempTon MOVFW Ton2 subwf f1, w ; w:=f-w = temp-Ton btfsc STATUS, C bsf PORTC,4 ; Lüfter an return ;************************************************************** end ;**************************************************************