|
;*******************************************************************************
;*
;* 子程序名: TI2CBus_SMM_def.inc
;* 程序名称: 单主方式下使用TWI接口的 I2C 总线程序(主设备)
;* 的寄存器和常数定义
;* 版本: 1.0
;* 适用 MCU 型号: AVR所有型号
;* 使用资源: r12,r16,r17,r18,r19,r20,r21,r22,r23,r30,r31
;*
;* 程序功能:
;* 本文件是使用TWI接口的 I2C 总线上的主器件与从器件通信的基本程序
;* 的寄存器和常数定义文件。
;*
;* 编作者:
;* 编作者 E-Mail: PTZSW@163.COM
;* 编制日期: 2005年3月8日
;*
;*******************************************************************************
;*
;* 低位寄存器使用: 1(r12)
;* 高位寄存器使用: 8(r16,r17,r18,r19,r20,r21,r22,r23)
;* 指针寄存器使用: Z
;*
;*******************************************************************************
;******** 依据硬件设置需修改的常数定义:
;*** I2C 总线的比特率常数定义:
;下面以单片机的时钟= 11.0592 MHz,I2C 总线的比特率≈307K(Bit)为依据进行定义。
; 单片机的时钟
;比特率计算公式 = ─────────────────
; TWPS
; 16+2×(I2CTWI_BR_BR)×4
.equ I2CTWI_BR_BR = 10 ;定义 TWI 比特率寄存器的数值
;TWI 工作在主机模式时,
;TWBR 值应该不小于10 。
.equ I2CTWI_BR_SR = 0 ;定义 TWI 状态寄存器中
;TWI 预分频位(TWPS)的数值
;******** 本程序寄存器变量定义:
.def TI2C_DataNum = r12 ;在 I2C 总线上存取的数据个数
.def TI2C_TEMP = r16 ;暂存寄存器
.def TI2C_DeviceAddr= r17 ;I2C 总线上存取的设备地址
.def TI2C_DataAddr1 = r18 ;I2C 总线上存取数据的存储地址1
.def TI2C_DataAddr2 = r19 ;I2C 总线上存取数据的存储地址2
.def TI2C_DaAdNum = r20 ;在 I2C 总线上存取数据的存储地址个数
.def TI2C_Data = r21 ;在 I2C 总线上存取的数据
.def TI2C_ErrorNum = r22 ;I2C 总线发生错误次数寄存器
.def TI2C_CNT = r23 ;循环计数器
;******** 本程序常数定义:
.equ TI2C_M_Start = $08 ;START 已发送状态码
.equ TI2C_M_REPSTA = $10 ;重复 START 已发送状态码
.equ TI2C_MT_SLA_A = $18 ;SLA+W 已发送,接收到 ACK 状态码
.equ TI2C_MT_SLA_NA = $20 ;SLA+W 已发送,接收到 NOTACK 状态码
.equ TI2C_MT_DT_A = $28 ;数据已发送,接收到 ACK 状态码
.equ TI2C_MT_DT_NA = $30 ;数据已发送,接收到 NOTACK 状态码
.equ TI2C_MT_Fail = $38 ;SLA+W 或数据的仲裁失败状态码
.equ TI2C_MR_SLA_A = $40 ;SLA+R 已发送,接收到 ACK 状态码
.equ TI2C_MR_SLA_NA = $48 ;SLA+R 已发送,接收到 NOTACK 状态码
.equ TI2C_MR_DT_A = $50 ;接收到数据,ACK 已返回状态码
.equ TI2C_MR_DT_NA = $58 ;接收到数据,NOTACK 已返回状态码
.equ TI2C_MR_Fail = $38 ;SLA+W 或数据的仲裁失败状态码
.equ TI2C_ErrorNumI = $10 ;允许 I2C 总线发生错误次数值(16 次)
;★★★★★ 定义文件结束!!! ★★★★★
;*******************************************************************************
;*
;* 子程序名: TI2CBus_SMM.asm
;* 程序名称: 单主方式下使用TWI接口的 I2C 总线程序(主设备)
;* 版本: 1.0
;* 适用 MCU 型号: AVR所有型号
;* 使用资源: r16,r17,r18,r19,r20,r21,r22
;*
;* 程序功能:
;* 本程序是使用TWI接口的 I2C 总线上的主器件与从器件通信的基本程序。
;* 在 I2C 总线上,单一主器件方式受限制于单一总线控制器。在绝大部分应用设计
;* 中并不需要 I2C 总线提供的多主器件功能。本程序共包括二个子程序。分别为存
;* 取单个字节数据到 I2C 总线上从器件的子程序。其入口条件和出口条件见各子程
;* 序的具体说明。
;*
;* 注意:
;* ①.对于有些器件如:EEPROM 等,在两次调用子程序之间应间隔 5~10 ms 。
;* ②.针对各种 I2C 总线的器件对数据存取地址的不同,二个子程序都分别对各
;* 种 I2C 总线的器件进行了分类,共分为下面三类:
;* ⑴.不需要数据的存取地址。
;* ⑵.数据的存取地址为 1 个字节。
;* ⑶.数据的存取地址为 2 个字节。
;* 无论那一类,在调用子程序前都应对“TI2C_DaAdNum”(r20)置值,且只能分别置
;* 0、1、2 这三个数值。
;*
;* 编作者:
;* 编作者 E-Mail: PTZSW@163.COM
;* 编制日期: 2005年3月8日
;*
;*******************************************************************************
;*
;* 指令条数: 241 + return
;* 指令执行周期: 不确定 + return
;* 低位寄存器使用: None
;* 高位寄存器使用: 7 (r16,r17,r18,r19,r20,r21,r22)
;* 指针寄存器使用: None
;*
;*******************************************************************************
;******** 本程序包括的定义文件:
.include "TI2CBus_SMM_def.inc" ;寄存器变量和常数定义
;******** 程序指令代码清单:
;*******************************************************************************
;* 本程序共包括下面二个子程序:
;*
;* “TI2C_Write_Single” ------ 向 I2C 总线上的设备写一个字节数据子程序
;*
;* “TI2C_Read_Single” ------- 从 I2C 总线上的设备读一个字节数据子程序
;*
;*******************************************************************************
;*******************************************************************************
;*
;* 向 I2C 总线上的设备写一个字节数据子程序 - “TI2C_Write_Single”
;*
;* 说明:
;* 本子程序用于在单主方式下使用TWI接口向 I2C 总线上的设备写一个字节数据。
;* 本子程序己包括了按数据手册上的说明,对各种状态码出错进行处理的程序。
;*
;* 注意:
;* 在设置“TI2C_DeviceAddr”(I2C 总线上写入数据的设备地址)的值时,要保留
;* 其最后一位必须为 0 。此位用于控制数据的传送方向。
;*
;* 入口条件: 根据设备的情况,按是否需要写数据的存储地址分为下列三种情况:
;* ①.不需要写数据的存储地址,即“TI2C_DaAdNum”(r20)=0时,
;* 需设置下面这几个寄存器数值:
;* TI2C_DaAdNum(r20)-------- 在 I2C 总线上数据的存储地址个数(=0)
;* TI2C_DeviceAddr(r17)----- I2C 总线上写入数据的设备地址
;* TI2C_Data(r21)----------- 在 I2C 总线上写入的数据
;* ②.当写数据的存储地址不大于 256 B,即“TI2C_DaAdNum”(r20)=1时,
;* 需设置下面这几个寄存器数值:
;* TI2C_DaAdNum(r20)-------- 在 I2C 总线上数据的存储地址个数(=1)
;* TI2C_DeviceAddr(r17)----- I2C 总线上写入数据的设备地址
;* TI2C_DataAddr1(r18)------ I2C 总线上存取数据的存储地址1
;* TI2C_Data(r21)----------- 在 I2C 总线上写入的数据
;* ③.当写数据的存储地址不大于 64 KB,即“TI2C_DaAdNum”(r20)=2时,
;* 需设置下面这几个寄存器数值:
;* TI2C_DaAdNum(r20)-------- 在 I2C 总线上数据的存储地址个数(=2)
;* TI2C_DeviceAddr(r17)----- I2C 总线上写入数据的设备地址
;* TI2C_DataAddr1(r18)------ I2C 总线上存取数据的存储地址1
;* TI2C_DataAddr2(r19)------ I2C 总线上存取数据的存储地址2
;* TI2C_Data(r21)----------- 在 I2C 总线上写入的数据
;*
;* 指令条数: 106 + return
;* 指令执行周期: 不确定 + return
;* 低位寄存器使用: None
;* 高位寄存器使用: 7 (r16,r17,r18,r19,r20,r21,r22)
;* 指针寄存器使用: None
;*
;*******************************************************************************
TI2C_Write_Single:
clr TI2C_ErrorNum ;错误次数计数器清 0
TI2C_WRS_Initialization:
ldi TI2C_TEMP,I2CTWI_BR_BR ;置 I2C 总线的通讯比特率
out TWBR,TI2C_TEMP
ldi TI2C_TEMP,I2CTWI_BR_SR
out TWSR,TI2C_TEMP
TI2C_WRS_Start:
ldi TI2C_TEMP,(1<<TWINT)|(1<<TWSTA)|(1<<TWEN)
out TWCR,TI2C_TEMP ;使能TWI接口为 I2C 总线
;并发出 START 信号(起始条件)
TI2C_WRS_GetACK1:
in TI2C_TEMP,TWCR ;等待 TWINT 置位,TWINT 置位表示
sbrs TI2C_TEMP,TWINT ;数椐已发送,及收到应答信号
rjmp TI2C_WRS_GetACK1
TI2C_WRS_StatusCode1:
in TI2C_TEMP,TWSR ;读取 TWI 状态寄存器的状态字内容
andi TI2C_TEMP,$f8 ;屏蔽预分频位
cpi TI2C_TEMP,TI2C_M_Start ;检查状态字是否为 START 信号已发送状态码?
breq TI2C_WRS_SLAW ;是,则继续
;否,进入错误处理
;-----------------------------------
; 此段程序用于发出 START 信号错误处理,并发出重复的 START 信号
TI2C_WRS_SCE_MStart:
inc TI2C_ErrorNum ;错误次数 + 1
cpi TI2C_ErrorNum,TI2C_ErrorNumI;检查错误次数是否超过设定的次数?
brlo TI2C_WRS_SCE_MStart1 ;否,则继续
rjmp TI2C_WRS_Error_End ;是,转至告警和结束传送处理
TI2C_WRS_SCE_MStart1:
ldi TI2C_TEMP,(1<<TWINT)|(1<<TWSTA)|(1<<TWEN)
out TWCR,TI2C_TEMP ;使能TWI接口为 I2C 总线
;并发出重复的 START 信号(起始条件)
TI2C_WRS_SCE_GetACK:
in TI2C_TEMP,TWCR ;等待 TWINT 置位,TWINT 置位表示
sbrs TI2C_TEMP,TWINT ;数椐已发送,及收到应答信号
rjmp TI2C_WRS_SCE_GetACK
TI2C_WRS_SCE_StatusCode:
in TI2C_TEMP,TWSR ;读取 TWI 状态寄存器的状态字内容
andi TI2C_TEMP,$f8 ;屏蔽预分频位
cpi TI2C_TEMP,TI2C_M_REPSTA ;检查状态字是否为重复的 START 信号已发送?
brne TI2C_WRS_SCE_MStart ;否,进入发出重复的 START 信号错误处理
;是,则继续
;*** 此段程序结束
TI2C_WRS_SLAW:
andi TI2C_DeviceAddr,$fe ;写数据的设备地址 + 传送方向(写数据)
out TWDR,TI2C_DeviceAddr
ldi TI2C_TEMP,(1<<TWINT)|(1<<TWEN)
out TWCR,TI2C_TEMP ;向 I2C 总线上发送
TI2C_WRS_Get_ACK2:
in TI2C_TEMP,TWCR ;等待 TWINT 置位,TWINT 置位表示
sbrs TI2C_TEMP,TWINT ;数椐已发送,及收到应答信号
rjmp TI2C_WRS_Get_ACK2
TI2C_WRS_StatusCode2:
in TI2C_TEMP,TWSR ;读取 TWI 状态寄存器的状态字内容
andi TI2C_TEMP,$f8 ;屏蔽预分频位
cpi TI2C_TEMP,TI2C_MT_SLA_A ;检查状态字是否为 SLA+W 已发送,
;接收到 ACK 状态码?
breq TI2C_WRS_DataAddr1 ;是,则继续
;否,进入错误处理
;-----------------------------------
; 此段程序用于 SLA+W 已发送,接收到 ACK 错误处理
TI2C_WRS_SCE_SLAW:
cpi TI2C_TEMP,TI2C_MT_SLA_NA ;检查状态字是否为 SLA+W 已发送,
;接收到 NOTACK 状态码?
brne TI2C_WRS_SCE_SLAW1 ;否,则继续
;是,进入错误处理
rjmp TI2C_WRS_SCE_MStart ;转向发出重复的 START 信号
TI2C_WRS_SCE_SLAW1:
rjmp TI2C_WRS_Error_End ;转至告警和结束传送处理,
;因为此 I2C 总线为单主模式,不会出现总线
;优先权仲裁失败状态码,所以如果出现非上述
;两种状态码,则 I2C 总线发生致命错误。
;如果为多主模式,那么在此应插入转为从机
;模式程序,以便让胜出主机寻址。
;*** 此段程序结束
TI2C_WRS_DataAddr1:
cpi TI2C_DaAdNum,$00 ;检查是否需要写存取数据的存储地址?
brne TI2C_WRS_DataAddr11 ;是,则继续
rjmp TI2C_WRS_Data ;否,跳过写存储地址,直接写数据
TI2C_WRS_DataAddr11:
out TWDR,TI2C_DataAddr1 ;写存取数据存储地址1
ldi TI2C_TEMP,(1<<TWINT)|(1<<TWEN)
out TWCR,TI2C_TEMP ;向 I2C 总线上发送
TI2C_WRS_Get_ACK31:
in TI2C_TEMP,TWCR ;等待TWINT 置位,TWINT 置位表示
sbrs TI2C_TEMP,TWINT ;数椐已发送,及收到应答信号
rjmp TI2C_WRS_Get_ACK31
TI2C_WRS_StatusCode31:
in TI2C_TEMP,TWSR ;读取 TWI 状态寄存器的状态字内容
andi TI2C_TEMP,$f8 ;屏蔽预分频位
cpi TI2C_TEMP,TI2C_MT_DT_A ;检查状态字是否为数据已发送,
;接收到 ACK 状态码?
breq TI2C_WRS_DataAddr2 ;是,则继续
;否,进入错误处理
;-----------------------------------
; 此段程序用于数据已发送,接收到 ACK 错误处理
TI2C_WRS_SCE_DataAddr1:
cpi TI2C_TEMP,TI2C_MT_DT_NA ;检查状态字是否为数据已发送,
;接收到 NOTACK 状态码?
brne TI2C_WRS_SCE_DataAddr11 ;否,则继续
;是,进入错误处理
rjmp TI2C_WRS_SCE_MStart ;转向发出重复的 START 信号
TI2C_WRS_SCE_DataAddr11:
rjmp TI2C_WRS_Error_End ;转至告警和结束传送处理,
;因为此 I2C 总线为单主模式,不会出现总线
;优先权仲裁失败状态码,所以如果出现非上述
;两种状态码,则 I2C 总线发生致命错误。
;如果为多主模式,那么在此应插入转为从机
;模式程序,以便让胜出主机寻址。
;*** 此段程序结束
TI2C_WRS_DataAddr2:
dec TI2C_DaAdNum ;检查是否需要写数据存储地址2?
brne TI2C_WRS_DataAddr21 ;是,则继续
rjmp TI2C_WRS_Data ;否,跳过,直接写数据
TI2C_WRS_DataAddr21:
inc TI2C_DaAdNum ;存取数据的存储地址个数返回为原数值
out TWDR,TI2C_DataAddr2 ;写存取数据存储地址2
ldi TI2C_TEMP,(1<<TWINT)|(1<<TWEN)
out TWCR,TI2C_TEMP ;向 I2C 总线上发送
TI2C_WRS_Get_ACK32:
in TI2C_TEMP,TWCR ;等待TWINT 置位,TWINT 置位表示
sbrs TI2C_TEMP,TWINT ;数椐已发送,及收到应答信号
rjmp TI2C_WRS_Get_ACK32
TI2C_WRS_StatusCode32:
in TI2C_TEMP,TWSR ;读取 TWI 状态寄存器的状态字内容
andi TI2C_TEMP,$f8 ;屏蔽预分频位
cpi TI2C_TEMP,TI2C_MT_DT_A ;检查状态字是否为数据已发送,
;接收到 ACK 状态码?
breq TI2C_WRS_Data ;是,则继续
;否,进入错误处理
;-----------------------------------
; 此段程序用于数据已发送,接收到 ACK 错误处理
TI2C_WRS_SCE_DataAddr2:
cpi TI2C_TEMP,TI2C_MT_DT_NA ;检查状态字是否为数据已发送,
;接收到 NOTACK 状态码?
brne TI2C_WRS_SCE_DataAddr12 ;否,则继续
;是,进入错误处理
rjmp TI2C_WRS_SCE_MStart ;转向发出重复的 START 信号
TI2C_WRS_SCE_DataAddr12:
rjmp TI2C_WRS_Error_End ;转至告警和结束传送处理,
;因为此 I2C 总线为单主模式,不会出现总线
;优先权仲裁失败状态码,所以如果出现非上述
;两种状态码,则 I2C 总线发生致命错误。
;如果为多主模式,那么在此应插入转为从机
;模式程序,以便让胜出主机寻址。
;*** 此段程序结束
TI2C_WRS_Data:
out TWDR,TI2C_Data ;写发送的数椐
ldi TI2C_TEMP,(1<<TWINT)|(1<<TWEN)
out TWCR,TI2C_TEMP ;向 I2C 总线上发送
TI2C_WRS_Get_ACK4:
in TI2C_TEMP,TWCR ;等待TWINT 置位,TWINT 置位表示
sbrs TI2C_TEMP,TWINT ;数椐已发送,及收到应答信号
rjmp TI2C_WRS_Get_ACK4
TI2C_WRS_StatusCode4:
in TI2C_TEMP,TWSR ;读取 TWI 状态寄存器的状态字内容
andi TI2C_TEMP,$f8 ;屏蔽预分频位
cpi TI2C_TEMP,TI2C_MT_DT_A ;检查状态字是否为数据已发送,
;接收到 ACK 状态码?
breq TI2C_WRS_Stop ;是,则继续
;否,进入错误处理
;-----------------------------------
; 此段程序用于数据已发送,接收到 ACK 错误处理
TI2C_WRS_SCE_Data:
cpi TI2C_TEMP,TI2C_MT_DT_NA ;检查状态字是否为数据已发送,
;接收到 NOTACK 状态码?
brne TI2C_WRS_SCE_Data1 ;否,则继续
;是,进入错误处理
rjmp TI2C_WRS_SCE_MStart ;转向发出重复的 START 信号
TI2C_WRS_SCE_Data1:
rjmp TI2C_WRS_Error_End ;转至告警和结束传送处理,
;因为此 I2C 总线为单主模式,不会出现总线
;优先权仲裁失败状态码,所以如果出现非上述
;两种状态码,则 I2C 总线发生致命错误。
;如果为多主模式,那么在此应插入转为从机
;模式程序,以便让胜出主机寻址。
;*** 此段程序结束
TI2C_WRS_Stop:
ldi TI2C_TEMP,(1<<TWINT)|(1<<TWSTO)|(1<<TWEN)
out TWCR,TI2C_TEMP ;使能TWI接口为 I2C 总线
;并发出停止条件
wdr ;复位看门狗定时器
rjmp TI2C_WRS_RET ;返回
TI2C_WRS_Error_End:
ldi TI2C_TEMP,(1<<TWINT)|(1<<TWSTO)|(1<<TWEN)
out TWCR,TI2C_TEMP ;使能TWI接口为 I2C 总线
;并发出停止条件
wdr ;复位看门狗定时器
;此处插入错误处理告警程序
TI2C_WRS_RET:
ret ;子程序返回
;*******************************************************************************
;*
;* 从 I2C 总线上的设备读一个字节数据子程序 - “TI2C_Read_Single”
;*
;* 说明:
;* 本子程序用于在单主方式下使用TWI接口从 I2C 总线上的设备读一个字节数据。
;* 本子程序己包括了按数据手册上的说明,对各种状态码出错进行处理的程序。
;*
;* 注意:
;* 在设置“TI2C_DeviceAddr”(I2C 总线上读取数据的设备地址)的值时,要保留
;* 其最后一位必须为 0 。此位用于控制数据的传送方向。
;*
;* 入口条件: 根据设备的情况,按是否需要写数据的存储地址分为下列三种情况:
;* ①.不需要写数据的存储地址,即“TI2C_DaAdNum”(r20)=0时,
;* 需设置下面这几个寄存器数值:
;* TI2C_DaAdNum(r20)-------- 在 I2C 总线上数据的存储地址个数(=0)
;* TI2C_DeviceAddr(r17)----- I2C 总线上读取数据的设备地址
;* ②.当写数据的存储地址不大于 256 B,即“TI2C_DaAdNum”(r20)=1时,
;* 需设置下面这几个寄存器数值:
;* TI2C_DaAdNum(r20)-------- 在 I2C 总线上数据的存储地址个数(=1)
;* TI2C_DeviceAddr(r17)----- I2C 总线上读取数据的设备地址
;* TI2C_DataAddr1(r18)------ I2C 总线上存取数据的存储地址1
;* ③.当写数据的存储地址不大于 64 KB,即“TI2C_DaAdNum”(r20)=2时,
;* 需设置下面这几个寄存器数值:
;* TI2C_DaAdNum(r20)-------- 在 I2C 总线上数据的存储地址个数(=2)
;* TI2C_DeviceAddr(r17)----- I2C 总线上读取数据的设备地址
;* TI2C_DataAddr1(r18)------ I2C 总线上存取数据的存储地址1
;* TI2C_DataAddr2(r19)------ I2C 总线上存取数据的存储地址2
;* 出口条件:
;* 程序正确运行结束后,将对会下面这个寄存器变量置值。
;* TI2C_Data(r21)----------- 从 I2C 总线上读取的数据
;* 对于程序运行是否正确,使用“T 标志”进行判断。
;* ①.当 I2C 总线上读取数据正确完成后,T 标志 = 0 (清除 T 标志)。
;* ②.I2C 总线上读取数据发生错误时,T 标志 = 1 (置值 T 标志)。
;*
;* 指令条数: 135 + return
;* 指令执行周期: 不确定 + return
;* 低位寄存器使用: None
;* 高位寄存器使用: 7 (r16,r17,r18,r19,r20,r21,r22)
;* 指针寄存器使用: None
;*
;*******************************************************************************
TI2C_Read_Single:
clt ;清除 T 标志
clr TI2C_ErrorNum ;错误次数计数器清 0
TI2C_RDS_Initialization:
ldi TI2C_TEMP,I2CTWI_BR_BR ;置 I2C 总线的通讯比特率
out TWBR,TI2C_TEMP
ldi TI2C_TEMP,I2CTWI_BR_SR
out TWSR,TI2C_TEMP
TI2C_RDS_Start:
ldi TI2C_TEMP,(1<<TWINT)|(1<<TWSTA)|(1<<TWEN)
out TWCR,TI2C_TEMP ;使能TWI接口为 I2C 总线
;并发出 START 信号(起始条件)
TI2C_RDS_GetACK1:
in TI2C_TEMP,TWCR ;等待 TWINT 置位,TWINT 置位表示
sbrs TI2C_TEMP,TWINT ;数椐已发送,及收到应答信号
rjmp TI2C_RDS_GetACK1
TI2C_RDS_StatusCode1:
in TI2C_TEMP,TWSR ;读取 TWI 状态寄存器的状态字内容
andi TI2C_TEMP,$f8 ;屏蔽预分频位
cpi TI2C_TEMP,TI2C_M_Start ;检查状态字是否为 START 信号已发送状态码?
breq TI2C_RDS_SLAW ;是,则继续
;否,进入错误处理
;-----------------------------------
; 此段程序用于发出 START 信号错误处理,并发出重复的 START 信号
TI2C_RDS_SCE_MStart:
inc TI2C_ErrorNum ;错误次数 + 1
cpi TI2C_ErrorNum,TI2C_ErrorNumI;检查错误次数是否超过设定的次数?
brlo TI2C_RDS_SCE_MStart1 ;否,则继续
rjmp TI2C_RDS_Error_End ;是,转至告警和结束传送处理
TI2C_RDS_SCE_MStart1:
ldi TI2C_TEMP,(1<<TWINT)|(1<<TWSTA)|(1<<TWEN)
out TWCR,TI2C_TEMP ;使能TWI接口为 I2C 总线
;并发出重复的 START 信号(起始条件)
TI2C_RDS_SCE_GetACK:
in TI2C_TEMP,TWCR ;等待 TWINT 置位,TWINT 置位表示
sbrs TI2C_TEMP,TWINT ;数椐已发送,及收到应答信号
rjmp TI2C_RDS_SCE_GetACK
TI2C_RDS_SCE_StatusCode:
in TI2C_TEMP,TWSR ;读取 TWI 状态寄存器的状态字内容
andi TI2C_TEMP,$f8 ;屏蔽预分频位
cpi TI2C_TEMP,TI2C_M_REPSTA ;检查状态字是否为重复的 START 信号已发送?
brne TI2C_RDS_SCE_MStart ;否,进入发出重复的 START 信号错误处理
;是,则继续
;*** 此段程序结束
TI2C_RDS_SLAW:
cpi TI2C_DaAdNum,$00 ;检查是否需要写存取数据的存储地址?
brne TI2C_RDS_SLAW1 ;是,则继续
rjmp TI2C_RDS_SLAR ;否,跳过写存储地址,直接发出 SLA + R
TI2C_RDS_SLAW1:
andi TI2C_DeviceAddr,$fe ;读数据的设备地址 + 传送方向(写数据)
out TWDR,TI2C_DeviceAddr
ldi TI2C_TEMP,(1<<TWINT)|(1<<TWEN)
out TWCR,TI2C_TEMP ;向 I2C 总线上发送
TI2C_RDS_Get_ACK2:
in TI2C_TEMP,TWCR ;等待 TWINT 置位,TWINT 置位表示
sbrs TI2C_TEMP,TWINT ;数椐已发送,及收到应答信号
rjmp TI2C_RDS_Get_ACK2
TI2C_RDS_StatusCode2:
in TI2C_TEMP,TWSR ;读取 TWI 状态寄存器的状态字内容
andi TI2C_TEMP,$f8 ;屏蔽预分频位
cpi TI2C_TEMP,TI2C_MT_SLA_A ;检查状态字是否为 SLA+W 已发送,
;接收到 ACK 状态码?
breq TI2C_RDS_DataAddr1 ;是,则继续
;否,进入错误处理
;-----------------------------------
; 此段程序用于 SLA+W 已发送,接收到 ACK 错误处理
TI2C_RDS_SCE_SLAW:
cpi TI2C_TEMP,TI2C_MT_SLA_NA ;检查状态字是否为 SLA+W 已发送,
;接收到 NOTACK 状态码?
brne TI2C_RDS_SCE_SLAW1 ;否,则继续
;是,进入错误处理
rjmp TI2C_RDS_SCE_MStart ;转向发出重复的 START 信号
TI2C_RDS_SCE_SLAW1:
rjmp TI2C_RDS_Error_End ;转至告警和结束传送处理,
;因为此 I2C 总线为单主模式,不会出现总线
;优先权仲裁失败状态码,所以如果出现非上述
;两种状态码,则 I2C 总线发生致命错误。
;如果为多主模式,那么在此应插入转为从机
;模式程序,以便让胜出主机寻址。
;*** 此段程序结束
TI2C_RDS_DataAddr1:
out TWDR,TI2C_DataAddr1 ;写存取数据存储地址1
ldi TI2C_TEMP,(1<<TWINT)|(1<<TWEN)
out TWCR,TI2C_TEMP ;向 I2C 总线上发送
TI2C_RDS_Get_ACK31:
in TI2C_TEMP,TWCR ;等待TWINT 置位,TWINT 置位表示
sbrs TI2C_TEMP,TWINT ;数椐已发送,及收到应答信号
rjmp TI2C_RDS_Get_ACK31
TI2C_RDS_StatusCode31:
in TI2C_TEMP,TWSR ;读取 TWI 状态寄存器的状态字内容
andi TI2C_TEMP,$f8 ;屏蔽预分频位
cpi TI2C_TEMP,TI2C_MT_DT_A ;检查状态字是否为数据已发送,
;接收到 ACK 状态码?
breq TI2C_RDS_DataAddr2 ;是,则继续
;否,进入错误处理
;-----------------------------------
; 此段程序用于数据已发送,接收到 ACK 错误处理
TI2C_RDS_SCE_DataAddr1:
cpi TI2C_TEMP,TI2C_MT_DT_NA ;检查状态字是否为数据已发送,
;接收到 NOTACK 状态码?
brne TI2C_RDS_SCE_DataAddr11 ;否,则继续
;是,进入错误处理
rjmp TI2C_RDS_SCE_MStart ;转向发出重复的 START 信号
TI2C_RDS_SCE_DataAddr11:
rjmp TI2C_RDS_Error_End ;转至告警和结束传送处理,
;因为此 I2C 总线为单主模式,不会出现总线
;优先权仲裁失败状态码,所以如果出现非上述
;两种状态码,则 I2C 总线发生致命错误。
;如果为多主模式,那么在此应插入转为从机
;模式程序,以便让胜出主机寻址。
;*** 此段程序结束
TI2C_RDS_DataAddr2:
dec TI2C_DaAdNum ;检查是否需要写数据存储地址的高字节?
brne TI2C_RDS_DataAddr21 ;是,则继续
rjmp TI2C_RDS_RepeatStart ;否,跳过,直接准备读数据
TI2C_RDS_DataAddr21:
inc TI2C_DaAdNum ;存取数据的存储地址个数返回为原数值
out TWDR,TI2C_DataAddr2 ;写存取数据存储地址2
ldi TI2C_TEMP,(1<<TWINT)|(1<<TWEN)
out TWCR,TI2C_TEMP ;向 I2C 总线上发送
TI2C_RDS_Get_ACK32:
in TI2C_TEMP,TWCR ;等待TWINT 置位,TWINT 置位表示
sbrs TI2C_TEMP,TWINT ;数椐已发送,及收到应答信号
rjmp TI2C_RDS_Get_ACK32
TI2C_RDS_StatusCode32:
in TI2C_TEMP,TWSR ;读取 TWI 状态寄存器的状态字内容
andi TI2C_TEMP,$f8 ;屏蔽预分频位
cpi TI2C_TEMP,TI2C_MT_DT_A ;检查状态字是否为数据已发送,
;接收到 ACK 状态码?
breq TI2C_RDS_RepeatStart ;是,则继续
;否,进入错误处理
;-----------------------------------
; 此段程序用于数据已发送,接收到 ACK 错误处理
TI2C_RDS_SCE_DataAddr2:
cpi TI2C_TEMP,TI2C_MT_DT_NA ;检查状态字是否为数据已发送,
;接收到 NOTACK 状态码?
brne TI2C_RDS_SCE_DataAddr12 ;否,则继续
;是,进入错误处理
rjmp TI2C_RDS_SCE_MStart ;转向发出重复的 START 信号
TI2C_RDS_SCE_DataAddr12:
rjmp TI2C_RDS_Error_End ;转至告警和结束传送处理,
;因为此 I2C 总线为单主模式,不会出现总线
;优先权仲裁失败状态码,所以如果出现非上述
;两种状态码,则 I2C 总线发生致命错误。
;如果为多主模式,那么在此应插入转为从机
;模式程序,以便让胜出主机寻址。
;*** 此段程序结束
TI2C_RDS_RepeatStart:
ldi TI2C_TEMP,(1<<TWINT)|(1<<TWSTA)|(1<<TWEN)
out TWCR,TI2C_TEMP ;使能TWI接口为 I2C 总线
;并发出重复的 START 信号(起始条件)
TI2C_RDS_RS_GetACK:
in TI2C_TEMP,TWCR ;等待 TWINT 置位,TWINT 置位表示
sbrs TI2C_TEMP,TWINT ;数椐已发送,及收到应答信号
rjmp TI2C_RDS_RS_GetACK
TI2C_RDS_RS_StatusCode:
in TI2C_TEMP,TWSR ;读取 TWI 状态寄存器的状态字内容
andi TI2C_TEMP,$f8 ;屏蔽预分频位
cpi TI2C_TEMP,TI2C_M_REPSTA ;检查状态字是否为重复的 START 信号已发送?
breq TI2C_RDS_SLAR ;是,则继续
;否,进入发出重复的 START 信号错误处理
;-----------------------------------
; 此段程序用于发出重复的 START 信号错误处理
inc TI2C_ErrorNum ;错误次数 + 1
cpi TI2C_ErrorNum,TI2C_ErrorNumI;检查错误次数是否超过设定的次数?
brlo TI2C_RDS_RepeatStart ;否,则继续
rjmp TI2C_RDS_Error_End ;是,转至告警和结束传送处理
;*** 此段程序结束
TI2C_RDS_SLAR:
ori TI2C_DeviceAddr,$01 ;读数据的设备地址 + 传送方向(读数据)
out TWDR,TI2C_DeviceAddr
ldi TI2C_TEMP,(1<<TWINT)|(1<<TWEN)
out TWCR,TI2C_TEMP ;向 I2C 总线上发送
TI2C_RDS_SLAR_Get_ACK:
in TI2C_TEMP,TWCR ;等待 TWINT 置位,TWINT 置位表示
sbrs TI2C_TEMP,TWINT ;数椐已发送,及收到应答信号
rjmp TI2C_RDS_SLAR_Get_ACK
TI2C_RDS_SLAR_StatusCode:
in TI2C_TEMP,TWSR ;读取 TWI 状态寄存器的状态字内容
andi TI2C_TEMP,$f8 ;屏蔽预分频位
cpi TI2C_TEMP,TI2C_MR_SLA_A ;检查状态字是否为 SLA+R 已发送,
;接收到 ACK 状态码?
breq TI2C_RDS_Data ;是,则继续
;否,进入错误处理
;-----------------------------------
; 此段程序用于 SLA+R 已发送,接收到 ACK 错误处理
TI2C_RDS_SCE_SLAR:
inc TI2C_ErrorNum ;错误次数 + 1
cpi TI2C_ErrorNum,TI2C_ErrorNumI;检查错误次数是否超过设定的次数?
brlo TI2C_RDS_SCE_SLAR1 ;否,则继续
rjmp TI2C_RDS_Error_End ;是,转至告警和结束传送处理
TI2C_RDS_SCE_SLAR1:
cpi TI2C_TEMP,TI2C_MR_SLA_NA ;检查状态字是否为 SLA+R 已发送,
;接收到 NOTACK 状态码?
brne TI2C_RDS_SCE_SLAR2 ;否,则继续
;是,进入错误处理
rjmp TI2C_RDS_RepeatStart ;转向发出重复的 START 信号
TI2C_RDS_SCE_SLAR2:
rjmp TI2C_RDS_Error_End ;转至告警和结束传送处理,
;因为此 I2C 总线为单主模式,不会出现总线
;优先权仲裁失败状态码,所以如果出现非上述
;两种状态码,则 I2C 总线发生致命错误。
;如果为多主模式,那么在此应插入转为从机
;模式程序,以便让胜出主机寻址。
;*** 此段程序结束
TI2C_RDS_Data:
ldi TI2C_TEMP,(1<<TWINT)|(1<<TWEN)
out TWCR,TI2C_TEMP ;清除 TWINT 位,启动接收数据
TI2C_RDS_Data1:
in TI2C_TEMP,TWCR ;等待 TWINT 置位,TWINT 置位表示
sbrs TI2C_TEMP,TWINT ;已从 I2C 总线上接收到数据
rjmp TI2C_RDS_Data1
in TI2C_Data,TWDR ;读取接收到的数据
TI2C_RDS_StatusCode4:
in TI2C_TEMP,TWSR ;读取 TWI 状态寄存器的状态字内容
andi TI2C_TEMP,$f8 ;屏蔽预分频位
cpi TI2C_TEMP,TI2C_MR_DT_NA ;检查状态字是否为接收到数据,
;NOTACK 已返回状态码?
breq TI2C_RDS_Stop ;是,则继续
;否,进入错误处理
;-----------------------------------
;*** 此段程序用于接收到数据,NOTACK 已返回错误处理
TI2C_RDS_SCE_Data:
inc TI2C_ErrorNum ;错误次数 + 1
cpi TI2C_ErrorNum,TI2C_ErrorNumI;检查错误次数是否超过设定的次数?
brlo TI2C_RDS_SCE_Data1 ;否,则继续
rjmp TI2C_RDS_Error_End ;是,转至告警和结束传送处理
TI2C_RDS_SCE_Data1:
cpi TI2C_TEMP,TI2C_MR_DT_A ;检查状态字是否为接收到数据,
;ACK 已返回状态码?
brne TI2C_RDS_SCE_Data2 ;否,则继续
;是,进入错误处理
rjmp TI2C_RDS_RepeatStart ;转向发出重复的 START 信号
TI2C_RDS_SCE_Data2:
rjmp TI2C_RDS_Error_End ;转至告警和结束传送处理,
;因为此 I2C 总线为单主模式,不会出现总线
;优先权仲裁失败状态码,所以如果出现非上述
;两种状态码,则 I2C 总线发生致命错误。
;如果为多主模式,那么在此应插入转为从机
;模式程序,以便让胜出主机寻址。
;*** 此段程序结束
TI2C_RDS_Stop:
ldi TI2C_TEMP,(1<<TWINT)|(1<<TWSTO)|(1<<TWEN)
out TWCR,TI2C_TEMP ;使能TWI接口为 I2C 总线
;并发出停止条件
wdr ;复位看门狗定时器
rjmp TI2C_RDS_RET ;返回
TI2C_RDS_Error_End:
ldi TI2C_TEMP,(1<<TWINT)|(1<<TWSTO)|(1<<TWEN)
out TWCR,TI2C_TEMP ;使能TWI接口为 I2C 总线
;并发出停止条件
wdr ;复位看门狗定时器
;此处插入错误处理告警程序
set ;置 T 标志
TI2C_RDS_RET:
ret ;子程序返回
;*******************************************************************************
;*
;* 子程序名: TI2CBus_SMM_Page.asm
;* 程序名称: 单主方式下使用TWI接口的 I2C 总线程序(主设备)
;* 版本: 1.0
;* 适用 MCU 型号: AVR所有型号
;* 使用资源: r12,r16,r17,r18,r19,r20,r21,r22,r23,r30,r31
;*
;* 程序功能:
;* 本程序是使用TWI接口的 I2C 总线上的主器件与从器件通信的基本程序。
;* 在 I2C 总线上,单一主器件方式受限制于单一总线控制器。在绝大部分应用设计
;* 中并不需要 I2C 总线提供的多主器件功能。本程序共包括二个子程序。分别为与
;* SRAM (静态随机存储器)交换存取多个字节数据到 I2C 总线上从器件的子程序。
;* 其入口条件和出口条件见各子程序的具体说明。
;*
;* 注意:
;* ①.对于有些器件如:EEPROM 等,在两次调用子程序之间应间隔 5~10 ms 。
;* ②.针对各种 I2C 总线的器件对数据存取地址的不同,二个子程序都分别对各
;* 种 I2C 总线的器件进行了分类,共分为下面三类:
;* ⑴.不需要数据的存取地址。
;* ⑵.数据的存取地址为 1 个字节。
;* ⑶.数据的存取地址为 2 个字节。
;* 无论那一类,在调用子程序前都应对“TI2C_DaAdNum”(r20)置值,且只能分别置
;* 0、1、2 这三个数值。
;*
;* 编作者:
;* 编作者 E-Mail: PTZSW@163.COM
;* 编制日期: 2005年3月8日
;*
;*******************************************************************************
;*
;* 指令条数: 134 + return
;* 指令执行周期: 不确定 + return
;* 低位寄存器使用: 1(r12)
;* 高位寄存器使用: 8(r16,r17,r18,r19,r20,r21,r22,r23)
;* 指针寄存器使用: Z
;*
;*******************************************************************************
;******** 本程序包括的定义文件:
;.include "TI2CBus_SMM_def.inc" ;寄存器变量和常数定义
;******** 本程序需调用的子程序定义:
.include "TI2CBus_SMM.asm" ;单主方式下使用TWI接口的 I2C 总线程序
;******** 程序指令代码清单:
;*******************************************************************************
;* 本程序共包括下面二个子程序:
;*
;* “TI2C_Write_FSRAM” ------- 从 SRAM 中向 I2C 总线上的设备写多个字节子程序
;*
;* “TI2C_Read_TSRAM” -------- 从 I2C 总线上的设备读取多个字节到 SRAM 中子程序
;*
;*******************************************************************************
;*******************************************************************************
;*
;* 从 SRAM 中向 I2C 总线上的设备写多个字节数据子程序 - “TI2C_Write_FSRAM”
;*
;* 说明:
;* 本子程序用于在单主方式下使用TWI接口从由 Z 指针指向起始地址的 SRAM 中
;* 向 I2C 总线上的设备写入多个字节数据。但一次最多不超过 255 个字节。本子程序己
;* 包括了按数据手册上的说明,对各种状态码出错进行处理的程序。
;*
;* 注意:
;* ①.在设置“TI2C_DeviceAddr”(I2C 总线上写入数据的设备地址)的值时,要保
;* 留其最后一位必须为 0 。此位用于控制数据的传送方向。
;* ②.程序运行结束后,将恢复 Z 指针为原来的数值。下列这些寄存器变量的数值
;* “TI2C_DeviceAddr”(r17)、“TI2C_DataAddr1”(r18)、“TI2C_DataAddr2”
;* (r19)、“TI2C_DaAdNum”(r20)、“TI2C_DataNum”(r12)为原来的数值。
;*
;* 入口条件: 根据设备的情况,按是否需要写数据的存储地址分为下列三种情况:
;* ①.不需要写数据的存储地址,即“TI2C_DaAdNum”(r20)=0时,
;* 需设置下面这几个寄存器数值:
;* TI2C_DaAdNum(r20)-------- 在 I2C 总线上数据的存储地址个数(=0)
;* TI2C_DeviceAddr(r17)----- I2C 总线上写入数据的设备地址
;* TI2C_DataNum(r12)-------- 向 I2C 总线上写入的数据个数
;* Z 指针 -------------------- 指向在 SRAM 中多个字节数据的起始地址
;* ②.当写数据的存储地址不大于 256 B,即“TI2C_DaAdNum”(r20)=1时,
;* 需设置下面这几个寄存器数值:
;* TI2C_DaAdNum(r20)-------- 在 I2C 总线上数据的存储地址个数(=1)
;* TI2C_DeviceAddr(r17)----- I2C 总线上写入数据的设备地址
;* TI2C_DataAddr1(r18)------ I2C 总线上存取数据的存储地址1
;* TI2C_DataNum(r12)-------- 向 I2C 总线上写入的数据个数
;* Z 指针 -------------------- 指向在 SRAM 中多个字节数据的起始地址
;* ③.当写数据的存储地址不大于 64 KB,即“TI2C_DaAdNum”(r20)=2时,
;* 需设置下面这几个寄存器数值:
;* TI2C_DaAdNum(r20)-------- 在 I2C 总线上数据的存储地址个数(=2)
;* TI2C_DeviceAddr(r17)----- I2C 总线上写入数据的设备地址
;* TI2C_DataAddr1(r18)------ I2C 总线上存取数据的存储地址1
;* TI2C_DataAddr2(r19)------ I2C 总线上存取数据的存储地址2
;* TI2C_DataNum(r12)-------- 向 I2C 总线上写入的数据个数
;* Z 指针 -------------------- 指向在 SRAM 中多个字节数据的起始地址
;*
;* 指令条数: 115 + return
;* 指令执行周期: 不确定 + return
;* 低位寄存器使用: 1 (r12)
;* 高位寄存器使用: 8 (r16,r17,r18,r19,r20,r21,r22,r23)
;* 指针寄存器使用: Z
;*
;*******************************************************************************
TI2C_Write_FSRAM:
push ZL ;压入寄存器中的数值到堆栈
push ZH
in TI2C_TEMP,SREG ;压状态寄存器中的标志值到堆栈
push TI2C_TEMP
clr TI2C_ErrorNum ;错误次数计数器清 0
TI2C_WR_Initialization:
ldi TI2C_TEMP,I2CTWI_BR_BR ;置 I2C 总线的通讯比特率
out TWBR,TI2C_TEMP
ldi TI2C_TEMP,I2CTWI_BR_SR
out TWSR,TI2C_TEMP
TI2C_WR_Start:
ldi TI2C_TEMP,(1<<TWINT)|(1<<TWSTA)|(1<<TWEN)
out TWCR,TI2C_TEMP ;使能TWI接口为 I2C 总线
;并发出 START 信号(起始条件)
TI2C_WR_GetACK1:
in TI2C_TEMP,TWCR ;等待 TWINT 置位,TWINT 置位表示
sbrs TI2C_TEMP,TWINT ;数椐已发送,及收到应答信号
rjmp TI2C_WR_GetACK1
TI2C_WR_StatusCode1:
in TI2C_TEMP,TWSR ;读取 TWI 状态寄存器的状态字内容
andi TI2C_TEMP,$f8 ;屏蔽预分频位
cpi TI2C_TEMP,TI2C_M_Start ;检查状态字是否为 START 信号已发送状态码?
breq TI2C_WR_SLAW ;是,则继续
;否,进入错误处理
;-----------------------------------
; 此段程序用于发出 START 信号错误处理,并发出重复的 START 信号
TI2C_WR_SCE_MStart:
inc TI2C_ErrorNum ;错误次数 + 1
cpi TI2C_ErrorNum,TI2C_ErrorNumI;检查错误次数是否超过设定的次数?
brlo TI2C_WR_SCE_MStart1 ;否,则继续
rjmp TI2C_WR_Error_End ;是,转至告警和结束传送处理
TI2C_WR_SCE_MStart1:
ldi TI2C_TEMP,(1<<TWINT)|(1<<TWSTA)|(1<<TWEN)
out TWCR,TI2C_TEMP ;使能TWI接口为 I2C 总线
;并发出重复的 START 信号(起始条件)
TI2C_WR_SCE_GetACK:
in TI2C_TEMP,TWCR ;等待 TWINT 置位,TWINT 置位表示
sbrs TI2C_TEMP,TWINT ;数椐已发送,及收到应答信号
rjmp TI2C_WR_SCE_GetACK
TI2C_WR_SCE_StatusCode:
in TI2C_TEMP,TWSR ;读取 TWI 状态寄存器的状态字内容
andi TI2C_TEMP,$f8 ;屏蔽预分频位
cpi TI2C_TEMP,TI2C_M_REPSTA ;检查状态字是否为重复的 START 信号已发送?
brne TI2C_WR_SCE_MStart ;否,进入发出重复的 START 信号错误处理
;是,则继续
;*** 此段程序结束
TI2C_WR_SLAW:
andi TI2C_DeviceAddr,$fe ;写数据的设备地址 + 传送方向(写数据)
out TWDR,TI2C_DeviceAddr
ldi TI2C_TEMP,(1<<TWINT)|(1<<TWEN)
out TWCR,TI2C_TEMP ;向 I2C 总线上发送
TI2C_WR_Get_ACK2:
in TI2C_TEMP,TWCR ;等待 TWINT 置位,TWINT 置位表示
sbrs TI2C_TEMP,TWINT ;数椐已发送,及收到应答信号
rjmp TI2C_WR_Get_ACK2
TI2C_WR_StatusCode2:
in TI2C_TEMP,TWSR ;读取 TWI 状态寄存器的状态字内容
andi TI2C_TEMP,$f8 ;屏蔽预分频位
cpi TI2C_TEMP,TI2C_MT_SLA_A ;检查状态字是否为 SLA+W 已发送,
;接收到 ACK 状态码?
breq TI2C_WR_DataAddr1 ;是,则继续
;否,进入错误处理
;-----------------------------------
; 此段程序用于 SLA+W 已发送,接收到 ACK 错误处理
TI2C_WR_SCE_SLAW:
cpi TI2C_TEMP,TI2C_MT_SLA_NA ;检查状态字是否为 SLA+W 已发送,
;接收到 NOTACK 状态码?
brne TI2C_WR_SCE_SLAW1 ;否,则继续
;是,进入错误处理
rjmp TI2C_WR_SCE_MStart ;转向发出重复的 START 信号
TI2C_WR_SCE_SLAW1:
rjmp TI2C_WR_Error_End ;转至告警和结束传送处理,
;因为此 I2C 总线为单主模式,不会出现总线
;优先权仲裁失败状态码,所以如果出现非上述
;两种状态码,则 I2C 总线发生致命错误。
;如果为多主模式,那么在此应插入转为从机
;模式程序,以便让胜出主机寻址。
;*** 此段程序结束
TI2C_WR_DataAddr1:
cpi TI2C_DaAdNum,$00 ;检查是否需要写存取数据的存储地址?
brne TI2C_WR_DataAddr11 ;是,则继续
rjmp TI2C_WR_Data ;否,跳过写存储地址,直接写数据
TI2C_WR_DataAddr11:
out TWDR,TI2C_DataAddr1 ;写存取数据存储地址1
ldi TI2C_TEMP,(1<<TWINT)|(1<<TWEN)
out TWCR,TI2C_TEMP ;向 I2C 总线上发送
TI2C_WR_Get_ACK31:
in TI2C_TEMP,TWCR ;等待TWINT 置位,TWINT 置位表示
sbrs TI2C_TEMP,TWINT ;数椐已发送,及收到应答信号
rjmp TI2C_WR_Get_ACK31
TI2C_WR_StatusCode31:
in TI2C_TEMP,TWSR ;读取 TWI 状态寄存器的状态字内容
andi TI2C_TEMP,$f8 ;屏蔽预分频位
cpi TI2C_TEMP,TI2C_MT_DT_A ;检查状态字是否为数据已发送,
;接收到 ACK 状态码?
breq TI2C_WR_DataAddr2 ;是,则继续
;否,进入错误处理
;-----------------------------------
; 此段程序用于数据已发送,接收到 ACK 错误处理
TI2C_WR_SCE_DataAddr1:
cpi TI2C_TEMP,TI2C_MT_DT_NA ;检查状态字是否为数据已发送,
;接收到 NOTACK 状态码?
brne TI2C_WR_SCE_DataAddr11 ;否,则继续
;是,进入错误处理
rjmp TI2C_WR_SCE_MStart ;转向发出重复的 START 信号
TI2C_WR_SCE_DataAddr11:
rjmp TI2C_WR_Error_End ;转至告警和结束传送处理,
;因为此 I2C 总线为单主模式,不会出现总线
;优先权仲裁失败状态码,所以如果出现非上述
;两种状态码,则 I2C 总线发生致命错误。
;如果为多主模式,那么在此应插入转为从机
;模式程序,以便让胜出主机寻址。
;*** 此段程序结束
TI2C_WR_DataAddr2:
dec TI2C_DaAdNum ;检查是否需要写数据存储地址2?
brne TI2C_WR_DataAddr21 ;是,则继续
rjmp TI2C_WR_Data ;否,跳过,直接写数据
TI2C_WR_DataAddr21:
inc TI2C_DaAdNum ;存取数据的存储地址个数返回为原数值
out TWDR,TI2C_DataAddr2 ;写存取数据存储地址2
ldi TI2C_TEMP,(1<<TWINT)|(1<<TWEN)
out TWCR,TI2C_TEMP ;向 I2C 总线上发送
TI2C_WR_Get_ACK32:
in TI2C_TEMP,TWCR ;等待TWINT 置位,TWINT 置位表示
sbrs TI2C_TEMP,TWINT ;数椐已发送,及收到应答信号
rjmp TI2C_WR_Get_ACK32
TI2C_WR_StatusCode32:
in TI2C_TEMP,TWSR ;读取 TWI 状态寄存器的状态字内容
andi TI2C_TEMP,$f8 ;屏蔽预分频位
cpi TI2C_TEMP,TI2C_MT_DT_A ;检查状态字是否为数据已发送,
;接收到 ACK 状态码?
breq TI2C_WR_Data ;是,则继续
;否,进入错误处理
;-----------------------------------
; 此段程序用于数据已发送,接收到 ACK 错误处理
TI2C_WR_SCE_DataAddr2:
cpi TI2C_TEMP,TI2C_MT_DT_NA ;检查状态字是否为数据已发送,
;接收到 NOTACK 状态码?
brne TI2C_WR_SCE_DataAddr12 ;否,则继续
;是,进入错误处理
rjmp TI2C_WR_SCE_MStart ;转向发出重复的 START 信号
TI2C_WR_SCE_DataAddr12:
rjmp TI2C_WR_Error_End ;转至告警和结束传送处理,
;因为此 I2C 总线为单主模式,不会出现总线
;优先权仲裁失败状态码,所以如果出现非上述
;两种状态码,则 I2C 总线发生致命错误。
;如果为多主模式,那么在此应插入转为从机
;模式程序,以便让胜出主机寻址。
;*** 此段程序结束
TI2C_WR_Data:
clr TI2C_CNT ;清除循环计数器
TI2C_WR_Data1:
ld TI2C_Data,Z+ ;从 SRAM 中读取要发送的数椐
out TWDR,TI2C_Data ;写发送的数椐
ldi TI2C_TEMP,(1<<TWINT)|(1<<TWEN)
out TWCR,TI2C_TEMP ;向 I2C 总线上发送
TI2C_WR_Get_ACK4:
in TI2C_TEMP,TWCR ;等待TWINT 置位,TWINT 置位表示
sbrs TI2C_TEMP,TWINT ;数椐已发送,及收到应答信号
rjmp TI2C_WR_Get_ACK4
TI2C_WR_StatusCode4:
in TI2C_TEMP,TWSR ;读取 TWI 状态寄存器的状态字内容
andi TI2C_TEMP,$f8 ;屏蔽预分频位
cpi TI2C_TEMP,TI2C_MT_DT_A ;检查状态字是否为数据已发送,
;接收到 ACK 状态码?
breq TI2C_WR_Data2 ;是,则继续
;否,进入错误处理
;-----------------------------------
; 此段程序用于数据已发送,接收到 ACK 错误处理
TI2C_WR_SCE_Data:
cpi TI2C_TEMP,TI2C_MT_DT_NA ;检查状态字是否为数据已发送,
;接收到 NOTACK 状态码?
brne TI2C_WR_SCE_Data1 ;否,则继续
;是,进入错误处理
clr TI2C_TEMP ;Z 指针退回到起始地址值
inc TI2C_CNT ;其算法为:将 Z 指针减去己发送的数据个数,
sub ZL,TI2C_CNT ;再减去其预增量 1 。
sbc ZH,TI2C_TEMP
rjmp TI2C_WR_SCE_MStart ;转向发出重复的 START 信号
TI2C_WR_SCE_Data1:
rjmp TI2C_WR_Error_End ;转至告警和结束传送处理,
;因为此 I2C 总线为单主模式,不会出现总线
;优先权仲裁失败状态码,所以如果出现非上述
;两种状态码,则 I2C 总线发生致命错误。
;如果为多主模式,那么在此应插入转为从机
;模式程序,以便让胜出主机寻址。
;*** 此段程序结束
TI2C_WR_Data2:
inc TI2C_CNT ;循环计数器 + 1
cpse TI2C_CNT,TI2C_DataNum ;所有数据个数全部写完否?是,转到结束
rjmp TI2C_WR_Data1 ;否,继续写下一个数据
TI2C_WR_Stop:
ldi TI2C_TEMP,(1<<TWINT)|(1<<TWSTO)|(1<<TWEN)
out TWCR,TI2C_TEMP ;使能TWI接口为 I2C 总线
;并发出停止条件
wdr ;复位看门狗定时器
rjmp TI2C_WR_RET ;返回
TI2C_WR_Error_End:
ldi TI2C_TEMP,(1<<TWINT)|(1<<TWSTO)|(1<<TWEN)
out TWCR,TI2C_TEMP ;使能TWI接口为 I2C 总线
;并发出停止条件
wdr ;复位看门狗定时器
;此处插入错误处理告警程序
TI2C_WR_RET:
pop TI2C_TEMP
out SREG,TI2C_TEMP ;弹出堆栈中的标志值到状态寄存器
pop ZH ;弹出堆栈中的数值到寄存器
pop ZL
ret ;子程序返回
;*******************************************************************************
;*
;* 从 I2C 总线上的设备读取多个字节数据到 SRAM 中子程序 - “TI2C_Read_TSRAM”
;*
;* 说明:
;* 本子程序用于在单主方式下使用TWI接口从 I2C 总线上的设备读取多个字节数
;* 据到由 Z 指针指向起始地址的 SRAM 中。但一次最多不超过 255 个字节。本子程序己
;* 包括了按数据手册上的说明,对各种状态码出错进行处理的程序。
;*
;* 注意:
;* ①.在设置“TI2C_DeviceAddr”(I2C 总线上读取数据的设备地址)的值时,要保
;* 留其最后一位必须为 0 。此位用于控制数据的传送方向。
;* ②.程序运行结束后,将恢复 Z 指针为原来的数值。下列这些寄存器变量的数值
;* “TI2C_DeviceAddr”(r17)、“TI2C_DataAddr1”(r18)、“TI2C_DataAddr2”
;* (r19)、“TI2C_DaAdNum”(r20)、“TI2C_DataNum”(r12)为原来的数值。
;*
;* 入口条件: 根据设备的情况,按是否需要写数据的存储地址分为下列三种情况:
;* ①.不需要写数据的存储地址,即“TI2C_DaAdNum”(r20)=0时,
;* 需设置下面这几个寄存器数值:
;* TI2C_DaAdNum(r20)-------- 在 I2C 总线上数据的存储地址个数(=0)
;* TI2C_DeviceAddr(r17)----- I2C 总线上读取数据的设备地址
;* TI2C_DataNum(r12)-------- 从 I2C 总线上读取的数据个数
;* Z 指针 -------------------- 指向在 SRAM 中多个字节数据的起始地址
;* ②.当写数据的存储地址不大于 256 B,即“TI2C_DaAdNum”(r20)=1时,
;* 需设置下面这几个寄存器数值:
;* TI2C_DaAdNum(r20)-------- 在 I2C 总线上数据的存储地址个数(=1)
;* TI2C_DeviceAddr(r17)----- I2C 总线上读取数据的设备地址
;* TI2C_DataAddr1(r18)------ I2C 总线上存取数据的存储地址1
;* TI2C_DataNum(r12)-------- 从 I2C 总线上读取的数据个数
;* Z 指针 -------------------- 指向在 SRAM 中多个字节数据的起始地址
;* ③.当写数据的存储地址不大于 64 KB,即“TI2C_DaAdNum”(r20)=2时,
;* 需设置下面这几个寄存器数值:
;* TI2C_DaAdNum(r20)-------- 在 I2C 总线上数据的存储地址个数(=2)
;* TI2C_DeviceAddr(r17)----- I2C 总线上读取数据的设备地址
;* TI2C_DataAddr1(r18)------ I2C 总线上存取数据的存储地址1
;* TI2C_DataAddr2(r19)------ I2C 总线上存取数据的存储地址2
;* TI2C_DataNum(r12)-------- 从 I2C 总线上读取的数据个数
;* Z 指针 -------------------- 指向在 SRAM 中多个字节数据的起始地址
;* 出口条件:
;* 程序运行结束后,将读取的数据送到由 Z 指针指向起始地址的 SRAM 中。
;* Z 指针 -------------------- 指向在 SRAM 中多个字节数据的起始地址
;*
;* 指令条数: 19 + return
;* 指令执行周期: 不确定 + return
;* 低位寄存器使用: 1 (r12)
;* 高位寄存器使用: 8 (r16,r17,r18,r19,r20,r21,r22,r23)
;* 指针寄存器使用: Z
;*
;*******************************************************************************
TI2C_Read_TSRAM:
push ZL ;压入寄存器中的数值到堆栈
push ZH
push TI2C_DataAddr2
push TI2C_DataAddr1
in TI2C_TEMP,SREG ;压状态寄存器中的标志值到堆栈
push TI2C_TEMP
clr TI2C_CNT ;清除循环计数器
TI2C_Read_TSRAM1:
rcall TI2C_Read_Single ;读入单个字节
brts TI2C_RD_RET ;正确读入单个字节否?错误,转至结束
st Z+,TI2C_Data ;存储进 SRAM 中
inc TI2C_DataAddr2 ;存取数据的存储地址2 + 1
;--------------------------------------------------------------------------
;注:如果数据的存取地址为 1 个字节,用下面这条指令代替上面条指令。
; inc TI2C_DataAddr1 ;存取数据的存储地址1 + 1
inc TI2C_CNT ;循环计数器 + 1
cpse TI2C_CNT,TI2C_DataNum ;所有数据个数全部读取完否?是,转到结束
rjmp TI2C_Read_TSRAM1 ;否,继续读取下一个数据
TI2C_RD_RET:
pop TI2C_TEMP
out SREG,TI2C_TEMP ;弹出堆栈中的标志值到状态寄存器
pop TI2C_DataAddr1
pop TI2C_DataAddr2
pop ZH ;弹出堆栈中的数值到寄存器
pop ZL
ret ;子程序返回 |
|