Code:
list p=16f628
;**************************************************************
;* Pinbelegung
;* ----------------------------------
;* PORTA: 0 SDA out
;* 1 CLK in
;* 2 SDA in
;* 3 CLK out
;* 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
;*
;*
;**************************************************************
;
;sprut (zero) Bredendiek 12/2003
;
; Temperaturmessung mit LM75
; Anzeige am LCD-Display
;
; Prozessor 16F628
;
; Prozessor-Takt 10 MHz
;
; IIC am PortA
; LCD am PortB
;
; Temperaturanzeige mit 0,5°C Genauigkeit
;
;
;**********************************************************
; Includedatei für den 16F628 einbinden
#include <P16f628.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
buf equ 0x22 ; puffer für I2C
Temp_h equ 0x23 ; Temperatur in grad
Temp_l equ 0x24 ; 0.5°C auf Bit 7
count equ 0x2B ; universeller zähler
loops equ 0x2C ; timer für wait
loops2 equ 0x2D ; timer für wait
LcdStatus equ 0x2E ;
LcdDaten equ 0x2F ;
; 8-Bit Rechenregister
xw0 EQU 0x32 ;LSB
; 8-Bit Rechenregister
f0 EQU 0x3A ;LSB
; Dezimalstellen
HdH EQU 0x4B ;3 Hunderter
HdZ EQU 0x4C ;2 Zehner
HdE EQU 0x4D ;1 Einer
HdX EQU 0x4E ; Puffer für eine Dezimalstelle
BcdDaten equ 0x4F
BcdDaten1 equ 0x50
; Konstanten festlegen
; 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)
; für I2C
#define SDAo PORTA,0 ;Daten output
#define SDAi PORTA,2 ;Daten input
#define SCL PORTA,3 ;Takt
#define SCLo PORTA,3 ;Takt
#define SCLi PORTA,1 ;Takt input
Ini_con Equ B'00000000' ; TMR0 -> Interupt disable
Ini_opt Equ B'00000010' ; pull-up
;********************************************************
org 0
goto Init
;********************************************************
; 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
movlw B'11100110' ; PortA alle input außer RA0,3,4
movwf TRISA
bcf STATUS, RP0 ; Bank 0
clrf PORTA
clrf PORTB
movlw Ini_con ; Interupt disable
movwf INTCON
; 16F628 alle Comparatoreingänge auf Digital umschalten
BSF CMCON, CM0
BSF CMCON, CM1
BSF CMCON, CM2
;Display initialisieren
call InitLcd
call i2c_reset
nop
nop
; Temp register einstellen
call i2c_on ; Bus aktiv
movlw H'90' ; 1001 0000
call i2c_tx ; LM75 zum schreiben adressieren
movlw 0
call i2c_tx ; Temp adressieren
call i2c_off ; Bus freigeben
mainloop
; Cursor home
movlw 1
call OutLcdControl
; Temp messen
bsf PORTA,4 ; DEBUG
call i2c_on ; Bus aktiv
movlw H'91' ; 1001 0001
call i2c_tx ; LM75 zum lesen adressieren
call i2c_rxack
movwf Temp_h ; Byte in Speicherzelle Datenpuffer retten
call i2c_rx
movwf Temp_l ; Byte in Speicherzelle Datenpuffer retten
call i2c_off ; Bus freigeben
bcf PORTA,4 ; DEBUG
; Temp anzeigen
movfw Temp_h
movwf f0
call OutDez8 ; Anzeige der Grad
movlw '.'
movwf LcdDaten
call OutLcdDaten
movlw '0'
btfsc Temp_l, 7
movlw '5'
movwf LcdDaten
call OutLcdDaten
call OutGC
movlw D'250' ; 250 ms Pause
movwf loops
call WAIT
goto mainloop
;*****************************************************************
; Routinen für I2C
; Bus übernehmen i2c_on
; W senden i2c_tx
; Byte empfangen i2c_rx (nach w und RXData und SSPBUF)
; Bus freigeben i2c_off
;*****************************************************************
i2c_reset
bsf SDAo
bsf SCLo
nop
movlw 9
movwf buf
i2c_reset1
nop
bcf SCLo
nop
nop
nop
nop
nop
bsf SCLo
nop
decfsz buf, f
goto i2c_reset1
nop
call i2c_on
nop
bsf SCLo
nop
nop
bcf SCLo
nop
call i2c_off
return
i2c_on
; wenn SDA und SCL beide High, dann SDA auf Low ziehen
bsf SCL ; failsave
bsf SDAo ; failsave
;testen, ob der Bus frei ist
btfss SCLi
goto i2c_on ; Taktleitung frei?
btfss SDAi
goto i2c_on ; Datenleitung frei?
bcf SDAo
nop
bcf SCL
return
i2c_tx
; w über I2C senden
; takt ist unten
; daten sind unten
call WrI2cW ; 8 Bit aus W nach I2C
; ACK muß nun empfangen werden
; Takt ist low
bsf SDAo ;Datenleitung loslassen
bsf SCL ; ACK Takt high
i2c_tx2
btfss SCLi
goto i2c_tx2
nop
;i2c_tx1
; btfsc SDAi ; ACK empfangen?
; goto i2c_tx1 ; nein SDA ist high
bcf SCL ; ja , Takt beenden
bcf SDAo
return
i2c_rxack
; takt ist unten
; daten sind unten
call RdI2cW ; 8 von I2C nach W
; Takt ist unten
; ACK muß nun gesendet werden
bcf SDAo
nop
nop
nop
nop
bsf SCL
i2c_rxack1
btfss SCLi
goto i2c_rxack1
nop
bcf SCL
bcf SDAo
return
i2c_rx
; takt ist unten
; daten sind unten
call RdI2cW ; 8 von I2C nach W
; Takt ist unten
; kein ACK
nop
nop
bsf SDAo
nop
bsf SCL
i2c_rx1
btfss SCLi
goto i2c_rx1
nop
bcf SCL
bcf SDAo
return
i2c_off
; SCL ist Low und SDA ist Low
nop
nop
bsf SCL
nop
bsf SDAo
return
;*****************************************************
; I2C-Peride ist 2,5 µs
; PIC-Zyklus ist 4/10MHz = 0,4µs
; -> Takt muß für 3 Zyklen H und für 3 Zyklen L sein
; + 1 Zyklus Reserve
;schiebt das Byte aus W in den I2C
; MSB zuerst
; 78 Takte
WrI2cW
; Takt unten, Daten unten
; Datenbyte in w
movwf buf
movlw 8
movwf count ; 8 Bits
WrI2cW1
; Datenleitung setzen
bcf SDAo
rlf buf,f
btfsc STATUS,C ; 0?
bsf SDAo ; nein, 1
nop
bsf SCL ; Taht high
WrI2cW2
btfss SCLi
goto WrI2cW2
bcf SCL ; Takt low
decfsz count,f ; 8 Bits raus?
goto WrI2cW1 ; nein
return ; ja
;liest das Byte aus I2C nach W
; takt ist unten
; daten sind unten
RdI2cW
clrf buf
movlw 8
movwf count
bsf SDAo ;failsave
RdI2cW1
nop
clrc
btfsc SDAi
setc
rlf buf,f
bsf SCL ; Takt high
RdI2cW2
btfss SCLi
goto RdI2cW2
bcf SCL ; Takt low
decfsz count,f ; 8 Bits drinn?
goto RdI2cW1 ; nein
movfw buf ; ja fertig
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
;*****************************************************
;+++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'00001111' ; 9 display on
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
;*******************************************************************************
; String ' °C' am LCD ausgeben
OutGC
movlw ' '
movwf LcdDaten
call OutLcdDaten
movlw B'11011111' ; °
movwf LcdDaten
call OutLcdDaten
movlw 'C'
movwf LcdDaten
call OutLcdDaten
return
;*****************************************************
;+++Mathematik-Routinen*******************************
;*****************************************************
;**************************************************************
; 8 Bit Wert (f1,f0) auf LCD dezimal anzeigen
OutDez8 ;8-bit (f0) als Dez zum Lcd
call Hex2Dez8
movfw HdH
Call Bcd4Bit
movfw HdZ
Call Bcd4Bit
movfw HdE
Call Bcd4Bit
return
; 100 = 0000 0064 h
; 10 = 0000 000A h
; 1 = 0000 0001 h
Hex2Dez8 ; 8-bit (f1) in 3-stellen BCD
movlw 0x64
movwf xw0
call Hex2Dez1 ; 100er
movfw HdX
movwf HdH
movlw 0x0A
movwf xw0
call Hex2Dez1 ; 10er
movfw HdX
movwf HdZ
movfw f0
movwf HdE
return
Hex2Dez1
clrf HdX
decf HdX, f
HdLoop
incf HdX, f
movf xw0, w ; f0=f0-xw0
subwf f0, f
btfsc STATUS, C ;Überlauf
goto HdLoop ;Stelle 1 mehr
movf xw0,W ; low byte
addwf f0,F ; low byte add
return
Bcd4Bit ;low-4 Bit als BCD ausgeben
movwf BcdDaten
movlw B'00110000'
ADDwf BcdDaten, f ;ASCII-wandeln (+48)
movlw B'00111010'
subwf BcdDaten, w
btfss STATUS, C ;Test auf A ... F
goto BcdOk
movlw .7
addwf BcdDaten, f ;korrigiere A...F (+7)
BcdOk
movfw BcdDaten
call OutLcdDaten
return
end
Der Seiten link ist:
Lesezeichen