STM32模拟iic驱动eeprom24c128
STM32之EEPROM驱动

STM32之EEPROM驱动本⽂介绍如何使⽤STM32标准外设库驱动EEPROM,本例程驱动的EEPROM为AT24C02,通讯协议为IIC,使⽤IO⼝模拟⽅式。
本⽂适合对单⽚机及C语⾔有⼀定基础的开发⼈员阅读,MCU使⽤STM32F103VE系列。
1. EEPROM简介EEPROM全称为EEPROM(Electrically Erasable Programmable Read Only Memory)是电可擦除可编程只读存储器。
虽然名称为只读存储器,但是擦除和写⼊都是直接使⽤电路控制,不需要再使⽤外部设备来擦写,即设备在运⾏过程中即可随时擦除和写⼊。
可以按字节为单位修改数据,⽆需整个芯⽚擦除,且掉电后数据不丢失,⼀般⽤来存储⼀些配置信息,以便系统重新上电的时候加载。
2. 常⽤EEPROM⼀般常⽤的EEPROM为ATMEL公司(已被Microchip收购)的AT24Cxx系列,常⽤容量从1K到64Kbit不等,换算成字节为128到8K Bytes,可以根据项⽬需求和价格综合考虑选型。
3. EEPROM操作说明AT24C02容量为2Kbit,即256Byte,地址范围为0~255,即0~0xFF,使⽤1个字节即可表⽰,因此地址长度为1字节。
3.1. 通讯⽅式IAT24C02使⽤IIC协议跟MCU通讯。
3.2. 设备地址如果仅接⼊⼀个AT24C02,可以将设备的A0、A1、A2引脚全部接⼊低电平,那么此时该设备的地位为0x50,再增加⼀位读写标志位,最终读取操作时地址为0xA1,写⼊操作时地址为0xA0。
3.3. 读取数据读取当前字节:MCU直接发起读操作,设备返回当前字节,当前字节⾃动加1,该操作较少使⽤。
读取指定地址⼀个字节:MCU先向AT24C02写⼊⼀个地址,然后再发起⼀个读操作,AT24C02返回该地址存储的字节。
连续读取:MCU发起读当前字节,或者读指定地址字节,设备返回数据,MCU发送ACK,设备继续返回后续地址数据,直到MCU发送NACK,设备不再返回数据。
基于STM32的IIC_EEPROM案例说明

IIC_EEPROM说明书
一:原理图
IIC_EEPROM电路图
二:工作原理
使用IIC控制器读写IIC_EEPROM中的数据。
开启IIC控制器,IIC_SCL产生正确的时序,通过判断总线的状态,通过IIC_SDA传输数据。
请参考《STM32中文参考资料》的IIC相关内容。
三:实验现象及操作
本实验使用使用串口通信显示数据。
在上位机上打开串口助手,波特率设置为115200,无校验。
串口助手中使用文本接受模式。
按RESET键后,可发现串口助手接受区中显示,“这是一个IIC_EEPROM测试例程”字符串;
在按下一次K3键,程序网IIC_EEPROM中写入0x00,0x01,0x02,0x03等等共20个数据,在串口助手中有显示,然后会自动读取IIC_EEPROM中的数据并发送给PC机;
若再次按下K3键,数据会乘2再写入;
再按下K3键,数据则会乘3再写入;
依次类推。
单片机模拟I2C总线读写EEPROM(24CXX)程序一

单片机模拟I2C总线读写EEPROM(24CXX)程序一下面是一个最简单的读写程序,可以用来检测线路状况。
先附上程序和电路,后面附有说明。
电路:说明:P2 口的LED 都是我用来检测电路执行到哪一步的,个人觉得一目了然。
程序:#include #define unit unsigned int#define uchar unsigned charint ok;sbit scl=P0;sbit sda=P0;sb it led0=P2;sbit led1=P2;sb it led2=P2 ;sbit led3=P2;sb it led4=P2;sb it led5=P2 ;sbit led6=P2;sb it led7=P2;delay(void) //delay{ int i; led1=1; for(i=0;istart(void) //start{ sda=1; scl=1; delay(); sda=0; delay(); scl=0; led0=0;}stop(void) //stop{ sda=0; scl=1; delay(); sda=1; delay(); scl=0;}checkanswer(void) //check answer{ sda=1; scl=1; if(sda==1) { F0=1; led7=0; } scl=0; led3=0;}sendabyte(int temps) //send a byte{ uchar n=8; while(n--) { led2=1; if((temps&0x80)==0x80){ sda=1; scl=1; delay(); scl=0;}else{ sda=0; scl=1; delay(); scl=0;}temps=tempsreciveabyte() //recive a byte{ uchar n=8,tempr; while(n--) {//uchar idata *abyte scl=1;tempr=temprmain(void) //MAIN{start();sendabyte(0xa0);checkanswer();if(F0==1) return;sendabyte(0x00);checkanswer();if(F0==1) return;sendabyte(0x11);checkanswer();if(F0==1) return;/*-----------------------*/start(); sendabyte(0xa0);checkanswer();if(F0==1) return;。
STM32模拟iic驱动eeprom24c128

