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

📄 twi_main.doc

📁 iic for avr very good
💻 DOC
📖 第 1 页 / 共 2 页
字号:
        state=ST_FAIL;
        break;
    }

    if (state==ST_FAIL)
    {//错误处理
        strTWI.FAILCNT++;
        if (strTWI.FAILCNT<FAIL_MAX)
        {//重试次数未超出最大值,
            TWCR=(1<<TWSTA)|TW_ACT;				//发生错误,启动start信号
        }
        else
        {//否则停止
            TWCR=(1<<TWSTO)|TW_ACT;				//发送停止信号,不会再产生中断了
            strTWI.STATUS=TW_FAIL;
        }
    }
    state++;
    strTWI.STATE=state;							//保存状态
}



int main(void)
{
    unsigned char i;
    //上电默认DDRx=0x00,PORTx=0x00 输入,无上拉电阻
    PORTA=0xFF;									//不用的管脚使能内部上拉电阻。
    PORTB=0xFF;
    PORTC=0xFF;									//SCL,SDA使能了内部的10K上拉电阻
    PORTD=0xFF;

    //TWI初始化
    TWSR=0x00;									//预分频=0^4=1
    TWBR=TWBR_SET;
    TWAR=0x00;									//主机模式,该地址无效
    TWCR=0x00;									//关闭TWI模块
    sei();										//使能全局中断
    strTWI.STATUS=TW_OK;

    TWI_RW(SLA_24CXX+(ADDR_24C02<<1)+TW_WRITE,0x10,&ORGDATA[0],8);
    //从0x10地址开始写入8个字节数据
    while(strTWI.STATUS==TW_BUSY);				//等待操作完成
    if (strTWI.STATUS==TW_FAIL)
    {
        //操作失败?
    }
    _delay_ms(10);								//延时等待编程完成
    while(1)
    {
        i=TWI_RW(SLA_24CXX+(ADDR_24C02<<1)+TW_READ,0x10,&CMPDATA[0],8);
        //从0x10地址开始读出8个字节数据
        while(strTWI.STATUS==TW_BUSY);			//等待操作完成
        //如果不加等待,则需要检测返回值i才能知道当前操作是否执行了
        // 0 OP_BUSY 之前的操作没完成,没执行当前操作
        // 1 OP_RUN  当前操作执行中
        if (strTWI.STATUS==TW_FAIL)
        {
            //操作失败?
        }
        //读取成功,对比ORGDATA和CMPDATA的数据

        i=TWI_RW(SLA_24CXX+(ADDR_24C02<<1)+TW_READ,0x00,&BUFFER[0],256);
        //从0x00地址开始读出256个字节数据(整个ATC24C02)
        while(strTWI.STATUS==TW_BUSY);			//等待操作完成
    };
}
/*
两线串行接口总线定义
	两线接口TWI很适合于典型的处理器应用。
	TWI协议允许系统设计者只用两根双向传输线就可以将128个不同的设备互连到一起。
	这两根线一是时钟SCL,一是数据SDA。外部硬件只需要两个上拉电阻,每根线上一个。
	所有连接到总线上的设备都(必须)有自己的地址。
 注意:就是说不能有两个相同地址的设备
	TWI协议解决了总线仲裁的问题。
	
	所有 TWI 兼容的器件的总线驱动都是漏极开路或集电极开路的。这样就实现了对接口操作非常关键的线与功能。
	TWI器件输出为"0”时,TWI总线会产生低电平。
	当所有的TWI器件输出为三态时,总线会输出高电平,允许上拉电阻将电压拉高。
 注意:为保证所有的总线操作,凡是与TWI 总线连接的AVR 器件必须上电。
 
	与总线连接的器件数目受如下条件限制:
	总线电容要低于400pF,而且可以用7 位从机地址进行寻址。
	两个不同的规范,一种是总线速度低于100 kHz,而另外一种是总线速度高达400 kHz。
	
SCL和SDA引脚
	SCL与SDA为MCU的 TWI接口引脚。
	引脚的输出驱动器包含一个波形斜率限制器以满足TWI 规范。
	引脚的输入部分包括尖峰抑制单元以去除小于50ns 的毛刺。
	当相应的端口设置为SCL与SDA引脚时,可以使能I/O口内部的10K上拉电阻,这样可省掉外部的上拉电阻
注意:如果要作高速通讯或者从机数量较多,最好还是外接合适的上拉电阻
 
比特率发生器单元
	TWI工作于主机模式时,比特率发生器控制时钟信号SCL的周期。
	具体由TWI状态寄存器TWSR的预分频系数以及比特率寄存器TWBR设定。
	当TWI工作在从机模式时,不需要对比特率或预分频进行设定,但从机的CPU时钟频率必须大于TWI时钟线SCL频率的16倍。
注意,从机可能会延长SCL 低电平的时间,从而降低TWI 总线的平均时钟周期。
	SCL的频率根据以下的公式产生:
		fSCL=fCPU/((16+2(TWBR)(4^TWPS))
	TWBR = TWI比特率寄存器的数值
	TWPS = TWI状态寄存器预分频的数值
Note:TWI 工作在主机模式时,TWBR 值应该不小于10,否则主机会在SDA 与 SCL 产生错误输出作为提示信号。
	问题出现于TWI 工作在主机模式下,向从机发送Start + SLA + R/W 的时候(不需要真的有从机与总线连接)。
	
控制单元
	控制单元监听TWI 总线,并根据 TWI 控制寄存器TWCR 的设置作出相应的响应。
	当TWI总线上产生需要应用程序干预处理的事件时,TWI 中断标志位TWINT 置位。
	在下一个时钟周期, TWI 状态寄存器TWSR 被表示这个事件的状态码字所更新。
	在其它时间里,TWSR 的内容为一个表示无事件发生的特殊状态字。
	一旦TWINT 标志位置"1”,时钟线SCL 即被拉低,暂停TWI 总线上的数据传输,让用户程序处理事件。
	在下列状况出现时, TWINT 标志位置位:
	? 在TWI 传送完START/REPEATED START 信号之后
	? 在TWI 传送完SLA+R/W 数据之后
	? 在TWI 传送完地址字节之后
	? 在TWI 总线仲裁失败之后
	? 在TWI 被主机寻址之后( 广播方式或从机地址匹配)
	? 在TWI 接收到一个数据字节之后
	? 作为从机工作时, TWI 接收到STOP 或REPEATED START 信号之后
	? 由于非法的START 或STOP 信号造成总线错误时
 
TWI 寄存器说明
	
TWI 比特率寄存器- TWBR
	? Bits 7..0 – TWI 比特率寄存器
		TWBR 为比特率发生器分频因子。
		比特率发生器是一个分频器,在主机模式下产生SCL时钟频率。
		比特率计算公式请见前面的[比特率发生器单元]
		
TWI 控制寄存器- TWCR
	TWCR 用来控制TWI操作。
	它用来使能TWI,通过施加START到总线上来启动主机访问,产生接收器应答,产生STOP 状态,以及在写入数据到TWDR 寄存器时控制总线的暂停等。
	这个寄存器还可以给出在TWDR 无法访问期间,试图将数据写入到TWDR 而引起的写入冲突信息。
	? Bit 7 – TWINT: TWI 中断标志
		当TWI 完成当前工作,希望应用程序介入时TWINT 置位。
		若SREG 的I 标志以及TWCR寄存器的TWIE 标志也置位,则MCU 执行TWI 中断例程。
		当TWINT 置位时, SCL信号的低电平被延长。
		TWINT 标志的清零必须通过软件写"1” 来完成。
		执行中断时硬件不会自动将其改写为"0”。
		要注意的是,只要这一位被清零,TWI 立即开始工作。
		因此,在清零TWINT 之前一定要首先完成对地址寄存器TWAR,状态寄存器TWSR,以及数据寄存器TWDR 的访问。
	? Bit 6 – TWEA: 使能TWI 应答
		TWEA 标志控制应答脉冲的产生。
		若TWEA 置位,出现如下条件时接口发出ACK 脉冲:
		1. 器件的从机地址与主机发出的地址相符合
		2. TWAR 的TWGCE 置位时接收到广播呼叫
		3. 在主机/ 从机接收模式下接收到一个字节的数据
		将TWEA 清零可以使器件暂时脱离总线。
		置位后器件重新恢复地址识别。	
	? Bit 5 – TWSTA: TWI START 状态标志
		当CPU 希望自己成为总线上的主机时需要置位TWSTA。
		TWI 硬件检测总线是否可用。
		若总线空闲,接口就在总线上产生START 状态。
		若总线忙,接口就一直等待,直到检测到一个STOP 状态 ,然后产生START 以声明自己希望成为主机。
		发送START之后软件必须清零TWSTA。
	? Bit 4 – TWSTO: TWI STOP 状态标志
		在主机模式下,如果置位TWSTO,TWI 接口将在总线上产生STOP 状态,然后TWSTO自动清零。
		在从机模式下,置位TWSTO 可以使接口从错误状态恢复到未被寻址的状态。
		此时总线上不会有STOP 状态产生,但TWI 返回一个定义好的未被寻址的从机模式且释放SCL 与SDA 为高阻态。
	? Bit 3 – TWWC: TWI 写碰撞标志
		当TWINT 为低时写数据寄存器TWDR 将置位TWWC。
		当TWINT 为高时,每一次对TWDR 的写访问都将更新此标志。
	? Bit 2 – TWEN: TWI 使能
		TWEN 位用于使能TWI操作与激活TWI接口。
		当TWEN位被写为"1”时,TWI引脚将I/O引脚切换到SCL 与SDA 引脚,使能波形斜率限制器与尖峰滤波器。
		如果该位清零, TWI接口模块将被关闭,所有TWI 传输将被终止。
	? Bit 0 – TWIE: 使能TWI 中断
		当SREG 的I 以及TWIE 置位时,只要TWINT 为"1”, TWI 中断就激活。
		
TWI 状态寄存器- TWSR
	? Bits 7..3 – TWS: TWI 状态
		这5位用来反映TWI 逻辑和总线的状态。
		不同的状态代码将会在后面的部分描述。
		注意从TWSR 读出的值包括5 位状态值与2 位预分频值。
		检测状态位时设计者应屏蔽预分频位为"0”。这使状态检测独立于预分频器设置。
	? Bits 1..0 – TWPS: TWI 预分频位
		这两位可读/ 写,用于控制比特率预分频因子。
		预分频系数为4的n次方
		计算比特率的公式见前面的[比特率发生器单元]
		
TWI 数据寄存器- TWDR
	在发送模式, TWDR 包含了要发送的字节;
	在接收模式, TWDR 包含了接收到的数据。
	当TWI 接口没有进行移位工作(TWINT 置位) 时这个寄存器是可写的。
	在第一次中断发生之前用户不能够初始化数据寄存器。
	只要TWINT 置位,TWDR 的数据就是稳定的。
	在数据移出时,总线上的数据同时移入寄存器。
	TWDR 总是包含了总线上出现的最后一个字节,除非MCU 是从掉电或省电模式被TWI 中断唤醒。此时TWDR 的内容没有定义。
	总线仲裁失败时,主机将切换为从机,但总线上出现的数据不会丢失。
	ACK 的处理由 TWI逻辑自动管理, CPU 不能直接访问ACK。
	? Bits 7..0 – TWD: TWI 数据寄存器
		根据状态的不同,其内容为要发送的下一个字节,或是接收到的数据。
 
TWI(从机) 地址寄存器-TWAR
	TWAR 的高7 位为从机地址。
	工作于从机模式时,TWI 将根据这个地址进行响应。
	主机模式不需要此地址。
	在多主机系统中, TWAR需要进行设置以便其他主机访问自己。
	TWAR 的LSB 用于识别广播地址 (0x00)。
	器件内有一个地址比较器。一旦接收到的地址和本机地址一致,芯片就请求中断。
	? Bits 7..1 – TWA: TWI 从机地址寄存器
		其值为从机地址。
	? Bit 0 – TWGCE: 使能TWI 广播识别
		置位后MCU 可以识别TWI 总线广播。
 
使用TWI 
	AVR的TWI接口是面向字节和基于中断的。
	所有的总线事件,如接收到一个字节或发送了一个START 信号等,都会产生一个TWI 中断。
	由于TWI 接口是基于中断的,因此TWI接口在字节发送和接收过程中,不需要应用程序的干预。
	TWCR寄存器的TWI中断允许位[TWIE]和全局中断允许位[I]一起决定了应用程序是否响应TWINT标志位产生的中断请求。
	如果TWIE 被清零,应用程序只能采用轮询TWINT 标志位的方法来检测TWI 总线状态。
	当TWINT 标志位置"1” 时,表示TWI 接口完成了当前的操作,等待应用程序的响应。
	在这种情况下,TWI 状态寄存器TWSR 包含了表明当前TWI 总线状态的值。
	应用程序可以读取TWCR 的状态码,判别此时的状态是否正确,并通过设置TWCR 与TWDR 寄存器,决定在下一个TWI 总线周期TWI 接口应该如何工作。	
 
各种模式下的状态码列表(TWSR已屏蔽预分频位)
twi.h里面有定义,现附上中文描述
 
主机发送状态码
#define TW_START				0x08	//START已发送
#define TW_REP_START			0x10	//重复START已发送
#define TW_MT_SLA_ACK			0x18	//SLA+W 已发送收到ACK
#define TW_MT_SLA_NACK			0x20	//SLA+W 已发送接收到NOT ACK
#define TW_MT_DATA_ACK			0x28	//数据已发送接收到ACK
#define TW_MT_DATA_NACK			0x30	//数据已发送接收到NOT ACK
#define TW_MT_ARB_LOST			0x38	//SLA+W 或数据的仲裁失败
 
 
主机接收状态码
//#define TW_START				0x08	//START已发送
//#define TW_REP_START			0x10	//重复START已发送
#define TW_MR_ARB_LOST			0x38	//SLA+R 或NOT ACK 的仲裁失败
#define TW_MR_SLA_ACK			0x40	//SLA+R 已发送接收到ACK
#define TW_MR_SLA_NACK			0x48	//SLA+R 已发送接收到NOT ACK
#define TW_MR_DATA_ACK			0x50	//接收到数据ACK 已返回
#define TW_MR_DATA_NACK			0x58	//接收到数据NOT ACK已返回
 
从机接收状态码
#define TW_SR_SLA_ACK			0x60	//自己的SLA+W 已经被接收ACK已返回
#define TW_SR_ARB_LOST_SLA_ACK	0x68	//SLA+R/W 作为主机的仲裁失败;自己的SLA+W 已经被接收ACK 已返回
#define TW_SR_GCALL_ACK			0x70	//接收到广播地址ACK 已返回
#define TW_SR_ARB_LOST_GCALL_ACK 0x78	//SLA+R/W 作为主机的仲裁失败;接收到广播地址ACK已返回
#define TW_SR_DATA_ACK			0x80	//以前以自己的SLA+W被寻址;数据已经被接收ACK已返回
#define TW_SR_DATA_NACK			0x88	//以前以自己的SLA+W被寻址;数据已经被接收NOT ACK已返回
#define TW_SR_GCALL_DATA_ACK	0x90	//以前以广播方式被寻址;数据已经被接收ACK已返回
#define TW_SR_GCALL_DATA_NACK	0x98	//以前以广播方式被寻址;数据已经被接收NOT ACK已返回
#define TW_SR_STOP				0xA0	//在以从机工作时接收到STOP或重复START
 
 
从发送状态码
#define TW_ST_SLA_ACK			0xA8	//自己的SLA+R 已经被接收ACK 已返回
#define TW_ST_ARB_LOST_SLA_ACK	0xB0	//SLA+R/W 作为主机的仲裁失败;自己的SLA+R 已经被接收ACK 已返回
#define TW_ST_DATA_ACK			0xB8	//TWDR 里数据已经发送接收到ACK
#define TW_ST_DATA_NACK			0xC0	//TWDR 里数据已经发送接收到NOT ACK
#define TW_ST_LAST_DATA			0xC8	//TWDR 的一字节数据已经发送(TWAE = “0”);接收到ACK
 
 
其它状态码
#define TW_NO_INFO				0xF8	//没有相关的状态信息;TWINT = “0”
#define TW_BUS_ERROR			0x00	//由于非法的START 或STOP 引起的总线错误
 
 
AT24C02/04/08 IIC接口EEPROM的特点
(不同公司的24系列EEPROM特性有部分不同,请参考数据手册)
	1 AT24C02/04/08 是一个2K/4K/8K位串行CMOS E2PROM 内部含有256/512/1024 个8位字节
	2 AT24C02有一个8 字节页写缓冲器,AT24C04/08/16 有一个16字节页写缓冲器
	3 通过器件地址输入端A0,A1,A2可以实现将最多
		8个24C02器件
		4个24C04器件
		2个24C08器件
		同时连接到总线上
	4 写操作
		1 字节写
		2 页写 	AT24C02是8字节/页 AT24C04/08是16字节/页
				注意:页写的地址只在当前页自动累加,页地址范围内循环。
		启动写命令后需要10ms(最大)的编程时间才能真正的把数据记录下来,编程期间器件不响应任何命令
	5 读操作
		1 立即地址读  地址自动累加,即为上次读/写操作地址+1(本程序不支持该操作)
		2 随机读     指定地址读一个字节
		3 连续读     连续读操作可通过立即读或随机读操作启动,由主机发出NAK和STOP来停止读操作
					读操作时地址计数器在AT24C02/04/08整个地址内增加,这样整个寄存器区域在可在一个读操作内全部读出
					循环读取,读到最后一个地址后,从第一个地址继续开始读
	6  写保护功能,由WP引脚控制,WP=VCC时,24C02的高1K位,24C04的高2K位,24C08的全部8K位都变成只读,不能写入
*/

⌨️ 快捷键说明

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