⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 i2c.asm

📁 Training embedded apps to process speech may be as easy as finding the right 8-bit micro. Don t let
💻 ASM
字号:
;#define  TWENTYMHZ  
;#define TENMHZ
#define FOURMHZ
; If the operation is successful, bit 7 of PC_OFFSET will be set, and
; the functions will return W=1.  If the memory is busy with a write
; cycle, it will not ACK the command.  The functions will return with
; bit 7 of PC_OFFSET cleared and and W will be set to 0.
;
; Must reside on the lower half of code page (address 0-FF).
; 
; Conditional assembly delays are included to meet standard mode timing
; specs.  For 4Mhz, define FOURMHZ at top of file.  For 10 Mhz, define ; TENMHZ. Applications running at slower clock rates & those operating
; within 4.5-5.5V may be able to remove some of the NOPs/Delay calls.
;
;********************************************************************** 
;***********************  EEPROM Subroutines  *************************
;********************************************************************** 
; Communication for EEPROM based on I2C protocol, with Acknowledge.
;
; Byte_Write: Byte write routine
;       Inputs:  EEPROM Address   EEADDR
;                EEPROM Data      EEDATA
;       Outputs: Return 01 in W if OK, else return 00 in W
;
; Page_Write: Page write routine - writes up to 8 bytes at a time
;       Inputs:  FSR    points to beginning of RAM buffer.
;		 W      number of bytes to write
;		 EEPROM Address   EEADDR
;                EEPROM Data      EEDATA
;       Outputs: Return 01 in W if OK, else return 00 in W
;
; Read_Current: Read EEPROM at address currently held by EE device. 
;       Inputs:  NONE
;       Outputs: EEPROM Data       EEDATA
;                Return 01 in W if OK, else return 00 in W
;
; Read_Random: Read EEPROM byte at supplied address
;       Inputs:  EEPROM Address    EEADDR
;       Outputs: EEPROM Data       EEDATA
;                Return 01 in W if OK, else return 00 in W
;
; Note: EEPROM subroutines will set bit 7 in PC_OFFSET register if the
;       EEPROM acknowledged OK, else that bit will be cleared.  This  
;       bit can be checked instead of refering to value returned in W
;
;	EEinterface file registers (EEAddress, EEDATA) are in common ram.
;	EEINTF file register is on Register Page 1.  Upon exit, Register
;	page is set to 0.
;********************************************************************** 
;
; OPERATION:
;     Byte Write:
;       load EEADDR and EEDATA
;       then CALL WRITE_BYTE
;
;     Page Write:
;	Load EEADDR
;	Load FSR with address of 1st byte to transfer
;	Load W with number of bytes to transfer (8 bytes max)
;	then CALL WRITE_PAGE
;
;     Read Random:
;       Load EEADDR
;       then CALL READ_RANDOM
;       data read returned in EEDATA
;
;     Read Current
;       no setup necessary
;       CALL READ_CURRENT
;       data read returned in EEDATA
;
;********************************************************************** 
;************************  Variable Listing  **************************
;********************************************************************** 
OK          EQU     01H
NO          EQU     00H

EE_OK       EQU     07H       ; Bit 7 in PC_OFFSET used as OK flag

cram	udata
EEADDR      res     1         ; EEPROM Address
EEDATA      res     1         ; EEPROM Data
EEBYTE      res     1         ; Byte sent to or received from
				; EEPROM (control, address, or data)
bytecount   res     1         ; # of bytes to write
COUNTER     res     1         ; Bit counter for serial transfer
PC_OFFSET   RES     1		; PC offset register (low order 4 bits), 
				;  value based on operating mode of EEPROM.
				;  Also, bit 7 used for EE_OK flag

;******************* Set up EEPROM control bytes **********************
;********************************************************************** 

READ_CURRENT
	MOVLW   B'10000100'	; PC offset for read current addr.
	MOVWF   PC_OFFSET 	; Load PC offset
	BSF	  STATUS,RP0	; set register page 1
	clrf	  PCLATH		
	GOTO    INIT_READ_CONTROL

WRITE_BYTE
	MOVLW   B'10000000'   ; PC offset for write byte.
	GOTO    INIT_WRITE_CONTROL

