STM32 IIC协议 读写EEPROM

EEPROM、MCU6050和OLED显示屏外设都是通过IIC协议【半双工】进行通信。

除此之外,另一个广泛地使用在系统内多个集成电路间的通讯协议:SPI。

目录

一、IIC物理层:

二、IIC协议层

1.IIC的读写过程

  1-主机写数据到从机:

2-主机由从机中读数据:

3-通讯复合格式

2.通讯的起始和停止信号

3.数据有效性

4.地址及数据方向

5.响应

三、程序

 1.IIC协议底层程序

1-配置IIC宏定义

2-初始化IIC用到的GPIO口

3-IIC底层通信的基本程序

 2.配置上层程序(EEPROM为例)

1-EEPROM检测函数

 2-写字节程序:

3-读字节程序:

4-读多个字节程序:

5-写多个字节程序:

四、问题汇总

1.如何读取、存储16个字节的数?

2.为什么传入的数据都是地址

一、IIC物理层:

MCU就是STM32。IIC协议就是一个支持多设备的总线,“总线”指多个设备(传感器)共用的信号线,由主机发起通信。一个IIC总线只使用两条总线线路,一条双向串行数据线(SDA),一条串行时钟线 (SCL)。数据线即用来表示数据,时钟线用于数据收发同步。

每个连接到总线的设备都有一个独立的地址,用7位的二进制数表示,主机可以利用这个地址进行不同设备之间的访问。

总线通过上拉电阻接到电源(在STM32里面是连接到3.3V)。当IIC设备空闲时,会输出高阻态,而当所有设备都空闲,都输出高阻态时,由上拉电阻把总线拉成高电平。(在数字电路里面,3.3V是逻辑1,0V是逻辑0,高阻态相当于断路)。

设备表达逻辑0或1的方法:如果所有的设备都空闲,都在输出高阻态,那么整条总线都可以通过上拉电阻拉到3.3V,也就是逻辑1;如果只要有一个设备没有空闲,那么通过这个设备总线就会连接到GND,这根总线就会拉成0V,变成逻辑0.所以:IIC里面,逻辑0的优先级是高于逻辑1这就是仲裁机制。多个主机同时使用总线时,为了防止数据冲突,会利用仲裁方式决定由哪个设备占用总线。

相同的输出模式在GPIO口的应用:GPIO可以通过开漏输出模式输出高阻态,此I/O口的电压就由外界的上拉电阻拉高决定。如果我们想通过I/O口输出一个5V的电压,就可以将其设置成开漏输出模式,外接5V的上拉电阻,就可以输出5V电压。

二、IIC协议层

IIC的协议定义了通讯的起始和停止信号、数据有效性、响应、仲裁、时钟同步和地址广播等环节。

1.IIC的读写过程

  1-主机写数据到从机:

S:主机发送起始信号

SLAVE_ADDRESS: 从机地址

A/A非:应答(ACK)或非应答(NACK)信号

应答位:返回0,应答成功;返回1,应答失败。

主机发送起始信号之后,开始对地址进行点名,收到从机应答信号之后,开始传输数据。传输数据的过程是一个字节一个字节传输的,主机传完一个字节之后,就要等待从机去应答。如果从机返回了一个非应答信号,就说明从机接收的数据已经够多了,主机就会暂停传输,产生结束信号“P”。

2-主机由从机中读数据:

此过程与前面类似。

3-通讯复合格式

IIC的读和写复合在一起进行

大体过程与前面相同。

注意:我们确定读取/写入数据的从机是EEPROM而不是OLED,是取决于SLAVE_ADDRESS的。EEPROM总共能存储256个字节,那如何确定读取/写入数据是EEPROM的哪个字节?

第一次发送起始信号,确定是EEPROM的地址之后,先写数据,得到应答之后,发送一个数据,这个数据就是EEPROM的字节。然后再次发送开始信号,换成读数据,等待应答并且返回该字节内的数据。

2.通讯的起始和停止信号

当SCL线是高电平时,SDA线从高电平向低电平切换,这个情况表示通讯的起始。当SCL是高电平时SDA线由低电平向高电平切换,表示通讯的停止。

这两个信号都是由主机产生。

3.数据有效性

IIC使用SDA信号线来传输数据,使用SCL信号线进行数据同步。 SDA数据线在SCL的每个时钟周期传输一位数据(8位数据一个字节)。

