AT24C02学习笔记

看手册:

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.rhkb.cn/news/496579.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Vite内网ip访问,两种配置方式和修改端口号教程

目录 问题 两种解决方式 结果 总结 preview.host preview.port 问题 使用vite运行项目的时候&#xff0c;控制台会只出现127.0.0.1&#xff08;localhost&#xff09;本地地址访问项目。不可以通过公司内网ip访问&#xff0c;其他团队成员无法访问&#xff0c;这是因为没…

Python基础语法知识——列表、字典、元组与集合

列表&#xff08;list&#xff09;、字典(dictionary)、元组(tuple)与集合(set)都可以看成存储数据的容器&#xff0c;但是前两者常用&#xff0c;后两者用得相对较少。 目录 1 列表&#xff08;list) 1.1列表入门 1 列表&#xff08;list) 1.1列表入门 class1["李白…

JVM调优实践篇

理论篇 1多功能养鱼塘&#xff0d;JVM内存 大鱼塘O&#xff08;可分配内存&#xff09;&#xff1a; JVM可以调度使用的总的内存数&#xff0c;这个数量受操作系统进程寻址范围、系统虚拟内存总数、系统物理内存总数、其他系统运行所占用的内存资源等因素的制约。 小池塘A&a…

EKF 自动匹配维度 MATLAB代码

