首页 > 代码库 > AT24C02/04/08 地址理解

AT24C02/04/08 地址理解

 

该类器件要通过iic总线操作,读写过程中都要先寻址,这类器件地址有两个字节组成,如下表,1010是固定的,A表示器件地址,可以拉高和拉低,iic总线上可以并接2的几次方个器件。P表示具体的内部地址数,比如at24c02共有256个字节,第二个地址字节完全可以满足,不用P。但是at24c04一个有512个字节,需要9位地址线,第一个字节中的p就表示地址线了,p=0表示低256字节,1表示高256字节。
注意:一般页写可以连续写8个数据。主机每发送一个字节都要接受从机的应答信号。该类器件是采用iic总线进行操作的,器件地址根据容量的不同稍有不同,如下


对于芯片的A0,A1,A2脚:
24C01/02,A0,A1,A2都是从设备地址。
24C04,A1,A2是从设备地址,A0没用
24C08,A2是从设备地址,A0,A1没用
24C16及以上,A0,A1,A2都没用了。
技术分享
其中,A表示期间地址,p表示也地址,在读写的时候首先是起始条件+器件地址
器件地址如上所示在16k中,需要两个字节表示内部地址,正是p2/1/0 和8位具体的地址

 

AT24C08为例子

 

//端口定义

#define SCL_L GPIOB->BSRR |= 1<<(16+6)
#define SCL_H GPIOB->BSRR |= 1<<6
#define SDA_L GPIOB->BSRR |= 1<<(16+7)
#define SDA_H GPIOB->BSRR |= 1<<7 
#define SDA_RED GPIOB->IDR & 1<<7    //sda



#define    AT24C08Address    0xA0    // 8k 1010 A_2 P_1 P_0 R/W     数据地址 p1,p2+8位  共十个地址位
                                                              // p1 p0  4块(256字节) 一块16页 一页16字节



void GPIO_Init(void);    //初始化    
u8 IIC_ReadByte(void);
u8 IIC_WriteByte(u8 SendByte);
u8 IIC_STOP(void );
u8 IIC_START(void);
u8 AT24C02Read(u8 RomAddr);
u8 AT24C02Write(u8 RomAddr,u8 RegData);
u8 IIC_NACK(void);
u8 IIC_ACK(void) ;
u8 IIC_WaitAck(void) ;
u8 InitAT24C02(void);

/初始化PB6和PB7 PC13为输出口.并使能这两个口的时钟            

void GPIO_Init(void)
{
    RCC->APB2ENR|=1<<3;     //使能PORTB时钟
    RCC->APB2ENR|=1<<4;     //使能PORTC时钟
    GPIOB->CRL&=0X00FFFFFF; 
    GPIOB->CRL|=0X77000000; //PB6 PB7 开漏输出      

       
    //led
    GPIOC->CRH &=0XFF0FFFFF;
    GPIOC->CRH |=0X00300000;       //PC13推挽输出
     GPIOC->ODR |=1<<13;
}

u8 IIC_START()
{ 
    SCL_L; //准备
    SDA_H;   
    SCL_H; //scl 高电平 此时改变sda 结束或开始的标志
    if(!SDA_RED) //测试sda有没占用 若sda 被从机接地拉低 主机无法拉高
        return 0;
    SDA_L;
    if(SDA_RED) //总线出错
        return 0;
    SDA_L;       //主机钳住I2C总线,准备发送或接收数据 
    return 1;
       
}

u8 IIC_STOP()
{
    SCL_L;
    SDA_L;
    delay_us(4);
    SCL_H;
    delay_us(4);
    SDA_H;         //发送I2C总线结束信号 
    delay_us(4); 
    if(!SDA_RED)    //sda 被从机接地拉低 主机无法拉高
        return 0;
    return 1;
    
}

