当前位置: 首页 > news >正文

细说EEPROM芯片24C02的基础知识及其驱动程序设计

目录

一、接口和通信协议

1、设备地址

2、写1字节数据

3、连续写多字节数据

4、读1字节数据

5、连续读多字节数据

二、驱动程序设计

1、24cxx.h

2、24cxx.c 


         文章参照使用旺宝红龙开发板,STM32F407ZGT6 KIT V1.0。

一、接口和通信协议

        开发板上有一个I2C接口的EEPROM芯片AT24C02,是ATMEL公司的产品。因为其他一些厂家的芯片与AT24C02引脚和功能完全兼容,一般就统称为24C02。24C02存储容量为256字节,它的电路连接如图所示。其SDA和SCL引脚连接STM32F407芯片的I2C1接口,使用引脚PF0和PF9。WP是写保护引脚,WP接地时,对24C02芯片可读可写。

1、设备地址

        24C02的I2C设备地址组成如图所示。A2、A1、A0位由芯片的引脚A2、A1、A0的电平决定,原理图中这3个引脚都接地,所以都是0。最低位R/W是读写标志位,当主设备对24C02进行写操作时,R/W为0,进行读操作时,R/W为1。所以,24C02的写操作地址为0xA0(10100000),读操作地址为0xA1(10100001)。HAL驱动程序函数中需要传递I2C从设备的地址时,都使用写操作地址。

1

0

1

0

A2

A1

A0

R/W

MSB

LSB

2、写1字节数据

        24C02的读写操作比较简单,存储空间可反复读写。 

        MCU向24C02写入1字节数据的SDA传输内容和顺序如下图。

        操作的顺序如下:

  • ●主机发送起始信号,然后发送器件的写操作地址。
  • ● 24C02应答ACK后,主机再发送8位字地址,这是24C02内部存储单元的地址。8位地址的范围是0~255,也就是24C02内256字节存储单元的地址。
  • ● 24C02应答ACK后,主机再发送需要写入的1字节的数据。
  • ●从机接收完数据后,应答ACK,主机发停止信号结束传输。

 

3、连续写多字节数据

        24C02内部存储区域按页划分,每页8字节,所以256字节的存储单元分为32页,页的起始地址是8×N,其中,N=0,1,…,31。

        可以在一次I2C通信过程(一个起始信号与一个停止信号限定的通信过程)中向24C02连续写入多个字节的数据,SDA传输内容和顺序如下图。图中的n是数据存储的起始地址,存储的数据字节数为1+x。24C02会自动将接收的数据从指定的起始地址开始存储,但是要注意,连续写入的数据的存储位置不能超过页的边界,否则,将自动从这页的开始位置继续存储。

 

        所以,在连续写数据时,如果数据起始地址在页的起始位置,则一次最多可写8字节的数据。当然,数据存储起始地址也可以不在页的起始位置,这时要注意,一次写入的数据不要超过页的边界。

4、读1字节数据

        可以从24C02的任何一个存储位置读取1字节的数据,读取1字节数据时,SDA传输的内容和顺序如下图。主设备先进行一次写操作,写入需要读取的存储单元的地址,然后再进行一次读操作,读取的1字节数据就是所指定的存储地址的存储内容。

 

5、连续读多字节数据

        可以从24C02一次性连续读取多字节的数据,且读取数据时不受页边界的影响,也就是读取数据的长度可以超过8字节。连续读多个字节数据的SDA传输内容和顺序如下图。主设备先进行一次写操作,写入需要读取的存储单元的地址,然后再进行一次读操作,连续读取多字节,存储器内部将自动移动存储位置,且存储位置不受页边界的影响。

 

        在使用I2C的HAL驱动函数进行24C02的数据读写时,以上各图描述的传输时序是由I2C硬件接口完成的,工程师不需要理睬这些时序。

二、驱动程序设计

        使用I2C接口的HAL驱动函数,根据24C02的数据读写操作的定义,编写24C02的驱动程序,将24C02的一些常用操作封装为函数,以便其他项目调用。

        24C02的驱动程序文件包括头文件24cxx.h和源程序文件24cxx.c,头文件24cxx.h是24C02驱动程序的接口定义,其完整代码如下:

1、24cxx.h


/**  文件名:24cxx.h* 	功能描述: 24C02 EEPROM驱动程序,使用HAL库** 	(1)24C02是 256字节EEPROM,可以单个字节读写,连续读写时按页读写,每页8字节。所以,按页读写时最多8字节,页号0--31** 	(2)连续写入数据时要注意不要超过页的边界,否则从页的开始处重新写,会覆盖原来的内容。** 	(3)24C02地址是 0b1010xxxy, 其中xxx由芯片的地址引脚A2,A1,A0决定,一般接地,所以是0xA0, HAL库在读写时自动在最后一位写0或1进行读或写操作** 	(4)24C02的地址数据长度是8位,使用宏定义符号I2C_MEMADD_SIZE_8BIT*/#ifndef __24cxx_H
#define __24cxx_H#include "stm32f4xx_hal.h"
#include "i2c.h" 				//i2c.h中定义了hi2c2
/* 两个与硬件相关的定义,   */
#define I2C_HANDLE hi2c2		//I2C外设对象变量,利用i2c.h中定义的hi2c2
#define	DEV_ADDR_24CXX 0x00A0	//24C02的写地址
// EEPROM存储器参数
#define	PAGE_SIZE_24CXX 0x0008	//24C02的Page大小为8字节
#define	MEM_SIZE_24CXX (uint16_t)256 //24C02总共容量字节数,8*32=256字节//检查设备是否准备好
HAL_StatusTypeDef EP24C_IsDeviceReady(void);//在任意地址写入一个字节
HAL_StatusTypeDef EP24C_WriteOneByte(uint16_t memAddress, uint8_t byteData);//在任意地址读出一个字节
HAL_StatusTypeDef EP24C_ReadOneByte(uint16_t memAddress, uint8_t *byteData);//连续读取数据,任意地址,任意长度,不受页的限制
HAL_StatusTypeDef EP24C_ReadBytes(uint16_t memAddress, uint8_t *pBuffer, uint16_t bufferLen);/*限定在一个页内写入连续数据,最多8字节。任意起始地址,*但是起始地址+数据长度不能超过页边界,即不能超过地址8*N-1 */
HAL_StatusTypeDef EP24C_WriteInOnePage(uint16_t memAddress, uint8_t *pBuffer, uint16_t bufferLen);//写任意长的数据,可以超过8字节,但数据地址必须从页首开始,即 8*N
HAL_StatusTypeDef EP24C_WriteLongData(uint16_t memAddress, uint8_t *pBuffer, uint16_t bufferLen);#endif

        为便于程序的移植,在文件24cxx.h中定义一个宏I2C_HANDLE替代hi2c2。如果使用了不同的I2C接口,只需修改这个宏定义即可,而I2C接口的外设初始化由CubeMX自动生成的函数完成。在24cxx.h中还定义了表示24C02地址的宏DEV_ADDR_24CXX,如果实际电路中的24C02的I2C地址被修改了,修改这个宏即可

        在文件24cxx.h中定义了5个函数,前面4个都是直接封装I2C的HAL传输函数实现的,最后1个函数EP24C_WriteLongData()能自动将一个长的数据拆分为多个页(每页8字节)写入,这5个函数都使用I2C的阻塞式存储器数据传输函数。

2、24cxx.c 


/* 文件: 24cxx.c* 描述: 24C02驱动程序源程序文件
*/#include "24cxx.h"
#define	EP24C_TIMEOUT 200						//超时等待时间,单位:ms
#define	EP24C_MEMADD_SIZE I2C_MEMADD_SIZE_8BIT  //存储器地址大小,8位地址//检查设备是否准备好I2C通讯,返回HAL_OK 表示OK
HAL_StatusTypeDef EP24C_IsDeviceReady(void)
{uint32_t Trials=10;		//尝试次数HAL_StatusTypeDef result=HAL_I2C_IsDeviceReady(&I2C_HANDLE,DEV_ADDR_24CXX,Trials,EP24C_TIMEOUT);return result;
}//向任意地址写入一个字节的数据, memAddr是存储器内部地址,byteData是需要写入的1个字节的数据
HAL_StatusTypeDef EP24C_WriteOneByte(uint16_t memAddress,uint8_t byteData)
{HAL_StatusTypeDef result=HAL_I2C_Mem_Write(&I2C_HANDLE,DEV_ADDR_24CXX,memAddress,EP24C_MEMADD_SIZE,&byteData,1,EP24C_TIMEOUT);return	result;
}//从任意地址读出一个字节的数据, memAddr是存储器内部地址,byteData是读出的1个字节的数据,若返回HAL_OK表示读取成功
HAL_StatusTypeDef EP24C_ReadOneByte(uint16_t memAddress,uint8_t *byteData)
{HAL_StatusTypeDef result=HAL_I2C_Mem_Read(&I2C_HANDLE,DEV_ADDR_24CXX,memAddress,EP24C_MEMADD_SIZE,byteData,1,EP24C_TIMEOUT);return result;
}//连续读取数据,任意地址,任意长度,不受页的限制
HAL_StatusTypeDef EP24C_ReadBytes(uint16_t memAddress,uint8_t *pBuffer,uint16_t bufferLen)
{if(bufferLen>MEM_SIZE_24CXX)	//超过总存储容量return HAL_ERROR;HAL_StatusTypeDef result=HAL_I2C_Mem_Read(&I2C_HANDLE,DEV_ADDR_24CXX,memAddress,EP24C_MEMADD_SIZE,pBuffer,bufferLen,EP24C_TIMEOUT);return result;
}//限定在一个页内写入连续数据,最多8字节。任意起始地址,但是起始地址+数据长度不能超过页边界
HAL_StatusTypeDef EP24C_WriteInOnePage(uint16_t memAddress,uint8_t *pBuffer,uint16_t bufferLen)
{if(bufferLen>PAGE_SIZE_24CXX)	//数据长度不能大于页的大小return HAL_ERROR;HAL_StatusTypeDef result=HAL_I2C_Mem_Write(&I2C_HANDLE,DEV_ADDR_24CXX,memAddress,EP24C_MEMADD_SIZE,pBuffer,bufferLen,EP24C_TIMEOUT);return result;
}//写任意长的数据,可以超过8字节,但数据地址必须从页首开始,即 8*N。自动分解为多次写入
HAL_StatusTypeDef EP24C_WriteLongData(uint16_t memAddress,uint8_t *pBuffer,uint16_t bufferLen)
{if(bufferLen>MEM_SIZE_24CXX)	//超过总存储容量return HAL_ERROR;HAL_StatusTypeDef result=HAL_ERROR;if(bufferLen<=PAGE_SIZE_24CXX)	//不超过1个page,直接写入后退出{result=HAL_I2C_Mem_Write(&I2C_HANDLE,DEV_ADDR_24CXX,memAddress,EP24C_MEMADD_SIZE,pBuffer,bufferLen,EP24C_TIMEOUT);return result;}uint8_t *pt=pBuffer;			//临时指针,不能改变传入的指针uint16_t pageCount=bufferLen/PAGE_SIZE_24CXX;	//Page个数for(uint16_t i=0; i<pageCount; i++)	//一次写入一个page的数据{result=HAL_I2C_Mem_Write(&I2C_HANDLE,DEV_ADDR_24CXX,memAddress,EP24C_MEMADD_SIZE,pt,PAGE_SIZE_24CXX,EP24C_TIMEOUT);pt += PAGE_SIZE_24CXX;memAddress += PAGE_SIZE_24CXX;HAL_Delay(5);					//必须有延时,以等待页写完if (result != HAL_OK)return result;}uint16_t leftBytes=bufferLen % PAGE_SIZE_24CXX;  //余数if (leftBytes>0)					//写入剩余的数据result=HAL_I2C_Mem_Write(&I2C_HANDLE,DEV_ADDR_24CXX,memAddress,EP24C_MEMADD_SIZE,pt,leftBytes,EP24C_TIMEOUT);return result;
}

        24C02是I2C接口的存储器,使用I2C的HAL驱动程序中的存储器数据传输函数进行数据读写更方便。这几个函数就是封装了函数HAL_I2C_Mem_Write()和HAL_I2C_Mem_Read(),只是函数的接口定义更简化,便于用户程序调用。

  • 函数EP24C_WriteOneByte()用于在任意地址写入1字节数据。
  • 函数EP24C_ReadOneByte()用于从任意地址读取1字节数据。
  • 函数EP24C_ReadBytes()用于从任意地址开始读取任意长度的数据,不受每页8字节的限制。
  • 函数EP24C_WriteInOnePage()限定在一个页内写数据,可以是任意起始地址,但一次最多写入8字节。
  • 函数EP24C_WriteLongData()用于从一个页的起始地址开始写入超过8字节的数据,函数内部会将数据拆分为多个页,分为多次写入。

http://www.mrgr.cn/news/81591.html

相关文章:

  • 华为Ascend产品
  • 27.收益的定义是什么?
  • vscode【实用插件】Material Icon Theme 美化文件图标
  • 优化神马关键词排名原理(优化神马搜索引擎关键词排名规则)
  • bert微调下游任务-情感分析
  • Redis十大数据类型详解
  • 【达梦数据库】小版本升级之bin文件替换
  • 是德 皮安表Keysight B2980 系列常用指令 附带说明书原件
  • E-commerce .net+React(一)——项目初始化
  • Java数组深入解析:定义、操作、常见问题与高频练习
  • 高性能编程,C++的无锁和有锁编程方法的性能对比
  • 2023 年 12 月青少年软编等考 C 语言四级真题解析
  • 字节跳动Java开发面试题及参考答案(数据结构算法-手撕面试题)
  • Anaconda搭建Python虚拟环境并在Pycharm中配置(小白也能懂)
  • 【物联网技术与应用】实验16:模拟霍尔传感器实验
  • YOLOv9-0.1部分代码阅读笔记-detect.py
  • 高精度问题
  • H5st5.0.0协议分析
  • 穷举vs暴搜vs深搜vs回溯vs剪枝系列一>括号生成
  • 【c语言】简单的c程序设计
  • 生成10级子目录,每个子目录下有100个不同大小的文件
  • 并发编程 - 死锁的产生、排查与解决方案
  • Javaweb maven单元测试
  • 前缀树介绍
  • Google Cloud Architect 认证考试错题集7
  • 2024大模型在软件开发中的具体应用有哪些?(附实践资料合集)