SCL为高电平的时候SDA表示的数据有效,即此时的SDA为高电平时表示数据“1”,为低电平时表示数据“0”。当SCL为低电平时,SDA的数据无效,一般在这个时候SDA进行电平切换,为下一次表示数据做好准备。

4.地址及数据方向

IIC总线上的每个设备都有自己的独立地址,主机发起通讯时,通过SDA信号线发送设备地址(SLAVE_ADDRESS)来查找从机。设备地址可以是7位或10位。紧跟设备地址的一个数据位R/W用来表示数据传输方向,数据方向位为“1”时表示主机由从机读数据,该位为“0”时表示主机向从机写数据。

例如:EEPROM的地址确定:由A0、A1、A2引脚的值确定,比如A0接地,A1接3.3V.但在MINI板子上这三个引脚都接地(都是0,高4位是1010,是确定值,则地址位固定为1010 000x,x就是读/写模式位)【8位设备读地址:0XA1,写地址:0XA0】

5.响应

I2C的数据和地址传输都带响应。响应包括“应答(ACK)”和“非应答(NACK)”两种信号。每传输一个字节,都要带一个响应位。

传输时主机产生时钟,在第9个时钟时,数据发送端会释放SDA的控制权,由数据接收端控制SDA,若SDA为高电平,表示非应答信号(NACK),低电平表示应答信号(ACK)。【主机和从机都有可能成为发送端或者接收端

三、程序

 1.IIC协议底层程序

1-配置IIC宏定义

IIC协议的初始化GPIO端口函数,和一些产生起始信号、终止信号、应答信号,读取、写入字节等。该协议适用于全部IIC协议的模块,是较底层的函数,只需要修改相应的引脚、端口、时钟即可。

#define IIC_SCL_GPIO_CLK         RCC_APB2Periph_GPIOA//时钟
#define IIC_SCL_GPIO_PORT        GPIOA               //端口
#define IIC_SCL_GPIO_PIN         GPIO_Pin_2//pin 引脚

#define IIC_SDA_GPIO_CLK         RCC_APB2Periph_GPIOA//时钟
#define IIC_SDA_GPIO_PORT        GPIOA               //端口
#define IIC_SDA_GPIO_PIN         GPIO_Pin_3//pin

//控制引脚电平
#define EEPROM_IIC_SDA_1()			 GPIO_SetBits(IIC_SDA_GPIO_PORT,IIC_SDA_GPIO_PIN)//SDA 数据线 输出高电平
#define EEPROM_IIC_SDA_0()			 GPIO_ResetBits(IIC_SDA_GPIO_PORT,IIC_SDA_GPIO_PIN)

#define EEPROM_IIC_SCL_1()			 GPIO_SetBits(IIC_SCL_GPIO_PORT,IIC_SCL_GPIO_PIN)//SCL 时钟线 输出高电平
#define EEPROM_IIC_SCL_0()       GPIO_ResetBits(IIC_SCL_GPIO_PORT,IIC_SCL_GPIO_PIN)

//读取引脚电平
#define EEPROM_IIC_SDA_READ()  GPIO_ReadInputDataBit(IIC_SDA_GPIO_PORT,IIC_SDA_GPIO_PIN)//读取指定的输入端口引脚

2-初始化IIC用到的GPIO口

新建一个IIC通信的文件夹。IIC协议所用到的GPIO端口的初始化。EEPROM用到两个引脚:SDA和SCL其输出模式:开漏输出模式。

void IIC_GPIO_Config(void)//初始化相关的GPIO IIC-EEPROM
{
	GPIO_InitTypeDef GPIO_InitStruct;
	/*第一步:打开外设的时钟(RCC寄存器控制)*/
	RCC_APB2PeriphClockCmd(IIC_SCL_GPIO_CLK|IIC_SDA_GPIO_CLK,ENABLE);
	
	/*第二步:配置外设初始化结构体*/
	GPIO_InitStruct.GPIO_Pin = IIC_SCL_GPIO_PIN;
	GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_OD;//开漏输出
	GPIO_InitStruct.GPIO_Speed = GPIO_Speed_10MHz;
	
	/*第三步:调用外设初始化函数,把配置好的结构体成员写到寄存器里面*/
	GPIO_Init(IIC_SCL_GPIO_PORT,&GPIO_InitStruct);
	
	GPIO_InitStruct.GPIO_Pin = IIC_SDA_GPIO_PIN;
	GPIO_Init(IIC_SDA_GPIO_PORT,&GPIO_InitStruct);
}

