MCU-51:单片机之AT24C02学习

news2024/11/16 5:23:27

目录

  • 一、存储器介绍
    • 1.1 RAM
    • 1.2 ROM
  • 二、AT24C02
    • 2.1 AT24C02介绍
    • 2.2 引脚及应用电路
    • 2.3 内部结构框图
  • 三、I2C总线
    • 3.1 I2C总线介绍
    • 3.2 I2C电路规范
    • 3.3 I2C时序结构
    • 3.4 I2C数据帧
    • 3.5 AT24C02数据帧
  • 四、代码演示
    • 4.1 AT24C02数据存储
    • 4.2 秒表(定时器扫描按键数码管)
  • 注意:一定要看

一、存储器介绍

今天我们主要学习的是AT24C02,在学习前,我们先介绍下存储器
在这里插入图片描述
在这里插入图片描述

1.1 RAM

RAM主要分为SRAM(静态RAM)和DRAM(动态RAM),SRAM主要用于电脑CPU以及我们的单片机CPU;而DRAM主要用在电脑内存条以及手机的运行内存,因为电容器会掉电,所以需要不断进行扫描。

1.2 ROM

ROM主要分为Mask ROM(掩膜ROM),PROM(可编程ROM),EPROM(可擦除可编程ROM ),E2PROM (电可擦除可编程ROM ),这四个是一样的的,还有Flash(闪存),硬盘、软盘、光盘等。

二、AT24C02

2.1 AT24C02介绍

AT24C02是一种可以实现掉电不丢失的存储器,可用于保存单片机运行时想要永久保存的数据信息
存储介质:E2PROM
通讯接口:I2C总线
容量:256字节
在这里插入图片描述

2.2 引脚及应用电路

在这里插入图片描述

2.3 内部结构框图

在这里插入图片描述

三、I2C总线

3.1 I2C总线介绍

I2C总线(Inter IC BUS)是由Philips公司开发的一种通用数据总线
两根通信线:SCL(Serial Clock)、SDA(Serial Data)
同步、半双工,带数据应答
通用的I2C总线,可以使各种设备的通信标准统一,对于厂家来说,使用成熟的方案可以缩短芯片设计周期、提高稳定性,对于应用者来说,使用通用的通信协议可以避免学习各种各样的自定义协议,降低了学习和应用的难度

在这里插入图片描述

3.2 I2C电路规范

所有I2C设备的SCL连在一起,SDA连在一起
设备的SCL和SDA均要配置成开漏输出模式
SCL和SDA各添加一个上拉电阻,阻值一般为4.7KΩ左右
开漏输出和上拉电阻的共同作用实现了“线与”的功能,此设计主要是为了解决多机通信互相干扰的问题
在这里插入图片描述

3.3 I2C时序结构

起始条件:SCL高电平期间,SDA从高电平切换到低电平
终止条件:SCL高电平期间,SDA从低电平切换到高电平
在这里插入图片描述
发送一个字节:SCL低电平期间,主机将数据位依次放到SDA线上(高位在前),然后拉高SCL,从机将在SCL高电平期间读取数据位,所以SCL高电平期间SDA不允许有数据变化,依次循环上述过程8次,即可发送一个字节
在这里插入图片描述
发送应答:在接收完一个字节之后,主机在下一个时钟发送一位数据,数据0表示应答,数据1表示非应答
接收应答:在发送完一个字节之后,主机在下一个时钟接收一位数据,判断从机是否应答,数据0表示应答,数据1表示非应答(主机在接收之前,需要释放SDA)
在这里插入图片描述

3.4 I2C数据帧

发送一帧数据
在这里插入图片描述
先发送再接收数据帧(复合格式)
在这里插入图片描述

3.5 AT24C02数据帧

字节写:在WORD ADDRESS处写入数据DATA
在这里插入图片描述
MCU先发送一个开始信号(START)启动总线
接着跟上首字节,发送器件写操作地址(DEVICE ADDRESS)+写数据(0xA0)
等待应答信号(ACK)
发送数据的存储地址。24C02一共有256个字节的存储空间,地址从0x00~0xFF,想把数据存储>在哪个位置,此刻写的就是哪个地址。
发送要存储的数据第一字节、第二字节、…注意在写数据的过程中,E2PROM每个字节都会>回应一个“应答位0”,老告诉我们写E2PROM数据成功,如果没有回应答位,说明写入不成功。
发送结束信号(STOP)停止总线
在这里插入图片描述

