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

📄 i2cv10.inc

📁 本程序为某企业的税控机固件程序.基于东芝TMP93CS41 16位单片机编写,符合国家标准.该程序已经经过多次长期调试.
💻 INC
字号:
;***********************************************************
;程序名称:		I2C访问子程序
;程序开发:		前锋集团技术中心 江海波
;编写时间:		2004年12月17日
;软件环境:		供税控收款器QF561型的上层C语言使用
;硬件环境:		QF561型税控器,硬件环境V1.0
;			I2C芯片为MICROCHIP公司24LC256
;			基于I2C接口的EEPROM
;MCU:			TOSHIBA TMP93CS41@max 16M/1
;程序版本:		V1.00
;最后修订时间:		2004年12月17日
;修订部分说明:
;----------------------------------------------------------

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

;定义伪指令,当软,硬件结构改变时修改本位置上的指令即可完成程序修改

;----------------------------------------------------------
;I2C总线的数据线被定义在端口i2c_sda_port的i2c_sda_bit位上
i2c_sda_port	equ	PA
i2c_sda_bit	equ	7
;由于涉及方向转换,该端口的方向控制字为
i2c_s_p_cr	equ	PACR		;---I2C Sda Port Control Register
;----------------------------------------------------------
;I2C总线的时钟线被定义在端口i2c_scl_port的i2c_scl_bit位上
i2c_scl_port	equ	PA
i2c_scl_bit	equ	6
;----------------------------------------------------------
;I2C-EEPROM的写保护端被定义在i2c_pro_port的i2c_pro_bit位上
i2c_pro_port	equ	PA
i2c_pro_bit	equ	5
;----------------------------------------------------------
;两片EEPROM的选择由上层选择,其将读写数据头在
ee_rw		equ	0x100		;---EEprom Read or Write flag
;----------------------------------------------------------
;数据操作的地址高位由C语言给出,被放置在地址
data_addr_h	equ	0x101		;---DATA ADDRess High
;----------------------------------------------------------
;数据操作的地址低位由C语言给出,被放置在地址
data_addr_l	equ	0x102		;---DATA ADDRess Low
;----------------------------------------------------------
;数据操作的地址长度由C语言给出,其高段被放置在地址
data_leng_h	equ	0x103		;---DATA LENGth High
;----------------------------------------------------------
;数据操作的地址长度由C语言给出,其低段被放置在地址
data_leng_l	equ	0x104		;---DATA LENGth Low
;----------------------------------------------------------
;接收到的数据和要发送的数据的缓冲区首地址在:
i2c_buffer	equ	0x145
;----------------------------------------------------------
;为了方便程序调试和硬件Debug模式下的调试工作,程序安排了一个错误标志
;这个标志被定义在地址:
i2c_error_flag	equ	0x144
;----------------------------------------------------------
;由于I2C口线操作涉及方向改变,我们定义了一个内存空间以保存其方向字信息
i2c_port_cr	equ	PACR_RAM
;----------------------------------------------------------
;i2c_output和i2c_input两个函数亦需要做相应的调整
;----------------------------------------------------------
;通用寄存器分配:
;w:全局变量,用于发送和接受一个字节
;c:临时变量,仅在当前程序中使用,一般作为局部计数器
;b:临时变量,发送一个字节时做计数器用
;hl:全局变量,做发送/接收字节个数的计数器用
;xix:数据指针,指向缓冲区
;----------------------------------------------------------

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

;----------------------全局函数声明------------------------

PUBLIC	__i2cee_byte_rd		;---单字节随机地址读,由上层C语言调用
PUBLIC	__i2cee_byte_wr		;---单字节随机地址写,由上层C语言调用
PUBLIC	__i2cee_seri_rd		;---多字节连续地址读,由上层C语言调用
PUBLIC	__i2cee_seri_wr		;---单字节连续地址写,由上层C语言调用

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

;**********************端口方向控制************************

i2c_output:					;调用本函数,使得SDA为输出口
	or	(i2c_port_cr),0x80		;SDA线为输出口
	ld	(i2c_s_p_cr),(i2c_port_cr)	;口线设置
	ret

i2c_input:					;调用本函数,使得SDA为输入口
	and	(i2c_port_cr),0x7F		;SDA线为输入口
	ld	(i2c_s_p_cr),(i2c_port_cr)	;口线设置
	ret

;**********************I2C用延迟函数***********************

i2c_delay_5us:					;延迟5us,主要用于启动
	ld	c,0x03

i2c_d_5_loop:
	nop
	nop
	djnz	c,i2c_d_5_loop

	ret

i2c_delay_3us:					;延迟3us,主要用于发送函数
	ld	c,0x02

i2c_d_3_loop:
	nop
	djnz	c,i2c_d_3_loop

	ret

;**********************I2C发送函数*************************

i2c_send:					;调用本函数,发送W寄存器中的一个字节到总线上
	call	i2c_output			;口线设置为输出
	ld	b,0x08				;计数器,循环8次

