STM32之IIC总线控制ATC24C04

一、存储器介绍

1、电子密码存储概述

单片机的电子密码存储是一种将密码信息以电子形式存储在单片机内部的技术。它通常用于需要保护敏感信息或限制访问权限的应用程序,如安全系统、门禁系统、电子锁等。

电子密码存储可以通过多种方式实现,以下是其中一种常见的概述:

(1)存储器选择:选择适合存储密码的内部或外部存储器。内部存储器通常是非易失性存储器(如闪存),可以在断电情况下保持数据。外部存储器可以是EEPROM(可擦写可编程只读存储器)或其他非易失性存储器(FLASH)。

(2)加密算法:为了增加密码的安全性,可以使用加密算法对密码进行加密。常见的加密算法包括DES(数据加密标准)、AES(高级加密标准)等。密码存储之前,将密码使用加密算法进行加密,然后再存储在存储器中。

(3)存储密码:将经过加密的密码存储在选择的存储器中。可以根据具体需求选择存储密码所需的存储空间大小。

(4)访问控制:为了安全地访问存储的密码,通常需要实现访问控制机制。这可以包括密码验证、访问权限设置等。例如,在门禁系统中,用户可能需要输入正确的密码才能获得访问权限。

(5)密码修改:为了方便用户,通常需要提供一种方式允许用户修改已存储的密码。这可以通过输入当前密码和新密码来实现。

总之,单片机的电子密码存储是通过选择适当的存储器、加密算法和访问控制机制,将密码以电子形式存储在单片机内部的技术。这种技术提供了一种安全可靠的方法来存储和管理密码信息。

2、EEPROM存储器和Flash存储器区别

EEPROM存储器和Flash存储器都属于电可擦除存储器,但由于内部的构成它们有着以下几点区别:
擦写次数:EEPROM存储器能擦写10万次以上,而FLASH存储器一般为1万次以下。
存储容量:在体积(芯片封装大小)相等情况下FLASH存储器的容量大。
适用范围:EEPROM存储器常用于存储经常修改的一些参数(如用户的一些设定值),而FLASH存储器则一般用于存储程序或者一些只读性数据。
通信协议:EEPROM存储器使用IIC通信协议,FLASH存储器使用SPI通信协议。

二、AT24Cxx存储芯片

1、AT24Cxx芯片概述

AT24Cxx是Atmel公司生产的低功耗CMOS型EEPROM存储芯片,采用I2C总线方式进行数据读写,可工作于标准模式、快速模式和高速模式。主要特点是可读可写,掉电数据不丢失。目前常用的有24C02、24C04、24C08、24C16、24C32。

2、AT24C04芯片功能

AT24C04内含4K bit,即512字节存储空间,分成32每页16个字节。并且AT24C04内部把512字节的存储空间分为2部分,每部分256Byte。AT24C04芯片采用I2C总线方式进行数据读写,可工作于标准模式、快速模式和高速模式。AT24Cxx的写周期约为5ms,也就是在写操作后5ms才能正常读出数据

3、AT24C04芯片管脚描述

图AT24Cxx芯片功能管脚

管脚编号管脚名称功能管脚说明
1A0空管脚
2A1

地址输入脚。地址输入脚根据硬件原理图的连接确定,如果管脚接电源,则为1,

接地则为0。

3A2
5SCLI2C通讯接口的串行数据线
6SDAI2C通讯接口的串行时钟线
7WP

为读写保护管脚,低电平时,可以对整个AT24C04器件的512个字节进行读写操作;

高电平后,器件前256个地址的数据被保护,只能读,不可写入,后256个字节数据

可进行读写操作。

4、8GND、VCC芯片电源负极和电源正极

三、AT24C04存储芯片应用

1、AT24C04地址寻址