随机读:读出在WORD ADDRESS处的数据DATA
在这里插入图片描述
MCU先发送一个开始信号(START)启动总线
接着跟上首字节,发送器件写操作地址(DEVICE ADDRESS)+写数据(0xA0)
注意:这里写操作是为了要把所要读的数据的存储地址先写进去,告诉E2PROM要读取哪个地址的数据。
发送要读取内存的地址(WORD ADDRESS),通知E2PROM读取要哪个地址的信息。
重新发送开始信号(START)
发送设备读操作地址(DEVICE ADDRESS)对E2PROM进行读操作 (0xA1)
E2PROM会自动向主机发送数据,主机读取从器件发回的数据,在读一个字节后,MCU会回应一个应答信号(ACK)后,E2PROM会继续传输下一个地址的数据,MCU不断回应应答信号可以不断读取内存的数据
如果不想读了,告诉E2PROM不想要数据了,就发送一个“非应答位NAK(1)”。发送结束信号(STOP)停止总线
在这里插入图片描述
AT24C02的固定地址为1010,可配置地址本开发板上为000
所以SLAVE ADDRESS+W为0xA0,SLAVE ADDRESS+R为0xA1

四、代码演示

4.1 AT24C02数据存储

main.c

#include <REGX52.H>
#include "LCD1602.h"
#include "Key.h"
#include "AT24C02.h"
#include "Delay.h"

unsigned char KeyNum;
unsigned int Num;

void main()
{
	LCD_Init();
	LCD_ShowNum(1,1,Num,5);
	while(1)
	{
		KeyNum=Key();
		if(KeyNum==1)	//K1按键,Num自增
		{
			Num++;
			LCD_ShowNum(1,1,Num,5);
		}
		if(KeyNum==2)	//K2按键,Num自减
		{
			Num--;
			LCD_ShowNum(1,1,Num,5);
		}
		if(KeyNum==3)	//K3按键,向AT24C02写入数据
		{
			AT24C02_WriteByte(0,Num%256);
			Delay(5);
			AT24C02_WriteByte(1,Num/256);
			Delay(5);
			LCD_ShowString(2,1,"Write OK");
			Delay(1000);
			LCD_ShowString(2,1,"        ");
		}
		if(KeyNum==4)	//K4按键,从AT24C02读取数据
		{
			Num=AT24C02_ReadByte(0);
			Num|=AT24C02_ReadByte(1)<<8;
			LCD_ShowNum(1,1,Num,5);
			LCD_ShowString(2,1,"Read OK ");
			Delay(1000);
			LCD_ShowString(2,1,"        ");
		}
	}
}

AT24C02.c

#include <REGX52.H>
#include "I2C.h"

#define AT24C02_ADDRESS		0xA0

/**
  * @brief  AT24C02写入一个字节
  * @param  WordAddress 要写入字节的地址
  * @param  Data 要写入的数据
  * @retval 无
  */
void AT24C02_WriteByte(unsigned char WordAddress,Data)
{
	I2C_Start();
	I2C_SendByte(AT24C02_ADDRESS);
	I2C_ReceiveAck();
	I2C_SendByte(WordAddress);
	I2C_ReceiveAck();
	I2C_SendByte(Data);
	I2C_ReceiveAck();
	I2C_Stop();
}

/**
  * @brief  AT24C02读取一个字节
  * @param  WordAddress 要读出字节的地址
  * @retval 读出的数据
  */
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);
	I2C_ReceiveAck();
	Data=I2C_ReceiveByte();
	I2C_SendAck(1);
	I2C_Stop();
	return Data;
}

I2C.c

#include <REGX52.H>

sbit I2C_SCL=P2^1;
sbit I2C_SDA=P2^0;

/**
  * @brief  I2C开始
  * @param  无
  * @retval 无
  */
void I2C_Start(void)
{
	I2C_SDA=1;
	I2C_SCL=1;
	I2C_SDA=0;
	I2C_SCL=0;
}

/**
  * @brief  I2C停止
  * @param  无
  * @retval 无
  */
void I2C_Stop(void)
{
	I2C_SDA=0;
	I2C_SCL=1;
	I2C_SDA=1;
}

/**
  * @brief  I2C发送一个字节
  * @param  Byte 要发送的字节
  * @retval 无
  */