i2c_s_loop:
	rlc	1,w
	stcf	i2c_sda_bit,(i2c_sda_port)	;数据送到DSA线上
	call	i2c_delay_3us
	set	i2c_scl_bit,(i2c_scl_port)	;SCK=1
	call	i2c_delay_5us
	res	i2c_scl_bit,(i2c_scl_port)	;SCK=0
	djnz	b,i2c_s_loop			;循环发送8个BIT位
	res	i2c_sda_bit,(i2c_sda_port)	;SDA=0

	ret					;此时SDA=0,SCL=0

;**********************I2C接收函数*************************

i2c_rec:
	call	i2c_input			;口线设置为输入
	ld	b,0x08

i2c_r_loop:
	call	i2c_delay_5us
	set	i2c_scl_bit,(i2c_scl_port)	;SCK=1
	call	i2c_delay_5us			;NOTE1
	ldcf	i2c_sda_bit,(i2c_sda_port)	;采样SDA线,接收一个BIT位
	rl	1,w
	res	i2c_scl_bit,(i2c_scl_port)	;SCK=0
	djnz	b,i2c_r_loop			;循环接收8个BIT位

	ret					;此时SDA不定,SCL=0

;NOTE1:按照环境温度-40摄氏度到+125摄氏度设计

;***********************发送启动位*************************

i2c_start:
	call	i2c_output			;口线设置为输出

	set	i2c_scl_bit,(i2c_scl_port)	;口线初始化,SCL=1
	call	i2c_delay_5us
	set	i2c_sda_bit,(i2c_sda_port)	;口线初始化,SDA=1
	call	i2c_delay_5us			;NOTE2
	res	i2c_sda_bit,(i2c_sda_port)	;发送启动位,SDA=0
	call	i2c_delay_5us
	res	i2c_scl_bit,(i2c_scl_port)	;发送启动位,SCL=0

	ret					;此时SDA=0,SCL=0

;NOTE2:由PHILIPS的I2C协议2.0版,停止位和下一个启动位之间的时间间隔不得小于
;4.7us由于这里采用了一个停止位来做初始化,所以加入本延迟时间

;**********************发送停止位**************************

i2c_stop:
	call	i2c_output			;口线设置为输出
	set	i2c_scl_bit,(i2c_scl_port)	;发送停止位,SCL=1
	call	i2c_delay_5us
	set	i2c_sda_bit,(i2c_sda_port)	;发送停止位,SDA=1
	ret

;***********************应答检测***************************

i2c_ack_get:					;---I2C ACKnowledge GET
	call	i2c_input			;口线设置为输入

	set	i2c_scl_bit,(i2c_scl_port)	;发生应答检测脉冲SCL=1
	ldcf	i2c_sda_bit,(i2c_sda_port)	;采样总线
	jp	c,i2c_ack_er			;总线为1,说明无应答
	ld	(i2c_error_flag),0x04		;检测到了应答信号,写标志

i2c_ack_er:
	res	i2c_scl_bit,(i2c_scl_port)	;SCL=0
	ret					;此时SDA=0,SCL=0

;*********************应答发生*****************************

i2c_ack_gen:					;---I2C ACKnowledge GENerate
	call	i2c_output			;口线设置为输出

	res	i2c_sda_bit,(i2c_sda_port)	;SDA=0,开始应答
	set	i2c_scl_bit,(i2c_scl_port)	;发生应答检测脉冲,SCL=1
	call	i2c_delay_5us
	res	i2c_scl_bit,(i2c_scl_port)	;结束应答检测脉冲,SCL=0

	ret					;此时SDA=0,SCL=0

i2c_nack_gen:					;---I2C NotACKnowledge GENerate
	call	i2c_output			;口线设置为输出

	set	i2c_sda_bit,(i2c_sda_port)	;SDA=1,开始非应答
	set	i2c_scl_bit,(i2c_scl_port)	;发生应答检测脉冲,SCL=1
	call	i2c_delay_5us
	res	i2c_scl_bit,(i2c_scl_port)	;结束应答检测脉冲,SCL=0
	res	i2c_sda_bit,(i2c_sda_port)	;结束应答检测脉冲,SDA=0

	ret					;此时SDA=0,SCL=0

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

;-----------Main Of I2C EEPROM Transmit Function-----------

;********************单字节随机地址读************************

__i2cee_byte_rd:				;---signal byte,randum address read
	di					;关闭中断
	call	i2c_start			;启动总线
	ld	w,(ee_rw)			;载入C语言传递来的控制字
	and	w,0xFE				;发送控制字,方向为送出
	call	i2c_send			;发送
	call	i2c_ack_get			;接收应答信号

	ld	w,(data_addr_h)			;载入读取位置的高地址
	call	i2c_send			;发送
	call	i2c_ack_get			;接收应答信号

	ld	w,(data_addr_l)			;载入读取位置的低地址
	call	i2c_send			;发送
	call	i2c_ack_get			;接收应答信号

	call	i2c_start			;启动总线
	ld	w,(ee_rw)			;载入C语言传递来的控制字
	or	w,0x01				;发送控制字,方向为读入
	call	i2c_send			;发送
	ld	(i2c_error_flag),0x07		;初始化错误标志,为无应答
	call	i2c_ack_get			;接收应答信号
	call	i2c_rec				;接收
	ld	(i2c_buffer),w			;将收到的数据存在缓冲区

	call	i2c_nack_gen			;发送非应答信号

	call	i2c_stop			;停止总线
	ei	0x00				;完成任务后开中断
	ret

