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闪烁
时间: 2024-08-05 19:09:51

AT24C02/04/08 地址理解的相关文章

Bentley Maxsurf Enterprise V8i v20.00.04.08 Win32_64 2CD

Schlumberger Techlog 2013.3 Win64 1CD Bentley.OpenPlant.Isometric.Manager.V8i.SS5.08.11.09.404 1CD Delcam.PowerINSPECT.2013.R2.SP2-ISO 1DVD Arqcom.CAD-Earth.v4.0.2.AutoCAD.2013-2015 1CD Bentley.AECOsim.Building.Designer.V8i.SS5.08.11.09.747 1CD Bentl

IP地址理解_IP地址=网络地址+主机地址,但是具体前面多少是网络地址看题目说明

题目:   属于网络112.10.200.0/21的地址是() 112.10.206.0 112.10.217.0 112.10.224.0 112.10.198.0 分析解答: 总结: 首先,明白后面那个21是什么意思,21表示这个IP的前21位表示的是网络地址,那剩下的11位表示主机地址.IP地址共32位=4个字节*8位/字节: 其次,就是理解一个点隔开的就是一个字节,那么前面21位到哪了呢. 将200写成二进制=128+64+8=11001000,因此前面21位,截取200的前5位,剩余的

IPV6地址理解及配置

 理解: IPv6单播地址的类型可有多种,包括全球单播地址.链路本地地址和站点本地地址等. 1. 全球单播地址等同于IPv4公网地址,提供给网络服务提供商. 这种类型的地址允许路由前缀的聚合,从而限制了全球路由表项的数量. 2. 链路本地地址用于邻居发现协议和无状态自动配置中链路本地上节点 之间的通信.使用链路本地地址作为源或目的地址的数据报文不会被转发 到其他链路上. 3. 站点本地地址与IPv4中的私有地址类似.使用站点本地地址作为源或目 的地址的数据报文不会被转发到本站点(相当于一个私

JavaScript中指针和地址理解

个人理解:指针只是指向内存的一个索引:而地址则是内存中确切的位置. 下面是函数中关于指针和地址一个小例子: function sum(num1,num2){ return num1+num2; } alert(sum(10,10)); //20 var anotherSum=sum; alert(anotherSum(10,10)); //20 sum=null; alert(anotherSum(10,10)); //20 注意:使用不带圆括号的函数的名是访问函数指针,而非调用函数,所以 su

如何保存指针地址 理解指针的指针

有这样一个问题就是如何使用一个整数保存一个结构体或类以及其他类型的指针,这种需求在不同语言之间调用是存在的,例如有一个结构体A: struct A { char item1; int item2 }; 需要使用一个整数b,需要用b保存这个结构体指针的地址(struct A* a = new A),使得b的值就是a的指向的地址,你可能会想直接b = a就可以了,但是编译器都不会答应.因为类型不同,一个是整数一个是指向struct A的指针. 正确的方式如下: unsigned int b = 0;

2019.04.08打卡

1 #include <stdio.h> 2 #include <stdlib.h> 3 typedef int DataType; 4 typedef struct node{ 5 DataType data; 6 struct node *next; 7 }LinkNode,*LinkList; //LinkNode是JAVA中链表结点,此类可以存放int.long.float.double.byte.short.String.StringBuffer类型的数据 8 //定义单

&ldquo;耐撕&rdquo;团队 2016.04.08 站立会议

1. 时间 : 15:20--15:40 2. 人员 : Z 郑蕊 * 组长 (博客:http://www.cnblogs.com/zhengrui0452/), P 濮成林(博客:http://www.cnblogs.com/charliePU/), Q 齐嘉亮(博客:http://www.cnblogs.com/dendroaspis-polylepis/), M 张敏(博客:http://www.cnblogs.com/zhangminss/) 3. 会议内容: Part A : 回顾昨天

18.04.08 luoguP1019 单词接龙

题目描述 单词接龙是一个与我们经常玩的成语接龙相类似的游戏,现在我们已知一组单词,且给定一个开头的字母,要求出以这个字母开头的最长的“龙”(每个单词都最多在“龙”中出现两次),在两个单词相连时,其重合部分合为一部分,例如 beast和astonish,如果接成一条龙则变为beastonish,另外相邻的两部分不能存在包含关系,例如at 和 atide 间不能相连. 输入输出格式 输入格式: 输入的第一行为一个单独的整数n (n<=20)表示单词数,以下n 行每行有一个单词,输入的最后一行为一个单

2020.04.08

快速学习东西的思路 学习一个东西的时候,一个思路是向别人学习,看一下别人是怎么处理这个问题的,就比如scrivener或者Keepass,自己想要学习的话,可能是去学习官方的视频的教程,但是这样需要花的时间太长了,不能这么搞,应该先去知乎或者CSDN上面,看一下别人是怎么用这个软件的,会用的哪些个功能,之后,自己再去具体的学习,而不是一开始就将所有的功能都学个遍,这样即使,自己全学完了,可能到自己真正要用的时候,也忘的差不过了. ? 番茄工作法 突然想到,番茄工作法可能会是一个解决自己分心.拖延