void I2C_SendByte(unsigned char Byte)
{
	unsigned char i;
	for(i=0;i<8;i++)
	{
		I2C_SDA=Byte&(0x80>>i);
		I2C_SCL=1;
		I2C_SCL=0;
	}
}

/**
  * @brief  I2C接收一个字节
  * @param  无
  * @retval 接收到的一个字节数据
  */
unsigned char I2C_ReceiveByte(void)
{
	unsigned char i,Byte=0x00;
	I2C_SDA=1;
	for(i=0;i<8;i++)
	{
		I2C_SCL=1;
		if(I2C_SDA){Byte|=(0x80>>i);}
		I2C_SCL=0;
	}
	return Byte;
}

/**
  * @brief  I2C发送应答
  * @param  AckBit 应答位,0为应答,1为非应答
  * @retval 无
  */
void I2C_SendAck(unsigned char AckBit)
{
	I2C_SDA=AckBit;
	I2C_SCL=1;
	I2C_SCL=0;
}

/**
  * @brief  I2C接收应答位
  * @param  无
  * @retval 接收到的应答位,0为应答,1为非应答
  */
unsigned char I2C_ReceiveAck(void)
{
	unsigned char AckBit;
	I2C_SDA=1;
	I2C_SCL=1;
	AckBit=I2C_SDA;
	I2C_SCL=0;
	return AckBit;
}

AT24C02.h

#ifndef __AT24C02_H__
#define __AT24C02_H__

void AT24C02_WriteByte(unsigned char WordAddress,Data);
unsigned char AT24C02_ReadByte(unsigned char WordAddress);


#endif

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

4.2 秒表(定时器扫描按键数码管)

main.c

#include <REGX52.H>
#include "Timer0.h"
#include "Key.h"
#include "Nixie.h"
#include "Delay.h"
#include "AT24C02.h"

unsigned char KeyNum;
unsigned char Min,Sec,MiniSec;
unsigned char RunFlag;

void main()
{
	Timer0_Init();
	while(1)
	{
		KeyNum=Key();
		if(KeyNum==1)			//K1按键按下
		{
			RunFlag=!RunFlag;	//启动标志位翻转
		}
		if(KeyNum==2)			//K2按键按下
		{
			Min=0;				//分秒清0
			Sec=0;
			MiniSec=0;
		}
		if(KeyNum==3)			//K3按键按下
		{
			AT24C02_WriteByte(0,Min);	//将分秒写入AT24C02
			Delay(5);
			AT24C02_WriteByte(1,Sec);
			Delay(5);
			AT24C02_WriteByte(2,MiniSec);
			Delay(5);
		}
		if(KeyNum==4)			//K4按键按下
		{
			Min=AT24C02_ReadByte(0);	//读出AT24C02数据
			Sec=AT24C02_ReadByte(1);
			MiniSec=AT24C02_ReadByte(2);
		}
		Nixie_SetBuf(1,Min/10);	//设置显示缓存,显示数据
		Nixie_SetBuf(2,Min%10);
		Nixie_SetBuf(3,11);
		Nixie_SetBuf(4,Sec/10);
		Nixie_SetBuf(5,Sec%10);
		Nixie_SetBuf(6,11);
		Nixie_SetBuf(7,MiniSec/10);
		Nixie_SetBuf(8,MiniSec%10);
	}
}

/**
  * @brief  秒表驱动函数,在中断中调用
  * @param  无
  * @retval 无
  */
void Sec_Loop(void)
{
	if(RunFlag)
	{
		MiniSec++;
		if(MiniSec>=100)
		{
			MiniSec=0;
			Sec++;
			if(Sec>=60)
			{
				Sec=0;
				Min++;
				if(Min>=60)
				{
					Min=0;
				}
			}
		}
	}
}

void Timer0_Routine() interrupt 1
{
	static unsigned int T0Count1,T0Count2,T0Count3;
	TL0 = 0x18;		//设置定时初值
	TH0 = 0xFC;		//设置定时初值
	T0Count1++;
	if(T0Count1>=20)
	{
		T0Count1=0;
		Key_Loop();	//20ms调用一次按键驱动函数
	}
	T0Count2++;
	if(T0Count2>=2)
	{
		T0Count2=0;
		Nixie_Loop();//2ms调用一次数码管驱动函数
	}
	T0Count3++;
	if(T0Count3>=10)
	{
		T0Count3=0;
		Sec_Loop();	//10ms调用一次数秒表驱动函数
	}
}

