使用STM32的FLASH保存数据

使用STM32的FLASH保存数据

为了防止“掉电丢失数据”,我们最先想到的是EEPROM,但是若考虑到降低成本和PCB布线的空间,使用CPU内部的FLASH空间来保存数据,是最好的选择。尤其是在STM32芯片上,应用案例还是比较多的。

STM32的FLASH是以半字保存数据的,因此,我们可以将“掉电数据”以双字节为最小存储单位去进行访问。

STM32没有自带 的EEPROM,但是它具有 IAP功能,因此,我们可以把它的 FLASH 当成 EEPROM 来使用。

1、STM32_Internal_FLASH.h文件如下:

#ifndef _STM32_Internal_FLASH_H

#define _STM32_Internal_FLASH_H

#include "stm32f10x.h"

#include "sys.h"

#define STM32_FLASH_BASE_ADDRESS   ( (uint32_t)0x08000000 )

//STM32 FLASH的编程起始地址

#define STM32_FLASH_SIZE           512

//所选STM32FLASH容量大小(单位为K)

#if STM32_FLASH_SIZE<256                //CPUFLASH空间小于256K字节

#define STM_SECTOR_SIZE           1024  //每个扇区为1024个字节

#define STMFLASH_WriteLength_SIZE 512   //每个扇区为512个半字

#define STM32_FLASH_START_ADDRESS  ( (uint32_t)0x0800FC00 )

//数据保存到STM32F103C8T6最后一页,即第64,号码为63,页大小为1KB

#else

#define STM_SECTOR_SIZE              2048  //每个扇区为2048个字节

#define STMFLASH_WriteLength_SIZE 1024  //每个扇区为1024个半字

#define STM32_FLASH_START_ADDRESS  ( (uint32_t)0x0807F800 )

//数据保存到STM32F103ZET6最后一页,即第256,号码为255,页大小为2KB

#endif

union EEPROM_Uint16_Data_TYPE

{ unsigned char b[2];   //b[1]Data的高8位值相等;b[0]Data的低8位值相等;

  uint16_t Data;

};

union EEPROM_U32_Data_TYPE

{ u8 b[4]; //b[3]Data的高8位值相等;b[0]Data的低8位值相等;

  u32 Data;

};

union EEPROM_FLOAT_DATA_TYPE

{ u8 b[4];   //b[3]float_data的高8位值相等;b[0]float_data的低8位值相等;

  float float_data;

};

union EEPROM_DOUBLE_DATA_TYPE

{ u8 b[8];   //b[7]和float_data的高8位值相等;b[0]和float_data的低8位值相等;

  double float_data;

};

extern void STMFLASH_Read(u32 tReadAddr,u16 *pBuffer,u16 tSize);

extern void IAP_Write_APP_BIN(uint32_t gIAP_FlashAddress,u8 *pBuffer,u16 len);

extern void EEPROM_U16_Data_Write(u16 x,uint32_t addr);

extern u16 EEPROM_U16_Data_Read(uint32_t addr);

extern void EEPROM_U32_Data_Write(u32 x,uint32_t addr);

extern u32 EEPROM_U32_Data_Read(uint32_t addr);

extern void EEPROM_Float_Data_Write(float x,uint32_t addr);

extern float EEPROM_Float_Data_Read(uint32_t addr);

extern void EEPROM_Double_Data_Write(double x,uint32_t addr);

extern double EEPROM_Double_Data_Read(uint32_t addr);

extern void CPU_FLASH_Read_Write_Test(void);

#endif

2、STM32_Internal_FLASH.c文件如下:

#include "STM32_Internal_FLASH.h"

#include "stdio.h"

void STMFLASH_Read(u32 tReadAddr,u16 *pBuffer,u16 tSize);

void IAP_Write_APP_BIN(uint32_t gIAP_FlashAddress,u8 *pBuffer,u16 len);

void EEPROM_U16_Data_Write(u16 x,uint32_t addr);

u16 EEPROM_U16_Data_Read(uint32_t addr);

void EEPROM_U32_Data_Write(u32 x,uint32_t addr);

u32 EEPROM_U32_Data_Read(uint32_t addr);

void EEPROM_Float_Data_Write(float x,uint32_t addr);

float EEPROM_Float_Data_Read(uint32_t addr);

void EEPROM_Double_Data_Write(double x,uint32_t addr);

double EEPROM_Double_Data_Read(uint32_t addr);

void CPU_FLASH_Read_Write_Test(void);

//函数功能:CPUFLASH地址tReadAddr处读取半字(16位数据)

//tReadAddr:CPUFLASH地址(此地址必须为2的倍数!!)

//返回值:返回半字(16位数据)

u16 STMFLASH_ReadHalfWord(u32 tReadAddr)

{

         return *(vu16*)tReadAddr;

}

//CPUFLASH地址tReadAddr处读取tSize个半字(16位数据),保存到首地址为pBuffer的缓冲区中

//tReadAddr:起始地址

//pBuffer:数据指针

//tSize:半字(16)

void STMFLASH_Read(u32 tReadAddr,u16 *pBuffer,u16 tSize)      

{

         u16 i;

         for(i=0;i<tSize;i++)

         {

                   pBuffer[i]=STMFLASH_ReadHalfWord(tReadAddr);

                   //CPUFLASH地址tReadAddr处读取半字(16位数据)

                   tReadAddr=tReadAddr+2;//偏移2个字节.   

         }

}

//函数功能:STMFLASH_BUF[]中前STMFLASH_WriteLength个半字,FLASH起始地址为STMFLASH_WriteAddress开始处写入,在写之前不检查能否写入

//STMFLASH_WriteAddress:CPUFLASH起始地址

//STMFLASH_BUF:待写数据缓冲区的起始指针

//STMFLASH_WriteLength:需要写入"半字(16)"的个数

//STMFLASH_WriteLength;要写入的双字节数,待写数据在STMFLASH_BUF[]

//STMFLASH_BUF[STMFLASH_WriteLength_SIZE];//最多是2K字节,1K个双字节

void STMFLASH_Write_NoCheck(u32 STMFLASH_WriteAddress,u16 *STMFLASH_BUF,u16 STMFLASH_WriteLength)

{

         u16 k;

         for(k=0;k<STMFLASH_WriteLength;k++)

    //循环写入STMFLASH_WriteLength"半字"

         {

                   FLASH_ProgramHalfWord(STMFLASH_WriteAddress,STMFLASH_BUF[k]);

                   STMFLASH_WriteAddress=STMFLASH_WriteAddress+2;

       //CPUFLASH地址增加2,指向下一个地址

         }

}

const char IAP_FlashAddress1_REG[]="\r\nIAP_FlashAddress1=0x";

const char IAP_FlashAddress2_REG[]="\r\nIAP_FlashAddress2=0x";

//函数功能:pBuffer[]中前tSize个半字,FLASH起始地址为tWriteAddr开始处写入,在写之前检查能否写入

//IAP_FlashAddress:起始地址(此地址必须为2的倍数!!)

//pBuffer:数据指针,数据在IAP_Buffer[]

//tSize:装载烧写数据的数量,单位为半字,IAP_Buffer_Length一样

void STMFLASH_Write(uint32_t gIAP_FlashAddress,u16 *pBuffer,u16 tSize)

{

         u16 t;

         u16 i;

         u16 tmp;

         u8 flag;

         u16 STMFLASH_BUF[STMFLASH_WriteLength_SIZE];

    //最多是2K字节,1K个双字节

         u16 STMFLASH_WriteLength;

    //要写入的双字节数,待写数据在STMFLASH_BUF[]

         u32 STMFLASH_WriteAddress; //写地址

         u16 STMFLASH_BUF_Index;  //用来指示STMFLASH_BUF[]中待写数据的下标

         u16 STMFLASH_BUF_Load_Length;

    //用来指示STMFLASH_BUF[]中待装载的数据长度

         uint32_t gIAP_FlashSectorNumber; //扇区号从0开始

         uint32_t gIAP_FlashOffsetAddress;//其值为(IAP_FlashAddress-0X08000000)

(void)flag;

if( gIAP_FlashAddress<STM32_FLASH_BASE_ADDRESS||(gIAP_FlashAddress>=(STM32_FLASH_BASE_ADDRESS+1024*STM32_FLASH_SIZE)) )

                   return;//非法地址

         FLASH_Unlock();//解锁

         while(1)//循环写FLASH

         {

           gIAP_FlashOffsetAddress=gIAP_FlashAddress-STM32_FLASH_BASE_ADDRESS;

      //计算"待写数据"FLASH中的偏移地址

           gIAP_FlashSectorNumber=gIAP_FlashOffsetAddress/STM_SECTOR_SIZE;

      //计算"待写数据"FLASH中的扇区号码,0开始

           tmp=gIAP_FlashOffsetAddress%STM_SECTOR_SIZE;

      //计算"当前扇区"已经写了多少个字节

           STMFLASH_BUF_Index=tmp/2;//计算"当前扇区"已经写了多少个半字

           STMFLASH_BUF_Load_Length=STMFLASH_WriteLength_SIZE-STMFLASH_BUF_Index;

//计算"待写数据"的数量 

           if(tSize<=STMFLASH_BUF_Load_Length)

      //"待写数据的数量"没有越过当前扇区的范围

           {

                     flag=0;

                     STMFLASH_BUF_Load_Length=tSize;

           }

           else flag=1;

        

                   gIAP_FlashAddress=gIAP_FlashSectorNumber*STM_SECTOR_SIZE;

gIAP_FlashAddress=gIAP_FlashAddress+STM32_FLASH_BASE_ADDRESS;

//计算扇区的首地址

                   STMFLASH_Read(gIAP_FlashAddress,STMFLASH_BUF,STMFLASH_WriteLength_SIZE);//根据扇区首地址,读出整个扇区的内容

                   for(i=0;i<STMFLASH_BUF_Load_Length;i++)//检查"待写的区域"是否需要擦除

                   {

                            t=STMFLASH_BUF_Index+i;//计算"修改数据"的下标值

                            if(STMFLASH_BUF[t]!=0XFFFF)break;//需要擦除       

                   }

                   if(i<STMFLASH_BUF_Load_Length)//"待写的区域"需要擦除

                   {

                            FLASH_ErasePage(gIAP_FlashAddress);//根据扇区首地址,擦除这个扇区

                            for(i=0;i<STMFLASH_BUF_Load_Length;i++)//装载"待编程数据"

                            {

                                     t=STMFLASH_BUF_Index+i;

               //得到在STMFLASH_BUF[]中的下标偏移量

                                     STMFLASH_BUF[t]=pBuffer[i];

               //装载"待写数据"STMFLASH_BUF[]         

                            }

                            STMFLASH_WriteAddress=gIAP_FlashAddress;

            //"扇区首地址"作为"写起始地址"

                            STMFLASH_WriteLength=STMFLASH_BUF_Index+STMFLASH_BUF_Load_Length;

    //计算“写入半字的数量“

                            STMFLASH_Write_NoCheck(STMFLASH_WriteAddress,STMFLASH_BUF,STMFLASH_WriteLength);//写入整个扇区

                            tmp=STMFLASH_WriteLength;tmp=(u16)(tmp<<1);//计算已写字节数量

                            gIAP_FlashAddress=gIAP_FlashAddress+tmp;//记录写结束地址

             printf("%s",IAP_FlashAddress1_REG);

             printf("%x",gIAP_FlashAddress);                        

                   }

                   else//"待写的区域"不需要擦除

                   {

                            for(i=0;i<STMFLASH_BUF_Load_Length;i++)//装载"待编程数据"

                            {

                                     STMFLASH_BUF[i]=pBuffer[i];   

                            }

                            gIAP_FlashAddress=gIAP_FlashAddress+tmp;   //计算写起始地址

                            STMFLASH_WriteAddress=gIAP_FlashAddress;   //记录写地址

                            STMFLASH_WriteLength=STMFLASH_BUF_Load_Length;

            //计算“写入半字的数量“

                     STMFLASH_Write_NoCheck(STMFLASH_WriteAddress,STMFLASH_BUF,STMFLASH_WriteLength);

//写已经擦除了的,直接写入扇区剩余区间

                            tmp=STMFLASH_WriteLength;tmp=(u16)(tmp<<1);//计算已写字节数量

                            gIAP_FlashAddress=gIAP_FlashAddress+tmp;//记录写结束地址

                            printf("%s",IAP_FlashAddress2_REG);

             printf("%x",gIAP_FlashAddress);

                   }

                  

                   if(tSize==STMFLASH_BUF_Load_Length)

                   {

                            break;//写入结束了

                   }

                   else//写入未结束

                   {

                            gIAP_FlashSectorNumber++;//扇区编号增1

                            STMFLASH_BUF_Index=0;//偏移位置为0

                            pBuffer=pBuffer+STMFLASH_BUF_Load_Length;

//已经写了STMFLASH_BUF_Load_Length个半字,修改pBuffer指针,指向需要写的数据

                            tSize=tSize-STMFLASH_BUF_Load_Length;//计算"剩余的待写数据"的个数

                            if( tSize>(STMFLASH_WriteLength_SIZE) )//超过一个扇区

                                     STMFLASH_BUF_Load_Length=STMFLASH_WriteLength_SIZE;

                //下一个扇区还是写不完

                            else//不足一个扇区

                            {

                                     STMFLASH_BUF_Load_Length=tSize;//下一个扇区可以写完了

                            }

                   }      

         }

         FLASH_Lock();//上锁

}

//gIAP_FlashAddress:烧写数据的起始地址

//pBuffer[]:待烧写数据块的首地址

//len:烧写数据的数量(字节)

void IAP_Write_APP_BIN(uint32_t gIAP_FlashAddress,u8 *pBuffer,u16 len)

{

         u16 t;

         u16 i;

         u16 tmp1,tmp2;

         u16 gIAP_Buffer[1024];

         u16 gIAP_Buffer_Length;

if( gIAP_FlashAddress<STM32_FLASH_BASE_ADDRESS||(gIAP_FlashAddress>=(STM32_FLASH_BASE_ADDRESS+1024*STM32_FLASH_SIZE)) )return;//非法地址

         i=0;

         for(t=0;t<len;)//Len>2048则循环写入

         {

                   tmp1=*pBuffer;tmp1=(u16)(tmp1&0x00FF);pBuffer++;

                   tmp2=*pBuffer;tmp2=(u16)(tmp2<<8);tmp2=(u16)(tmp2&0xFF00);pBuffer++;

                   tmp2=(u16)(tmp2|tmp1);//合成半字(16),生成"待写数据"

                   gIAP_Buffer[i]=tmp2;i++;//"待写数据"保存到IAP_Buffer[]

                   if(i==STMFLASH_WriteLength_SIZE)//1K个半字,则执行写入CPUFLASH

                   {

                            i=0;

                            gIAP_Buffer_Length=STMFLASH_WriteLength_SIZE;

           //装载烧写数据的数量,单位为半字

                            STMFLASH_Write(gIAP_FlashAddress,gIAP_Buffer,gIAP_Buffer_Length);

                   }

                   t=t+2;//因为读取的是半字,所以要加2

         }

         if(i)//还有i个半字等待写入FLASH

         {

                   gIAP_Buffer_Length=i;//装载烧写数据的数量,单位为半字

                   STMFLASH_Write(gIAP_FlashAddress,gIAP_Buffer,gIAP_Buffer_Length);

        //将最后的一些内容字节写进去

         }

}

//函数功能:u16型数据x保存到CPUFLASH,保存数据的地址为addr;

void EEPROM_U16_Data_Write(u16 x,uint32_t addr)

{

         union EEPROM_Uint16_Data_TYPE  temp;

         temp.Data=x;

         IAP_Write_APP_BIN(addr,temp.b,2);

}

//函数功能:CPUFLASH中读取u16型数据

u16 EEPROM_U16_Data_Read(uint32_t addr)

{

         u16 rerurn_value;

         STMFLASH_Read(addr,&rerurn_value,1);

         //CPUFLASH地址addr处读取1个半字(16位数据),保存到首地址为"&rerurn_value"的缓冲区中

         //返回数据保存在rerurn_value

         return(rerurn_value);

}

//函数功能:u32型数据x保存到CPUFLASH,保存数据的地址为addr;

void EEPROM_U32_Data_Write(u32 x,uint32_t addr)

{

         union EEPROM_U32_Data_TYPE  temp;

         temp.Data=x;

         IAP_Write_APP_BIN(addr,temp.b,4);

}

//函数功能:CPUFLASH中读取u32型数据

u32 EEPROM_U32_Data_Read(uint32_t addr)

{

         union EEPROM_U32_Data_TYPE  temp;

         u16 rerurn_value;

         temp.Data=0;

         STMFLASH_Read(addr,&rerurn_value,1);

         //CPUFLASH地址addr处读取1个半字(16位数据),保存到首地址为"&rerurn_value"的缓冲区中

         //返回数据保存在rerurn_value

         temp.b[0]=(u8)( rerurn_value&0x00FF );

         temp.b[1]=(u8)( (u16)(rerurn_value>>8)&0x00FF );

         addr=addr+2;//因为数据是以半字保存的,因此地址addr需要加2

         STMFLASH_Read(addr,&rerurn_value,1);

         //CPUFLASH地址addr处读取1个半字(16位数据),保存到首地址为"&rerurn_value"的缓冲区中

         //返回数据保存在rerurn_value

         temp.b[2]=(u8)( rerurn_value&0x00FF );

         temp.b[3]=(u8)( (u16)(rerurn_value>>8)&0x00FF );

         return(temp.Data);

}

//函数功能:float型数据x保存到CPUFLASH,保存数据的地址为addr;

void EEPROM_Float_Data_Write(float x,uint32_t addr)

{

         union EEPROM_FLOAT_DATA_TYPE  temp;

         temp.float_data=x;

         IAP_Write_APP_BIN(addr,temp.b,4);

}

//函数功能:CPUFLASH中读取float型数据

float EEPROM_Float_Data_Read(uint32_t addr)

{

         union EEPROM_FLOAT_DATA_TYPE  temp;

         u16 rerurn_value;

         temp.float_data=0;

         STMFLASH_Read(addr,&rerurn_value,1);

         //CPUFLASH地址addr处读取1个半字(16位数据),保存到首地址为"&rerurn_value"的缓冲区中

         //返回数据保存在rerurn_value

         temp.b[0]=(u8)( rerurn_value&0x00FF );

         temp.b[1]=(u8)( (u16)(rerurn_value>>8)&0x00FF );

         addr=addr+2;//因为数据是以半字保存的,因此地址addr需要加2

         STMFLASH_Read(addr,&rerurn_value,1);

         //CPUFLASH地址addr处读取1个半字(16位数据),保存到首地址为"&rerurn_value"的缓冲区中

         //返回数据保存在rerurn_value

         temp.b[2]=(u8)( rerurn_value&0x00FF );

         temp.b[3]=(u8)( (u16)(rerurn_value>>8)&0x00FF );

         return(temp.float_data);

}

//函数功能:double型数据x保存到CPUFLASH,保存数据的地址为addr;

void EEPROM_Double_Data_Write(double x,uint32_t addr)

{

         union EEPROM_DOUBLE_DATA_TYPE  temp;

         temp.float_data=x;

         IAP_Write_APP_BIN(addr,temp.b,8);

}

//函数功能:CPUFLASH中读取double型数据

double EEPROM_Double_Data_Read(uint32_t addr)

{

         union EEPROM_DOUBLE_DATA_TYPE  temp;

         u16 rerurn_value;

         temp.float_data=0;

         STMFLASH_Read(addr,&rerurn_value,1);

         //CPUFLASH地址addr处读取1个半字(16位数据),保存到首地址为"&rerurn_value"的缓冲区中

         //返回数据保存在rerurn_value

         temp.b[0]=(u8)( rerurn_value&0x00FF );

         temp.b[1]=(u8)( (u16)(rerurn_value>>8)&0x00FF );

         addr=addr+2;//因为数据是以半字保存的,因此地址addr需要加2

         STMFLASH_Read(addr,&rerurn_value,1);

         //CPUFLASH地址addr处读取1个半字(16位数据),保存到首地址为"&rerurn_value"的缓冲区中

         //返回数据保存在rerurn_value

         temp.b[2]=(u8)( rerurn_value&0x00FF );

         temp.b[3]=(u8)( (u16)(rerurn_value>>8)&0x00FF );

         addr=addr+2;//因为数据是以半字保存的,因此地址addr需要加2

         STMFLASH_Read(addr,&rerurn_value,1);

         //CPUFLASH地址addr处读取1个半字(16位数据),保存到首地址为"&rerurn_value"的缓冲区中

         //返回数据保存在rerurn_value

         temp.b[4]=(u8)( rerurn_value&0x00FF );

         temp.b[5]=(u8)( (u16)(rerurn_value>>8)&0x00FF );

         addr=addr+2;//因为数据是以半字保存的,因此地址addr需要加2

         STMFLASH_Read(addr,&rerurn_value,1);

         //CPUFLASH地址addr处读取1个半字(16位数据),保存到首地址为"&rerurn_value"的缓冲区中

         //返回数据保存在rerurn_value

         temp.b[6]=(u8)( rerurn_value&0x00FF );

         temp.b[7]=(u8)( (u16)(rerurn_value>>8)&0x00FF );

         return(temp.float_data);

}

#define STM32_FLASH_U16_DATA_ADDRESS     (STM32_FLASH_START_ADDRESS)          //2个字节,如保存0xABCD

#define STM32_FLASH_U32_DATA_ADDRESS     (STM32_FLASH_U16_DATA_ADDRESS+2)     //4个字节,如保存0x12345678

#define STM32_FLASH_FLOAT_DATA_ADDRESS   (STM32_FLASH_U32_DATA_ADDRESS+4)     //4个字节,如保存123.456

#define STM32_FLASH_DOUBLE_DATA_ADDRESS  (STM32_FLASH_FLOAT_DATA_ADDRESS+4)   //8个字节,如保存1234567.89

#define STM32_FLASH_U16_DATA_ADDRESS1     (STM32_FLASH_DOUBLE_DATA_ADDRESS+8) //2个字节,如保存0xDCBA

#define STM32_FLASH_U32_DATA_ADDRESS1     (STM32_FLASH_U16_DATA_ADDRESS1+2)   //4个字节,如保存0x87654321

#define STM32_FLASH_FLOAT_DATA_ADDRESS1   (STM32_FLASH_U32_DATA_ADDRESS1+4)   //4个字节,如保存456.123

#define STM32_FLASH_DOUBLE_DATA_ADDRESS1  (STM32_FLASH_FLOAT_DATA_ADDRESS1+4) //8个字节,如保存89.1234567

const char Address_REG[]="\r\nAddress: ";

const char Data_REG[]="     Data: ";

/*

Address: 0807F800     Data: ABCD

Address: 0807F812     Data: DCBA

Address: 0807F802     Data: 12345678

Address: 0807F814     Data: 87654321

Address: 0807F806     Data: 123.456001

Address: 0807F818     Data: 456.122986

Address: 0807F80A     Data: 1234567.890000

Address: 0807F81C     Data: 89.123457

Modify Data Test

Address: 0807F800     Data: AAAA

Address: 0807F812     Data: BBBB

Address: 0807F802     Data: CCCCCCCC

Address: 0807F814     Data: DDDDDDDD

Address: 0807F806     Data: 111.222000

Address: 0807F818     Data: 333.444000

Address: 0807F80A     Data: 555.666000

Address: 0807F81C     Data: 777.888000

*/

void CPU_FLASH_Read_Write_Test(void)

