; *********** Macros definieren ************* Bank0 macro bcf STATUS,RP0 ;Bank 0 bcf STATUS,RP1 endm Bank1 macro bsf STATUS,RP0 ;Bank 1 bcf STATUS,RP1 endm Bank2 macro bcf STATUS,RP0 ;Bank 2 bsf STATUS,RP1 endm Bank3 macro bsf STATUS,RP0 ;Bank 3 bsf STATUS,RP1 endm ;*********** Konstanten definieren *********** constant PIC_Takt =.8000000 constant I2C_Takt =.400000 constant Wert_SSPADD =PIC_Takt/(.4*I2C_Takt)-.1 ;400kHz = 8MHz/(4*(SSPADD+1)) constant LM75_Adresse=0x90 ;I2C Adresse des Temperatursensors (LM75) constant sEPROM_Adresse=0xA0 ;I2C Adresse des seriellen EEPROMS (24C256) ;*** I2C initialisieren ************************************************************ movlw B'00001000' ;Master Mode movwf SSPCON Bank1 movlw Wert_SSPADD ;Taktfrequenz des I2C-Busses einstellen movwf SSPADD bsf SSPSTAT,SMP ;keine Kontrolle der Signalanstiegszeiten Bank0 bsf SSPCON,SSPEN ;MSSP-Modul einschalten call i2c_idle ;Test ob Bus frei ist ;*** I2C UNTERPROGRAMME ************************************************************ ; ; I2C-Bus im Master-Mode übernehmen ; Warten bis MSSP-Modul frei ist i2c_idle Bank1 btfsc SSPSTAT, R_W ;läuft eine Übertragung? goto $-1 ;ja, warten... i2c_idle_loop2 movfw SSPCON2 ;nein, läuft ein anderes Ereignis? andlw 0x1F ;test auf ACKEN, RCEN, PEN, RSEN, SEN btfss STATUS,Z goto i2c_idle_loop2 ;ja, warten... Bank0 return ;MSSP Modul ist nicht beschäftigt i2c_start call i2c_idle ;Bus frei? Bank1 bsf SSPCON2, SEN ;Bus Übernahme anweisen und Startbit senden btfsc SSPCON2, SEN ;Auf das Ende der Startkondition warten goto $-1 Bank0 return ;Restart aktivieren i2c_rstart call i2c_idle ;Bus frei? Bank1 bsf SSPCON2, RSEN ;Restart Sequence einleiten btfsc SSPCON2, RSEN goto $-1 Bank0 return ;ein Byte aus W senden ;Rückgabewert in W: 0=ACK empfangen, 1=ACK nicht empfangen i2c_tx movwf i2c_Puffer call i2c_idle ;Bus frei? bcf PIR1, SSPIF ;Lösche Interrupt Flag movfw i2c_Puffer movwf SSPBUF ;Byte wird gesendet btfsc SSPCON, WCOL ;Write Collision? goto i2c_tx_wcol btfss PIR1, SSPIF ;Senden fertig? goto $-1 Bank1 btfss SSPCON2, ACKSTAT ;Test ob ACK vom Slave empfangen wurde goto i2c_tx_ack Bank0 retlw .1 ;ACK wurde nicht empfangen i2c_tx_ack Bank0 retlw .0 ;ACK wurde empfangen i2c_tx_wcol Bank0 retlw .2 ;Write Collision Detected ;ein Byte vom Slave empfangen ohne ACK ;Rückgabewert in W i2c_rx call i2c_idle bcf PIR1,SSPIF ;Interrupt Flag löschen Bank1 bsf SSPCON2, RCEN ;Empfang einschalten Bank0 btfss PIR1,SSPIF ;Byte empfangen? goto $-1 ;noch nicht Bank1 bsf SSPCON2, ACKDT ;kein ACK senden (ACK=High) bsf SSPCON2, ACKEN ;sende negatives ACK btfsc SSPCON2, ACKEN ;fertig? goto $-1 Bank0 movfw SSPBUF ;Empfangenen Wert nach W return ;ein Byte vom Slave empfangen mit ACK ;Rückgabewert in W i2c_rx_ack call i2c_idle bcf PIR1,SSPIF ;Interrupt Flag löschen Bank1 bsf SSPCON2, RCEN ;Empfang einschalten Bank0 btfss PIR1,SSPIF ;Byte empfangen? goto $-1 ;noch nicht Bank1 bcf SSPCON2, ACKDT ;ACK senden bsf SSPCON2, ACKEN btfsc SSPCON2, ACKEN ;fertig? goto $-1 Bank0 movfw SSPBUF ;Empfangenen Wert nach W return ; I2C-Bus wieder freigeben i2c_stop call i2c_idle Bank1 bsf SSPCON2, PEN ;Stop Bit senden und Bus frei geben btfsc SSPCON2, PEN ;fertig? goto $-1 Bank0 return