WRITE_PAGE
	movwf	  bytecount	; save off number of bytes to send
	MOVLW	  B'10000111'   ; PC offset for write page.  EE_OK bit = 1
	goto	  INIT_WRITE_CONTROL

READ_PAGE
	movwf	  bytecount	; save off number of bytes to send
	MOVLW	  B'10001010'   ; PC offset for read page.  EE_OK bit = 1
	goto	  INIT_WRITE_CONTROL

READ_RANDOM
	MOVLW   B'10000011'   ; PC offset for read random.

INIT_WRITE_CONTROL
	MOVWF   PC_OFFSET     ; Load PC offset register,value preset in W
	MOVLW   B'10100000'   ; Control byte with write bit, bit 0 = '0'
  
START_BIT
	BSF	  STATUS,RP0	; set register page 1
	clrf	  PCLATH		
	BCF     EEINTF,EESDA  ; Start bit, EESDA and EESCL preset to '1'

;******* Set up output data (control, address, or data) and counter 
;********************************************************************** 
PREP_TRANSFER_BYTE
	MOVWF   EEBYTE        ; Byte to transfer to EEPROM already in W
	MOVLW   .8            ; Counter to transfer 8 bits
	MOVWF   COUNTER

;************  Clock out data (control, address, or data) byte  
;********************************************************************** 
OUTPUT_BYTE
#ifdef  FOURMHZ
        NOP
#endif
#ifdef  TENMHZ
        call    delay8        
#endif
#ifdef  TWENTYMHZ
        call    delay16
#endif
        RLF     EEBYTE, F     ; Rotate left,high order bit into carry 
        BCF     EEINTF,EESCL  ; Set clock low during data set-up
	
        BCF     EEINTF,EESDA  ; Set data low, if rotated carry bit is
        SKPNC                 ;   a '1', then:
        BSF     EEINTF,EESDA  ; reset data pin to one, else leave low
#ifdef  FOURMHZ
        NOP
#endif
#ifdef  TENMHZ
        call    delay8        ; Tlow 4700 nS (add 6 cycles at 10 Mhz)
#endif
#ifdef  TWENTYMHZ
        call    delay16        ; Tlow 4700 nS (add 6 cycles at 10 Mhz)
#endif
        BSF     EEINTF,EESCL  ; clock data into EEPROM
        DECFSZ  COUNTER, F    ; Repeat until entire byte is sent
        GOTO    OUTPUT_BYTE
#ifdef  FOURMHZ
       NOP                   ; Needed to meet Timing (Thigh=4000nS)
#endif
#ifdef  TENMHZ
        call    delay8
#endif
#ifdef  TWENTYMHZ
        call    delay16        ; Tlow 4700 nS (add 6 cycles at 10 Mhz)
#endif

;***********************  Acknowledge Check ***************************
;********************************************************************** 

        BCF     EEINTF,EESCL  ; Set EESCL low, 0.5us < ack valid < 3us
#ifdef  FOURMHZ
       NOP                   ; Needed to meet Timing (Tlow= 4700nS)
#endif
#ifdef  TENMHZ
        goto    $+1
#endif
#ifdef  TWENTYMHZ
        call    delay4
#endif
        BSF     EEINTF,EESDA    ; set data line high to check for ack
#ifdef  FOURMHZ
        GOTO    $+1       
#endif
#ifdef  TENMHZ
        call    delay6  ; Necessary for EESCL Tlow at low voltage
#endif
#ifdef  TWENTYMHZ
        call    delay12
#endif

        BSF     EEINTF,EESCL  ; Raise EESCL, EEPROM ack still valid
#ifdef  FOURMHZ
        NOP                   ; Tsu:dat (allow time for ack setup)
#endif
#ifdef  TENMHZ
        call    delay4
#endif
#ifdef  TWENTYMHZ
        call    delay8
#endif
        BTFSC   EEINTF,EESDA  ; Check EESDA for acknowledge (low)
        BCF     PC_OFFSET,EE_OK ; If EESDA high (no ack), set err flag
#ifdef  TENMHZ
        call    delay4
