【STM32】AT24C256硬件I2C读写,基于HAL库-程序员宅基地

技术标签: stm32  STM32单片机  1024程序员节  嵌入式硬件  单片机  

目录

一、简单介绍

二、配置工程

打开CubeMX,配置时钟,调试接口,工程名,目录等

配置iic

配置串口用于显示信息

三、硬件连接

四、代码编写

一、随机写入一个字节

测试代码

波形如下

代码编写

二、连续写入

代码如下

三、随机读取

测试代码

波形如下

代码编写

四、连续读取

代码如下

五、效果展示

五、驱动附录

AT24C256.h

AT24C256.c


一、简单介绍

EEPROM (Electrically Erasable Programmable read only memory)是指带电可擦可编程只读存储器。是一种掉电数据不丢失的存储芯片。 EEPROM 可以在电脑上或专用设备上擦除已有信息,重新编程。一般用在即插即用。

笔者所用模块为AT24C256,存储容量256Kb即32KB(32K字节)。模块的原理图如下

引脚名称  功能
A0-A1(A2其实是NC脚,原理图画得不对) 器件地址输入
SDA(原理图中的DATA脚) 串行数据
SCL 时钟
WP(原理图中的HOLD脚) 写保护(高电平有效)
VCC 接高电平(1.8-5.5V宽电压)
GND

驱动协议是IIC,考虑开启硬件IIC进行通信,笔者选择使用IIC2

二、配置工程

打开CubeMX,配置时钟,调试接口,工程名,目录等

配置iic

配置串口用于显示信息

三、硬件连接

如上一步的配置,将模块与单片机如下连接

PB10---->SCL

PB11---->SDA

VCC---->3V3

GND---->GND

四、代码编写

一、随机写入一个字节

先发送器件地址或上读写指令,再发送要写入的地址(占2个字节),再发送写入的字节,再发送停止位。

由于A0和A1均为低电平,即0,那么器件地址为0x50(0101 0000)

此时为写入,R/W就是0,经过组合后为0xA0

测试代码

即向AT24C256内存地址为0的地方写入数据“1”,需要注意的是AT24C256写入数据需要等待5~10ms,要加一个延时

波形如下

代码编写

void AT24C256_WriteByte(uint16_t addr,uint8_t dat)
{
	HAL_I2C_Mem_Write(&hi2c2,AT24C256_ADDR_WRITE,addr,AT24C256_ADDR_LEN,&dat,1,0xffff);
	HAL_Delay(AT24C256_WAIT_TIME_UINT);
}

二、连续写入

连续写入和随机写入差不多,只是如果一次写的个数超过一页的字节数或者地址计到一页的尾部时,会重新回到这页开头覆盖写过的数而不会自动翻页,这是需要处理的地方。

代码如下

/*
AT24C256有256K个位,即32KB,32k字节,寻址空间为0~0x7FFF,
分为两个字节,地址1为0~0x7F,地址AT24C256_ADDR_LEN为0~0xFF
一页有64个字节,分为512页
*/
void AT24C256_WriteMultiByte(uint16_t addr,uint8_t* dat,uint16_t n)
{
	uint16_t i = 0;
    uint16_t cnt = 0;        //写入字节计数
	uint16_t head;
	uint16_t left;
	uint16_t tail;
	
	if((n + addr - 1)/AT24C256_PAGE_SIZE == addr/AT24C256_PAGE_SIZE)		//如果在同一页
	{
		HAL_I2C_Mem_Write(&hi2c2, AT24C256_ADDR_WRITE, addr, AT24C256_ADDR_LEN, dat, n, 0xFFFF);
        HAL_Delay(AT24C256_WAIT_TIME_UINT*n);
	}
	else
	{
		head = (addr / AT24C256_PAGE_SIZE+1) * AT24C256_PAGE_SIZE - addr;	//开始页剩余待写入字节数
		left = n - head;													//除去开始页剩下字节数
		tail=left-left/AT24C256_PAGE_SIZE*AT24C256_PAGE_SIZE;				//末页待写入字节数
		HAL_I2C_Mem_Write(&hi2c2, AT24C256_ADDR_WRITE,addr,AT24C256_ADDR_LEN,dat,head,0xffff);
		HAL_Delay(AT24C256_WAIT_TIME_UINT*head);
		for(i=0;i<left/AT24C256_PAGE_SIZE;i++)
		{
			HAL_I2C_Mem_Write(&hi2c2, AT24C256_ADDR_WRITE, addr+head+i*AT24C256_PAGE_SIZE,\
			AT24C256_ADDR_LEN, dat+head+i*AT24C256_PAGE_SIZE,AT24C256_PAGE_SIZE, 0xFFFF);
			HAL_Delay(AT24C256_WAIT_TIME_UINT*AT24C256_PAGE_SIZE);
		}
		HAL_I2C_Mem_Write(&hi2c2, AT24C256_ADDR_WRITE,addr+head+i*AT24C256_PAGE_SIZE,AT24C256_ADDR_LEN,\
		dat+head+i*AT24C256_PAGE_SIZE,tail,0xffff);
		HAL_Delay(AT24C256_WAIT_TIME_UINT*tail);
	}	
}