注意:一定要看

千万不要直接复制代码,因为是模块化编写,模块的代码没有往上复制,大家一定要自己动手跟着教学视屏自己大!!!!!

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

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

相关文章

ECG信号处理——包括基本波检测、信号去噪、信号重建度量(Matlab代码实现)

目录 &#x1f4a5;1 概述 &#x1f4da;2 运行结果 &#x1f389;3 参考文献 &#x1f468;‍&#x1f4bb;4 Matlab代码 &#x1f4a5;1 概述 心电图&#xff08;ECG&#xff09;信号自动分析与诊断是目前信号处理领域中的研究热点之一,其真正实现将有力地促进医疗事业的…

集合引用类型——对象

介绍&#xff1a; 依据变量分类&#xff1a;ECMAScript变量包括两种不同类型的值&#xff1a;原始值和引用值。 依据类型分类&#xff1a;ECMAScript类型包括两种不同类型的值&#xff1a;基本数据类型和集合数据类型。 原始值和引用值&#xff1a; 原始值就是最简单的数据&am…

网络层IP

文章目录网络层基本概念IP报头分片和组装如何分片如何组合16位标识符13位片偏移3位标志网段划分IP地址的分类CIDRIP地址数量限制私有IP和公网IP运营商路由网络层 http和tcp只考虑了两端的问题&#xff0c;并没有考虑路途中的事情。路由查找 IP的构成&#xff1a;32位网络号主…

【Ctfer训练计划】——(八)

作者名&#xff1a;Demo不是emo 主页面链接&#xff1a;主页传送门 创作初心&#xff1a;舞台再大&#xff0c;你不上台&#xff0c;永远是观众&#xff0c;没人会关心你努不努力&#xff0c;摔的痛不痛&#xff0c;他们只会看你最后站在什么位置&#xff0c;然后羡慕或鄙夷座…

fx5u 脉冲输出指令PLSY(DPLSY)4种写法

本文描述三菱FX5U的 脉冲输出指令PLSY(DPLSY)&#xff0c;4种写法&#xff0c;都有效。 第一行&#xff1a;设置脉冲输出频率 第二行&#xff1a;DPLSY D0 K0 K1,FX5U &#xff0c;第二个参数是脉冲数量&#xff0c;设置为K0表示一值输出脉冲。 第三个参数是轴号K1,表示Y0脉冲…

2023跨年倒计时2023最炫烟花秀烟花代码

&#x1f4cb; 前言 &#x1f5b1; 博客主页&#xff1a;在下马农的碎碎念✍ 本文由在下马农原创&#xff0c;首发于CSDN&#x1f4c6; 首发时间&#xff1a;2022/12/30&#x1f4c5; 最近更新时间&#xff1a;2022/12/30&#x1f935; 此马非凡马&#xff0c;房星本是星。向前…

c#入门-补码

补码 明明我们用正数用的更多&#xff0c;如果把0归到负数里面&#xff0c;那么正数就是整的2n次方了。 为什么不这么做呢&#xff1f; 如果你的手表快了20分钟&#xff0c;你可以&#xff1a; 1.把他调慢20分钟 2.再调快11小时40分钟 其实负数就是一个特别大的正数。CPU没有…

Unity 基于法线和深度实现完美描边,可独立控制物体描边

目录前言自定义PostProcessOutlineShader关键代码说明1 使用深度绘制描边1.1 获得斜四方形UV坐标&#xff1a;1.2 采样四方向深度2 使用法线绘制描边3 解决倾斜表面白块问题3.1 计算视方向3.2 使用视方向修正阈值4 单独控制物体是否显示描边OutlineShader完整代码前言 最近项目…

github上传代码(亲测实用)

又被github上传代码折腾了我3个小时&#xff0c;各种问题都遇到过&#xff0c;最后写篇博客记录一下&#xff0c;方便后续上传。 github创建项目完成后&#xff0c;就会出现上传指令&#xff0c;如下图所示&#xff1a; 现在只需要按着命令的提示一步步执行&#xff1b; 1.点…

一文读懂HTTPS