3-IIC底层通信的基本程序

配置通讯的起始信号和终止信号,原理图见“通讯的起始和停止信号”。注意的是,要在电平升高/降低之前加一点延时,保持一段时间,因为硬件需要一些反应时间。延时函数使用原装的。

void IIC_Start(void)//产生起始信号
{
	EEPROM_IIC_SDA_1();
	EEPROM_IIC_SCL_1();
	i2c_Delay();//需要在这个状态下加一点延时,保持一段时间
	EEPROM_IIC_SDA_0();
	i2c_Delay();//产生起始信号
	
	EEPROM_IIC_SCL_0();
	i2c_Delay();
}

void IIC_Stop(void)//产生停止信号
{
	EEPROM_IIC_SDA_0();
	EEPROM_IIC_SCL_1();
	i2c_Delay();
	EEPROM_IIC_SDA_1();
	i2c_Delay();//产生停止信号
	
	EEPROM_IIC_SCL_0();
	i2c_Delay();
}

配置产生应答和非应答信号程序(接收端),原理图见“响应”。在应答程序内:配置完之后SDA拉成高电平,释放控制权,供其他设备使用。接着配置等待等待应答信号,无应答返回1;应答返回0。原理图见上图黄色部分。将SDA和SCL的电平都拉高,给个延时之后判断SDA返回的是高低电平,高电平返回无应答;低电平返回应答;最后再把SCL置0.

void IIC_Ask(void)//产生应答信号
{
	EEPROM_IIC_SDA_0();
	EEPROM_IIC_SCL_1();
	i2c_Delay();
	EEPROM_IIC_SCL_0();//SCL产生时钟
	i2c_Delay();//产生应答信号
	
	EEPROM_IIC_SDA_1();//SDA 拉成高电平,释放控制权,供其他设备使用
	i2c_Delay();
}

void IIC_NAsk(void)//产生非应答信号
{
	EEPROM_IIC_SDA_1();
	EEPROM_IIC_SCL_1();
	i2c_Delay();
	EEPROM_IIC_SCL_0();//SCL产生时钟
	i2c_Delay();//产生非应答信号
}

uint8_t IIC_Wait_Ask()//等待应答信号 无应答:1 应答:0
{
	uint8_t reply;
	
	EEPROM_IIC_SDA_1();//释放控制权
	EEPROM_IIC_SCL_1();
	i2c_Delay();
	
	if(EEPROM_IIC_SDA_READ() == 1)
	{
		reply = 1;
	}
	else 
	{
		reply = 0;
	}
	EEPROM_IIC_SCL_0();
	i2c_Delay();
	
	return reply;
}

配置写入一个字节的函数,通过for循环将数据一位一位传输过去,0X80:1000 0000,让要写入的数据一位一位的与0X80相与,直到整个数据都与其相与完毕。写入1的话返回1,写入0的话返回0。传输完之后,释放SDA控制权。

void IIC_Write_byte(uint8_t data)//写入一个字节
{
	uint8_t i;
	
	for(i=0;i<8;i++)
	{
		if(data & 0x80)//0X80:1000 0000 让要写入的数据一位一位的与 0X80 相与
		{              //下面的 data <<= 1;直到整个数据都与其相与完毕。
			EEPROM_IIC_SDA_1();//相与:写入1的话返回1,写入0的话返回0
		}
		else 
		{
			EEPROM_IIC_SDA_0();
		}
		i2c_Delay();
		
		EEPROM_IIC_SCL_1();
		i2c_Delay();
		EEPROM_IIC_SCL_0();//SCL产生时钟
		i2c_Delay();
		
		if(i == 7)
		{
			EEPROM_IIC_SDA_1();//释放控制权
		}
		
		data <<= 1;
	}
}

配置读取一个字节的函数,用temp暂存读取的数据,通过for循环全部读取。

uint8_t  IIC_Read_byte()//读取一个字节
{
	uint8_t i,temp=0;
	for(i=0;i<8;i++)
	{
		temp <<= 1;
		
		EEPROM_IIC_SCL_1();
		i2c_Delay();
		
		if(EEPROM_IIC_SDA_READ() == 1)
		{
			temp += 1;
		}//如果读取的数为1,就加进去;如果是0,就不操作
		
		EEPROM_IIC_SCL_0();//SCL产生时钟
		i2c_Delay();
	}
	
	return temp;
}

官方给的延时程序

static void i2c_Delay(void)//官方给的延时程序
{
	uint8_t i;

	/* 
	 	下面的时间是通过逻辑分析仪测试得到的。
    工作条件:CPU主频72MHz ,MDK编译环境,1级优化
  
		循环次数为10时,SCL频率 = 205KHz 
		循环次数为7时,SCL频率 = 347KHz, SCL高电平时间1.5us,SCL低电平时间2.87us 
	 	循环次数为5时,SCL频率 = 421KHz, SCL高电平时间1.25us,SCL低电平时间2.375us 
	*/
	for (i = 0; i < 10; i++);
}

 2.配置上层程序(EEPROM为例)

建立一个新的文件夹,存放上层的设备程序。

1-EEPROM检测函数

首先是EEPROM的检测函数,检测其是否存在。注意:如果是读模式下,还要我们自己给EEPROM返回一个非应答信号才能停止。

//返回值为1:连接失败;返回值为0:连接正常
uint8_t EEPROM_check_device(uint8_t addr)//检测EEPROM是否存在
{
	uint8_t result;
	
	IIC_Start();//发送起始信号
	IIC_Write_byte(addr);//发送 EEPROM 设备地址
	/*这个与写入一个字节的程序一样,因为 EEPROM 自己知道
	发送完起始信号之后,下一个写入的就是设备地址*/
	
	if(IIC_Wait_Ask())//检测响应信号
	{
		result = 1; 
	}
		//表示EEPROM不存在,无应答
	else
	{
		result = 0;
	}		//表示EEPROM存在
	
	IIC_NAsk();//如果是读模式下,还要我们自己给EEPROM返回一个非应答信号才能停止
	IIC_Stop();
	
	return result;
}

 写完后在主函数内进行判断,把EEPROM的设备地址传输过去,看能否检测得到,检测的结果通过串口返回回来。

 2-写字节程序:

如果检测的没有问题,就往EEPROM里面写入一个字节。先发送起始信号,发送EEPROM(写)的设备地址;检查响应信号,如果EEPROM应答,发送要写入的EEPROM的存储单元格地址(这个是根据具体的设备确定,有的设备不需要发送存储单元格地址,只要发送设备地址就可以写数据,但EEPROM要写);

WORD ADDRESS:往EEPROM里面的哪个存储空间写入字节。

DATA:写入的内容

再次检测响应信号,应答之后向EEPROM写入数据。写完之后再次检测响应信号,如果没有检测到响应信号(包括前面),就让他们停止并且返回0【goto 语句】。

由于EEPROM是有内部时序的,我们有时候需要连续调用写函数向EEPROM存储数据,所以我们要等待EEPROM内部时序完成之后再进行操作,所以我们写一个等待函数,放在起始信号之前和终止信号之后。这样就可以完成连续调用。

//返回值为1:等待超时;返回值为0:正常
uint8_t EEPROM_wait(void)//等待EEPROM内部时序完成
{
	uint16_t cycle = 0;
	
	while(EEPROM_check_device(EEPROM_ADDR | EEPROM_WRITE_DIR))//EEPROM无应答
	{
		cycle++;
		if(cycle>=10000) return 1;//等待超时
	}
	
	return 0;//完成等待
}

//返回值为1:写入正常;返回值为0:写入错误
uint8_t EEPROM_write_byte(uint8_t w_addr,uint8_t data)//往EEPROM里面写入一个字节
{            //w_addr:EEPROM 内存储单元格的地址(0-256),data:写入的数据
	if(EEPROM_wait() == 1) goto xiangying_w_fail;//超时

	IIC_Start();//发送起始信号
	IIC_Write_byte(EEPROM_ADDR | EEPROM_WRITE_DIR);//发送 EEPROM 设备地址
	/*这个与写入一个字节的程序一样,因为 EEPROM 自己知道
	发送完起始信号之后,下一个写入的就是设备地址*/
	
	if(IIC_Wait_Ask())//检测响应信号
		goto xiangying_w_fail;//表示EEPROM不存在,无应答
	else 
	{
		IIC_Write_byte(w_addr);//发送要写入的 EEPROM的存储单元格地址
		if(IIC_Wait_Ask())//检测响应信号
			goto xiangying_w_fail;
		else 
			IIC_Write_byte(data);//向 EEPROM写入数据
		if(IIC_Wait_Ask())//检测响应信号
			goto xiangying_w_fail;
		else {}
	}
	
	IIC_Stop();
	if(EEPROM_wait() == 1) goto xiangying_w_fail;//超时
	
	return 1;
	
xiangying_w_fail:
	IIC_Stop();
	return 0;
}