三、随机读取

要先发送一个假写的动作,把地址定位到要读的地方,然后再发送读指令,此时模块就会把数据一个接一个地clock出来了

测试代码

波形如下

代码编写

uint8_t AT24C256_ReadByte(uint16_t addr)
{
	uint8_t p;
	HAL_I2C_Mem_Read(&hi2c2,AT24C256_ADDR_READ,addr,AT24C256_ADDR_LEN,&p,1,0xffff);
	return p;
}

四、连续读取

由于连续读写的时候,地址会自动增加,并且会翻页,所以不必担心重复读取的问题,只要别读比最大地址范围还大的地址一般没有问题(经过笔者测试,如果读取0x8000地址的值,得到的是0x0000处的值),而且读数据不用等待,非常不错

代码如下

/*
连续读字节,参数为开始读地址,用来存储数据的地址,要读取的个数
*/
void AT24C256_ReadMultiByte(uint16_t addr,uint8_t* dat,uint16_t n)
{
	if(addr+n<0x8000)
	HAL_I2C_Mem_Read(&hi2c2,AT24C256_ADDR_READ,addr,AT24C256_ADDR_LEN,dat,n,0xffff);
}

五、效果展示

主函数main.c主要代码如下

#include "main.h"
#include "i2c.h"
#include "tim.h"
#include "usart.h"
#include "gpio.h"

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "AT24C256.h"
#include "stdio.h"
#include "stdlib.h"
/* USER CODE END Includes */

/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */

/* USER CODE END PTD */

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
#define TEST_BUFFER_LEN 1024
/* USER CODE END PD */

/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */

/* USER CODE END PM */

/* Private variables ---------------------------------------------------------*/

/* USER CODE BEGIN PV */
uint16_t x;
uint8_t buffer[TEST_BUFFER_LEN];
uint8_t b[TEST_BUFFER_LEN];
/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
/* USER CODE BEGIN PFP */

/* USER CODE END PFP */

/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */

/* USER CODE END 0 */

/**
  * @brief  The application entry point.
  * @retval int
  */
int main(void)
{
  /* USER CODE BEGIN 1 */

  /* USER CODE END 1 */

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_I2C1_Init();
  MX_I2C2_Init();
  MX_TIM2_Init();
  MX_USART1_UART_Init();
  /* USER CODE BEGIN 2 */

for(x=0;x<TEST_BUFFER_LEN;x++)
{
	*(buffer+x)=x%256;
}
printf("start\r\n");
AT24C256_WriteMultiByte(0x0,buffer,TEST_BUFFER_LEN);
printf("end\r\n");

  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
	  AT24C256_ReadMultiByte(0,b,TEST_BUFFER_LEN);
	  for(uint16_t i=0;i<TEST_BUFFER_LEN;i++)
	  {
		  x=AT24C256_ReadByte(i);
		  printf("addr:%d\t-->:%d\r\n",i,b[i]);
	  }
	  printf("\r\n\r\n\r\n");
	  HAL_Delay(1000);
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}

五、驱动附录

AT24C256.h

#ifndef AT24C256_H
#define AT24C256_H
#include "main.h"
#define	   AT24C256_ADDR_LEN 		2
#define    AT24C256_ADDR_WRITE  	0xA0
#define    AT24C256_ADDR_READ   	0xA1
#define    AT24C256_PAGE_SIZE		64
#define	   AT24C256_WAIT_TIME_UINT 	2
#define	   AT24C256_MEM_LEN 		0x8000
void AT24C256_WriteByte(uint16_t add,uint8_t dat);
uint8_t AT24C256_ReadByte(uint16_t add);
void AT24C256_WriteMultiByte(uint16_t add,uint8_t* dat,uint16_t n);
void AT24C256_Fill(uint8_t fill);
void AT24C256_ReadMultiByte(uint16_t addr,uint8_t* dat,uint16_t n);
#endif

AT24C256.c


#include "i2c.h"
#include "AT24C256.h"
#include "string.h"
uint8_t erase[512];