;*******************单字节随机地址写***********************

__i2cee_byte_wr:
	di					;关闭中断
	res	i2c_pro_bit,(i2c_pro_port)	;关写保护
	call	i2c_start			;启动总线
	ld	w,(ee_rw)			;载入C语言传递来的控制字
	and	w,0xFE				;发送控制字,方向为送出
	call	i2c_send			;发送
	call	i2c_ack_get			;接收应答信号

	ld	w,(data_addr_h)			;载入读取位置的高地址
	call	i2c_send			;发送
	call	i2c_ack_get			;接收应答信号

	ld	w,(data_addr_l)			;载入读取位置的低地址
	call	i2c_send			;发送
	call	i2c_ack_get			;接收应答信号

	ld	w,(i2c_buffer)			;从缓冲区载入要发送的数据
	call	i2c_send
	ld	(i2c_error_flag),0x07		;初始化错误标志,为无应答
	call	i2c_ack_get			;接收应答信号

	call	i2c_stop			;停止总线
	set	i2c_pro_bit,(i2c_pro_port)	;开写保护
	ei	0x00				;完成任务后开中断
	ret

;******************多字节连续地址读************************

__i2cee_seri_rd:
	di					;关闭中断
	call	i2c_start			;启动总线
	ld	w,(ee_rw)			;载入C语言传递来的控制字
	and	w,0xFE				;发送控制字,方向为送出
	call	i2c_send			;发送
	call	i2c_ack_get			;接收应答信号

	ld	w,(data_addr_h)			;载入读取位置的高地址
	call	i2c_send			;发送
	call	i2c_ack_get			;接收应答信号

	ld	w,(data_addr_l)			;载入读取位置的低地址
	call	i2c_send			;发送
	call	i2c_ack_get			;接收应答信号

	ld	xix,i2c_buffer			;载入缓冲区首地址
	ld	h,(data_leng_h)			;载入长度计数器高位
	ld	l,(data_leng_l)			;载入长度计数器低位

	call	i2c_start			;启动总线
	ld	w,(ee_rw)			;载入C语言传递来的控制字
	or	w,0x01				;发送控制字,方向为读入
	call	i2c_send			;发送
	ld	(i2c_error_flag),0x07		;初始化错误标志,为无应答
	call	i2c_ack_get			;接收应答信号

i2cee_b_r_loop:					;---I2C EEprom Bytes Read LOOP
	call	i2c_rec				;接收一个字节
	ld	(xix+),w			;将收到的数据存在缓冲区
	cp	hl,0x0001			;判断,最后一个字节接收后不产生应答脉冲
	jp	z,i2cee_b_r_fini		;最后一个字节到
	call	i2c_ack_gen			;发生应答信号
	djnz	hl,i2cee_b_r_loop		;循环接收

i2cee_b_r_fini:					;---I2C EEprom Byte Read FINIsh
	call	i2c_nack_gen			;发生非应答信号

	call	i2c_stop			;停止总线
	ei	0x00				;完成任务后开中断
	ret

;******************多字节连续地址写************************
__i2cee_seri_wr:
	di					;关闭中断
	res	i2c_pro_bit,(i2c_pro_port)	;关写保护
	call	i2c_start			;启动总线
	ld	w,(ee_rw)			;载入C语言传递来的控制字
	and	w,0xFE				;发送控制字,方向为送出
	call	i2c_send			;发送
	call	i2c_ack_get			;接收应答信号

	ld	w,(data_addr_h)			;载入读取位置的高地址
	call	i2c_send			;发送
	call	i2c_ack_get			;接收应答信号

	ld	w,(data_addr_l)			;载入读取位置的低地址
	call	i2c_send			;发送
	call	i2c_ack_get			;接收应答信号
	
	ld	xix,i2c_buffer			;载入缓冲区首地址
	ld	xde,0x00
	ld	e,(data_leng_h)
	add	xix,xde		
	ld	l,(data_leng_l)			;载入长度计数器低位NOTE3

i2cee_b_w_loop:					;---I2C EEprom Bytes Write LOOP
	ld	(i2c_error_flag),0x07		;初始化错误标志,为无应答
	ld	w,(xix+)			;从缓冲区载入要发送的数据
	call	i2c_send			;发送
	call	i2c_ack_get			;接收应答信号
	djnz	l,i2cee_b_w_loop		;循环发送

	call	i2c_stop			;停止总线
	set	i2c_pro_bit,(i2c_pro_port)	;开写保护
	
	ei	0x00				;完成任务后开中断
	ret

;NOTE3:由于页面限制,一次写入的字节总数不会超过64字节.

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

⌨️ 快捷键说明

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