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

📄 i2c.asm

📁 嵌入式 编写i2c,避免大家少走弯路
💻 ASM
字号:
.include "8515def.inc"				; change if an other device is used

;**** Global viic Constants ****

.equ  	vscl			=4		; SCL Pin number (port D)
.equ	vsda			=5
.equ	vwe			=3
.equ	viic_port		=portd
.equ	viic_pin		=pind
.equ	viic_ddr		=ddrd
.equ	read_sbuf	=$70
.equ	write_sbuf	=$80			; SDA Pin number (port D)

.equ	b_dir		= 0			; transfer direction bit in viic_adr

.equ	viic_rd		= 1
.equ	viic_wr		= 0

;**** Global Register Variables ****
.def	viic_data		= r15
.def	viic_delay		= r16
.def	start_address		= r17		; Delay loop variable
						; viic data transfer register
.def	viic_adr		= r18		; viic address and direction register
.def	viic_stat		= r19
.def	data_number		= r20		; viic bus status register

;**** Interrupt Vectors ****

.org $0000
	rjmp	RESET				; Reset handle

viic_hp_delay:
	ldi	viic_delay,2
viic_hp_delay_loop:
	dec	viic_delay
	brne	viic_hp_delay_loop
	ret

viic_qp_delay:
	ldi	viic_delay,1	
viic_qp_delay_loop:
	dec	viic_delay
	brne	viic_qp_delay_loop
	ret


viic_rep_start:
	sbi	viic_ddr,vscl		; force SCL low
	cbi	viic_ddr,vsda		; release SDA
	rcall	viic_hp_delay		; half period delay
	cbi	viic_ddr,vscl		; release SCL
	rcall	viic_qp_delay		; quarter period delay

viic_start:				
	mov	viic_data,viic_adr		; copy address to transmitt register
	sbi	viic_ddr,vsda		; force SDA low
	rcall	viic_qp_delay		; quarter period delay


viic_write:
	sec				; set carry flag
	rol	viic_data			; shift in carry and out bit one
	rjmp	viic_write_first
viic_write_bit:
	lsl	viic_data			; if transmit register empty
viic_write_first:
	breq	viic_get_ack		;	goto get acknowledge
	sbi	viic_ddr,vscl		; force SCL low

	brcc	viic_write_low		; if bit high
	nop				;	(equalize number of cycles)
	cbi	viic_ddr,vsda		;	release SDA
	rjmp	viic_write_high
viic_write_low:				; else
	sbi	viic_ddr,vsda		;	force SDA low
	rjmp	viic_write_high		;	(equalize number of cycles)
viic_write_high:
	rcall	viic_hp_delay		; half period delay
	cbi	viic_ddr,vscl		; release SCL
	rcall	viic_hp_delay		; half period delay

	rjmp	viic_write_bit


viic_get_ack:
	sbi	viic_ddr,vscl		; force SCL low
	cbi	viic_ddr,vsda		; release SDA
	rcall	viic_hp_delay		; half period delay
	cbi	viic_ddr,vscl		; release SCL

viic_get_ack_wait:
	sbis	viic_pin,vscl		; wait SCL high 
					;(In case wait states are inserted)
	rjmp	viic_get_ack_wait

	clt				; clear carry flag
	sbic	viic_pin,vsda		; if SDA is high
	set				;	set carry flag
	rcall	viic_hp_delay		; half period delay
	ret



viic_do_transfer:
	sbrs	viic_adr,b_dir		; if dir = write
	rjmp	viic_write		;	goto write data


viic_read:
	rol	viic_stat
	
	clr	viic_data			; store acknowledge
					; (used by viic_put_ack)
	inc	viic_data		; data = 0x01
viic_read_bit:				; do
	sbi	viic_ddr,vscl		; 	force SCL low
	rcall	viic_hp_delay		;	half period delay

	cbi	viic_ddr,vscl		;	release SCL
	rcall	viic_hp_delay		;	half period delay

	clc				;	clear carry flag
	sbic	viic_pin,vsda		;	if SDA is high
	sec				;		set carry flag

	rol	viic_data			; 	store data bit
	brcc	viic_read_bit		; while receive register not full



viic_put_ack:
	sbi	viic_ddr,vscl		; force SCL low

	ror	viic_stat		; get status bit
	brcc	viic_put_ack_low	; if bit low goto assert low
	cbi	viic_ddr,vsda		;	release SDA
	rjmp	viic_put_ack_high
viic_put_ack_low:			; else
	sbi	viic_ddr,vsda		;	force SDA low
viic_put_ack_high:

	rcall	viic_hp_delay		; half period delay
	cbi	viic_ddr,vscl		; release SCL
viic_put_ack_wait:
	sbis	viic_pin,vscl		; wait SCL high
	rjmp	viic_put_ack_wait
	rcall	viic_hp_delay
	sbi	viic_ddr,vscl	
	cbi	viic_ddr,vsda		; half period delay
	ret

viic_stop:
	sbi	viic_ddr,vscl		; force SCL low
	sbi	viic_ddr,vsda		; force SDA low
	rcall	viic_hp_delay		; half period delay
	cbi	viic_ddr,vscl		; release SCL
	rcall	viic_qp_delay		; quarter period delay
	cbi	viic_ddr,vsda		; release SDA
	rcall	viic_hp_delay		; half period delay
	ret


viic_init:
	clr	viic_stat			; clear viic status register (used
						; as a temporary register)
	out	viic_port,viic_stat		; set viic pins to open colector
	out	viic_ddr,viic_stat
	ret


write_data:
        ldi	viic_adr,$A0+viic_wr		; Set device address and write
	rcall	viic_start	             	; Send start condition and address
        mov	viic_data,start_address		; Write word address (0x00)
	rcall	viic_do_transfer
	clr	xh
	ldi	xl,write_sbuf
	
write_loop:	 
	ld	viic_data,x      		; Execute transfer
	rcall	viic_do_transfer
	inc 	xl
	dec	data_number
	brne	write_loop			; Execute transfer
        rcall	viic_stop	
        ret
             	               	 ; Send stop condition

Read_data: 

	ldi	viic_adr,$A0+viic_wr			; Set device address and write
	rcall	viic_start				; Send start condition and address

        mov	viic_data,start_address	               		; Write word address
	rcall	viic_do_transfer			; Execute transfer

	ldi	viic_adr,$A0+viic_rd	              		; Set device address and read
	rcall	viic_rep_start
	clr	xh
	ldi	xl,read_sbuf	              		; Send repeated start condition and address
read_loop:
	clc			              		; Set no acknowledge (read is followed by a stop condition)
	rcall	viic_do_transfer
	st	x,viic_data	
	inc	xl
	dec 	data_number
	brne	read_loop			; Execute transfer (read)

	rcall	viic_stop
	ret		               		; Send stop condition - releases bus



RESET:
main:	
	ldi	r16,high(ramend)
	out	sph,r16
	ldi	r16,low(ramend)
	out 	spl,r16
	ldi	r16,$01
	clr	xh
	ldi	xl,write_sbuf
set_data:	
	st	x,r16
	inc 	r16
	inc	xl
	cpi	r16,$0f
	brne	set_data
call_loop:		
	
	rcall	viic_init
	ldi	start_address,$0
	ldi	data_number,6		; initialize viic interface
        rcall	write_data
 
        ldi	start_address,$0
	ldi	data_number,6
        rcall	read_data
        rjmp	call_loop

⌨️ 快捷键说明

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