void AT24C256_WriteByte(uint16_t addr,uint8_t dat)
{
	HAL_I2C_Mem_Write(&hi2c2,AT24C256_ADDR_WRITE,addr,AT24C256_ADDR_LEN,&dat,1,0xffff);
	HAL_Delay(AT24C256_WAIT_TIME_UINT);
}
/*
AT24C256有256K个位,即32KB,32k字节,寻址空间为0~0x7FFF,
分为两个字节,地址1为0~0x7F,地址2为0~0xFF
一页有64个字节,分为512页
*/
void AT24C256_WriteMultiByte(uint16_t addr,uint8_t* dat,uint16_t n)
{
	uint16_t i = 0;
    uint16_t cnt = 0;        //写入字节计数
	uint16_t head;
	uint16_t left;
	uint16_t tail;
	
	if((n + addr - 1)/AT24C256_PAGE_SIZE == addr/AT24C256_PAGE_SIZE)		//如果在同一页
	{
		HAL_I2C_Mem_Write(&hi2c2, AT24C256_ADDR_WRITE, addr, AT24C256_ADDR_LEN, dat, n, 0xFFFF);
    HAL_Delay(AT24C256_WAIT_TIME_UINT*n);
	}
	else
	{
		head = (addr / AT24C256_PAGE_SIZE+1) * AT24C256_PAGE_SIZE - addr;	//开始页剩余待写入字节数
		left = n - head;													//除去开始页剩下字节数
		tail=left-left/AT24C256_PAGE_SIZE*AT24C256_PAGE_SIZE;				//末页待写入字节数
		HAL_I2C_Mem_Write(&hi2c2, AT24C256_ADDR_WRITE,addr,AT24C256_ADDR_LEN,dat,head,0xffff);
		HAL_Delay(AT24C256_WAIT_TIME_UINT*head);
		for(i=0;i<left/AT24C256_PAGE_SIZE;i++)
		{
			HAL_I2C_Mem_Write(&hi2c2, AT24C256_ADDR_WRITE, addr+head+i*AT24C256_PAGE_SIZE,\
			AT24C256_ADDR_LEN, dat+head+i*AT24C256_PAGE_SIZE,AT24C256_PAGE_SIZE, 0xFFFF);
			HAL_Delay(AT24C256_WAIT_TIME_UINT*AT24C256_PAGE_SIZE);
		}
		HAL_I2C_Mem_Write(&hi2c2, AT24C256_ADDR_WRITE,addr+head+i*AT24C256_PAGE_SIZE,AT24C256_ADDR_LEN,\
		dat+head+i*AT24C256_PAGE_SIZE,tail,0xffff);
		HAL_Delay(AT24C256_WAIT_TIME_UINT*tail);
	}	
}


uint8_t AT24C256_ReadByte(uint16_t addr)
{
	uint8_t p;
	HAL_I2C_Mem_Read(&hi2c2,AT24C256_ADDR_READ,addr,AT24C256_ADDR_LEN,&p,1,0xffff);
	return p;
}
/*
连续读字节,参数为开始读地址,用来存储数据的地址,要读取的个数
*/
void AT24C256_ReadMultiByte(uint16_t addr,uint8_t* dat,uint16_t n)
{
	if(addr+n<0x8000)
	HAL_I2C_Mem_Read(&hi2c2,AT24C256_ADDR_READ,addr,AT24C256_ADDR_LEN,dat,n,0xffff);
}
void AT24C256_Fill(uint8_t fill)
{
	memset(erase,fill,512);
	for(uint16_t i=0;i<64;i++)
	{
		AT24C256_WriteMultiByte(i*512,erase,512);
	}
}
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/weixin_56719449/article/details/133843386

智能推荐

vue引入原生高德地图_前端引入原生地图-程序员宅基地

文章浏览阅读556次,点赞2次,收藏3次。由于工作上的需要,今天捣鼓了半天高德地图。如果定制化开发需求不太高的话,可以用vue-amap,这个我就不多说了,详细就看官网 https://elemefe.github.io/vue-amap/#/zh-cn/introduction/install然而我们公司需要英文版的高德,我看vue-amap中好像没有这方面的配置,而且还有一些其他的定制化开发需求,然后就只用原生的高德。其实原生的引入也不复杂,但是有几个坑要填一下。1. index.html注意,引入的高德js一定要放在头部而_前端引入原生地图

ViewGroup重写大法 (一)-程序员宅基地

文章浏览阅读104次。本文介绍ViewGroup重写,我们所熟知的LinearLayout,RelativeLayout,FrameLayout等等,所有的容器类都是ViewGroup的子类,ViewGroup又继承View。我们在熟练应用这些现成的系统布局的时候可能有时候就不能满足我们自己的需求了,这是我们就要自己重写一个容器来实现效果。ViewGroup重写可以达到各种效果,下面写一个简单的重写一个Vi..._viewgroup 重写

Stm32学习笔记,3万字超详细_stm32笔记-程序员宅基地

文章浏览阅读1.8w次,点赞279次,收藏1.5k次。本文章主要记录本人在学习stm32过程中的笔记,也插入了不少的例程代码,方便到时候CV。绝大多数内容为本人手写,小部分来自stm32官方的中文参考手册以及网上其他文章;代码部分大多来自江科大和正点原子的例程,注释是我自己添加;配图来自江科大/正点原子/中文参考手册。笔记内容都是平时自己一点点添加,不知不觉都已经这么长了。其实每一个标题其实都可以发一篇,但是这样搞太琐碎了,所以还是就这样吧。_stm32笔记

CTS(13)---CTS 测试之Media相关测试failed 小结(一)_mediacodec框架 cts-程序员宅基地

文章浏览阅读1.8k次。Android o CTS 测试之Media相关测试failed 小结(一)CTSCTS 即兼容性测试套件,CTS 在桌面设备上运行,并直接在连接的设备或模拟器上执行测试用例。CTS 是一套单元测试,旨在集成到工程师构建设备的日常工作流程(例如通过连续构建系统)中。其目的是尽早发现不兼容性,并确保软件在整个开发过程中保持兼容性。CTS 是一个自动化测试工具,其中包括两个主要软件组件:CTS tra..._mediacodec框架 cts

chosen.js插件使用,回显,动态添加选项-程序员宅基地

文章浏览阅读4.5k次。官网:https://harvesthq.github.io/chosen/实例化$(".chosen-select").chosen({disable_search_threshold: 10});赋值var optValue = $(".chosen-select").val();回显1.设置回显的值$(".chosen-select").val(“opt1”);2.触发cho..._chosen.js

C++ uint8_t数据串如何按位写入_unit8_t 集合 赋值 c++-程序员宅基地

文章浏览阅读1.9k次。撸码不易,网上找不到,索性自己写,且撸且珍惜!void bitsWrite(uint8_t* buff, int pos, int size, uint32_t value){ uint32_t index[] = { 0x80000000, 0x40000000, 0x20000000, 0x10000000, 0x8000000, 0x4000000, 0x2000000, 0x1000000, 0x800000, 0x400000, 0_unit8_t 集合 赋值 c++

随便推点

Javaweb框架 思维导图_javaweb框架图-程序员宅基地

文章浏览阅读748次。javaweb知识点_javaweb框架图

adb的升级与版本更新_adb iptabls怎么升级-程序员宅基地

文章浏览阅读1.1w次,点赞3次,收藏16次。adb是没有自动升级的命令的,如果想要更新adb的版本,我们可以在网上找到自己想要的版本进行更新给大家提供几个版本https://pan.baidu.com/s/1yd0dsmWn5CK08MlyuubR7g&shfl=shareset 提取码: 94z81、下载解压后我们可以找到下面几个文件,并复制2、找到adb安装的文件夹下的platform-tools文件夹,我这里是..._adb iptabls怎么升级

微信苹果版删除所有的聊天记录的图文教程_mac微信怎么删除聊天列表-程序员宅基地

文章浏览阅读3.8k次。很多用户可能都知道怎么在Windows系统上删除微信的聊天记录,那么苹果电脑上的微信软件怎么删除所有的聊天记录呢?下面小编就专门来给大家讲下微信mac版删除所有的聊天记录的图文教程。点击后会弹出提示窗口,点击这里的确认按钮就可以将其清理掉了。在这里选择要清理的数据,然后点击下方右边的清理按钮就行了。在mac上打开微信后,点击左下角的横线图标。然后再点击这里的管理微信聊天数据按钮。打开了设置窗口,点击上方的“通用”。在这里点击下方的前往清理按钮。点击弹出菜单里的“设置”。_mac微信怎么删除聊天列表

【报错笔记】数据类型转换时报错:Request processing failed;nested exception is java.lang.NumberFormatException:..._request processing failed; nested exception is jav-程序员宅基地

文章浏览阅读7.7k次。数据类型转换时报错:Request processing failed;nested exception is java.lang.NumberFormatException:For input String “20151512345”报错原因:数字格式异常,接着后面有 For input string: “201515612343” 提示,这就告诉我们你当前想把 “201515612343” 转换成数字类型时出错了。解决方案:使用2015151612343这个数字太大了,所以直接使用string_request processing failed; nested exception is java.lang.numberformatexcepti

qml 自定义消息框_Qt qml 自定义消息提示框-程序员宅基地

文章浏览阅读387次。版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。本文链接:https://blog.csdn.net/a844651990/article/details/78376767Qt qml 自定义消息提示框QtQuick有提供比较传统的信息提示框MessageDialog,但是实际开发过程并不太能满足我们的需求。下面是根据controls2模块中..._qml 自定义 messagedialog

Redis.conf 默认出厂内容_默认出厂的原始redis.conf文件全部内容-程序员宅基地

文章浏览阅读599次。# Redis configuration file example.## Note that in order to read the configuration file, Redis must be# started with the file path as first argument:## ./redis-server /path/to/redis.conf # Note on units: when memory size is needed, it is pos._默认出厂的原始redis.conf文件全部内容

推荐文章

热门文章

相关标签