#endif
#ifdef  TWENTYMHZ
        call    delay8
#endif
        BCF     EEINTF,EESCL    ; Lower EESCL, EEPROM release bus
        BTFSS   PC_OFFSET,EE_OK ; If no error continue, else stop bit
        GOTO    STOP_BIT


;*****  Set up program counter offset, based on EEPROM operating mode  
;********************************************************************** 
STATEMACHINE

        MOVF    PC_OFFSET,W
        ANDLW   B'00001111'
        ADDWF   PCL, F
	  GOTO    INIT_ADDRESS    ;PC offset=0, write ctrl done,send addr
	GOTO    INIT_WRITE_DATA   ;PC offset=1, write addr done,send data
	GOTO    STOP_BIT          ;PC offset=2, write done, send stop bit
	GOTO    INIT_ADDRESS      ;PC offset=3, write ctrl done,send addr
	GOTO    INIT_READ_CONTROL ;PC offset=4, send read control
	GOTO    READ_BIT_COUNTER  ;PC offset=5, set counter and read byte
	GOTO    STOP_BIT          ;PC offset=6, random rd done,send stop
	GOTO    INIT_ADDRESS      ;PC offset=7, write ctrl done,send addr
	GOTO    INIT_WRITE_PAGE_DATA ;PC offset=8, wrt addr done,send dat
	GOTO    STOP_BIT          ;PC offset=9, write done, send stop bit
	GOTO    INIT_ADDRESS      ;PC offset=A, write ctrl done,send addr
	GOTO    INIT_READ_PAGE_CONTROL;PC offset=B,wrt addr done,send dat
	GOTO    READ_PAGE_BIT_COUNTER;PC offset=C, set counter &read byte


;**********  Initalize EEPROM data (address, data, or control) bytes  
;********************************************************************** 
INIT_ADDRESS
	INCF    PC_OFFSET, F ; Incr PC offset to 2 (write) or 4 (read)
	MOVF    EEADDR,W     ; Put EEPROM address in W, ready to send to EEPROM
	GOTO    PREP_TRANSFER_BYTE

INIT_WRITE_DATA
	INCF    PC_OFFSET, F ; Increment PC offset to go to STOP_BIT next
	MOVF    EEDATA,W     ; Put EEPROM data in W, ready to send to EE
	GOTO    PREP_TRANSFER_BYTE

INIT_WRITE_PAGE_DATA
	DECFSZ	bytecount,f	; count byte tx'd
	GOTO	$+2		; 
	INCF    PC_OFFSET, F    ; Increment PC offset, goto STOP_BIT next
	movf	INDF,W
	INCF	FSR,F		; bump pointer
	GOTO    PREP_TRANSFER_BYTE

INIT_READ_CONTROL
	BSF     EEINTF,EESCL ; Raise EESCL
	BSF     EEINTF,EESDA ; raise EESDA
	INCF    PC_OFFSET, F ; Increment PC offset to go to READ_BIT_COUNTER next
	MOVLW   B'10100001'  ; Set up read control byte, ready send to EE
	GOTO    START_BIT    ;   bit 0 = '1' for read operation


INIT_READ_PAGE_CONTROL
	BSF     EEINTF,EESCL ; Raise EESCL
	BSF     EEINTF,EESDA ; raise EESDA
	INCF    PC_OFFSET, F ; Increment PC offset to go to READ_BIT_COUNTER next
	MOVLW   B'10100001'  ; Set up read control byte,ready send to EE
	GOTO    START_BIT    ;   bit 0 = '1' for read operation

;***********************  Read EEPROM data  ***************************
;********************************************************************** 
READ_PAGE_BIT_COUNTER
	BSF     EEINTF,EESDA ; set bit to 1,  don't pull bus down.
	MOVLW   .8           ; Set counter,8 bits will be read in EEDATA
	MOVWF   COUNTER

READ_BYTE_RPC
#ifdef  TENMHZ
        call    delay6
#endif
#ifdef  TWENTYMHZ
        call    delay12
#endif
	BSF     EEINTF,EESCL ; Raise SCL,SDA valid. SDA input from ack
	SETC                 ; Assume bit to be read = 1
