关于I2C读写AT24C04存储芯片的一些浅显认知?

这两天一直在尝试往AT24C04芯片里面存储数据,试了几天了,发现能查找的相关资料还是很少的,有些东西搞不明白,说是可以看数据手册,但是我的英文视频不要太辣鸡了。翻译软件又翻译的不准确,所以只能自己摸索着试验了。所以这个东西很费时间啊?最终实验的结果是,我只能往前255个字节内写入数据,并能够保存下来,剩下的那257个字节要怎么存储呢?我一直没有什么头绪,特此我把我的实验结果分享出来!要是能够遇到大佬能够为我答疑解惑,我在这里感激不尽了!如果没有人替我解惑,就当我分享出来给大家学习吧!毕竟这个东西还是很稀缺的资源,国内应该有不少小伙伴会的,但是都没有分享出来。我来分享吧!也许我说的太过了,主要是我这几天视频和网页确实是没有少看,但是没有找到丁点线索,基本上千篇一律,都是互相抄袭的。

好了,我先把我写的I2C的底层驱动贴出来吧:

//我的I2C.c文件
#include "MyI2C.h"

void MyI2C_W_SCL(uint8_t value)
{
	GPIO_WriteBit(GPIOB, GPIO_Pin_11, (BitAction)value);
	Delay_us(10);
}

void MyI2C_W_SDA(uint8_t value)
{
	GPIO_WriteBit(GPIOB, GPIO_Pin_10, (BitAction)value);
	Delay_us(10);
}

uint8_t MyI2C_R_SDA(void)
{
	uint8_t BitValue;
	BitValue = GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_10);
	Delay_us(10);
	return BitValue;
}

void MyI2C_Init(void)
{
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
	
	GPIO_InitTypeDef GPIO_InitStruct;
	GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_OD;
	GPIO_InitStruct.GPIO_Pin = GPIO_Pin_10 | GPIO_Pin_11;
	GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOB, &GPIO_InitStruct);
	
	GPIO_SetBits(GPIOB, GPIO_Pin_10 | GPIO_Pin_11);
}

void MyI2C_Start(void)
{
	MyI2C_W_SDA(1);
	MyI2C_W_SCL(1);
	MyI2C_W_SDA(0);
	MyI2C_W_SCL(0);
}

void MyI2C_Stop(void)
{
	MyI2C_W_SDA(0);
	MyI2C_W_SCL(1);
	MyI2C_W_SDA(1);
}

void MyI2C_SendByte(uint8_t Byte)
{
	uint8_t i;
	for(i=0; i<8; i++)
	{
		MyI2C_W_SDA(Byte & (0x80>>i));
		MyI2C_W_SCL(1);
		MyI2C_W_SCL(0);
	}
}

uint8_t MyI2C_ReceiveByte(void)
{
	uint8_t i, Byte=0x00;
	MyI2C_W_SDA(1);
	for(i=0; i<8; i++)
	{
		MyI2C_W_SCL(1);
		if(MyI2C_R_SDA() == 1){Byte |= (0x80>>i);}
		MyI2C_W_SCL(0);
	}
	return Byte;
}


void MyI2C_SendACK(uint8_t ACK)
{
	
	MyI2C_W_SDA(ACK);
	MyI2C_W_SCL(1);
	MyI2C_W_SCL(0);
	
}

uint8_t MyI2C_ReceiveACK(void)
{
	uint8_t ACK;
	MyI2C_W_SDA(1);
	
	MyI2C_W_SCL(1);
	ACK = MyI2C_R_SDA();
	MyI2C_W_SCL(0);
	return ACK;
}

// 从机地址扫描程序(传入从机地址的变量)  最后读取变量就是从机地址
void MyI2C_Scan(uint8_t *addr)
{
	uint16_t i;
	for(i=0;i<256;i++)
	{
		MyI2C_Start();
		MyI2C_SendByte(i);
		uint8_t ACK = MyI2C_ReceiveACK();
		if(ACK == 0)
		{
			*addr = i;
		}
	}
}



下面是:我的I2C.h文件

#ifndef __MYI2C_H
#define __MYI2C_H

#include "stm32f10x.h"                  // Device header
#include "Delay.h"


void MyI2C_Init(void);

void MyI2C_Start(void);

void MyI2C_Stop(void);

void MyI2C_SendByte(uint8_t Byte);

uint8_t MyI2C_ReceiveByte(void);

void MyI2C_SendACK(uint8_t ACK);

uint8_t MyI2C_ReceiveACK(void);

// 从机地址扫描程序(传入从机地址的变量)  最后读取变量就是从机地址
void MyI2C_Scan(uint8_t *addr);


#endif

下面是AT24C256.c文件(刚开始时是手上有C256的芯片,试了一天后发现自己搞不定,就买了24C04芯片来实验,结果也没有搞定,好惭愧啊!所以文件名字也没有改!)

#include "AT24C256.h"

void AT_24C256_Init(void)
{
	MyI2C_Init();
}

// 我的I2C写单字节函数(16位地址, 要写入的字节)
void AT24C256_WriteByte(uint16_t addr, uint8_t data)
{
	MyI2C_Start();               //I2C开始信号
	MyI2C_SendByte(0xA0);              //I2C发送从机地址
	uint8_t ACK1 = MyI2C_ReceiveACK();  //接收应答位
	MyI2C_SendByte(addr>>8);           //I2C发送地址的高8位
	uint8_t ACK2 = MyI2C_ReceiveACK();  //接收应答位
	MyI2C_SendByte(addr % 256);        //I2C发送地址的低8位
	uint8_t ACK3 = MyI2C_ReceiveACK();  //接收应答位
	
	MyI2C_SendByte(data);               //I2C发送要写入的数据
	MyI2C_ReceiveACK();                //I2C接收应答位
	Delay_ms(20);	                   //延时20毫秒
	
	MyI2C_Stop();                   //I2C停止信号
	Delay_ms(20);                   //延时20毫秒
}


// 我的I2C写函数(16位地址, 要写入数组的首地址)
void AT24C256_WriteReg(uint16_t addr, uint8_t *data)
{
	uint8_t i;
	MyI2C_Start();
	MyI2C_SendByte(0xA0);
	uint8_t ACK1 = MyI2C_ReceiveACK();
	MyI2C_SendByte(addr>>8);
	MyI2C_ReceiveACK();
	MyI2C_SendByte(addr % 256);
	uint8_t ACK3 = MyI2C_ReceiveACK();
	for(i=0; i<17; i++)
	{
		MyI2C_SendByte(*data);
		uint8_t ACK4 = MyI2C_ReceiveACK();
		data++;
	}
	MyI2C_Stop();
	Delay_ms(5);
}

// 我的I2C读函数(16位的地址)
uint8_t AT24C256_ReadByte(uint16_t addr)
{
	MyI2C_Start();
	MyI2C_SendByte(0xA0);
	MyI2C_ReceiveACK();
	MyI2C_SendByte(addr>>8);
	MyI2C_ReceiveACK();
	MyI2C_SendByte(addr % 256);
	MyI2C_ReceiveACK();
	
	MyI2C_Start();
	MyI2C_SendByte(0xA1);
	MyI2C_ReceiveACK();
	
	uint8_t data = MyI2C_ReceiveByte();
		
	MyI2C_SendACK(1);
		
	MyI2C_Stop();
	return data;
}


// 我的I2C读函数(16位的地址, 接收数据的数组首地址,要接收的字节个数)
void AT24C256_ReadReg(uint16_t addr, uint8_t *data, uint16_t len)
{
	uint8_t i;
	MyI2C_Start();
	MyI2C_SendByte(0xA0);
	uint8_t ACK1 = MyI2C_ReceiveACK();
	MyI2C_SendByte(addr>>8);
	uint8_t ACK2 = MyI2C_ReceiveACK();
	MyI2C_SendByte(addr % 256);
	uint8_t ACK3 = MyI2C_ReceiveACK();
	MyI2C_Start();
	MyI2C_SendByte(0xA1);
	uint8_t ACK4 = MyI2C_ReceiveACK();
	for(i=0; i<len; i++)
	{
		*data = MyI2C_ReceiveByte();
		if(i==(len-1))
		{
			MyI2C_SendACK(1);
		}
		else
		{
			MyI2C_SendACK(0);
		}
		data++;
	}
	
	MyI2C_Stop();
	
}


下面是AT24C256.h文件:

#ifndef __AT24C256_H
#define __AT24C256_H

#include "stm32f10x.h"                  // Device header
#include "MyI2C.h"
#include "OLED.h"


void AT_24C256_Init(void);

// 我的I2C写单字节函数(16位地址, 要写入的字节)
void AT24C256_WriteByte(uint16_t addr, uint8_t data);

// 我的I2C写函数(16位地址, 要写入的值)
void AT24C256_WriteReg(uint16_t addr, uint8_t *data);

// 我的I2C读函数(16位的地址)
uint8_t AT24C256_ReadByte(uint16_t addr);

// 我的I2C读函数(16位的地址, 接收数据的数组首地址,要接收的字节个数)
void AT24C256_ReadReg(uint16_t addr, uint8_t *data, uint16_t len);

#endif

最后就是主函数中调用的文件了。

#include "stm32f10x.h"                  // Device header
#include "OLED.h"
#include "Delay.h"
#include "AT24C256.h"
#include "MyI2C.h"
#include "Serial.h"
uint8_t a[255];

uint8_t b[512];

void DX(uint16_t i,uint8_t d)
{
	//AT24C256_WriteByte((uint16_t)i,d);  //向传入的i地址写入数据d
	uint8_t data = AT24C256_ReadByte((uint16_t)i);//读取i地址下的数据赋值给data
	OLED_ShowHexNum(3,1,data,2);    //OLED显示data
	b[i]=data;                     //数组b中添加data
}
	

int main(void)
{
	OLED_Init();
	Serial_Init();
	AT_24C256_Init();
	
	uint16_t i;

	for(i=0;i<255; i++)
	{
		a[i]=0x11;
		//DX(i,i);    //调用DX函数传入地址i和要写入的值i
	}
	
	//AT24C256_WriteReg(0x0000,a);   //  地址0x0000:前15个地址被设置值
	AT24C256_WriteReg(0x1000,a);     //地址0x1000:从第16个地址到第31个地址被设置  共16个字节
	//AT24C256_WriteReg(0x2000,a);      // 地址0x2000:从第32个地址到第47个地址被设置  共16个字节
	//AT24C256_WriteReg(0x3000,a);      // 地址0x3000:继续设置 共16个字节
	//AT24C256_WriteReg(0x4000,a); 
	//AT24C256_WriteReg(0x5000,a);
	//AT24C256_WriteReg(0x6000,a);
	//AT24C256_WriteReg(0x7000,a);
	//AT24C256_WriteReg(0x8000,a);
	//AT24C256_WriteReg(0x9000,a);
	//AT24C256_WriteReg(0xa000,a);
	//AT24C256_WriteReg(0xb000,a);
	//AT24C256_WriteReg(0xc000,a);
	//AT24C256_WriteReg(0xd000,a);
	//AT24C256_WriteReg(0xe000,a);
	//AT24C256_WriteReg(0xf000,a);  // 地址0xf000:继续设置 共16个字节
	
	
	AT24C256_ReadReg(0x0000,b,255); //24C256读数据时可以一次性读多个字节,(参数:从哪个地址开始读,接收数据数组的地址,接收字节的个数)
	AT24C256_ReadReg(0x1000,b+255,255); 
	
	Serial_SendArray(b,512);  //串口发送数组b
}

如果哪个小伙伴看到了,能够在我的基础上又有了新的发现,望能告知,我在此感激不尽啊!

我找了好久也没有找到过AT24C04的页起始地址,英文文档我又看不懂,只能一个一个的试了。结果还是没有搞定。

###########################################################################

今天2024年12月9日,今天又看到了一点有用的信息,特此记录一下,有时间时验证了再改,那就是找到了,页地址的更改方法,之前就是一直写不到第二个256个字节里面去,今天这个信息对于写入第二个256字节是有所帮助的:

那就是页地址根本就不在寄存器地址内修改,而是从器件地址中修改,估计这个是正确的,不过也是需要验证的,我有时间了就来验证一下吧!好了,今天就到此为止,该进入睡眠了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

尚久龙

你的鼓励是我最大的动力!谢谢!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值