{

         u16 u16_Data;

         u32 u32_Data;

         float float_Data;

         double double_Data;

         EEPROM_U16_Data_Write(0xABCD,STM32_FLASH_U16_DATA_ADDRESS);

         EEPROM_U16_Data_Write(0xDCBA,STM32_FLASH_U16_DATA_ADDRESS1);

         EEPROM_U32_Data_Write(0x12345678,STM32_FLASH_U32_DATA_ADDRESS);

         EEPROM_U32_Data_Write(0x87654321,STM32_FLASH_U32_DATA_ADDRESS1);

         EEPROM_Float_Data_Write(123.456,STM32_FLASH_FLOAT_DATA_ADDRESS);

         EEPROM_Float_Data_Write(456.123,STM32_FLASH_FLOAT_DATA_ADDRESS1);

         EEPROM_Double_Data_Write(1234567.89,STM32_FLASH_DOUBLE_DATA_ADDRESS);

         EEPROM_Double_Data_Write(89.1234567,STM32_FLASH_DOUBLE_DATA_ADDRESS1);

         u16_Data=EEPROM_U16_Data_Read(STM32_FLASH_U16_DATA_ADDRESS);

         printf("%s",Address_REG);printf("%08X",STM32_FLASH_U16_DATA_ADDRESS);

         printf("%s",Data_REG);printf("%02X",u16_Data);

         u16_Data=EEPROM_U16_Data_Read(STM32_FLASH_U16_DATA_ADDRESS1);

         printf("%s",Address_REG);printf("%08X",STM32_FLASH_U16_DATA_ADDRESS1);

         printf("%s",Data_REG);printf("%02X",u16_Data);

         u32_Data=EEPROM_U32_Data_Read(STM32_FLASH_U32_DATA_ADDRESS);

         printf("%s",Address_REG);printf("%08X",STM32_FLASH_U32_DATA_ADDRESS);

         printf("%s",Data_REG);printf("%04X",u32_Data);

         u32_Data=EEPROM_U32_Data_Read(STM32_FLASH_U32_DATA_ADDRESS1);

         printf("%s",Address_REG);printf("%08X",STM32_FLASH_U32_DATA_ADDRESS1);

         printf("%s",Data_REG);printf("%04X",u32_Data);

         float_Data=EEPROM_Float_Data_Read(STM32_FLASH_FLOAT_DATA_ADDRESS);

         printf("%s",Address_REG);printf("%08X",STM32_FLASH_FLOAT_DATA_ADDRESS);

         printf("%s",Data_REG);printf("%f",float_Data);

         float_Data=EEPROM_Float_Data_Read(STM32_FLASH_FLOAT_DATA_ADDRESS1);

         printf("%s",Address_REG);printf("%08X",STM32_FLASH_FLOAT_DATA_ADDRESS1);

         printf("%s",Data_REG);printf("%f",float_Data);

         double_Data=EEPROM_Double_Data_Read(STM32_FLASH_DOUBLE_DATA_ADDRESS);

         printf("%s",Address_REG);printf("%08X",STM32_FLASH_DOUBLE_DATA_ADDRESS);

         printf("%s",Data_REG);printf("%lf",double_Data);

         double_Data=EEPROM_Double_Data_Read(STM32_FLASH_DOUBLE_DATA_ADDRESS1);

         printf("%s",Address_REG);printf("%08X",STM32_FLASH_DOUBLE_DATA_ADDRESS1);

         printf("%s",Data_REG);printf("%lf",double_Data);

//修改数据测试

  printf("\r\nModify Data Test");

         EEPROM_U16_Data_Write(0xAAAA,STM32_FLASH_U16_DATA_ADDRESS);

         EEPROM_U16_Data_Write(0xBBBB,STM32_FLASH_U16_DATA_ADDRESS1);

         EEPROM_U32_Data_Write(0xCCCCCCCC,STM32_FLASH_U32_DATA_ADDRESS);

         EEPROM_U32_Data_Write(0xDDDDDDDD,STM32_FLASH_U32_DATA_ADDRESS1);

         EEPROM_Float_Data_Write(111.222,STM32_FLASH_FLOAT_DATA_ADDRESS);

         EEPROM_Float_Data_Write(333.444,STM32_FLASH_FLOAT_DATA_ADDRESS1);

         EEPROM_Double_Data_Write(555.666,STM32_FLASH_DOUBLE_DATA_ADDRESS);

         EEPROM_Double_Data_Write(777.888,STM32_FLASH_DOUBLE_DATA_ADDRESS1);

         u16_Data=EEPROM_U16_Data_Read(STM32_FLASH_U16_DATA_ADDRESS);

         printf("%s",Address_REG);printf("%08X",STM32_FLASH_U16_DATA_ADDRESS);

         printf("%s",Data_REG);printf("%02X",u16_Data);

         u16_Data=EEPROM_U16_Data_Read(STM32_FLASH_U16_DATA_ADDRESS1);

         printf("%s",Address_REG);printf("%08X",STM32_FLASH_U16_DATA_ADDRESS1);

         printf("%s",Data_REG);printf("%02X",u16_Data);

         u32_Data=EEPROM_U32_Data_Read(STM32_FLASH_U32_DATA_ADDRESS);

         printf("%s",Address_REG);printf("%08X",STM32_FLASH_U32_DATA_ADDRESS);

         printf("%s",Data_REG);printf("%04X",u32_Data);

         u32_Data=EEPROM_U32_Data_Read(STM32_FLASH_U32_DATA_ADDRESS1);

         printf("%s",Address_REG);printf("%08X",STM32_FLASH_U32_DATA_ADDRESS1);

         printf("%s",Data_REG);printf("%04X",u32_Data);

         float_Data=EEPROM_Float_Data_Read(STM32_FLASH_FLOAT_DATA_ADDRESS);

         printf("%s",Address_REG);printf("%08X",STM32_FLASH_FLOAT_DATA_ADDRESS);

         printf("%s",Data_REG);printf("%f",float_Data);

         float_Data=EEPROM_Float_Data_Read(STM32_FLASH_FLOAT_DATA_ADDRESS1);

         printf("%s",Address_REG);printf("%08X",STM32_FLASH_FLOAT_DATA_ADDRESS1);

         printf("%s",Data_REG);printf("%f",float_Data);

         double_Data=EEPROM_Double_Data_Read(STM32_FLASH_DOUBLE_DATA_ADDRESS);

         printf("%s",Address_REG);printf("%08X",STM32_FLASH_DOUBLE_DATA_ADDRESS);

         printf("%s",Data_REG);printf("%lf",double_Data);

         double_Data=EEPROM_Double_Data_Read(STM32_FLASH_DOUBLE_DATA_ADDRESS1);

         printf("%s",Address_REG);printf("%08X",STM32_FLASH_DOUBLE_DATA_ADDRESS1);

         printf("%s",Data_REG);printf("%lf",double_Data);

}