#ifdef  TENMHZ
        call    delay6
#endif
#ifdef  TWENTYMHZ
        call    delay12
#endif
	BTFSS   EEINTF,EESDA ; Check if EESDA = 1
	CLRC                 ; if EESDA not = 1 then clear carry bit
	RLF     EEDATA, F    ; rotate carry bit (=EESDA) into EEDATA;
	BCF     EEINTF,EESCL ; Lower EESCL
	NOP
	BSF     EEINTF,EESDA ; reset EESDA
	DECFSZ  COUNTER, F   ; Decrement counter
	GOTO    READ_BYTE_RPC; Read next bit if not finished reading byte

	movf	EEDATA,w
	movwf	INDF		; write data to buffer
	incf	FSR,f		; increment buffer pointer
	decfsz	bytecount,f
	GOTO	SEND_ACK
	GOTO	SEND_NAK	; skip next 2 instructions
SEND_ACK
	BCF	EEINTF,EESDA	; Send an ACK (More reads to come)
	BSF     EEINTF,EESCL	; 
	NOP
	BCF     EEINTF,EESCL
	GOTO	READ_PAGE_BIT_COUNTER	
SEND_NAK
	BSF	EEINTF,EESDA	; Send an ACK (More reads to come)
	BSF     EEINTF,EESCL	; 
	NOP
	BCF     EEINTF,EESCL
	GOTO	STOP_BIT	; skip next 2 instructions
	
; end read page bit control

READ_BIT_COUNTER
	BSF     EEINTF,EESDA ; set data bit to 1, don't pull bus down.
	MOVLW   .8           ; Set counter so 8 bits will be read into EEDATA
	MOVWF   COUNTER

READ_BYTE_RBC
#ifdef  TENMHZ
        call    delay6
#endif
#ifdef  TWENTYMHZ
        call    delay12
#endif
	BSF     EEINTF,EESCL ; Raise SCL,SDA valid. SDA input from ack
	SETC                 ; Assume bit to be read = 1
#ifdef  TENMHZ
        call    delay6
#endif
#ifdef  TWENTYMHZ
        call    delay12
#endif
	BTFSS   EEINTF,EESDA ; Check if EESDA = 1
	CLRC                 ; if EESDA not = 1 then clear carry bit
	RLF     EEDATA, F    ; rotate carry bit (=EESDA) into EEDATA;
	BCF     EEINTF,EESCL ; Lower EESCL
	NOP
	BSF     EEINTF,EESDA ; reset EESDA
	DECFSZ  COUNTER, F   ; Decrement counter
	GOTO    READ_BYTE_RBC; Read next bit if not finished reading byte

	BSF     EEINTF,EESCL
	NOP
	BCF     EEINTF,EESCL
;***************  Generate a STOP bit and RETURN  *********************
;********************************************************************** 
STOP_BIT
	BCF     EEINTF,EESDA ; SDA=0 to prepare for transition to '1' 
	BSF     EEINTF,EESCL ; EESCL = 1 to prepare for STOP bit
#ifdef  FOURMHZ
        call    delay4  ; wait 4 cycles  Tsu:sto (4.7 us)
#endif
#ifdef  TENMHZ
        call    delay10
#endif
#ifdef  TWENTYMHZ
        call    delay20
#endif
	BSF     EEINTF,EESDA ; Stop bit, SDA to '1' while SCL high
	BCF	STATUS,RP0
    
	BTFSS   PC_OFFSET,EE_OK ; Check for error
	RETLW   NO              ; if error, send back NO 
	RETLW   OK         ; if no error, send back OK
#ifdef TWENTYMHZ
delay20 goto    delay18
delay18 goto    delay16
delay16 goto    delay14
delay14 goto    delay12
delay12 goto    delay10
delay10 goto    delay8
delay8  goto    delay6
delay6  goto    delay4
delay4  return
#endif
#ifdef TENMHZ
; delay function.  Wait a number of cycles.  
delay10 goto    delay8
delay8  goto    delay6
delay6  goto    delay4
delay4  return
#endif
#ifdef FOURMHZ
; delay function.  Wait a number of cycles.  
delay4  return
#endif

;********************************************************************** 

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -