单片机学习笔记---AT24C02数据存储

目录

AT24C02数据存储

准备工作

代码讲解

I2C.c

模拟起始位置的时序

模拟发送一个字节的时序

模拟接收应答的时序

模拟接收一个字节的时序

模拟发送应答的时序

模拟结束位置的时序

I2C.h 

AT24C02.c

字节写:在WORD ADDRESS(字地址)处写入数据DATA

随机读:读出在WORD ADDRESS处的数据DATA

AT24C02.h

 main.c


上一节讲了AT24C02和I2C相关的工作原理,这一节开始代码演示!

准备工作

新创建一个工程:AT24C02数据存储

把要用到的程序模块添加进来,这些程序模块都是我前面的博客里演示过的了

然后新建文件main.c,  AT24C02.c,  AT24C02.h, I2C.c, I2C.h

代码讲解

接下来就开始代码讲解:

I2C.c

首先我们先写I2C.c

在这个文件里面我们是按照上一篇博客所讲的各部分时序来逐个定义函数,函数体的内容就是模拟每一部分时序写的。

首先我们得根据原理图重新定义一下引脚

#include <REGX52.H>sbit I2C_SCL=P2^1;//将P2^1重命名为I2C_SCL
sbit I2C_SDA=P2^0;//将P2^0重命名为I2C_SDA
模拟起始位置的时序

void I2C_Start(void)
{I2C_SDA=1;I2C_SCL=1;I2C_SDA=0;//SCL高电平期间,SDA从高电平切换到低电平I2C_SCL=0;
}
模拟发送一个字节的时序

void I2C_SendByte(unsigned char Byte)
{unsigned char i;for(i=0;i<8;i++)//一个字节循环8次发送8位数据{//SCL低电平期间,主机将数据位依次放到SDA线上(高位在前)I2C_SDA=Byte&(0x80>>i);//从最高位开始取出,依次右移一位,直到取到最低位I2C_SCL=1;//然后拉高SCL,从机将在SCL高电平期间读取数据位I2C_SCL=0;//发送完一个字节后拉低SCL(下降沿)}
}

 注意:SCL当VCC等于5V的情况下是1000kHz=1MHz,而我们单片机的IO口翻转一次最快也就1微秒(大于0.4微秒),就是500Hz,由此可见它的频率比IO口翻转一次的频率还要快,所以即使我们拉高SCL立马又拉低也不会影响它的最大时钟,它也能很快读取到数据。

模拟接收应答的时序

unsigned char I2C_ReceiveAck(void)
{unsigned char AckBit;I2C_SDA=1;//主机接收应答之前先把SDA拉高,I2C_SCL=1;//在SCL位高电平时,主机检测从机是否应答//接下来我们不管从机的时序是怎么变化的//所以这里我们没有在代码中体现从机是拉低了SDA还是默认SDA就是高电平//我们的单片机是主机,24C02是从机。//主机和从机的程序是不一样的,我们只写主机,从机是主动检测的,//从机读取数据的时候是程序自动完成的,//我们只需要把主机的时序模拟出来就好了。AckBit=I2C_SDA;//主机接收从机的应答//如果从机不想应答或者从机不存在就默认SDA还是高电平//从机应答的话就拉低了SDA赋值给AckBitI2C_SCL=0;return AckBit;
}
模拟接收一个字节的时序

上图SDA紫色部分就是从机控制总线的时候

unsigned char I2C_ReceiveByte(void)
{unsigned char i,Byte=0x00;I2C_SDA=1;//接收之前把SDA释放for(i=0;i<8;i++)//一个字节循环8次读取8位数据{//SCL低电平期间,从机将数据位依次放到SDA线上(高位在前)I2C_SCL=1;//然后拉高SCL,主机将在SCL高电平期间读取数据位if(I2C_SDA){Byte|=(0x80>>i);}//从最高位开始读,依次右移一位,直到读到最低位I2C_SCL=0;}return Byte;
}
模拟发送应答的时序

void I2C_SendAck(unsigned char AckBit)
{I2C_SDA=AckBit;//主机发送应答给从机I2C_SCL=1;//SCL高电平期间,从机检测主机是否应答I2C_SCL=0;
}
模拟结束位置的时序

void I2C_Stop(void)
{I2C_SDA=0;//不管主机/从机是否应答,都要拉低SDA。I2C_SCL=1;I2C_SDA=1;//SCL高电平期间,SDA从低电平切换到高电平
}

I2C.h 

最后在I2C.h文件中声明一下这六个函数: 

#ifndef __I2C_H__
#define __I2C_H__void I2C_Start(void);
void I2C_Stop(void);
void I2C_SendByte(unsigned char Byte);
unsigned char I2C_ReceiveByte(void);
void I2C_SendAck(unsigned char AckBit);
unsigned char I2C_ReceiveAck(void);#endif