u8 IIC_WriteByte(u8 SendByte)
{
    u8 i =8;
    SCL_L;  //拉低时钟开始数据传输
    while(i--)
    {
        SCL_L;
        if(SendByte & 0x80)
            SDA_H;
        else
            SDA_L;
        SendByte<<=1;
        
        delay_us(4); //scl 产生脉冲
        SCL_H;
        delay_us(4);
    
    
    }
    SCL_L;

}

u8 IIC_ReadByte(void)
{
    u8 i =8,ReceiveByte;
  //  SDA_H; 
    while(i--)
    {
        SCL_L;
        delay_us(4);  //先给个脉冲
        SCL_H;       //拉高时钟开始数据接收 sda交给从机
        ReceiveByte <<=1;
        if(SDA_RED)
            ReceiveByte |=1;       
        delay_us(4);
    
    }
    SCL_L;
    return ReceiveByte;   
}

u8 IIC_WaitAck(void)  /*stm32 发送时用*/
{
    SCL_L;     //scl 低 主机方能改变sda
    delay_us(4);
    SDA_H;     //主机置高sda 等待回复 从机将拉低 sda 
    delay_us(2);
    SCL_H;     //产生脉冲
    
    if(SDA_RED)  //从机不拉低sda  即不回复
        return 0;
    SCL_L;
    return 1;

}

u8 IIC_ACK(void)  //主机必须在从机发出最后一个字节时产生一个响应    只讲主发送从接收
                  //从机发送器通知数据结束   “知道吗”
                /****stm32接收时用*/
{
    SCL_L;
    __nop();
    SDA_L;        //从机stm32响应 scl低时 拉低sda
    
    delay_us(4);
    SCL_H;
    delay_us(4);
    SCL_L;   
}
    
u8 IIC_NACK(void)   /****stm32接收时用*/
{
    SCL_L;
    __nop();
    SDA_H;        //从机stm32不响应 sda置高 
    
    delay_us(4);
    SCL_H;
    delay_us(4);
    SCL_L;    
} 


/********  AT24C02读写操作 ********/

u8 AT24C02Write(u8 RomAddr,u8 RegData)
{

    if(! IIC_START())
        return 0;
    IIC_WriteByte(AT24C08Address); //写模式
    if(!IIC_WaitAck())
    {
        IIC_STOP();
        return 0;
    }
    IIC_WriteByte(RomAddr);
    if(!IIC_WaitAck())
    {
        IIC_STOP();
        return 0;
    }
    IIC_WriteByte(RegData);
    if(!IIC_WaitAck())
    {
        IIC_STOP();
        return 0;
    }
    IIC_STOP();
    return 1;

}

u8  AT24C02Read(u8 RomAddr)
{
    u8 receive;
    if(!IIC_START())
    {
        IIC_STOP();
        return 0;
    }
    IIC_WriteByte(AT24C08Address);
    if(! IIC_WaitAck())
    {
        IIC_STOP();
        return 0;
    }
    IIC_WriteByte(RomAddr);
    if(! IIC_WaitAck())
    {
        IIC_STOP();
        return 0;
    }
    
    IIC_START();
    IIC_WriteByte(AT24C08Address+1); //配置成读模式
    if(! IIC_WaitAck())
    {
        IIC_STOP();
        return 0;
    }
    receive=IIC_ReadByte();
    IIC_NACK();
    IIC_STOP();
    return receive;
    
    
}

u8 H;  

int main(void)
{    
      
    Stm32_Clock_Init(9);     //系统时钟设置
    delay_init(72);             //延时初始化
    GPIO_Init();                   //初始化与LED连接的硬件接口 
    AT24C02Write(0x00,0xf5);
    H=AT24C02Read(0x00);
    
    
    if(H==0xf5)
    {
        while(1)
        {
        GPIOC->ODR &=0<<13;
         delay_ms(500);
         GPIOC->ODR |=1<<13;
         delay_ms(500);  
        }
    
    }
    else
        GPIOC->ODR |=1<<13;
        
}
//数据一致 led闪烁

 

AT24C02/04/08 地址理解