在写完写字节函数之后,可以在主函数内部加以判断,通过串口返回存储是否正确。

3-读字节程序:

注意的是,第一次发送的设备地址仍然是写模式下的地址;然后检测响应信号,发送要读出的EEPROM的存储单元格地址;再检测响应信号,发送第二次起始信号和第二次设备地址:读方向;再次检测响应信号,读出数据。

等待函数,只放在起始信号之前即可。

//返回值为1:读取正常;返回值为0:读取错误
uint8_t EEPROM_read_byte(uint8_t r_addr,uint8_t *data)//从EEPROM里面读取一个字节
{/*
	 r_addr:读EEPROM 哪个内存储单元格的地址(0-256),*data:读取到的数据存储到指针里面
	 data是数值,*data是地址
   C语言要把一个函数内的数据传输给外面的变量,必须通过指针进行值传递    
	*/
	if(EEPROM_wait() == 1) goto xiangying_r_fail;//超时

	IIC_Start(); //发送第一次起始信号
	IIC_Write_byte(EEPROM_ADDR | EEPROM_WRITE_DIR);//发送第一次设备地址:写方向
	
	if(IIC_Wait_Ask())//检测响应信号
		goto xiangying_r_fail;//表示EEPROM不存在,无应答
	else 
	{
		IIC_Write_byte(r_addr);//发送要读出的 EEPROM的存储单元格地址
		if(IIC_Wait_Ask())//检测响应信号
			goto xiangying_r_fail;
		else 
		{
			IIC_Start(); //发送第二次起始信号
			
			IIC_Write_byte(EEPROM_ADDR | EEPROM_READ_DIR);//发送第二次设备地址:读方向
			if(IIC_Wait_Ask())//检测响应信号
				goto xiangying_r_fail;
			else 
			{
				*data = IIC_Read_byte();				
			}
		}	
	}
	
	IIC_NAsk();
	IIC_Stop();	
	return 1;
	
xiangying_r_fail:
	IIC_NAsk();
	IIC_Stop();
	return 0;
}

4-读多个字节程序:

每读一个字节之后,发送一个应答信号;发送完之后,发送一个非应答信号即可。

//返回值为1:读取正常;返回值为0:读取错误
uint8_t EEPROM_read_bytes(uint8_t r_addr,uint8_t *data,uint16_t size)//从EEPROM里面读取n个字节
{/*
	 r_addr:读EEPROM 哪个内存储单元格的地址(0-256),*data:读取到的数据存储到指针里面
	 size:要读取多少个字节
	 data是数值,*data是地址
   C语言要把一个函数内的数据传输给外面的变量,必须通过指针进行值传递    
	*/
	if(EEPROM_wait() == 1) goto xiangying_r_fail;//超时

	IIC_Start(); //发送第一次起始信号
	IIC_Write_byte(EEPROM_ADDR | EEPROM_WRITE_DIR);//发送第一次设备地址:写方向
	
	if(IIC_Wait_Ask())//检测响应信号
		goto xiangying_r_fail;//表示EEPROM不存在,无应答
	else 
	{
		IIC_Write_byte(r_addr);//发送要读出的 EEPROM的存储单元格地址
		if(IIC_Wait_Ask())//检测响应信号
			goto xiangying_r_fail;
		else 
		{
			IIC_Start(); //发送第二次起始信号
			
			IIC_Write_byte(EEPROM_ADDR | EEPROM_READ_DIR);//发送第二次设备地址:读方向
			if(IIC_Wait_Ask())//检测响应信号
				goto xiangying_r_fail;
			else 
			{
				uint16_t i;
				for(i=0;i<size;i++)
				{
					*data = IIC_Read_byte();		
					if(i == size - 1) IIC_NAsk();//数据接收够了 
					else IIC_Ask();
					data++;//指针指向下一个数据
				}
			}
		}	
	}

	IIC_Stop();	
	return 1;
	
xiangying_r_fail:
	IIC_NAsk();
	IIC_Stop();
	return 0;
}

5-写多个字节程序:

一次性最多写入8个字节,每8个字节为1页,我们可以分页写入

三个形参:w_addr:EEPROM 内存储单元格的地址(0-256);

                 data:写入的数据;         size:要写入多少个字节

用for循环,采用地址对齐的方法,每8个字节(0-7)一页,在每一页的开头发送起始信号。在发送起始信号之前:每写完一页的结束,先发送一次stop信号,结束前面的写入操作,如果是第一次写入也不影响,因为后面有等待EEPROM内部时序完成的程序。

在第一页或者每写完8个字节都要走一遍发送终止、起始信号发送EEPROM设备地址,发送要写入的EEPROM的存储单元格地址。

全部输入完成之后,再发送总的停止信号,等待EEPROM内部时序完成。

//返回值为1:写入正常;返回值为0:写入错误
uint8_t EEPROM_write_bytes(uint8_t w_addr,uint8_t *data,uint16_t size)//往EEPROM里面写入一个字节
{/*w_addr:EEPROM 内存储单元格的地址(0-256),data:写入的数据
 size:要写入多少个字节*/
	uint16_t i;

	for(i=0;i<size;i++)
	{
		if(i == 0 || w_addr%8 == 0)//第一次或者每八次,i是从0-7的
		//采用地址对齐的方法,每8个字节(0-7)一页,在每一页的开头发送起始信号
		{
			/*每写完一页的结束,先发送一次stop信号,结束前面的写入操作
			如果是第一次写入也不影响,因为后面有等待EEPROM内部时序完成的程序*/
		  IIC_Stop();
			if(EEPROM_wait() == 1) goto xiangying_w_fail;//超时
			
			IIC_Start();//发送起始信号
			IIC_Write_byte(EEPROM_ADDR | EEPROM_WRITE_DIR);//发送 EEPROM 设备地址
			/*这个与写入一个字节的程序一样,因为 EEPROM 自己知道
			发送完起始信号之后,下一个写入的就是设备地址*/
			
			if(IIC_Wait_Ask())//检测响应信号
				goto xiangying_w_fail;//表示EEPROM不存在,无应答
			else 
			{
				IIC_Write_byte(w_addr);//发送要写入的 EEPROM的存储单元格地址
				if(IIC_Wait_Ask())//检测响应信号
					goto xiangying_w_fail;
			}
		}//在第一页或者每写完8个字节都要走一遍上面的程序

		IIC_Write_byte(*data);//向 EEPROM写入数据,一个字节一个字节的输入
		if(IIC_Wait_Ask())//检测响应信号
			goto xiangying_w_fail;
		data++;
		w_addr++;
	}

	/*全部输入完成之后*/
	IIC_Stop();
	if(EEPROM_wait() == 1) goto xiangying_w_fail;//超时 作用:等待EEPROM完成内部时序
	return 1;
	
xiangying_w_fail:
	IIC_Stop();
	return 0;
}

注意:写入和读出数据传递的形参都是地址(原因后面介绍)

四、问题汇总

1.如何读取、存储16个字节的数?

把数据的指针写入进去,要占两个存储空间(一个存储空间能存8个字节),所以在传递指针的时候,我们要强制转换为8位的指针。读出数据的时候用数组的方式,将两位分开读。

写入:ABCD,输出结果:

r_temp0 = cd,r_temp1 = ab;

输出顺序与输入顺序相反原因:16进制的数一般左边为高位,右边为低位。STM32是小端模式,是指数据的高字节保存在内存的高地址中,而数据的低字节保存在内存的低地址中。AB是高位,在temp1中。

然后我们再将其合并输出,将其转换为16位指针输出

printf("temp = %x",*(uint16_t *)r_temp);

2.为什么传入的数据都是地址

用指针把要写入的数据进行强制转换,一个字节一个字节地去读取数据的原始值(内部操作),然后通过write函数写进去。

读回来的时候也一样,先把原始值从EEPROM中读出来:

使用指针的方式把原始值强制转换为想要的数据类型

  • 10
    点赞
  • 56
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: STM32 I2CEEPROM跨页是指在使用STM32的I2C总线与EEPROM进行通信时,当需要入的数据跨越了EEPROM的页边界时的处理方式。EEPROM是一种可擦非易失性存储器,通常将数据按页(page)进行存储,每页包含固定数量的字节。 当需要向EEPROM中的一个页入数据时,可以使用I2C总线发送一组连续的入命令。但当需要跨页入数据时,就需要分为多个步骤来完成: 1. 发送入命令:首先,通过I2C总线发送一个入命令,指定要入的EEPROM地址。 2. 入数据至页边界:将将要入的数据按页边界切割,将数据的第一部分EEPROM的当前页。 3. 切换至下一页:如果需要入的数据跨越了页边界,就需要切换到下一页。通过I2C总线发送一个新的入命令,指定下一页的地址。 4. 入剩余数据:将剩余的数据入新的页中。 需要特别注意的是,在跨页入时,需要保持I2C总线的稳定。在切换页的过程中,可能会出现一些延迟。为了确保稳定性,可以在发送入命令之后,等待一段时间,以确保EEPROM已切换到新的页。 总结起来,STM32 I2CEEPROM跨页,需要将要入的数据按页边界切割,并在切换页时保持I2C总线的稳定性。 ### 回答2: STM32是一种微控制器,具有许多输入/输出接口(I/O接口),其中包括IIC(Inter-Integrated Circuit)接口。EEPROM(Electrically Erasable Programmable Read-Only Memory)是一种常用的非易失性存储器。 在STM32中,使用IICEEPROM可以通过跨页的方式实现。跨页是一种技术,允许在一次传输中向EEPROM的多个页中连续入数据。具体步骤如下: 1. 配置STM32的IIC接口模块。首先,需要设置相关寄存器以启用IIC接口,并配置通信速率和其他参数。 2. 初始化EEPROM。在进行IIC之前,需要初始化EEPROM。这可能包括发送一些特定的命令和设置寄存器。 3. 选择入的页。要进行跨页,需要选择要入的起始页。可以使用特定的命令和地址选择页。在接收到页选择命令后,EEPROM将准备好接收数据。 4. 传输数据。将待入的数据传输到IIC接口,并将其发送到EEPROM。在跨页操作中,数据会自动从一个页传输到下一个页。可以通过循环迭代来传输更多数据。 5. 等待入完成。在数据传输完毕后,需要等待EEPROM完成入操作。通常,EEPROM会有一个内部标志位来指示入是否完成。可以通过查询此标志位来等待入操作的完成。 6. 关闭IIC接口。在完成操作后,需要关闭IIC接口,以便其他设备可以使用该接口。 请注意,具体的实现细节可能会因不同的STM32系列和EEPROM型号而有所不同。因此,建议参考相应的STM32和EEPROM芯片的数据手册,以获取更详细的信息和代码示例。 ### 回答3: IIC(Inter-Integrated Circuit)是一种串行通信协议,常被用来连接微控制器与外部设备。在STM32微控制器中,使用IIC总线可以实现对EEPROM(Electrically Erasable Programmable Read-Only Memory)的操作。 对于EEPROM的跨页操作,即在入数据时,需要跨越EEPROM的页边界进行入。通常,EEPROM内部的数据存储以页为单位分割,每一页包含多个字节的数据。当入数据时,如果需要跨越页边界,就需要对两个相邻页的数据进行处理。 在使用STM32的IICEEPROM进行跨页操作时,可以按照以下步骤进行: 1. 初始化IIC总线和相关的引脚设置,确保正确连接STM32和EEPROM。 2. 设置EEPROM地址,确定要入的页和具体的地址。 3. 将待入的数据按照页的边界进行分割,分为需要入的第一个页和第二个页的数据。 4. 先发送入第一个页数据的命令,同时发送第一个页数据的地址和数据。 5. 等待IIC总线的传输完成,并确认入第一个页数据是否成功。 6. 如果入第一个页数据成功,再发送入第二个页数据的命令,同时发送第二个页数据的地址和数据。 7. 等待IIC总线的传输完成,并确认入第二个页数据是否成功。 8. 在每一步操作完成后,需要根据EEPROM的ACK信号来判断是否入成功。 在进行EEPROM的跨页操作时,需要注意以下几点: - 需要保证跨页入的数据长度不超出一个页的容量。 - 入数据时需要正确设置地址,并按照页的边界进行分割。 - 在入数据后,需要通过确认ACK信号来验证入是否成功。 - 需要正确处理IIC总线的通信协议,包括起始位、地址位、数据位和停止位等。 总结来说,使用STM32的IIC总线EEPROM时,可以通过合适的设置和使用跨页操作来实现对EEPROM数据的

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值