AT24C02.c

接下来写AT24C02.c

AT24C02.c的内容主要是按我上一篇博客讲过的这个流程图来逐个调用I2C.c中的六个函数:

字节写:在WORD ADDRESS(字地址)处写入数据DATA

随机读:读出在WORD ADDRESS处的数据DATA(这其实是一种复合格式)

上一篇博客我写过AT24C02的固定地址为1010可配置地址本开发板上为000,所以从机的写地址SLAVE ADDRESS+W为0xA0,从机的读地址SLAVE ADDRESS+R为0xA1

所以我们可以先重定义从机的写地址,将从机的写地址重定义为AT24C02_ADDRESS,然后从机的读地址我们到时候直接给字节的最低位置1就可以了:

从机的写地址=0xA0=AT24C02_ADDRESS=1010 0000

从机的读地址=AT24C02_ADDRESS|0x01=1010 0000|0000 0001=1010 0001=0xA1

#include <REGX52.H>
#include "I2C.h"#define AT24C02_ADDRESS		0xA0 //将从机的写地址重定义为AT24C02_ADDRESS
字节写:在WORD ADDRESS(字地址)处写入数据DATA

按照字节写的流程图写函数体:

void AT24C02_WriteByte(unsigned char WordAddress,Data)//Data的类型和wordAddress一样
{I2C_Start();//起始位置I2C_SendByte(AT24C02_ADDRESS);//发送从机地址I2C_ReceiveAck();//接收应答I2C_SendByte(WordAddress);//发送字节地址I2C_ReceiveAck();//接收应答I2C_SendByte(Data);//发送数据I2C_ReceiveAck();//接收应答I2C_Stop();//结束位置
}
随机读:读出在WORD ADDRESS处的数据DATA

按照字节写的流程图写函数体:

unsigned char AT24C02_ReadByte(unsigned char WordAddress)
{unsigned char Data;I2C_Start();//写的起始位置I2C_SendByte(AT24C02_ADDRESS);//发送从机地址I2C_ReceiveAck();//接收应答I2C_SendByte(WordAddress);//发送字节地址I2C_ReceiveAck();//接收应答I2C_Start();//读的起始位置I2C_SendByte(AT24C02_ADDRESS|0x01);//发送从机地址,将从机的写地址的最低位置1I2C_ReceiveAck();//接收应答//前面说过从机接收了什么数据怎么接收的数据我们在代码中不体现出来,//我们只写主机的程序Data=I2C_ReceiveByte();//我们只要把从机里面那个指定的字节地址处的数据读出来赋值给DataI2C_SendAck(1);//读取完一个字节可以不用再应答从机I2C_Stop();//结束位置return Data;//返回读出来的数据
}

AT24C02.h

声明一下这两个函数

#ifndef __AT24C02_H__
#define __AT24C02_H__void AT24C02_WriteByte(unsigned char WordAddress,Data);
unsigned char AT24C02_ReadByte(unsigned char WordAddress);#endif

 main.c

 接下来我们在主程序里实现在WORD ADDRESS(字地址)处写入数据DATA,然后读出在WORD ADDRESS处的数据DATA,最后在液晶屏上显示我们写入并读出来的数据,结合独立按键的功能完成这个效果

先定义两个变量:

#include <REGX52.H>
#include "LCD1602.h"
#include "Key.h"
#include "AT24C02.h"
#include "Delay.h"unsigned char KeyNum;//键码
unsigned int Num;//初值,16位数据,范围是0~65535

主程序(请认真结合注释理清每一句代码的逻辑意思)