该 M A T L A B MATLAB MATLAB代码实现了扩展卡尔曼滤波( E

C++第五六单元测试

1【单选题】在公有派生类的成员函数不能直接访问基类中继承来的某个成员&#xff0c;则该成员一定是基类中的&#xff08; C &#xff09;。&#xff08;2.0分&#xff09; A、公有成员B、保护成员C、私有成员D、保护成员或私有成员 注意从类外访问与从派生类中访问 2【单…

TDengine 新功能 VARBINARY 数据类型

1. 背景 VARBINARY 数据类型用于存储二进制数据&#xff0c;与 MySQL 中的 VARBINARY 数据类型功能相同&#xff0c;VARBINARY 数据类型长度可变&#xff0c;在创建表时指定最大字节长度&#xff0c;使用进按需分配存储&#xff0c;但不能超过建表时指定的最大值。 2. 功能说明…

rust windwos 两个edit框

use winapi::shared::minwindef::LOWORD; use windows::{core::*,Win32::{Foundation::*,Graphics::Gdi::{BeginPaint, EndPaint, PAINTSTRUCT},System::LibraryLoader::GetModuleHandleA,UI::WindowsAndMessaging::*,}, };// 两个全局静态变量&#xff0c;用于保存 Edit 控件的…

代码随想录Day51 99. 岛屿数量,99. 岛屿数量,100. 岛屿的最大面积。

1.岛屿数量深搜 卡码网题目链接&#xff08;ACM模式&#xff09;(opens new window) 题目描述&#xff1a; 给定一个由 1&#xff08;陆地&#xff09;和 0&#xff08;水&#xff09;组成的矩阵&#xff0c;你需要计算岛屿的数量。岛屿由水平方向或垂直方向上相邻的陆地连接…

邮箱手机号脱敏

项目场景&#xff1a; 提示&#xff1a;这里简述项目相关背景&#xff1a; 输入框的脱敏&#xff0c;当输入的时候显示正常&#xff0c;失去焦点部分显示**** 问题描述 提示&#xff1a;这里描述项目中遇到的问题&#xff1a; 脱敏可以封装 一下成为一个方法&#xff0c;挂…

C语言----变量与常量

目录 变量 变量的分类 常量 分类&#xff1a; 1. 字符型常量 2. 字符串常量 3. 整形常量 4. 浮点型常量 5. 指数常量 6. 标识常量 变量 概念&#xff1a;在程序运行中发生改变的量 定义格式&#xff1a; 存储类型(一般存储类型是可以省略的) 数据类型 变量名 aut…

SQLite本地数据库的简介和适用场景——集成SpringBoot的图文说明

前言&#xff1a;现在项目普遍使用的数据库都是MySQL&#xff0c;而有些项目实际上使用SQLite既足矣。在一些特定的项目中&#xff0c;要比MySQL更适用。 这一篇文章简单的介绍一下SQLite&#xff0c;对比MySQL的优缺点、以及适用的项目类型和集成SpringBoot。 1. SQLite 简介 …

线性代数行列式

目录 二阶与三阶行列式 二元线性方程组与二阶行列式 三阶行列式 全排列和对换 排列及其逆序数 对换 n阶行列式的定义 行列式的性质 二阶与三阶行列式 二元线性方程组与二阶行列式 若是采用消元法解x1、x2的话则得到以下式子 有二阶行列式的规律可得&#xff1a;分…

闲谭Scala(3)--使用IDEA开发Scala

1. 背景 广阔天地、大有作为的青年&#xff0c;怎么可能仅仅满足于命令行。 高端大气集成开发环境IDEA必须顶上&#xff0c;提高学习、工作效率。 开整。 2. 步骤 2.1 创建工程 打开IDEA&#xff0c;依次File-New-Project…&#xff0c;不好意思我的是中文版&#xff1a;…

http 请求总结get

关于get请求传递body的问题 错误代码 有400 , 415 等情况 <!doctype html><html lang"zh"><head><title>HTTP Status 400 – 错误的请求</title><style type"text/css">body {font-family:Tahoma,Arial,sans-seri…

CCF-GESP 等级考试 2023年12月认证C++五级真题解析

2023年12月真题 一、单选题&#xff08;每题2分&#xff0c;共30分&#xff09; 正确答案&#xff1a;C 考察知识点&#xff1a;算法 解析&#xff1a;fiboA 是很好理解的&#xff0c;但是执行效率不高&#xff0c;有的计算是重复的&#xff0c;导致效率低。 正确答案&#xf…

Vscode + gdbserver远程调试开发板指南:

本章目录 步骤环境准备网络配置vscode配置步骤 (全图示例)开发板配置开始调试注意: 每次断开之后&#xff0c;开发板都需要重新启动gdbserver才可调试。 参考链接: 步骤 环境准备 将交叉编译链路径加入$PATH变量&#xff1a;确保系统能够找到所需的工具。 export PATH$PATH:/p…

Docker【初识Docker】

目录 为什么会出现Docker这门技术喃&#xff1f; 应用开发和部署的困境 容器技术的先兆 Docker 的出现&#xff1a;简化容器化 Docker 技术的关键创新&#xff1a; Docker 的广泛应用和变革 什么是 Docker&#xff1f; Docker的历史 早期背景&#xff1a;容器化和虚拟化…

金融租赁系统的发展与全球化战略实施探讨

内容概要 金融租赁系统的演变并非一帆风顺&#xff0c;像一场跌宕起伏的电影。首先&#xff0c;咱们得看看它的起源及现状。随着经济的快速发展&#xff0c;金融租赁逐渐作为一种灵活的融资手段崭露头角。在中国市场中&#xff0c;企业对设备和技术更新换代的需求日益迫切&…

畅游 Linux 开发天地:yum 与 vim 详解

&#x1f31f; 快来参与讨论&#x1f4ac;&#xff0c;点赞&#x1f44d;、收藏⭐、分享&#x1f4e4;&#xff0c;共创活力社区。&#x1f31f; &#x1f6a9;用通俗易懂且不失专业性的文字&#xff0c;讲解计算机领域那些看似枯燥的知识点&#x1f6a9; 前言 在当今数字…

C++--------继承

一、继承的基本概念 继承是 C 中的一个重要特性&#xff0c;它允许一个类&#xff08;派生类或子类&#xff09;继承另一个类&#xff08;基类或父类&#xff09;的属性和方法。这样可以实现代码的重用和建立类之间的层次关系。 #include <iostream>// 基类 class Base…