CPU "F:\USER0\PROG\CROSS-32 4.0\PIC16XX.TBL" HOF "INHX8M" WDLN 2 ;Word lenght must be 2 TITL "GPC_4A4 Code Example 1 - V1.00" ; PMB ELECTRONICS ; PAUL BEALING ; www.pmb.co.mz ; paul@pmb.co.nz ; March 2001 ; Copyright PMB 2002 ; For use with the PMB GPC_4A4 PIC micro board. ; This code will run in a PIC16F84 at 4MHz. ;****************************************************************************** ; GENERAL INTRODUCTION ; The RTC and EEPROM are connected to the same PIC I/O pins. ; This means that you must be careful when accessing either part. ; The RTC is accessed by taking the RESET line (RA4) high. If the RESET line is ; low, the RTC will ignore the data/clock lines. ; RA4 is also connected to E1 of the EEPROM, a device address line. ; The EEPROM is effectively device #2 (1010010)when the RTC is being accessed. ; This means that the RTC is accessed, not the eeprom. ;****************************************************************************** ; N O T E S ;****************************************************************************** ; Version Notes ; ttg_1a1_01 30-09-01 ; Created from tim_2a2_02. ;****************************************************************************** ; FLAGS USED BY PROGRAM ;****************************************************************************** ; FLAGS1 ; 00000000 ; |||||||| ; |||||||\-- I2C dummy write 1 = yes ; ||||||\--- ADC begin/process pass flag 1 = aquire ; |||||\---- button 1 first pass flag 1 = yes ; ||||\----- hysterisis "on" counter running 1 = yes ; |||\------ dusk/dawn done processing flag 1 = dark done ; ||\------- hysterisis "off" counter running 1 = yes ; |\-------- dusk (light level) 1 = dark ; \--------- piezo buzzer 1 = on ; FLAGS2 ; 00000000 = beep control, flags #2 ; |||||||| ; |||||||`- beep gap done ; 1 = yes ; ||||||`-- beep done ; 1 = yes ; |||||`--- beep running ; 1 = yes ; ||||`---- manual/auto beep mode ; 1 = auto ; |||`----- key beep ; 1 = yes ; ||`------ yes beep ; 1 = yes ; |`------- no beep ; 1 = yes ; `-------- alarm beep ; 1 = yes ; FLAGS3 ; 00000000 ; |||||||| ; |||||||\-- config mode timer (1) running 1 = yes ; ||||||\--- config mode timer (1) timed out 1 = yes ; |||||\---- gp timer 2 running 1 = yes ; ||||\----- gp timer 2 timed out 1 = yes ; |||\------ main timer (3) running 1 = yes ; ||\------- main timer (3) timed out 1 = yes ; |\-------- EEPROM write failure 1 = failed ; \--------- 1 = yes ; FLAGS4 ; 00000000 ; |||||||| ; |||||||\-- 1st pass for light level set-up 1 = yes ; ||||||\--- 1 = yes ; |||||\---- 1 = yes ; ||||\----- 1 = yes ; |||\------ 1 = yes ; ||\------- 1 = yes ; |\-------- 1 = yes ; \--------- 1 = yes ; INPUT1 ; 00000000 = INPUT STATUS REGISTER #1 ; |||||||| ; |||||||`- = . 1 = yes ; ||||||`-- = . 1 = yes ; |||||`--- = . 1 = yes ; ||||`---- = . 1 = yes ; |||`----- = . 1 = yes ; ||`------ = . 1 = yes ; |`------- = . 1 = yes ; `-------- = . 1 = yes ; SWSTAT switch status ; 0 = ; 0 = ; 0 = ; 0 = ; 0 = flag, allows off timer to run only once following a switch activation ; 0 = flag, set during window for double press ; 0 = flag, timing on period ; 0 = flag, timing off period ; INPUT2 ; 00000000 = INPUT STATUS REGISTER #2 ; |||||||| ; |||||||`- = . ; ||||||`-- = switch 1 ; |||||`--- = . ; ||||`---- = . ; |||`----- = switch 2 ; ||`------ = . ; |`------- = . ; `-------- = . ; SWACT switch activated (on-off) latched ; SWDBL switch double activation ; SWLONG switch long activation ;****************************************************************************** ;****************************************************************************** ;****************************************************************************** ;****************************************************************************** ;****************************************************************************** ;****************************************************************************** ;****************************************************************************** ;****************************************************************************** ORG 2007H ; DEVICE CONFIGURATION REGISTER CONFIG EQU 00000000011111B ; PIC16F84 ;****************************************************************************** ;****************************************************************************** ;* D E C L A R A T I O N S * ;****************************************************************************** ;****************************************************************************** ; REGISTER ASSIGNMENTS (indicates bank number, B = 1 & 2) W EQU 0000H ; F EQU 0001H ; INDF EQU 0000H ; 0 TMR0 EQU 0001H ; 0 TIMER 0 PCL EQU 0002H ; B PROGRAM COUNTER, LOWER 8 BITS STATUS EQU 0003H ; B STATUS FSR EQU 0004H ; B ? PORTA EQU 0005H ; 0 PORT A PORTB EQU 0006H ; 0 PORT B PCLATH EQU 000AH ; 0 PROGRAM COUNTER, UPPER 5 BITS INTCON EQU 000BH ; 0 INTERRUPT CONTROL OPTION EQU 0081H ; 1 OPTION TRISA EQU 0085H ; 1 DDRA TRISB EQU 0086H ; 1 DDRB PCON EQU 0087H ; 1 ;----- STATUS Bits -------------------------------------------------------- IRP EQU 7H ; 0 RP1 EQU 6H ; 0 RP0 EQU 5H ; 0 NOT_TO EQU 4H ; 0 NOT_PD EQU 3H ; 0 Z EQU 2H ; 0 DC EQU 1H ; 0 C EQU 0H ; 0 ;----- INTCON Bits -------------------------------------------------------- GIE EQU 7H ; B ADIE EQU 6H ; B TOIE EQU 5H ; B timer overflow interrupt enable INTE EQU 4H ; B port B RB0 interrupt enable RBIE EQU 3H ; B TOIF EQU 2H ; B INTF EQU 1H ; B RBIF EQU 0H ; B ;----- OPTION Bits -------------------------------------------------------- NOT_RBPU EQU 7H ; 1 INTEDG EQU 6H ; 1 T0CS EQU 5H ; 1 T0SE EQU 4H ; 1 PSA EQU 3H ; 1 PS2 EQU 2H ; 1 PS1 EQU 1H ; 1 PS0 EQU 0H ; 1 ;----- PCON Bits ---------------------------------------------------------- POR EQU 1H ; 1 BOR EQU 0H ; 1 ;----- Configuration Bits ------------------------------------------------- _BODEN_ON EQU 3FFFH ; _BODEN_OFF EQU 3FBFH ; _CP_ON EQU 004FH ; _CP_OFF EQU 3FFFH ; _PWRTE_OFF EQU 3FFFH ; _PWRTE_ON EQU 3FF7H ; _WDT_ON EQU 3FFFH ; _WDT_OFF EQU 3FFBH ; _LP_OSC EQU 3FFCH ; _XT_OSC EQU 3FFDH ; _HS_OSC EQU 3FFEH ; _RC_OSC EQU 3FFFH ; ;****************************************************************************** ; RAM VARIABLE ASSIGNMENTS ORG 000CH ; USER RAM ADDRESS FLAGS1 DFS 1 ; 0C ; GP FLAGS REGISTER #1 FLAGS2 DFS 1 ; 0D ; GP FLAGS REGISTER #2 FLAGS3 DFS 1 ; 0E ; GP FLAGS REGISTER #3 FLAGS4 DFS 1 ; 0F ; GP FLAGS REGISTER #4 TIC DFS 1 ; 10 ; Number of 10ms intervals/sec 0-99. SAV_W DFS 1 ; 14 ; PLACE TO SAVE W DURING INT SAV_ST DFS 1 ; 15 ; PLACE TO SAVE STAT DURING INT GPTIM1 DFS 1 ; 18 ; general purpose timer CNTR1 DFS 1 ; 19 ; config mode timer CNTR2 DFS 1 ; 1A ; ? OPDEL1 DFS 1 ; 1D ; short delay counter BEEPC1 DFS 1 ; 1E ; beep generation timer CTOUT DFS 1 ; 21 ; config timeout CDCNTR DFS 1 ; 22 ; count-down counter (time-out) INPUT1 DFS 1 ; 30 ; input status register INPUT2 DFS 1 ; 31 ; input status register LOADCNT DFS 1 ; 35 ; I2C variable RXDAT DFS 1 ; 36 ; I2C receive data byte TXDAT DFS 1 ; 37 ; I2C transmit data byte I2CADD DFS 1 ; 38 ; I2C address I2CWRK DFS 1 ; 39 ; I2C working register BITCNT DFS 1 ; 3A ; I2C bit counter RDBCNT DFS 1 ; 3B ; I2C read byte counter TMP1 DFS 1 ; 3C ; temp value #1 TMP2 DFS 1 ; 3D ; temp value #2 CFG1 DFS 1 ; 3F ; config flags (from EEPROM) CFG2 DFS 1 ; 40 ; (from EEPROM) CFG3 DFS 1 ; 41 ; (from EEPROM) CFG4 DFS 1 ; 42 ; (from EEPROM) PAUL DFS 1 ; 43 ; debug variable ; end = 4F ;****************************************************************************** ;****************************************************************************** ; CONSTANTS ;****************************************************************************** ;****************************************************************************** EXT_IO EQU 0H ; PORT B output diagnostic output RELAY_1 EQU 1H ; PORT B output relay RELAY_2 EQU 2H ; PORT B output relay LED_GN EQU 3H ; PORT B output LED (green) LED_RD EQU 4H ; PORT B output LED (red) IO_B5 EQU 5H ; PORT B input IO_B6 EQU 6H ; PORT B input IO_B7 EQU 7H ; PORT B input IO_A0 EQU 0H ; PORT A input IO_A1 EQU 1H ; PORT A input DAT_I2C EQU 2H ; PORT A input I2C data line CLK_I2C EQU 3H ; PORT A output I2C clock line RTC_I2C EQU 4H ; PORT A output RTC/I2C DDRA EQU 00000111B ; PORT-A data direction default DDRB EQU 11100000B ; PORT-B data direction default ;****************************************************************************** ;****************************************************************************** ;****************************************************************************** ;****************************************************************************** ;****************************************************************************** ;****************************************************************************** ;****************************************************************************** ;****************************************************************************** ;* R E S E T A N D I N T E R R U P T V E C T O R S * ;****************************************************************************** ORG 0000H ; RESET VECTOR GOTO START ORG 0004H ; INTERRUPT VECTOR GOTO ISR ;****************************************************************************** ;****************************************************************************** ;****************************************************************************** ;****************************************************************************** ;****************************************************************************** ;****************************************************************************** ;****************************************************************************** ;****************************************************************************** ; P R O G R A M C O D E S T A R T S H E R E ;****************************************************************************** ; INITALISATION CODE START BCF INTCON,GIE ; DISABLE GLOBAL INTERRUPTS BTFSC INTCON,GIE ; ensure global interrupt disabled GOTO START ; not disabled BSF STATUS,RP0 ; select bank 1 MOVLW DDRA ; default data direction MOVWF TRISA ; Port A DDR MOVLW DDRB ; default data direction MOVWF TRISB ; Port B DDR ( varies during operation) MOVLW 01000111B ; pullups; int on +ve edge, Prescale=256 on timer MOVWF OPTION BCF STATUS,RP0 ; select bank 0 MOVLW 00000000B ; port A outputs, default state MOVWF PORTA ; write MOVLW 00000000B ; port B outputs, default state MOVWF PORTB ; write BCF INTCON,RBIF ; clear RB int flag BSF INTCON,TOIE ; enable timer overflow interrupt ;************ ; CLEAR RAM MOVLW 0CH ; last byte of RAM MOVWF FSR ; indirect addressing register START1 CLRF INDF ; clear byte INCF FSR,F ; next address MOVLW 4FH ; last byte (+1) SUBWF FSR,W ; check BTFSS STATUS,Z ; finished GOTO START1 ; next byte ;************ ; preset variables & config MOVLW 240D ; 240 = 10ms timeout MOVWF TMR0 ; preload timer. BCF PORTA,RTC_I2C ; make low for EEPROM BSF INTCON,GIE ; global interrupt enable ;************ ; startup ; CALL LOADCFG ; load defaults from EEPROM CALL RTCINI ; initalise RTC ;****************************************************************************** ;****************************************************************************** ;****************************************************************************** ;****************************************************************************** ;****************************************************************************** ;****************************************************************************** ;****************************************************************************** ;****************************************************************************** ; M A I N P R O G R A M L O O P ;****************************************************************************** CORE CLRWDT ; reset watchdog timer ;------------------------------------------------------ ; main core loop functions ;------------------------------------------------------ ;------------------------------------------------------ ; end of core loop ;------------------------------------------------------ CORE99 GOTO CORE ; loop core ;************************END OF MAIN LOOP**************************** ;****************************************************************************** ;****************************************************************************** ;****************************************************************************** ;****************************************************************************** ;****************************************************************************** ;****************************************************************************** ;****************************************************************************** ;****************************************************************************** ; I N T E R R U P T S E R V I C E ;****************************************************************************** ; This Handler routes interrupts to the correct ISR. ;****************************************************************************** ; Push Status and W register to preserve core processing ISR MOVWF SAV_W ; save "W" for return MOVF STATUS,W ; MOVWF SAV_ST ; save "STATUS" for return ; determine interrupt source BTFSC INTCON,TOIF ; test flag? CALL ISR_TO ; timer interrupt service routine BTFSC INTCON,INTF ; test flag? CALL ISR_INT ; external interrupt service routine ; diagnostic o/p ISR_99 MOVF FLAGS1,W ; CALL DAT_TX ; diagnostic TX MOVF FLAGS2,W ; CALL DAT_TX ; diagnostic TX MOVF FLAGS3,W ; CALL DAT_TX ; diagnostic TX ; first pass complete BCF FLAGS4,0 ; 1st pass complete ; restore Status and W registers MOVF SAV_ST,W MOVWF STATUS ; restore STATUS MOVF SAV_W,W ; restore W RETFIE ; return, enabling global INT ; GP subroutine to disable interrupts INT_OFF BCF INTCON,GIE ; disable global interrupts BTFSC INTCON,GIE ; ensure global interrupt disabled GOTO INT_OFF ; not disabled ; CLRWDT ; reset watchdog timer RETURN ; done ;****************************************************************************** ; EXTERNAL INTERRUPT SERVICE ROUTINE ;****************************************************************************** ISR_INT BCF INTCON,INTF ; clear external interrupt flag BCF INTCON,INTE ; disable external interrupt RETURN ; finished ;****************************************************************************** ; TIMER OVERFLOW INTERRUPT SERVICE ;****************************************************************************** ISR_TO BCF INTCON,TOIF ; clear TO Interrupt Flag ; 10ms=10,000us ; 10,000 /256 = 39.025 MOVLW 217D ; 256-39 = 217, 39counts=10ms MOVWF TMR0 ; restore timer value for next interval RETURN ; finished ;****************************************************************************** ;****************************************************************************** ;****************************************************************************** ;****************************************************************************** ;****************************************************************************** ;****************************************************************************** ;****************************************************************************** ;****************************************************************************** ; G E N E R A L S U B R O U T I N E S ;****************************************************************************** ; add more here ;************************************************************************ ; LOAD/SAVE EEPROM CONFIGURATION ;************************************************************************ ; Load configuration from EEPROM to RAM LOADCFG CALL INTOFF ; interrupts disabled MOVLW 00H ; set address to read MOVWF I2CADD ; " MOVLW 01D ; set byte counter to 01 MOVWF RDBCNT ; " MOVLW CFG1 ; set address to put data MOVWF FSR ; " BSF FLAGS1,0 ; dummy write, sets address CALL EE_WR ; write eeprom BCF FLAGS1,4 ; clr flag (multiple bytes read) CALL EE_RD ; read byte/s now CALL INTON ; interrupts enabled RETURN ; done ;************ ; Save configuration from RAM to EEPROM SAVECFG MOVF CFG1,W ; get data MOVWF TXDAT ; data to save MOVLW 00H ; set address to write MOVWF I2CADD ; " CALL EE_WRV ; write and verify 1 byte ; done RETURN ;************************************************************************ ; INTERRUPT ENABLE/DISABLE ;************************************************************************ INTON BSF INTCON,GIE ; global interrupt enable RETURN ; done ;************ INTOFF BCF INTCON,GIE ; disable global interrupt BTFSC INTCON,GIE ; ensure global interrupt disabled GOTO INTOFF ; not disabled RETURN ; done ;************************************************************************ ;************************************************************************ ;************************************************************************ ;************************************************************************ ;************************************************************************ ; RTC SUBROUTINES ;************************************************************************ ;************************************************************************ ;************************************************************************ ;************************************************************************ ;************************************************************************ ; RTC Initalisation ; This routine will enable the RTC clock. ; write enable RTCINI BSF PORTA,RTC_I2C ; set reset high MOVLW 10001110B ; command byte (111-write) CALL RTCTX ; send command byte MOVLW 00000000B ; data byte CALL RTCTX ; send byte BCF PORTA,RTC_I2C ; set reset low ; enable osc. CALL BIT_DLY ; short delay BSF PORTA,RTC_I2C ; set reset high MOVLW 10000000B ; command byte (000-write) CALL RTCTX ; send command byte MOVLW 00000000B ; data byte (enable) CALL RTCTX ; send byte BCF PORTA,RTC_I2C ; set reset low ; finished RETURN ; finished ;****************************************************************************** ;****************************************************************************** ; RTC ROUTINES (low level) ;****************************************************************************** ;****************************************************************************** ; These subroutines handle communications with the RTC device. ; DATA line must have a pullup to +5v ; CLOCK line is always an output ; These are the low level routines. ; RTCRX receive byte from slave (returned in "RXDAT") ; RTCTX transmit byte to slave (from "W") ;************************************************************************ ; SEND DATA BYTE IN "W" TO RTC ; Single byte transmission to RTC (LSB first) ; The data is changed while the clock is low, the clock is then ; pulsed high. ; This routine does not include taking the RTC reset line high during ; data transfer. ; Call with the data byte to send in "W". RTCTX MOVWF I2CWRK ; move to working register (for RLF) BSF STATUS,RP0 ; select bank 1 BCF TRISA,DAT_I2C ; data line = output BCF STATUS,RP0 ; select bank 0 MOVLW 08D ; bit count MOVWF BITCNT ; counter ; write RTCTX1 CLRWDT ; reset watchdog timer RRF I2CWRK,F ; move bit to carry BTFSS STATUS,C ; GOTO RTCTX2 ; BSF PORTA,DAT_I2C ; data = 1 GOTO RTCTX3 ; RTCTX2 BCF PORTA,DAT_I2C ; data = 0 RTCTX3 CALL BIT_DLY ; bit delay BSF PORTA,CLK_I2C ; set clock bit CALL BIT_DLY ; bit delay BCF PORTA,CLK_I2C ; clear clock bit DECFSZ BITCNT,F ; decrement bit counter GOTO RTCTX1 ; next bit ; finished BSF STATUS,RP0 ; select bank 1 BSF TRISA,DAT_I2C ; data line = input BCF STATUS,RP0 ; select bank 0 BSF PORTA,DAT_I2C ; return data line to rest state BSF PORTA,CLK_I2C ; set clock bit CALL BIT_DLY ; bit delay BCF PORTA,CLK_I2C ; clear clock bit RETURN ; finished ;************ ; RECEIVE DATA BYTE TO "DIN" (PIC) ; Single byte reception from RTC (LSB first) returned in "RXDAT" ; Data from the RTC is valid following the falling edge of the clock. ; Data should be read on the rising edge of the clock. RTCRX BSF STATUS,RP0 ; select bank 1 BSF TRISA,DAT_I2C ; data line = input BCF STATUS,RP0 ; select bank 0 MOVLW 08D ; bit count MOVWF BITCNT ; counter ; read RTCRX1 CLRWDT ; reset watchdog timer BSF PORTA,CLK_I2C ; set clock bit CALL BIT_DLY ; bit delay BTFSC PORTA,DAT_I2C ; test data bit GOTO RTCRX2 ; high = set carry BCF STATUS,C ; clear the carry GOTO RTCRX3 ; RTCRX2 BSF STATUS,C ; set the carry RTCRX3 RRF RXDAT,F ; move data in from carry BCF PORTA,CLK_I2C ; clear clock bit CALL BIT_DLY ; bit delay DECFSZ BITCNT,F ; decrement bit counter GOTO RTCRX1 ; next bit ; finished RETURN ; finished ;************************************************************************ ;************************************************************************ ;************************************************************************ ;************************************************************************ ;************************************************************************ ; SERIAL EEPROM SUBROUTINES ;************************************************************************ ;************************************************************************ ;************************************************************************ ;************************************************************************ ;************************************************************************ ; WRITE 1 BYTE & VERIFY ; The data byte must already be in "TXDAT". ; The address to write to must already be in "I2CADD". EE_WRV MOVLW 05D ; write attempt count MOVWF LOADCNT ; counter EE_V1 BCF FLAGS1,0 ; ensure normal-write CALL EE_WR ; normal write BSF FLAGS1,0 ; dummy-write to reset the address CALL EE_WR ; dummy-write now BSF FLAGS1,4 ; set flag (read 1 byte) CALL EE_RD ; read data byte MOVF RXDAT,W ; get received data SUBWF TXDAT,W ; compare BTFSC STATUS,Z ; GOTO EE_V9 ; verify pass DECFSZ LOADCNT,F ; attempt counter GOTO EE_V1 ; retry ; fail EE_V8 BSF FLAGS3,6 ; flag EEPROM write failure RETURN ; finished ; pass EE_V9 BCF FLAGS3,6 ; flag EEPROM write passed RETURN ; finished ;************ ; WRITE 1 BYTE TO EEPROM ; The byte in "TXDAT" is written to the address in "I2CADD". ; This routine sends the device select byte and the address before the data to ; be written. ; A dummy-write is achieved by first setting (BSF FLAGS1,0) ; A dummy-write sends only the device select byte, address byte and stop. ; A data write also sends a data byte before the stop and waits for programming ; to complete before returning. ; The bytes are transfered to "W" for actual sending (I2CTX subroutine). EE_WR CALL I2CST ; generate start MOVLW 10100000B ; I2C device address into W CALL I2CTX ; send device address MOVF I2CADD,W ; get write address into W CALL I2CTX ; send address byte BTFSC FLAGS1,0 ; dummy write ? GOTO EE_WR1 ; skip (dummy write to set address) MOVF TXDAT,W ; get data into W CALL I2CTX ; send data byte EE_WR1 CALL I2CSTOP ; generate stop BTFSS FLAGS1,0 ; dummy write ? CALL DEL60 ; write delay EE_WR2 BCF FLAGS1,0 ; clr flag RETURN ; finished ;************ ; READ DATA FROM EEPROM ; The EEPROM address to be read is set with a dummy write (see EE_WR). ; The first address to read is passed in "I2CADD". ; The data read is saved, FSR indexed & consecutive bytes. ; If FLAGS1,4 is set, only 1 byte is read & returned in RXDAT (for verify) ; FSR register is incremented, unless FLAGS1,4 is set. ; The number of bytes to be read is set by RDBCNT (defaults to 1) ; read example ; MOVLW ??? ; set address to read ; MOVWF I2CADD ; " ; MOVLW 03D ; set byte counter to 03 optional ; MOVWF RDBCNT ; " " ; MOVLW DUSK ; set address to put data ; MOVWF FSR ; " ; BSF FLAGS1,0 ; dummy write, sets address ; CALL EE_WR ; write eeprom ; BCF FLAGS1,4 ; clr flag (multiple bytes read) ; CALL EE_RD ; read byte/s now ; start EE_RD CALL I2CST ; generate start ; send address MOVLW 10100001B ; I2C device address into W CALL I2CTX ; send device address ; read data EE_RD1 CALL I2CRX ; read data byte BTFSC FLAGS1,4 ; set = read only 1 byte GOTO EE_RD2 ; clear = read multiple bytes MOVF RXDAT,W ; save data byte MOVWF INDF ; " INCF FSR,F ; next address DECFSZ RDBCNT,F ; byte counter GOTO EE_RD3 ; continue ; stop EE_RD2 CALL I2CSTOP ; generate stop BSF FLAGS1,4 ; read only one byte RETURN ; finished ; ack EE_RD3 CALL I2CACK ; send ACK GOTO EE_RD1 ; read next byte ;****************************************************************************** ;****************************************************************************** ; I2C ROUTINES (low level) ;****************************************************************************** ;****************************************************************************** ; These subroutines handle communications with I2C slave devices. ; these can include: ; 24C02 EEPROM (address = 1010xxxd) ; 24C04 EEPROM (address = 1010xxxd) ; DATA line must have a pullup to +5v ; CLOCK line is always an output ; These are the low level routines. ; I2CST generate start condition ; I2CRX receive byte from slave (returned in "RXDAT") ; I2CTX transmit byte to slave (from "TXDAT") ; I2CACK generate acknowledge ; I2CNAK generate negative acknowledge ; I2CSTOP generate stop condition ; BIT_DLY I2C bit delay (adjust for clock speed)(10D = 4MHz) ;************************************************************************ ;************ ; GENERATE I2C START CONDITION (PIC) ; make DATA high to low while CLOCK high I2CST BSF STATUS,RP0 ; select bank 1 BCF TRISA,DAT_I2C ; data line = output BCF STATUS,RP0 ; select bank 0 BSF PORTA,CLK_I2C ; set clock bit BSF PORTA,DAT_I2C ; ensure data bit = high CALL BIT_DLY ; bit delay BCF PORTA,DAT_I2C ; make data bit = low CALL BIT_DLY ; bit delay BCF PORTA,CLK_I2C ; clear clock bit RETURN ; finished ;************ ; SEND DATA BYTE IN "W" (PIC) ; Single byte transmission to I2C slave (MSB first) ; The data is changed while the clock is low, the clock is then ; pulsed high. ; W holds the data byte to send. I2CTX MOVWF I2CWRK ; move to working register (for RLF) BSF STATUS,RP0 ; select bank 1 BCF TRISA,DAT_I2C ; data line = output BCF STATUS,RP0 ; select bank 0 MOVLW 08D ; bit count MOVWF BITCNT ; counter I2CTX1 CLRWDT ; reset watchdog timer RLF I2CWRK,F ; move bit to carry BTFSS STATUS,C ; GOTO I2CTX2 ; BSF PORTA,DAT_I2C ; data = 1 GOTO I2CTX3 ; I2CTX2 BCF PORTA,DAT_I2C ; data = 0 I2CTX3 CALL BIT_DLY ; bit delay BSF PORTA,CLK_I2C ; set clock bit CALL BIT_DLY ; bit delay BCF PORTA,CLK_I2C ; clear clock bit DECFSZ BITCNT,F ; decrement bit counter GOTO I2CTX1 ; next bit BSF STATUS,RP0 ; select bank 1 BSF TRISA,DAT_I2C ; data line = input BCF STATUS,RP0 ; select bank 0 BSF PORTA,DAT_I2C ; return data line to rest state BSF PORTA,CLK_I2C ; set clock bit CALL BIT_DLY ; bit delay ; SAMPLE ACK HERE IF REQUIRED BCF PORTA,CLK_I2C ; clear clock bit RETURN ; finished ;************ ; RECEIVE DATA BYTE TO "DIN" (PIC) ; Single byte reception from I2C slave (MSB first) returned in "RXDAT" ; Data from the slave is valid following the falling edge of the clock. ; Data should be read on the rising edge of the clock. ; Data is returned in RXDAT. I2CRX BSF STATUS,RP0 ; select bank 1 BSF TRISA,DAT_I2C ; data line = input BCF STATUS,RP0 ; select bank 0 MOVLW 08D ; bit count MOVWF BITCNT ; counter ; read I2CRX1 CLRWDT ; reset watchdog timer BSF PORTA,CLK_I2C ; set clock bit CALL BIT_DLY ; bit delay BTFSC PORTA,DAT_I2C ; test data bit GOTO I2CRX2 ; high = set carry BCF STATUS,C ; clear the carry GOTO I2CRX3 ; I2CRX2 BSF STATUS,C ; set the carry I2CRX3 RLF RXDAT,F ; move data in from carry BCF PORTA,CLK_I2C ; clear clock bit CALL BIT_DLY ; bit delay DECFSZ BITCNT,F ; decrement bit counter GOTO I2CRX1 ; next bit RETURN ; finished ;************ ; SEND ACK (PIC) ; Sends I2C acknowledge (after each received byte) ; A & X are unchanged I2CACK BSF STATUS,RP0 ; select bank 1 BCF TRISA,DAT_I2C ; data line = output BCF STATUS,RP0 ; select bank 0 BCF PORTA,DAT_I2C ; data = 0 CALL BIT_DLY ; bit delay BSF PORTA,CLK_I2C ; set clock bit CALL BIT_DLY ; bit delay BCF PORTA,CLK_I2C ; clear clock bit CALL BIT_DLY ; bit delay RETURN ; finished ;************ ; SEND NACK + STOP CONDITION (PIC) ; Sends I2C negative acknowledge (on completion of receive) ; A & X are unchanged I2CNAK BSF STATUS,RP0 ; select bank 1 BCF TRISA,DAT_I2C ; data line = output BCF STATUS,RP0 ; select bank 0 BSF PORTA,DAT_I2C ; data = 1 BSF PORTA,CLK_I2C ; set clock bit CALL BIT_DLY ; bit delay BCF PORTA,CLK_I2C ; clear clock bit ;************ ; SEND STOP CONDITION (PIC) ; make DATA low to high while CLK high ; A & X are unchanged I2CSTOP BSF STATUS,RP0 ; select bank 1 BCF TRISA,DAT_I2C ; data line = output BCF STATUS,RP0 ; select bank 0 BCF PORTA,DAT_I2C ; data = 0 CALL BIT_DLY ; bit delay BSF PORTA,CLK_I2C ; set clock bit CALL BIT_DLY ; bit delay BSF PORTA,DAT_I2C ; data = 1 BSF STATUS,RP0 ; select bank 1 BSF TRISA,DAT_I2C ; data line = input BCF STATUS,RP0 ; select bank 0 RETURN ; finished ;************ ; I2C BIT DELAYS (PIC) ; bit delay (depends on clock speed) BIT_DLY MOVLW 10D ; delay time MOVWF GPTIM1 ; counter BDEL1 CLRWDT ; reset watchdog timer DECFSZ GPTIM1,F ; test counter GOTO BDEL1 ; loop RETURN ; finished ;************************************************************************ ; Short Delays ;************************************************************************ ; 60mS (+ or - 10mS) (RTI based) DEL60 MOVLW 06D ; delay time MOVWF GPTIM1 ; counter DEL601 CLRWDT ; reset watchdog timer MOVF GPTIM1,F ; test counter BTFSS STATUS,Z ; GOTO DEL601 ; loop RETURN ; finished ; 2 SEC (+ or - 10mS) (RTI based) DEL25S MOVLW 25D ; delay time (0.25 seconds) MOVWF GPTIM1 ; counter GOTO DEL2S1 ; continue DEL2S MOVLW 200D ; delay time (2 seconds) MOVWF GPTIM1 ; counter DEL2S1 CLRWDT ; reset watchdog timer MOVF GPTIM1,F ; test counter BTFSS STATUS,Z ; GOTO DEL2S1 ; loop RETURN ; finished ;****************************************************************************** ;****************************************************************************** ;****************************************************************************** ;****************************************************************************** ;****************************************************************************** ; Data I/O ROUTINES (debug) ;****************************************************************************** ;****************************************************************************** ;****************************************************************************** ;****************************************************************************** ;****************************************************************************** ; Send data in W out via external I/O. ; 8 bits, short pulse = low, long pulse = high, MSB first. DAT_TX MOVWF TMP2 ; data to send MOVLW 8 ; bit counter MOVWF TMP1 ; " BCF PORTB,EXT_IO ; make output low NOP ; 1 bit delay DATTX1 BSF PORTB,EXT_IO ; make output high RLF TMP2,F ; get data bit BTFSS STATUS,C ; test BCF PORTB,EXT_IO ; make data low NOP ; 3 bit delay NOP ; " NOP ; " BCF PORTB,EXT_IO ; make data low NOP ; 1 bit delay DECFSZ TMP1,F ; bit count -1 GOTO DATTX1 ; loop MOVF TMP2,W ; restore W RETURN ;************************************************************************ ; misc ;************************************************************************ ; copyright notice ORG 03E0H ; address MSG1 DFB "4G4P4C4_444A444 404V40414 " ; GPC_4A4 0V01 RETLW 00H MSG2 DFB "4(4C4)4 4P4M4B4 42404042" ; (C) PMB 2002 RETLW 00H END