#include "string.h"

//CPU的最后一个扇区

void Write_CPU_Last_SECTOR (void)

{

         u8 buf[STM_SECTOR_SIZE];

         memset(buf,0,STM_SECTOR_SIZE);

         buf[0]=0x11;

         buf[1]=0x22;

         buf[2]=0x33;

         buf[3]=0x44;

         buf[4]=0x55;

         buf[5]=0x66;

         buf[6]=0x77;

         buf[7]=0x88;

         buf[STM_SECTOR_SIZE-9]=0x99;

         buf[STM_SECTOR_SIZE-8]=0x88;

         buf[STM_SECTOR_SIZE-7]=0x77;

         buf[STM_SECTOR_SIZE-6]=0x66;

         buf[STM_SECTOR_SIZE-5]=0x55;

         buf[STM_SECTOR_SIZE-4]=0x44;

         buf[STM_SECTOR_SIZE-3]=0x33;

         buf[STM_SECTOR_SIZE-2]=0x22;

         buf[STM_SECTOR_SIZE-1]=0x11;

         IAP_Write_APP_BIN(STM32_FLASH_START_ADDRESS,buf,STM_SECTOR_SIZE);

}

3、测试结果:

编译配置:

使用J-Flash烧写程序,启动CPU,然后再读回程序,发现以前保存的数据仍旧存在,便于反复烧写,方便生产。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/320868.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

使用Beego创建API项目并自动化文档

最近需要使用Go写一个Web API项目&#xff0c;可以使用Beego与Gin来写此类项目&#xff0c;还是非常方便的&#xff0c;这里就介绍一下使用Beego来创建的Web API项目并自动化文档的方法。 使用Gin创建API项目并自动化文档参见&#xff1a;使用Gin编写Web API项目并自动化文档 …

软件FMEA的时机:架构设计、详设阶段——FMEA软件

免费试用FMEA软件-免费版-SunFMEA 软件FMEA&#xff08;故障模式与影响分析&#xff09;是一种预防性的质量工具&#xff0c;旨在识别软件中可能存在的故障模式&#xff0c;并分析其对系统性能、安全性和可靠性的影响。在软件开发生命周期中&#xff0c;选择适当的时机进行FME…

十七岁少女夸小沈阳:我瞅你长得有一种大海的感觉呢!

十七岁少女夸小沈阳&#xff1a;我瞅你长得有一种大海的感觉呢&#xff01; ——小品《超级大明星》&#xff08;上&#xff09;的台词 小沈阳&#xff1a;THANK YOU 哦了 不用拍 感谢大家 非常的感谢所有的好朋友们 把你们热情而洋溢的掌声呢 送给我们所有的演员 这…

[VulnHub靶机渗透] Hackademic: RTB1

&#x1f36c; 博主介绍&#x1f468;‍&#x1f393; 博主介绍&#xff1a;大家好&#xff0c;我是 hacker-routing &#xff0c;很高兴认识大家~ ✨主攻领域&#xff1a;【渗透领域】【应急响应】 【Java、PHP】 【VulnHub靶场复现】【面试分析】 &#x1f389;点赞➕评论➕收…

linux内核网络源码--通知链

内核的很多子系统之间有很强的依赖性&#xff0c;其中一个子系统侦测到或者产生的事件&#xff0c;其他子系统可能都有兴趣&#xff0c;为了实现这种交互需求&#xff0c;linux使用了所谓的通知链。 本章我们将看到 通知链如何声明以及网络代码定义了哪些链 内核子系统如何向通…

【yolov8】yolov8剪枝训练流程

yolov8剪枝训练流程 流程&#xff1a; 约束剪枝微调 一、正常训练 yolo train model./weights/yolov8s.pt datayolo_bvn.yaml epochs100 ampFalse projectprun nametrain二、约束训练 2.1 修改YOLOv8代码&#xff1a; ultralytics/yolo/engine/trainer.py 添加内容&#…

深度学习之基于Vgg19预训练卷积神经网络图像风格迁移系统

欢迎大家点赞、收藏、关注、评论啦 &#xff0c;由于篇幅有限&#xff0c;只展示了部分核心代码。 文章目录 一项目简介 二、功能三、系统四. 总结 一项目简介 一、项目背景 在数字艺术和图像处理领域&#xff0c;图像风格迁移技术一直备受关注。该技术可以将一幅图像的内容和…

MATLAB实现杜拉德公式和凯夫公式的计算固液混合料浆临界流速

MATLAB实现杜拉德公式和凯夫公式的计算固液混合料浆临界流速: 杜拉德公式是用来计算非均质固液混合料浆在输送管中的临界速度的公式&#xff0c;具体形式为&#xff1a; uL FL (2gD / (ρ0 - ρ1))^(1/2) 其中&#xff1a; uL&#xff1a;表示料浆的临界速度&#xff0c;…

什么是泛域名证书?与普通SSL证书有什么区别