(1)芯片器件寻址
AT24C04的芯片地址为1010,其地址控制格式为1010A2A1P0R/W。其中A2、A1为可编程地址选择位(A0为空引脚),数据空间由P0位决定,当P0位为“0”时,将对AT24C04的0~255空间数据进行操作;当P0位为“1”时,将对AT24C04的256~511空间数据进行操作。A2、A1引脚接高、低电平得到确定的两位编码加上P0位的数据与芯片地址(1010)形成7位器件的地址码,在7位地址编码最后1位加上数据方向为则构成了AT24C04芯片器件寻址的控制字节(如图12.11所示)。
操作0-255数据空间器件地址 + 写方向 = 10100000 == 0xA0
操作0-255数据空间器件地址 + 读方向 = 10100000 == 0xA1

AT24CXX控制字节格式

(2)片内子地址寻址
芯片片内寻址可对内部512Byte中的任意1个字节进行读/写操作,其寻址范围为00~1FF,共512个寻址单位。但在操作数据寻址的时候需要注意,由于AT24C04芯片分为2个数据区,使用P0为加以区别,当P0 = 0时,操作的是0~255的地址单元,当P0 = 1时,操作的是256~511的地址单元。

2、AT24C04芯片时序操作

(1)单字节写操作时序

  单字节写操作要求在发送起始命令和从器件地址信息(R/W位清零)给从器件后,等待从器件产生应答信号,主器件发送1个字节子地址,即存储器内部地址,因AT24C04容量为512字节,所以子地址为0~512(需要注意P0位的参数,如果P0位参数为0,则无法操作256~511的地址)。主器件在收到从器件的另一个应答信号后,在接下来的时钟周期里主机发送8位数据,EEPROM再次应答,并在主器件产生停止信号后开始内部数据的擦写。在内部擦写过程中EEPROM不再应答主器件的任何请求。

AT24CXX单字节操作时序

起始条件 --> 器件地址 + 写方向 -->接收AT24C04的应答 --> 就是8位的数据(代表要写到这个AT24C04的哪个位置)-->接收AT24C04的应答 --> 发送8位的数据--> 接收AT24C04的应答-->停止条件

(2)页写操作时序

AT24C04提供32个16字节的页空间,用页写AT24C04可以一次写入16个字节数据,页写操作初始化与字节写相同,但在EEPROM接受到1字节数据后单片机并不发送停止条件,而是继续发送15字节数据,在每接受一字节数据,EEPROM发送一位应答。在发送完8字节数据后,单片机需发送停止信号以终止操作
在进行页写操作时,存储器的子地址低三位会自动增一,但由于高位并不自增,所以在子地址加到页空间边界,即写入16字节后,下一字节会自动写入该页空间的第一字节,覆盖之前的数据,并且如果连续写入数据的地址超过256,地址将从0地址重新开始,从0地址开始的数据将覆盖之前的数据。AT42C04在接收到n+1字节数据和主器件发送的停止信号后启动内部写周期将数据写到数据区,所有接收的数据在一个写周期内写入EEPROM芯片内部。

AT24CXX页写操作时序

起始条件 --> 器件地址 + 写方向 -->接收AT24C04的应答 --> 就是8位的数据(代表要写到这个AT24C04的哪个位置)-->接收AT24C04的应答 --> 不断发送8位的数据(不能超过当前这一页的地址,否则会回到开头覆盖写入)--> 接收AT24C04的应答-->停止条件

(3)单字节读操作时序

主器件首先通过发送起始信号,接着发送从器件地址,在接收到应答后,再发送想读取的字节数据的地址执行一个伪写操作。在AT24C04应答之后,主器件重新发送发送起始信号和从器件地址(此时的器件地址最低位为1,表示读操作),此时子地址指向的为之前定义的值,AT24C04响应并发送应答信号,然后输出所要求的一个 8 位字节数据,主器件在接收到数据后发送非应答信号,并产生停止条件。

AT24CXX单字节读操作时序

起始条件 --> 器件地址 + 写方向 -->接收AT24C04的应答 --> 就是8位的数据(代表要读到这个AT24C04的哪个位置)--> 接收AT24C04的应答 -->起始条件 --> 器件地址 + 读方向 -->接收AT24C04的应答 -->接收AT24c04发送过来的数据 -->读完了回非应答信号 --> 停止条件

