搜索
bottom↓
回复: 18

一个己调试好的 TWI/I2C 汇编程序带读写AT24C1024程序

[复制链接]

出0入0汤圆

发表于 2005-3-14 21:33:03 | 显示全部楼层 |阅读模式
;*******************************************************************************

;*

;* 子程序名:          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                             ;子程序返回

出0入0汤圆

发表于 2005-5-13 12:37:26 | 显示全部楼层
我看应该把楼上的东东整理为范例,以方便大家搜索!

出0入0汤圆

发表于 2005-5-14 01:00:45 | 显示全部楼层
学习学习

出0入0汤圆

发表于 2005-5-15 15:32:31 | 显示全部楼层
太长了,我晕!!!

出0入0汤圆

发表于 2005-6-29 22:19:02 | 显示全部楼层
能否再写一个C的?然后做成范例?

出0入0汤圆

发表于 2005-7-1 02:03:16 | 显示全部楼层
牛啊~

向你学习~



读写1024要不要那么长的代码啊。头晕了。。用c不是简单多了?(我怎么也变懒了)

出0入0汤圆

发表于 2006-9-11 12:55:36 | 显示全部楼层
。。。。

东西是好东西,但是ASM实在懒得看啊!!

出0入0汤圆

发表于 2007-4-18 22:52:00 | 显示全部楼层
你这个程序看起来唬人,其实根本就不能运行,尤其是mega以后的型号,这个程序根本走不通。一看就知道和datasheet上给的一样,自己都没有思考,还说适用avr所有型号,呵呵。。。

出0入0汤圆

发表于 2007-4-19 06:13:51 | 显示全部楼层
请楼上的不要这么说.这个程序能正确运行,我在M8,M16,M128都正确.

出0入0汤圆

 楼主| 发表于 2007-4-30 21:05:03 | 显示全部楼层
今天想用C重编这个程序,重新看一下以前的思路,发现有这么多的朋友评论,就做一个回复。

谢谢8楼的肯定,人都喜欢赞扬,我这个凡夫俗子也不能免俗,呵呵。。。 这个程序我在ATMega16上运行,可以正确运行。

7楼讲的也没有错,我们写程序如果不看datasheet,那岂非天才。datasheet上给的例程一般都是比较好的。

出0入0汤圆

发表于 2007-4-30 23:03:00 | 显示全部楼层
这太多了,眼睛都花了,用C或者BASIC真方便太多了,也很稳定!

出0入0汤圆

发表于 2007-5-1 15:57:49 | 显示全部楼层
楼主不错,经常看到你给的汇编范例很详细,很工整,多谢了

出0入0汤圆

发表于 2007-10-13 09:21:33 | 显示全部楼层
谢谢楼主  这个程序我试过了  全部通过了   多谢  而且注释很详细
头像被屏蔽

出0入0汤圆

发表于 2007-10-13 10:17:20 | 显示全部楼层
注解得真详细,赞一个。另这么长的汇编,佩服!

出0入0汤圆

发表于 2007-10-13 10:37:35 | 显示全部楼层
两年多了,怎么才浮上来...

Armok:
精华(酷)帖怎么搜呀?我从人工整理的关键字中只找到6条记录,从来不变。

出0入0汤圆

发表于 2007-10-14 00:35:41 | 显示全部楼层
可惜不是C的

出0入0汤圆

发表于 2010-9-27 17:06:33 | 显示全部楼层
我找了几天,终于在这里找到了 TWI读写AT24C1024汇编程序带程序。非常感谢!现在使用汇编程序已经很难寻觅了。

出0入0汤圆

发表于 2010-10-18 17:11:47 | 显示全部楼层
牛XXXX

出0入0汤圆

发表于 2013-4-23 22:28:14 | 显示全部楼层
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-5-6 14:47

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表