随着互联网的发展&#xff0c;越来越多的网站开始使用SSL证书来保护用户的隐私和安全。在SSL证书中&#xff0c;泛域名SSL证书和普通域名证书是两种常见的类型。那么&#xff0c;什么是泛域名SSL证书&#xff0c;与普通域名证书有什么区别呢&#xff1f; 首先&#xff0c;我们来…

投资者悄然收购二手楼梯楼,在杭州豪掷巨资购买12套!

独家首发 -------------- 日前杭州中介流传&#xff0c;一名投资客大举收购二手楼梯楼&#xff0c;下手就是12套&#xff0c;显示出一些具有前瞻性眼光的投资者悄悄放弃电梯楼&#xff0c;选择了处于价格洼地的楼梯楼。 二手楼梯楼当下被严重低估&#xff0c;在一线城市的二手楼…

【文献阅读】 The ITS Irregular Terrain Model(Longely-Rice模型)海上电波传播模型

前言 因为最近在做海上通信的一个项目&#xff0c;所以需要对海上的信道进行建模&#xff0c;所以才阅读到了这一篇文献&#xff0c;下面的内容大部分是我的个人理解&#xff0c;如有错误&#xff0c;请见谅。欢迎在评论区和我一起讨论。 Longely-Rice模型介绍 频率介于 20 …

AI摄影教程,让你实现写真自由!

AI摄影&#xff0c;就是用AI生成写真照片 和传统摄影不同的是&#xff0c;传统的摄影需要先妆造、布景&#xff0c;然后再进行拍摄&#xff0c;前后需要耗费的时间精力非常多 而AI摄影只需要在电脑上上传十几张自己的日常照片&#xff0c;就能根据自己的喜好去生成各种梦幻、甚…

软件测试经理工作日常随记【2】-接口自动化

软件测试主管工作日常随记【2】-接口自动化 1.接口自动化 jmeter-反电诈项目 这个我做过的一个非常有意义的项目&#xff0c;和腾讯合作的&#xff0c;主要为用户拦截并提示所有可能涉及到的诈骗类型&#xff0c;并以裂变的形式扩展用户&#xff0c;这个项目前期后端先完成&…

设计宝典与速查手册,设计师必备资料合集

一、资料描述 本套设计资料&#xff0c;大小194.34M&#xff0c;共有13个文件。 二、资料目录 01-《商业设计宝典》.pdf 02-《色彩速查宝典》.pdf 03-《配色宝典》.pdf 04-《解读色彩情感密码》.pdf 05-《行业色彩应用宝典》.pdf 06-《构图宝典》.pdf 07-《创意宝典》…

上位机图像处理和嵌入式模块部署(树莓派4b下ros安装方法)

【 声明&#xff1a;版权所有&#xff0c;欢迎转载&#xff0c;请勿用于商业用途。 联系信箱&#xff1a;feixiaoxing 163.com】 随着嵌入式开发板算力越来越强&#xff0c;很多的同学开始用树莓派做一些ros开发的工作。目前来说&#xff0c;ros有两个版本&#xff0c;分别是ro…

【RPC】Dubbo接口测试

关于rpc&#xff0c;推荐看看这篇 &#xff1a; 既然有HTTP协议&#xff0c;为什么还要有RPC 一、Dubbo 是一款alibaba开源的高性能服务框架&#xff1a; 分布式服务框架高性能和透明化的RPC远程服务调用方案SOA服务治理方案 二、Dubbo基础架构 三、 Dubbo接口测试 1、jme…

MambaMOS:基于激光雷达的三维运动物体分割与运动感知状态空间模型

MambaMOS:基于激光雷达的三维运动物体分割与运动感知状态空间模型 摘要INTRODUCTIONRelated WorkMethod MambaMOS: LiDAR-based 3D Moving Object Segmentation with Motion-aware State Space Model 摘要 激光雷达基于的运动目标分割&#xff08;MOS&#xff09;旨在利用之前…

一站式PDF解决方案:如何部署自己的PDF全能工具(Docker部署和群晖部署教程)

文章目录 📖 介绍 📖🏡 演示环境 🏡📒 开始部署 📒📝 Docker部署📝 群晖部署📝 本地安装⚓️ 相关链接 ⚓️📖 介绍 📖 在数字化办公的今天,PDF文件几乎成了我们日常工作中不可或缺的一部分。但你是否曾因为PDF文件的编辑、转换、合并等问题而头疼?如果…

Python类方法探秘:从单例模式到版本控制

引言&#xff1a; 在Python编程中&#xff0c;类方法作为一种特殊的实例方法&#xff0c;以其独特的魅力在众多编程范式中脱颖而出。它们不仅提供了无需实例即可调用的便捷性&#xff0c;还在设计模式、版本控制等方面发挥着重要作用。本文将通过几个生动的示例&#xff0c;带您…

STM32——GPIO篇

技术笔记&#xff01; 1. 什么是GPIO&#xff1f; GPIO是通用输入输出端口&#xff08;General-purpose input/output&#xff09;的英文简写&#xff0c;是所有的微控制器必不可少的外设之一&#xff0c;可以由STM32直接驱动从而实现与外部设备通信、控制以及采集和捕获的功…