void main()
{LCD_Init();LCD_ShowNum(1,1,Num,5);while(1){KeyNum=Key();if(KeyNum==1)	//K1按键,Num自增{Num++;//第一次就按K1的时候,由0变成1LCD_ShowNum(1,1,Num,5);}if(KeyNum==2)	//K2按键,Num自减{Num--;//第一次就按K2的时候,由0变成65535LCD_ShowNum(1,1,Num,5);}if(KeyNum==3)	//K3按键,向AT24C02写入数据{AT24C02_WriteByte(0,Num%256);//在字地址0处,写入Num的低八位//%256是16进制取低8位的方法//因为Num是unsigned int型占2个字节即16位数据//所以把Num的低8位取出来写入Delay(5);//写进去不能立马读出来,ROM一般要2~3ms才能写完//手册上的写周期是5ms,意味着我们每次写入之后需要Delay 5msAT24C02_WriteByte(1,Num/256);在字地址1处,写入Num的高八位// 或256是16进制取高8位的方法Delay(5);LCD_ShowString(2,1,"Write OK");Delay(1000);//延时1000ms=1sLCD_ShowString(2,1,"        ");//第2行第1列清屏}if(KeyNum==4)	//K4按键,从AT24C02读取数据{Num=AT24C02_ReadByte(0);//低八位的字地址是0,把低八位数据读出来赋值给NumNum|=AT24C02_ReadByte(1)<<8;//高八位的字地址1,把八位数据读出来每个左移8就是高八位LCD_ShowNum(1,1,Num,5);LCD_ShowString(2,1,"Read OK ");Delay(1000);LCD_ShowString(2,1,"        ");}}
}

注意:

写进去立马读出来能读到吗?

不能!

为什么不能?

我们看一下手册上的写周期是5ms

这个写周期意味着我们每次写入之后需要Delay 5ms,写的数据帧stop一旦结束,它内部要执行一些操作,把数据写出去。所以ROM要比RAM慢一些,因为ROM有个写入时间,它这个是最长5ms,经过实测写个数据大概两三毫秒就能写完,所以我们每次写入之后需要Delay 5ms。

效果展示

效果请看视频:

AT24C02数据存储

以上就是本篇内容!

之后有时间还会补充一个“秒表(定时器扫描按键数码管)”的示例代码,敬请关注!

源码会放在评论区,自取!如有问题可评论区留言。

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

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

相关文章

「Linux」软件安装

MySQL5.7在CentOS安装 安装 配置yum仓库 更新密钥&#xff1a;rpm --import https://repo.mysql.com/RPM-GPG-KEY-mysql-2022安装MySQL yum库&#xff1a;rpm -Uvh http://repo.mysql.com//mysql57-community-release-el7-7.noarch.rpm使用yum安装MySQL&#xff1a;yum -y in…

WebSocket原理详解

目录 1.引言 1.1.使用HTTP不断轮询 1.2.长轮询 2.websocket 2.1.概述 2.2.websocket建立过程 2.3.抓包分析 2.4.websocket的消息格式 3.使用场景 4.总结 1.引言 平时我们打开网页&#xff0c;比如购物网站某宝。都是点一下列表商品&#xff0c;跳转一下网页就到了商品…

电动汽车上哪些部位用到了电机?

一、背景 电动汽车中除了主驱动电机之外的其他电机的控制复杂度因电机的种类和功能而异。 一般来说&#xff0c;助力转向电机、空调风扇电机、冷却水泵电机等辅助电机的控制相对较为简单。这些电机通常只需要进行简单的开/关控制或速度调节&#xff0c;以满足车辆的基本需求。…

【实战】一、Jest 前端自动化测试框架基础入门(中) —— 前端要学的测试课 从Jest入门到TDD BDD双实战(二)

文章目录 一、Jest 前端自动化测试框架基础入门5.Jest 中的匹配器toBe 匹配器toEqual匹配器toBeNull匹配器toBeUndefined匹配器和toBeDefined匹配器toBeTruthy匹配器toBeFalsy匹配器数字相关的匹配器字符串相关的匹配器数组相关的匹配器异常情况的匹配器 6.Jest 命令行工具的使…

【Langchain Agent研究】SalesGPT项目介绍(三)

【Langchain Agent研究】SalesGPT项目介绍&#xff08;二&#xff09;-CSDN博客 上节课&#xff0c;我们介绍了salesGPT项目的初步的整体结构&#xff0c;poetry脚手架工具和里面的run.py。在run.py这个运行文件里&#xff0c;引用的最主要的类就是SalesGPT类&#xff0c;今天我…

ARP请求的构造过程

ARP请求的构造过程&#xff1a; ARP请求的构造&#xff1a; 当设备A&#xff08;发起者&#xff09;想要与设备B&#xff08;目标&#xff09;通信&#xff0c;但它只知道设备B的IP地址&#xff08;例如&#xff0c;192.168.1.2&#xff09;&#xff0c;而不知道其MAC地址。设备…

算法沉淀——链表(leetcode真题剖析)

算法沉淀——链表 01.两数相加02.两两交换链表中的节点03.重排链表04.合并 K 个升序链表05.K个一组翻转链表 链表常用技巧 1、画图->直观形象、便于理解 2、引入虚拟"头节点" 3、要学会定义辅助节点&#xff08;比如双向链表的节点插入&#xff09; 4、快慢双指针…

从源码学习访问控制符使用

从源码学习访问控制符使用 Java中的访问控制符 ​ 在Java中&#xff0c;有四个访问控制符&#xff1a;public、protected、default&#xff08;默认或缺省&#xff0c;不使用关键字&#xff09;和private。 ​ 它们的访问范围如下&#xff1a; public&#xff1a;公共访问权…

【从零到Offer】MySQL最左匹配

前言 ​ 相信大家在日常开发时&#xff0c;也经常能听到“最左匹配”这个词&#xff0c;那么什么是最左匹配呢&#xff1f;本篇文章就带你一起探索“最左匹配”的神奇秘密。 什么是最左匹配 ​ 最左匹配&#xff0c;通常指的是最左前缀匹配原则&#xff0c;即MySQL在检索数据…

联想thinkpad-E450双系统升级记

早期笔记本联想thinkpad-E450双系统 大约16年花4000多大洋&#xff0c;买了一台thinkpad-E450屏幕是16寸本&#xff0c;有AMD独立显卡&#xff0c;i5cpu&#xff0c;4G内存。 . 后来加了一个同型号4G内存组成双通道&#xff0c; . 加了一个三星固态500G&#xff0c; . 换了一个…

【C++】类的隐式类型转换

文章目录 前言一、隐式类型转换二、explicit关键字总结 前言 一、隐式类型转换 C 类的隐式类型转换是指当一个类定义了适当的构造函数或转换函数时&#xff0c;可以在需要时自动进行类型转换&#xff0c;而无需显式调用转换函数或构造函数。这使得代码更具灵活性和简洁性。下面…

备战蓝桥杯---动态规划(入门2)

今天主要介绍区间dp比较难的题&#xff1a; 下面是分析&#xff1a; 我们如果先固定点V0&#xff0c;那我们得去枚举两个点使它构成三角形&#xff0c;同时求目标值也比较难确定&#xff08;起始与终止都带0&#xff09;&#xff0c;于是我们考虑固定边&#xff0c;我们固定v0…

DS18B20 与 单总线

学习链接&#xff1a;学习B站 up 主金善愚的DS18B20课程 一、单总线概述 单总线芯片&#xff0c;在其内部的 ROM 中都编制好了唯一的序列号&#xff08;64位&#xff09;。 单总线芯片在应用时对时序的要求非常高。 二、单总线的基本操作 三、DS18B20的主要性能 电源电压范围&…

「数据结构」哈希表1:基本概念

&#x1f387;个人主页&#xff1a;Ice_Sugar_7 &#x1f387;所属专栏&#xff1a;Java数据结构 &#x1f387;欢迎点赞收藏加关注哦&#xff01; 基本概念 &#x1f349;哈希表&#x1f349;哈希冲突&#x1f34c;负载因子调节&#x1f34c;解决哈希冲突&#x1f95d;1. 闭散…

34 使用 LNMP 架构部署动态网站环境

源码包程序 LNMP 动态网站部署架构 LNMP 动态网站部署架构是一套由 Linux Nginx MySQL PHP 组成的动态网站系统 解决方案。 1. 准备工作 在使用源码包安装服务程序之前&#xff0c;首先要让安装主机具备编译程序源码的环境。这需要 具备 C 语言、C语言、Perl 语言的编译器&…

【Linux系统学习】2.Linux基础命令

Linux基础命令 Linux的目录结构 Linux命令入门 目录切换相关命令(cd/pwd) 相对路径、绝对路径和特殊路径符 创建目录命令(mkdir) 文件操作命令part1(touch、cat、more&#xff09; 文件操作命令part2(cp、mv、rm&#xff09; 查找命令(which、find&#xff09; grep、wc和管道符…

AI绘画作品的展示和变现-2

4.7 制作红包封面 中国的节日和传统文化元素仍然可以成为创作者们的创作灵感&#xff0c;创造出更多的变现机会。比如元宵节&#xff0c;可以制作大型元宵图案&#xff0c;进行引流并卖出元宵。 而春分、谷雨等节气也可以成为创作的灵感来源&#xff0c;创作出与之相关的图案&…

双场板功率GaN HEMT电容模型以精确模拟开关行为

标题&#xff1a;Capacitance Modeling in Dual Field-Plate Power GaN HEMT for Accurate Switching Behavior&#xff08;TED.16年&#xff09; 摘要 本文提出了一种基于表面电位的紧凑模型&#xff0c;用于模拟具有栅极和源极场板&#xff08;FP&#xff09;结构的AlGaN/G…

更新至2022年,各省人口高质量城镇化指标体系构建原始数据(13个指标)

更新至2022年&#xff0c;各省人口高质量城镇化指标体系构建原始数据 1、时间&#xff1a;更新至2022年&#xff0c;具体每个指标时间见下文 2、来源&#xff1a;整理自国家统计局、统计年鉴 3、范围&#xff1a;31省市 4、指标&#xff1a; 2008-2022年每十万人口高等学校…

vue3 腾讯tdesign 后台管理框架的使用

1.介绍 TDesign 是具有包容性的设计体系&#xff0c;它强调为业务提供产品、服务等过程中&#xff0c;追求以人为本、人人受益的包容性&#xff0c;要求搭建过程中&#xff0c;了解业务底层&#xff0c;理解业务场景的多样性&#xff0c;并在繁杂的业务场景中寻找共性和特性&a…