(4)连续读操作时序

  连续读操作初始部分与单字节操作相同,在AT24C04发送完一个8 位字节数据后,主器件产生一个应答信号来响应,告知AT24C04主器件要求更多的数据。对应每个主机产生的应答信号,AT24C04将发送一个 8 位数据字节,当主器件发送非应答信号并发送停止位时结束此读操作。读操作可以连续进行,EEPROM内部地址会自动增加,这样整个寄存器区域在可在一个读操作内全部读出。当读取的字节超过最大地址时,地址计数器将翻转到0并继续输出数据字节。

AT24CXX连续读操作时序

起始条件 --> 器件地址 + 写方向 -->接收AT24C04的应答 --> 就是8位的数据(代表要读到这个AT24C04的哪个位置)-->接收AT24C04的应答 -->起始条件 --> 器件地址 + 读方向 -->接收AT24C04的应答 -->不断接收AT24c04发送过来的数据 -->直到回非应答信号才结束这次的接收 --> 停止条件

四、实例

#include "iic.h"/****************************
函数功能:初始化IIC总线的IO口
函数形参:void
函数返回值:void
函数说明:
PA8 -- SCL -- 推挽输出
PC9 -- SDA 
1.输入输出模式切换
SDA线既可以接收数据也可以发送数据
输入模式的时候不能输出数据
输出模式的时候可以读取数据
2.开漏输出
开漏输出:只能输出低电平
如果输出高电平就是断开输出电路
****************************/
void Iic_PortInit(void)
{GPIO_InitTypeDef  GPIO_InitStruct;//定义了一个结构体变量//1. 打开GPIOB的时钟RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE);//2. 配置GPIO口功能GPIO_InitStruct.GPIO_Mode = GPIO_Mode_OUT;//配置输出模式GPIO_InitStruct.GPIO_OType = GPIO_OType_PP;//配置为推挽GPIO_InitStruct.GPIO_Pin = GPIO_Pin_8;//选择8号管脚GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL;//无上下拉GPIO_InitStruct.GPIO_Speed = GPIO_Low_Speed;//低速GPIO_Init(GPIOA, &GPIO_InitStruct); GPIO_InitStruct.GPIO_OType = GPIO_OType_OD;//配置为开漏GPIO_InitStruct.GPIO_Pin = GPIO_Pin_9;//选择9号管脚GPIO_Init(GPIOC, &GPIO_InitStruct); 
}/****************************
函数功能:起始条件
函数形参:void
函数返回值:void
函数说明:在时钟线高电平期间,数据线产生下降沿
****************************/
void IIC_Start(void)
{SDA_H;SCL_H;Delay_Us(2);//起始条件的建立时间SDA_L; Delay_Us(2);//起始条件的保持时间SCL_L;//保证周期完整
}/****************************
函数功能:停止条件
函数形参:void
函数返回值:void
函数说明:在时钟线高电平期间,数据线产生上升沿
****************************/
void IIC_Stop(void)
{SDA_L;SCL_H;Delay_Us(2);//停止条件的建立时间SDA_H;Delay_Us(2);//停止和启动条件之间的总线空闲时间
}/****************************
函数功能:发送应答位
函数形参:u8 ack
函数返回值:void
函数说明:0:代表应答
1:代表非应答
****************************/
void Send_Ack(u8 ack)
{SCL_L;//发送方准备发送数据if(ack){SDA_H;}else{SDA_L;}Delay_Us(2);//发送数据所需要的时间SCL_H;Delay_Us(2);//接收数据所需要的时间SCL_L;Delay_Us(2);//保证一个完整的周期
}/****************************
函数功能:接收应答位
函数形参:void
函数返回值:u8
函数说明:0:代表应答1:代表非应答
****************************/
u8 Receive_Ack(void)
{u8 ack = 0;SDA_H;//断开输出电路SCL_L;//发送方准备发送数据Delay_Us(2);//发送数据所需要的时间SCL_H;if(SDA){ack = 1;}Delay_Us(2);//接收数据所需要的时间SCL_L;Delay_Us(2);//保证一个完整的周期return ack;
}/****************************
函数功能:发送一个字节并接收一个应答位
函数形参:u8 data
函数返回值:u8
函数说明:0:代表应答1:代表非应答
****************************/
u8 Send_Byte_Receive_Ack(u8 data)
{u8 i,ack = 0;for(i = 0; i < 8; i++){SCL_L;//发送方准备发送数据//1100 0011//0100 0000if(data & 0x80 >> i){SDA_H;}elseSDA_L;Delay_Us(2);//发送数据所需要的时间SCL_H;Delay_Us(2);//接收数据所需要的时间}ack = Receive_Ack();return ack;
}/****************************
函数功能:接收一个字节并发送一个应答位
函数形参:u8 data
函数返回值:u8
函数说明:0:代表应答1:代表非应答
****************************/
u8 Receive_Byte_Send_Ack(u8 ack)
{u8 i = 0;u8 data = 0;for(i = 0; i < 8; i++){SCL_L;//发送方准备发送数据Delay_Us(2);//发送数据所需要的时间SDA_H;//断开输出电路SCL_H;data <<= 1;//空出最低位if(SDA){data |= 1;}Delay_Us(2);//接收数据所需要的时间}Send_Ack(ack);return data;
}
#include "at24c04.h"/****************************
函数功能:页写
函数形参:u8 addr---写入的地址
u8 *str---写入的数据
u8 num--写入的个数
函数返回值:u8
函数说明:
****************************/
u8 AT24C04_PAGE_WRITE(u8 addr,u8 *str, u8 num)
{IIC_Start();if(Send_Byte_Receive_Ack(AT24C04_WRITEADDRESS))//先发器件地址写方向{IIC_Stop();return 1;}if(Send_Byte_Receive_Ack(addr))//发送写入的地址{IIC_Stop();return 2;}while(num--)//不断发送数据{if(Send_Byte_Receive_Ack(*str)){IIC_Stop();return 3;}str++;}IIC_Stop();Delay_ms(5);return 0;
}
/****************************
函数功能:读数据
函数形参:u8 addr---写入的地址
u8 *str---写入的数据
u8 num--写入的个数
函数返回值:u8
函数说明:****************************/
u8 AT24C04_READ(u8 addr,u8 *str, u8 num)
{IIC_Start();if(Send_Byte_Receive_Ack(AT24C04_WRITEADDRESS))//先发器件地址写方向{IIC_Stop();return 4;}if(Send_Byte_Receive_Ack(addr))//发送写入的地址{IIC_Stop();return 5;}IIC_Start();//起始条件if(Send_Byte_Receive_Ack(AT24C04_READADDRESS))//发送读的地址{IIC_Stop();return 6;}	num = num - 1;while(num--){*str = Receive_Byte_Send_Ack(0);//前面的数据都发应答str++;}*str = Receive_Byte_Send_Ack(1);//后面的数据发非应答IIC_Stop();return 0;
}
#ifndef __IIC_H_
#define __IIC_H_#include "stm32f4xx.h"
#include "delay.h"#define SCL_H  GPIO_SetBits(GPIOA,GPIO_Pin_8)
#define SCL_L  GPIO_ResetBits(GPIOA,GPIO_Pin_8)
#define SDA_H  GPIO_SetBits(GPIOC,GPIO_Pin_9)
#define SDA_L  GPIO_ResetBits(GPIOC,GPIO_Pin_9)
#define SDA    GPIO_ReadInputDataBit(GPIOC,GPIO_Pin_9)void Iic_PortInit(void);
void IIC_Start(void);
void IIC_Stop(void);
u8 Send_Byte_Receive_Ack(u8 data);
u8 Receive_Byte_Send_Ack(u8 ack);#endif
#ifndef __AT24C04_H_
#define __AT24C04_H_#include "stm32f4xx.h"
#include "iic.h"#define AT24C04_WRITEADDRESS 0XA0
#define AT24C04_READADDRESS 0XA1u8 AT24C04_READ(u8 addr,u8 *str, u8 num);
u8 AT24C04_PAGE_WRITE(u8 addr,u8 *str, u8 num);#endif

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

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

相关文章

Linux内核进程管理

什么是进程 进程的概念 进程是处于执行期的程序和他所占用资源的总称。进程就是运行的代码&#xff0c;进程的声明从代码开始运行那一刻开始&#xff1b;单纯的程序并非是是一个进程&#xff0c;一个程序也可能不只包含一个进程。 进程和线程的区别&#xff0c;与联系 线程…

Redis常用数据类型--String

String 常用命令SETGETMGETMSETSETNXINCR/DECRINCRBY/DECRBYINCRBYFLOATAPPENDGETRANGESETRANGESTRLEN 内部编码典型应用场景 常用命令 SET 将 string 类型的 value 设置到 key 中。如果 key 之前存在&#xff0c;则覆盖&#xff0c;⽆论原来的数据类型是什么。之 前关于此 k…

mysql8安装基础操作(一)

一、下载mysql8.0 1.查看系统glibc版本 这里可以看到glibc版本为2.17&#xff0c;所以下载mysql8.0的版本时候尽量和glibc版本对应 [rootnode2 ~]# rpm -qa |grep -w glibc glibc-2.17-222.el7.x86_64 glibc-devel-2.17-222.el7.x86_64 glibc-common-2.17-222.el7.x86_64 gl…

.NET高级面试指南专题三【线程和进程】

在C#中&#xff0c;线程&#xff08;Thread&#xff09;和进程&#xff08;Process&#xff09;是多任务编程中的重要概念&#xff0c;它们用于实现并发执行和多任务处理。 进程&#xff08;Process&#xff09;&#xff1a; 定义&#xff1a; 进程是正在运行的程序的实例&…

C#,数据检索算法之插值搜索(Interpolation Search)的源代码

数据检索算法是指从数据集合&#xff08;数组、表、哈希表等&#xff09;中检索指定的数据项。 数据检索算法是所有算法的基础算法之一。 本文提供插值搜索&#xff08;Interpolation Search&#xff09;的源代码。 1 文本格式 using System; namespace Legalsoft.Truffer.…

CSS color探索

CSS 颜色探索 在 CSS 的世界里&#xff0c;颜色为网页元素赋予了丰富的视觉效果。通过预定义的颜色名称、RGB、HEX、HSL&#xff0c;以及支持透明度的 RGBA 和 HSLA&#xff0c;我们可以创造出各种吸引人的设计。接下来&#xff0c;我们将通过示例代码来深入了解这些颜色应用。…

kafka-顺序消息实现

kafka-顺序消息实现 场景 在购物付款的时候&#xff0c;订单会有不同的订单状态&#xff0c;对应不同的状态事件&#xff0c;比如&#xff1a;待支付&#xff0c;支付成功&#xff0c;支付失败等等&#xff0c;我们会将这些消息推送给消息队列 &#xff0c;后续的服务会根据订…

CSS基础细节学习

目录 一.CSS--网页的美容师 二.语法规范及选择器的介绍 一.CSS--网页的美容师 CSS是层叠样式表( Cascading Style Sheets )的简称&#xff0c;有时我们也会称之为CSS样式表或级联样式表。 CSS是也是一种标记语言&#xff0c;CSS主要用于设置HTML页面中的文本内容(字体、大小…

log4j2 java api 入门介绍

概述 Log4j 2 API 提供了应用程序应该编码的接口&#xff0c;并提供了实现者创建日志实现所需的适配器组件。 虽然 Log4j 2 在 API 和实现之间被分解&#xff0c;但这样做的主要目的不是允许多个实现&#xff0c;尽管这当然是可能的&#xff0c;而是明确定义在“正常”应用程…

应急响应-内存分析

在应急响应过程中&#xff0c;除了上述几个通用的排查项&#xff0c;有时也需要对应响应服务器进行内存的提权&#xff0c;从而分析其中的隐藏进程。 内存的获取 内存的获取方法有如下几种&#xff1a; 基于用户模式程序的内存获取&#xff1b;基于内核模式程序的内存获取&a…

常用MQ产品的对比

常用MQ产品的对比 本文整理了常用MQ之间的对比&#xff0c;旨在帮助大家在实际项目中选择MQ产品。 消息队列对比参照表 注&#xff1a; 对照表来自&#xff1a;消息队列对比参照表 &#xff0c;对比维度比较全面&#xff0c;结果个人比较认同&#xff0c;强烈建议参考。 Rock…

Docker安装RcoketMQ

1、Docker安装RcoketMQ-4.9.4 在同级文件夹创建目录config&#xff0c;并在里面创建文件broker.conf&#xff0c;文件内容如下&#xff1a; brokerClusterNameDefaultCluster brokerNamebroker-a brokerId0 deleteWhen04 fileReservedTime48 brokerRoleASYNC_MASTER flushDis…

Python网络爬虫实战——实验5:Python爬虫之selenium动态数据采集实战

【实验内容】 本实验主要介绍和使用selenium库在js动态加载网页中数据采集的作用。 【实验目的】 1、理解动态加载网页的概念 2、学习Selenium库基本使用 3、掌握动态加载数据采集流程 【实验步骤】 步骤1理解动态加载网页 步骤2学习使用Selenium库 步骤3 采集河北政府采购…

Python初学者学习记录——python基础综合案例:数据可视化——地图可视化

一、基础地图使用 1、基础地图演示 2、基础地图演示——视觉映射器 from pyecharts.charts import Map from pyecharts.options import VisualMapOpts# 准备地图对象 map Map() # 准备数据 data [("北京市", 99),("上海市", 199),("湖南省", 2…

1 月 28日算法练习-前缀和

小郑的蓝桥平衡串 思路&#xff1a;把 L 看成 1&#xff0c;Q 看成 -1&#xff0c;利用前缀和来得到输入串的前缀子串中LQ 的和&#xff0c;利用前缀和差的性质得到子串&#xff0c;通过枚举看它是否平衡。 将L看做1&#xff0c;Q看做&#xff0d;1&#xff0c;只有当某个区间…

如何快速上手一个vue框架

安装nvm 下载nvm-setup.zip&#xff1a; https://github.com/coreybutler/nvm-windows/releases 解压安装nvm&#xff1a; 创建两个文件夹&#xff0c;一个是nvm的安装位置&#xff0c;另一个是node.js的下载位置。不需要配置环境变量和修改setting文件了 检查nvm是否安装成功…

不常见知识点汇总

目录 1.关于输入流&#xff08;cin&#xff09;1.1 cin.fail()1.2 cin.clear()1.3 cin.ignore() 随时补充&#xff01;&#xff01;&#xff01; 1.关于输入流&#xff08;cin&#xff09; 问题描述&#xff1a; int input 0; cin >> input; while (cin.fail()) {cin.…

Linux 增加 SWAP 空间

一、需求 通过阿里云启动项目时&#xff0c;使用Vuepress build编译静态页面时内存需要800MB&#xff0c;导致内存不够&#xff0c;因此考虑使用swap方式&#xff0c;置换一些内存资源存放swap磁盘。 [rootxxx myblog]# npm run docs:dev> myblog1.0.0 docs:dev > vuep…

全角色服务、全场景支撑、全业务应用的新一代智慧教室

新一代智慧教室以“数智化助力高质量人才培养”为核心目标&#xff0c;以AI赋能的智能硬件为基础构建多形态智慧教学环境&#xff0c;以中台为支撑实现数据、设备、系统、业务的互联互通、开放共享&#xff0c;以平台全面覆盖教学应用&#xff0c;采集、汇聚、挖掘、分析课前课…

【解决】IntelliJ IDEA 重命名 Shift + F6 失效

IntelliJ IDEA 重命名 Shift F6 失效 问题解决 问题 Idea 重命名 Shift F6 &#xff0c;一直没反应 解决 调查发现原因是微软新版的输入法冲突了。需要设置【使用以前版本的微软拼音输入法】解决兼容性。 设置 -> 时间和语言 -> 区域 -> 语言选项 -> 键盘选项…