大家第一次接触 HTTPS 协议的时候是不是和我一样&#xff0c;非常困惑。 这玩意概念又多又繁琐。尤其是里面的公钥私钥啥的。 当时就特别想知道&#xff0c;为什么用公钥加密却不能用公钥解密&#xff1f; 看完这篇文章你会弄明白&#xff0c;同时还会解锁很多HTTPS里的细节…

ansible的安装

自定义环境 1.操作环境 角色主机名IP地址组名 控制主机 server.example.com 192.168.90.134 server 受控主机 node1.example.com 192.168.90.135 node1 受控主机 node2.example.com 192.168.90.133 node2 需要保准三台主机能够互相通信。设置同一种网络模式&#xff0…

Tic-Tac-Toe可能棋局搜索的实现(python)

目录 1. 前言 2. 算法流程 3. 代码实现 3.1 终局及胜负判定方法 3.2 搜索邻节点 3.3 打印棋盘状态 3.4 代码 4. 小结 1. 前言 Tic-Tac-Toe中文常译作井字棋&#xff0c;即在3 x 3的棋盘上&#xff0c;双方轮流落子&#xff0c;先将3枚棋子连成一线的一方获得胜利。Tic-…

✿✿✿JavaScript --- jQuery框架一

目 录 1.jQuery的介绍和在线学习网址以及下载网址 2.jQuery的功能和优势 3.引用jQuery库和第一个案例 4.jQuery代码格式和注释 5.jQuery如何达到获取原生的DOM对象 6.jQuery选择器&#xff08;CSS对比版&#xff09; (1)常见选择器 (2)高级选择器以及方法 (3)属性选择…

单片机基础知识

目录 一、单片机基本认知 二、IO口输入和输出 三、点亮一个LED 1、编程实现LED闪烁 2、按下按键点亮灯 3、按键的消抖 4、记录状态位来控制LED 一、单片机基本认知 单片机和PC电脑相比的话&#xff0c;相当于电脑的主板 单片机是一种集成电路芯片。单片机又称单片微控…

S32DS_Optimization优化选项

S32DS_Optimization优化选项 S32DS3.4的选项, 右击工程后出现的选项 char is signed 让char类型为有符号, 类似signed char bitfield is unsigned 当声明不使用signed/unsigned时, 控制位字段是否无符号; 默认signed(因为基本整形(int等)也是signed) Function sections 默认情…

C语言—动态内存管理和柔性数组

目录 1. C/C的内存开辟 2. 为什么存在动态内存分配 3. 动态内存函数介绍 3.1 malloc 和 free 3.2 calloc() 3.3 realloc() 4. 常见的动态内存错误 4.1 对NULL指针的解引用操作 4.2 对动态开辟的空间越界访问 4.3 对非动态内存开辟的空间进行free&#xff08;&…

外贸谈判前需要注意的4p

01Past了解客户的过去 当一个客户找到我们的时候&#xff0c;作为业务&#xff0c;我们需要第一时间回复客户所问到的问题。让客户感受到&#xff0c;他需要的产品我们公司可以提供。于此同时&#xff0c;在客户沟通意愿度较高的时候&#xff0c;我们不妨多跟客户沟通一下几个问…

Java学习笔记 --- MySQL-索引和事务

一、索引 索引的原理 1、没有索引会全表扫描&#xff0c;从而查找速度会很慢 2、使用索引会形成一个索引的数据结构&#xff0c;比如二叉树 3、索引的代价 磁盘占用 对 dml&#xff08;update、delete、insert&#xff09;语句的效率影响 索引的类型 1、主键索引&#xff…

2022年圣诞节 | 用代码实现简单圣诞树

2022年圣诞节到来啦&#xff0c;很高兴这次我们又能一起度过~ 一、前言 本文我们用 Python 来画一棵带背景音乐效果的雪夜圣诞树以及使用 HTMLCSSJS 在页面渲染出动态圣诞树&#xff0c;所涉及到的源码均来自GitHub开源站点。 二、效果展示 Python HTMLCSSJS 三、编码实现 …

(六)汇编语言——包含多个段的程序

目录 使用数据 使用栈 代码 总结 使用数据 首先&#xff0c;我们来看一个问题&#xff0c;就是编程计算0123H&#xff0c;0456H&#xff0c;0789H&#xff0c;0abcH&#xff0c;0defH&#xff0c;0fedH&#xff0c;0cbaH&#xff0c;0987H的和&#xff0c;结果存在ax寄存器…