STM32模拟iic驱动eeprom24c128void IIC_Init(void) //IIC初始化函数{GPIO_InitTypeDef GPIO_InitStructure;RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOE, ENABLE);//使能GPIOB时钟GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2|GPIO_Pin_3;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //推挽输出GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOE, &GPIO_InitStructure);GPIO_SetBits(GPIOE,GPIO_Pin_2|GPIO_Pin_3); //PE2,PE3 输出高}void IIC_Start(void) //IIC开始函数{SDA_OUT(); //sda线输出IIC_SDA=1;IIC_SCL=1;delay_us(5);IIC_SDA=0;//START:when CLK is high,DATA change form high to lowdelay_us(5);IIC_SCL=0; //钳住I2C总线,准备发送或接收数据}void IIC_Stop(void) //IIC停止函数{SDA_OUT();//sda线输出IIC_SCL=0;IIC_SDA=0;//STOP:when CLK is high DATA change form low to highdelay_us(5);IIC_SCL=1;IIC_SDA=1;//发送I2C总线结束信号delay_us(5);}u8 IIC_Wait_Ack(void) //等待应答{u8 ucErrTime=0;SDA_IN(); //SDA设置为输入IIC_SDA=1;delay_us(5);IIC_SCL=1;delay_us(1);while(READ_SDA){ucErrTime++;if(ucErrTime>250){IIC_Stop();return 1;}}IIC_SCL=0;//时钟输出0return 0;}void IIC_Ack(void) //SDA输出低电平,IIC应答{IIC_SCL=0;SDA_OUT();IIC_SDA=0;delay_us(2);IIC_SCL=1;delay_us(4);IIC_SCL=0;}void IIC_NAck(void) //SDA输出高电平,IIC非应答{IIC_SCL=0;SDA_OUT();IIC_SDA=1;delay_us(2);IIC_SCL=1;delay_us(4);IIC_SCL=0;}void IIC_Send_Byte(u8 txd) //IIC发送一个字节{u8 t;SDA_OUT(); //数据线输出模式IIC_SCL=0; //拉低时钟开始数据传输for(t=0;t<8;t++){IIC_SDA=(txd&0x80)>>7;txd<<=1;delay_us(5); //对TEA5767这三个延时都是必须的IIC_SCL=1;delay_us(5);IIC_SCL=0;delay_us(5);}}u8 IIC_Read_Byte(unsigned char ack) //IIC读取一个字节{unsigned char i,receive=0;SDA_IN();//SDA设置为输入for(i=0;i<8;i++ ){IIC_SCL=0;delay_us(5);IIC_SCL=1;receive<<=1;if(READ_SDA){receive++;}delay_us(5);}if (!ack)IIC_NAck();//发送nACKelseIIC_Ack(); //发送ACKreturn receive;}void AT24CXX_Init(void) //AT254C128初始化{IIC_Init();}u8 AT24CXX_ReadOneByte(u16 ReadAddr) //AT24C128读取一个字节{u8 temp=0;IIC_Start();IIC_Send_Byte(0XA0); //发送写命令IIC_Wait_Ack();IIC_Send_Byte(ReadAddr>>8);//发送高地址IIC_Wait_Ack();IIC_Send_Byte(ReadAddr%256); //发送低地址IIC_Wait_Ack();IIC_Start();IIC_Send_Byte(0XA1); //进入接收模式IIC_Wait_Ack();temp=IIC_Read_Byte(0);IIC_Stop(); //产生一个停止条件return temp;}void AT24CXX_WriteOneByte(u16 WriteAddr,u8 DataToWrite) {IIC_Start();IIC_Send_Byte(0XA0); //发送写命令IIC_Wait_Ack();IIC_Send_Byte(WriteAddr>>8);//发送高地址IIC_Wait_Ack();IIC_Send_Byte(WriteAddr%256); //发送低地址IIC_Wait_Ack();IIC_Send_Byte(DataToWrite); //发送字节IIC_Wait_Ack();IIC_Stop();//产生一个停止条件delay_ms(20);}u8 AT24CXX_Check(void){u8 temp;temp=AT24CXX_ReadOneByte(12333);//避免每次开机都写AT24CXXif(temp==0X55){return 0;}else//排除第一次初始化的情况{AT24CXX_WriteOneByte(12333,0X55);temp=AT24CXX_ReadOneByte(12333);if(temp==0X55){return 0;}}return 1;}void AT24CXX_Read(u16 ReadAddr,u8 *pBuffer,u16 NumToRead) {while(NumToRead){*pBuffer++=AT24CXX_ReadOneByte(ReadAddr++);NumToRead--;}}void AT24CXX_Write(u16 WriteAddr,u8 *pBuffer,u16 NumToWrite) {while(NumToWrite--){AT24CXX_WriteOneByte(WriteAddr,*pBuffer);WriteAddr++;pBuffer++;}}BY MaiLaoDie。
STM32 读写 EEPROM 24C02方法

函数功能:写入 24C02 EEPROM 的内部数据 参数:I2Cx,选定 STM32 的 I2C 接口,x 可以是 1 或 2
Address,24C02 的地址 Subaddress,EEPROM 读取的数据地址 s,为存放连续读取的数据缓冲数组 number,为读取连续数据的长度 注意:使用前确保总线已经结束 ------------------------------------------------------------*/ void EEPROM_24C02_Write(I2C_TypeDef* I2Cx, uint8_t Address, uint8_t Subaddress, vu8 *s, vu8 number) { //启动总线 I2C_GenerateSTART(I2Cx, ENABLE);
//Test on EV6 and clear it while(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));
//In the case of a single data transfer disable ACK before reading the data I2C_AcknowledgeConfig(I2Cx, DISABLE);
while((number - 1) > 0) {
number--;
//Read a byte from the EEPROM *s = I2C_ReceiveData(I2Cx);
stm32Flash模拟eeprom心得(精品)

stm32Flash模拟eeprom心得(精品)STM32F10某FLASH模拟EEPROM心得花了几天时间研究tm32用Flah模拟EEPROM的问题,终于彻底弄懂了这种机制,由于我英文很菜,所以官方文档没有仔细看,而是直接去抠官方给出的例子程序,当然这种方法比较笨,但最终效果是一样的。
下面仅将我学习过程中的一些心得体会给大家介绍一下,希望能对需要的人有所帮助,有不足之处望大家积极指正。
首先推荐大家看的文档就是ST的官方文档《AN2594.pdf》和前辈总结出的《STM32FLASH模拟EEPROM使用和优化.pdf》和已经优化过的例程代码《FW_V3.1.0优化(FLASH模拟EEPROM).rar》下面开始进入主题1.为什么要用flah模拟eeprom?在许多应用场合下需要用eeprom保存非易失性的数据,但是意法半导体为了控制成本,没有在STM32F10某系列芯片中集成EEPROM,所以我们就需要用其内部集成的FLASH通过软件模拟EEPROM来达到同样的效果。
2.tm32中的片上FLASH特点根据《STM32F10某闪存编程》中的介绍,以小容量为例(如下图),我们要使用的是32个1K字节/页的主存储空间,也就是说这段空间里除了保存用户代码的部分,其余部分我们是可以利用其作为数据存储使用的。
tm32的FLASH分为主存储块和信息块。
主存储块用于保存具体的程序代码和用户数据,信息块用于负责由tm32出厂是放置2KB的启动程序(Bootloader)并锁死,用户无法更改。
选项字节存储芯片的配置信息及对主存储块的保护信息。
STM32的FLASH主存储块按页组织,有的产品每页1KB,有的产品每页2KB。
页面典型的用途就是用于按页擦除FLASH。
从这点来看,页面有点像通用FLASH的扇区上图中FLASH一页大小为1KB。
范围为从地址0某08000000开始的32KB内。
对Flah的写入操作要“先擦除后写入”的原则;闪存的读写涉及一个概念,字(Word)32bit和半字(HalfWord)16bit,虽然STM32FLASH也是由字节组成,但STM32FLASH的编程每次都是以16bit半字为单位,且FLASH地址必须为偶数,否则会出错。
STM32的I2C-EEPROM已调试成功

STM32的I2C-EEPROM已调试成功万利的I2C-EEPROM例程有些问题,经本人两个昼夜的反复试验,已修改完善。
修改了两个地方,在void I2C_EE_BufferWrite(u8* pBuffer, u8 WriteAddr, u16 NumByteToWrite)写操作函数和void I2C_EE_BufferRead(u8* pBuffer, u8 ReadAddr, u16 NumByteToRead)读操作函数体内的开头先要执行一句I2C_EE_WaitEepromStandbyState();这样在以后调用写操作函数和读操作函数时就不用执行I2C_EE_WaitEepromStandbyState()了。
但上电复位后先要执行一次读操作,以后就可以无限制的随便调用这两个函数了。
详细如下。
/* Includes ------------------------------------------------------------------*/#include "stm32f10x_lib.h"#include "i2c_ee.h"#include"delay.h"/* Private typedef -----------------------------------------------------------*//* Private define ------------------------------------------------------------*/#define I2C_Speed 10000#define I2C1_SLAVE_ADDRESS7 0xA0#define I2C_PageSize 4/* Private macro -------------------------------------------------------------*//* Private variables ---------------------------------------------------------*/u16 EEPROM_ADDRESS;/* Private function prototypes -----------------------------------------------*/void I2C_Configuration(void);/************************************************************** ****************** Function Name : I2C_Configuration* Description : I2C Configuration* Input : None* Output : None* Return : None*************************************************************** ****************/void I2C_Configuration(void){GPIO_InitTypeDef GPIO_InitStructure;I2C_InitTypeDef I2C_InitStructure;/* Configure I2C1 pins: SCL and SDA */GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;//开漏输出GPIO_Init(GPIOB, &GPIO_InitStructure);/* I2C configuration */I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;//设置 I2C为 I2C 模式I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2;//I2C快速模式 Tlow / Thigh = 2I2C_InitStructure.I2C_OwnAddress1 = I2C1_SLAVE_ADDRESS7;//设置第一个设备地址I2C_InitStructure.I2C_Ack = I2C_Ack_Enable;//使能应答I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;//应答 7位地址I2C_InitStructure.I2C_ClockSpeed = I2C_Speed;//设置时钟频率/* I2C Peripheral Enable */I2C_Cmd(I2C1, ENABLE);//使能I2C外设/* Apply I2C configuration after enabling it */I2C_Init(I2C1, &I2C_InitStructure);}/************************************************************** ****************** Function Name : I2C_EE_Init* Description : Initializes peripherals used by the I2C EEPROM driver.* Input : None* Output : None* Return : None*************************************************************** ****************/void I2C_EE_Init(){/* I2C configuration */I2C_Configuration();/* depending on the EEPROM Address selected in thei2c_ee.h file */#ifdef EEPROM_Block0_ADDRESS/* Select the EEPROM Block0 to write on */EEPROM_ADDRESS = EEPROM_Block0_ADDRESS;#endif#ifdef EEPROM_Block1_ADDRESS/* Select the EEPROM Block1 to write on */EEPROM_ADDRESS = EEPROM_Block1_ADDRESS;#endif#ifdef EEPROM_Block2_ADDRESS/* Select the EEPROM Block2 to write on */EEPROM_ADDRESS = EEPROM_Block2_ADDRESS;#endif#ifdef EEPROM_Block3_ADDRESS/* Select the EEPROM Block3 to write on */EEPROM_ADDRESS = EEPROM_Block3_ADDRESS;#endif}/************************************************************** ****************** Function Name : I2C_EE_BufferWrite* Description : Writes buffer of data to the I2C EEPROM.* Input : - pBuffer : pointer to the buffer containing the data to be* written to the EEPROM.* - WriteAddr : EEPROM's internal address to write to.* - NumByteToWrite : number of bytes to write to the EEPROM.* Output : None* Return : NonepBuffer:指向要写入数据数组的指针WriteAddr:24c02中要写入数据的首地址NumByteToWrite:写入的字节数*************************************************************** ****************/void I2C_EE_BufferWrite(u8* pBuffer, u8 WriteAddr, u16 NumByteToWrite)//将缓冲器的数据写入EEPROM{u8 NumOfPage = 0, NumOfSingle = 0, Addr = 0, count = 0;Addr = WriteAddr % I2C_PageSize;//写入地址是每页的第几位count = I2C_PageSize - Addr;//在开始的一页要写入的个数NumOfPage = NumByteT oWrite / I2C_PageSize;//要写入的页数NumOfSingle = NumByteToWrite % I2C_PageSize;//不足一页的个数I2C_EE_WaitEepromStandbyState();//EEPROM设为待命状态/* If WriteAddr is I2C_PageSize aligned */if(Addr == 0) //写入地址是页的开始{/* If NumByteToWrite < I2C_PageSize */if(NumOfPage == 0) //数据小于一页{I2C_EE_PageWrite(pBuffer, WriteAddr, NumOfSingle);//写少于一页的数据I2C_EE_WaitEepromStandbyState();//EEPROM设为待命状态}/* If NumByteToWrite > I2C_PageSize */else //数据大于等于一页{while(NumOfPage--)//要写入的页数{I2C_EE_PageWrite(pBuffer, WriteAddr, I2C_PageSize); //写一页的数据I2C_EE_WaitEepromStandbyState();//EEPROM设为待命状态WriteAddr += I2C_PageSize;pBuffer += I2C_PageSize;}if(NumOfSingle!=0)//剩余数据小于一页{I2C_EE_PageWrite(pBuffer, WriteAddr, NumOfSingle);//写少于一页的数据I2C_EE_WaitEepromStandbyState();//EEPROM设为待命状态}}}/* If WriteAddr is not I2C_PageSize aligned */else //写入地址不是页的开始{/* If NumByteToWrite < I2C_PageSize */if(NumOfPage== 0) //数据小于一页{I2C_EE_PageWrite(pBuffer, WriteAddr, NumOfSingle);//写少于一页的数据I2C_EE_WaitEepromStandbyState();//EEPROM设为待命状态}/* If NumByteToWrite > I2C_PageSize */else//数据大于等于一页{NumByteToWrite -= count;NumOfPage = NumByteT oWrite / I2C_PageSize; //重新计算要写入的页数NumOfSingle = NumByteToWrite % I2C_PageSize;//重新计算不足一页的个数if(count != 0)//在此处count一定不为0,此判断条件好象有点多余{I2C_EE_PageWrite(pBuffer, WriteAddr, count);//将开始的空间写满一页I2C_EE_WaitEepromStandbyState();//EEPROM设为待命状态WriteAddr += count;pBuffer += count;}while(NumOfPage--)//要写入的页数{I2C_EE_PageWrite(pBuffer, WriteAddr, I2C_PageSize);//写一页的数据I2C_EE_WaitEepromStandbyState();//EEPROM设为待命状态WriteAddr += I2C_PageSize;pBuffer += I2C_PageSize;}if(NumOfSingle != 0)//剩余数据小于一页{I2C_EE_PageWrite(pBuffer, WriteAddr, NumOfSingle); //写少于一页的数据I2C_EE_WaitEepromStandbyState();//EEPROM设为待命状态}}}}/************************************************************** ****************** Function Name : I2C_EE_ByteWrite* Description : Writes one byte to the I2C EEPROM.* Input : - pBuffer : pointer to the buffer containing the data to be* written to the EEPROM.* - WriteAddr : EEPROM's internal address to write to.* Output : None* Return : NonepBuffer:指向要写入数据数组的指针WriteAddr:24c02中要写入数据的首地址*************************************************************** ****************/void I2C_EE_ByteWrite(u8* pBuffer, u8 WriteAddr)//写一个字节到EEPROM{/* Send STRAT condition */I2C_GenerateSTART(I2C1, ENABLE);//产生 I2Cx传输 START条件/* Test on EV5 and clear it */while(!I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_MODE_SELECT)); //检查最近一次I2C事件是否是输入的事件/* Send EEPROM address for write */I2C_Send7bitAddress(I2C1, EEPROM_ADDRESS, I2C_Direction_Transmitter);//向指定的从 I2C设备传送地址字,选择发送方向/* Test on EV6 and clear it */while(!I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));//检查最近一次 I2C事件是否是输入的事件/* Send the EEPROM's internal address to write to */I2C_SendData(I2C1, WriteAddr);//通过外设 I2Cx发送地址/* Test on EV8 and clear it */while(!I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_BYTE_TRANSMITTED));//检查最近一次 I2C事件是否是输入的事件/* Send the byte to be written */I2C_SendData(I2C1, *pBuffer); //通过外设 I2Cx发送数据/* Test on EV8 and clear it */while(!I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_BYTE_TRANSMITTED));//检查最近一次 I2C事件是否是输入的事件/* Send STOP condition */I2C_GenerateSTOP(I2C1, ENABLE);//产生 I2Cx传输 STOP条件}/************************************************************** ****************** Function Name : I2C_EE_PageWrite* Description : Writes more than one byte to the EEPROM with a single WRITE* cycle. The number of byte can't exceed the EEPROM page size.* Input : - pBuffer : pointer to the buffer containing the data to be* written to the EEPROM.* - WriteAddr : EEPROM's internal address to write to.* - NumByteToWrite : number of bytes to write to the EEPROM.* Output : None* Return : NonepBuffer:指向要写入数据数组的指针WriteAddr:24c02中要写入数据的首地址NumByteToWrite:写入的字节数*************************************************************** ****************/void I2C_EE_PageWrite(u8* pBuffer, u8 WriteAddr, u8 NumByteToWrite)//写少于一页的数据{/* Send START condition */I2C_GenerateSTART(I2C1, ENABLE);//产生 I2Cx传输 START条件/* Test on EV5 and clear it */while(!I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_MODE_SELECT)); //检查最近一次I2C事件是否是输入的事件/* Send EEPROM address for write */I2C_Send7bitAddress(I2C1, EEPROM_ADDRESS, I2C_Direction_Transmitter);//向指定的从 I2C设备传送地址字,选择发送方向/* Test on EV6 and clear it */while(!I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)); //检查最近一次 I2C事件是否是输入的事件/* Send the EEPROM's internal address to write to */I2C_SendData(I2C1, WriteAddr); //通过外设 I2Cx发送地址/* Test on EV8 and clear it */while(! I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED)); //检查最近一次I2C 事件是否是输入的事件/* While there is data to be written */while(NumByteT oWrite--){/* Send the current byte */I2C_SendData(I2C1, *pBuffer); //通过外设 I2Cx发送数据/* Point to the next byte to be written */pBuffer++;/* Test on EV8 and clear it */while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED));//检查最近一次 I2C事件是否是输入的事件}/* Send STOP condition */I2C_GenerateSTOP(I2C1, ENABLE);//产生 I2Cx传输 STOP条件}/************************************************************** ****************** Function Name : I2C_EE_BufferRead* Description : Reads a block of data from the EEPROM.* Input : - pBuffer : pointer to the buffer that receives the data read* from the EEPROM.* - ReadAddr : EEPROM's internal address to read from.* - NumByteT oRead : number of bytes to read from the EEPROM.* Output : None* Return : NonepBuffer:指向要保存读出数据的数组的指针ReadAddr:24c02中要读出数据的首地址NumByteToRead:读出的字节数*************************************************************** ****************/void I2C_EE_BufferRead(u8* pBuffer, u8 ReadAddr, u16 NumByteToRead)//将EEPROM的数据读入缓冲器{I2C_EE_WaitEepromStandbyState();//EEPROM设为待命状态/* Send START condition */I2C_GenerateSTART(I2C1, ENABLE);//产生 I2Cx传输 START条件/* Test on EV5 and clear it */while(!I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_MODE_SELECT));//检查最近一次 I2C事件是否是输入的事件/* In the case of a single data transfer disable ACK before reading the data */if(NumByteToRead==1){I2C_AcknowledgeConfig(I2C1, DISABLE);//使能或者失能指定I2C的应答功能}/* Send EEPROM address for write */I2C_Send7bitAddress(I2C1, EEPROM_ADDRESS, I2C_Direction_Transmitter);//向指定的从 I2C设备传送地址字,选择发送方向/* Test on EV6 and clear it */while(!I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));//检查最近一次 I2C事件是否是输入的事件/* Clear EV6 by setting again the PE bit */I2C_Cmd(I2C1, ENABLE);//使能或者失能 I2C外设/* Send the EEPROM's internal address to write to */I2C_SendData(I2C1, ReadAddr); //通过外设 I2Cx发送地址/* Test on EV8 and clear it */while(!I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_BYTE_TRANSMITTED));//检查最近一次 I2C事件是否是输入的事件/* Send STRAT condition a second time */I2C_GenerateSTART(I2C1, ENABLE);//产生 I2Cx传输 START条件/* Test on EV5 and clear it */while(!I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_MODE_SELECT));//检查最近一次 I2C事件是否是输入的事件/* Send EEPROM address for read */I2C_Send7bitAddress(I2C1, EEPROM_ADDRESS, I2C_Direction_Receiver);//向指定的从I2C设备传送地址字,选择接收方向/* Test on EV6 and clear it */while(!I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED));//检查最近一次 I2C事件是否是输入的事件/* While there is data to be read */while(NumByteT oRead){/* Test on EV7 and clear it */if(I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_BYTE_RECEIVED)) //检查最近一次I2C事件是否是输入的事件{if(NumByteToRead == 2){/* Disable Acknowledgement */I2C_AcknowledgeConfig(I2C1, DISABLE);//使能或者失能指定I2C的应答功能}if(NumByteToRead == 1){/* Send STOP Condition */I2C_GenerateSTOP(I2C1, ENABLE);//产生 I2Cx传输 STOP条件}/* Read a byte from the EEPROM */*pBuffer = I2C_ReceiveData(I2C1);//返回通过 I2Cx最近接收的数据/* Point to the next location where the byte read will be saved */pBuffer++;/* Decrement the read bytes counter */NumByteToRead--;}}/* Enable Acknowledgement to be ready for another reception */I2C_AcknowledgeConfig(I2C1, ENABLE);//使能或者失能指定I2C的应答功能}/************************************************************** ****************** Function Name : I2C_EE_WaitEepromStandbyState* Description : Wait for EEPROM Standby state* Input : None* Output : None* Return : None*************************************************************** ****************/void I2C_EE_WaitEepromStandbyState(void) //EEPROM设为待命状态{vu16 SR1_Tmp = 0;do{/* Send START condition */I2C_GenerateSTART(I2C1, ENABLE);//产生 I2Cx传输 START条件/* Read I2C1 SR1 register */SR1_Tmp = I2C_ReadRegister(I2C1, I2C_Register_SR1);//读取指定的 I2C寄存器 I2C_SR1 并返回其值/* Send EEPROM address for write */I2C_Send7bitAddress(I2C1, EEPROM_ADDRESS, I2C_Direction_Transmitter);//向指定的从I2C设备传送地址字,选择发送方向}while(!(I2C_ReadRegister(I2C1, I2C_Register_SR1) & 0x0002));//地址发送结束/* Clear AF flag */I2C_ClearFlag(I2C1, I2C_FLAG_AF);//清除 I2Cx的应答错误标志位}。
STM32模拟EEPROM的使用和优化

((uint8_t)0x05)
uint16_t VirtAddVarTab[NumbOfVar] = {0, 1, 2}; //NumbOfVar 定义的比用的多实际是{0, 1, 2, 0, 0},虚拟地址 0 的数据换页后将出现旧数据覆盖最新数据
EE_WriteVariable(VirtAddVarTab[1], VarValue); temp=0; EE_ReadVariable(0, &temp);//不换页读出数据是对的,换页后读出数据错误 }
}
//====================================================================================
int main(void) { uint16_t temp;
for (VarValue = 0; VarValue < 100; VarValue++) {
EE_WriteVariable(VirtAddVarTab[0], VarValue); } for (VarValue = 0; VarValue < 50; VarValue++) {
} }
STM32 FLASH 模拟 EEPROM 使用注意: 不少人问该程序的 FLASH 保存数据多少和使用寿命 保存数据多少跟 FLASH 页大小有关,如果页大小是 1K 那么只能保存 1024/4-1=256-1 个 16 位数据,如果你保 存 8 位数,你可以 2 个 8 位数据组合后保存或者直接保存,如果保存 32 位数据那就拆成 2 个 16 位保存,当然 关于寿命 现在 STM32 的 FLASH 寿命是 10000 次, 如果你保存 255 个数据那么每次修改 1 个数据 FLASH 就要擦写 1 次,如果你保存 1 个数据,那么你修改 255 次该页才擦 1 次,继续用另外 1 页,建议保存数据个数不要超过 50%,当然如果你的数据基本都不修改你保存 255 个也是没有任何问题(你的数据都不修改根本不用关心寿命问题了:)。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
STM32模拟iic驱动eeprom24c128
void IIC_Init(void) //IIC初始化函数
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOE, ENABLE);
//使能GPIOB时钟
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2|GPIO_Pin_3;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOE, &GPIO_InitStructure);
GPIO_SetBits(GPIOE,GPIO_Pin_2|GPIO_Pin_3); //PE2,PE3 输出高
}
void IIC_Start(void) //IIC开始函数
{
SDA_OUT(); //sda线输出
IIC_SDA=1;
IIC_SCL=1;
delay_us(5);
IIC_SDA=0;//START:when CLK is high,DATA change form high to low
delay_us(5);
IIC_SCL=0; //钳住I2C总线,准备发送或接收数据}
void IIC_Stop(void) //IIC停止函数
{
SDA_OUT();//sda线输出
IIC_SCL=0;
IIC_SDA=0;//STOP:when CLK is high DATA change form low to high
delay_us(5);
IIC_SCL=1;
IIC_SDA=1;//发送I2C总线结束信号
delay_us(5);
}
u8 IIC_Wait_Ack(void) //等待应答
{
u8 ucErrTime=0;
SDA_IN(); //SDA设置为输入
IIC_SDA=1;
delay_us(5);
IIC_SCL=1;
delay_us(1);
while(READ_SDA)
{
ucErrTime++;
if(ucErrTime>250)
{
IIC_Stop();
return 1;
}
}
IIC_SCL=0;//时钟输出0
return 0;
}
void IIC_Ack(void) //SDA输出低电平,IIC应答{
IIC_SCL=0;
SDA_OUT();
IIC_SDA=0;
delay_us(2);
IIC_SCL=1;
delay_us(4);
IIC_SCL=0;
}
void IIC_NAck(void) //SDA输出高电平,IIC非应答{
IIC_SCL=0;
SDA_OUT();
IIC_SDA=1;
delay_us(2);
IIC_SCL=1;
delay_us(4);
IIC_SCL=0;
}
void IIC_Send_Byte(u8 txd) //IIC发送一个字节{
u8 t;
SDA_OUT(); //数据线输出模式
IIC_SCL=0; //拉低时钟开始数据传输
for(t=0;t<8;t++)
{
IIC_SDA=(txd&0x80)>>7;
txd<<=1;
delay_us(5); //对TEA5767这三个延时都是必须的
IIC_SCL=1;
delay_us(5);
IIC_SCL=0;
delay_us(5);
}
}
u8 IIC_Read_Byte(unsigned char ack) //IIC读取一个字节{
unsigned char i,receive=0;
SDA_IN();//SDA设置为输入
for(i=0;i<8;i++ )
{
IIC_SCL=0;
delay_us(5);
IIC_SCL=1;
receive<<=1;
if(READ_SDA)
{
receive++;
}
delay_us(5);
}
if (!ack)
IIC_NAck();//发送nACK
else
IIC_Ack(); //发送ACK
return receive;
}
void AT24CXX_Init(void) //AT254C128初始化
{
IIC_Init();
}
u8 AT24CXX_ReadOneByte(u16 ReadAddr) //AT24C128读取一个字节
{
u8 temp=0;
IIC_Start();
IIC_Send_Byte(0XA0); //发送写命令
IIC_Wait_Ack();
IIC_Send_Byte(ReadAddr>>8);//发送高地址
IIC_Wait_Ack();
IIC_Send_Byte(ReadAddr%256); //发送低地址
IIC_Wait_Ack();
IIC_Start();
IIC_Send_Byte(0XA1); //进入接收模式
IIC_Wait_Ack();
temp=IIC_Read_Byte(0);
IIC_Stop(); //产生一个停止条件
return temp;
}
void AT24CXX_WriteOneByte(u16 WriteAddr,u8 DataToWrite) {
IIC_Start();
IIC_Send_Byte(0XA0); //发送写命令
IIC_Wait_Ack();
IIC_Send_Byte(WriteAddr>>8);//发送高地址
IIC_Wait_Ack();
IIC_Send_Byte(WriteAddr%256); //发送低地址
IIC_Wait_Ack();
IIC_Send_Byte(DataToWrite); //发送字节
IIC_Wait_Ack();
IIC_Stop();//产生一个停止条件
delay_ms(20);
}
u8 AT24CXX_Check(void)
{
u8 temp;
temp=AT24CXX_ReadOneByte(12333);//避免每次开机都写AT24CXX
if(temp==0X55)
{
return 0;
}
else//排除第一次初始化的情况
{
AT24CXX_WriteOneByte(12333,0X55);
temp=AT24CXX_ReadOneByte(12333);
if(temp==0X55)
{
return 0;
}
}
return 1;
}
void AT24CXX_Read(u16 ReadAddr,u8 *pBuffer,u16 NumToRead) {
while(NumToRead)
{
*pBuffer++=AT24CXX_ReadOneByte(ReadAddr++);
NumToRead--;
}
}
void AT24CXX_Write(u16 WriteAddr,u8 *pBuffer,u16 NumToWrite) {
while(NumToWrite--)
{
AT24CXX_WriteOneByte(WriteAddr,*pBuffer);
WriteAddr++;
pBuffer++;
}
}
BY MaiLaoDie。