搜索
bottom↓
回复: 17

复习老掉牙的知识-STM32F407实现FLASH模拟EEPROM

[复制链接]

出0入0汤圆

发表于 2019-1-10 16:50:25 | 显示全部楼层 |阅读模式
程序使用办法和注意事项在代码下面介绍
主要代码如下:
#if !defined  (_FLASH_H)
#define _FLASH_H
#define FLASH_ADR 0x08010000
#define u8 unsigned char
#define u16 unsigned int
#define u32 unsigned long int
union union_temp16
{
  unsigned int un_temp16;
  unsigned char un_temp8[2];
}my_unTemp16;
typedef struct
{
         u8 apn[20];
         u8 useName[20];
         u8 password[20];
         u8 serverIP[16];
         u8 port[6];
         u8 useCall[3][15];
}configStruct;
void FlashWriteStr( u32 flash_add, u16 len, u16* data )
{         u16 byteN = 0;
         FLASH_Unlock();
         //FLASH_ErasePage(flash_add);
         while( len )
         {
                        my_unTemp16.un_temp8[0] = *(data+byteN);
                        my_unTemp16.un_temp8[1] = *(data+byteN+1);
                        FLASH_ProgramHalfWord( flash_add+byteN , my_unTemp16.un_temp16 );

                        if( 1==len ){
                        break;
                        }
                        else{
                                byteN += 2;
                                len -= 2;
                        }
                }
                FLASH_Lock();}
void FlashReadStr( u32 flash_add, u16 len, u16* data )
{
        u16 byteN = 0;
        while( len )
        {
                my_unTemp16.un_temp16 = *(vu16*)(flash_add+byteN);
                if( 1==len )
                {
                        *(data+byteN) = my_unTemp16.un_temp8[0];
                        break;
                }
                else
                {
                        *(data+byteN) = my_unTemp16.un_temp8[0];
                        *(data+byteN+1) = my_unTemp16.un_temp8[1];
                        byteN += 2;
                        len -= 2;
                }
        }
}
#endif
使用办法:使用该程序无需调用多余库函数,写入时调用FlashWriteStr(FLASH_ADR,2,&data[0]);读函数时使用FlashReadStr(FLASH_ADR,2,&data[0]);
读写数据均需要使用数组。
注意事项:
1、在写函数时关掉了擦除扇区功能,FLASH_ErasePage(flash_add);函数可以在一个区块内完成数据在不同地址的独立读写功能
2、读写函数必须使用两字节以上定义方式例如int,long等,因为FLASH存储一次写入16Bit.
3、使用时着重注意看门狗,如果喂狗时间太长建议关闭看门狗功能,或者做好互斥
据资料说使用FLASH模拟EEPROM的寿命比EEPROM少一个数量级,不知哪位对此有相对客观的见解!

阿莫论坛20周年了!感谢大家的支持与爱护!!

月入3000的是反美的。收入3万是亲美的。收入30万是移民美国的。收入300万是取得绿卡后回国,教唆那些3000来反美的!

出0入4汤圆

发表于 2019-1-10 17:14:45 | 显示全部楼层
据资料说使用FLASH模拟EEPROM的寿命比EEPROM少一个数量级,不知哪位对此有相对客观的见解!
好像只有10000次,他这个应用肯定是一些不经常改变的数据,例如校准数据。
要是一天变三次的数据估计会把flash写坏。

出0入362汤圆

发表于 2019-1-10 17:54:31 | 显示全部楼层
用st官方的不就行了, 写N次才擦除一次
我用的:
flash_eeprom.h
  1. /// @file flash_eeprom.h
  2. #ifndef _FLASH_EEPROM_H
  3. #define _FLASH_EEPROM_H

  4. void FLASH_EEPROM_Config(void);
  5. void FLASH_EEPROM_ReadAll(void);
  6. void FLASH_EEPROM_WriteWord(unsigned short addr, unsigned short data);
  7. unsigned short FLASH_EEPROM_ReadWord(unsigned short addr);
  8. void FLASH_EEPROM_WriteData(unsigned short addr, void* data, int num);
  9. void FLASH_EEPROM_ReadData(unsigned short addr, void* data, int num);

  10. #endif
复制代码


flash_eeprom.c
  1. #include "flash_eeprom.h"
  2. #include "usart.h" // for debug

  3. // 在bootloader里只能读到bootloader区的结尾, 因此这时END_OF_CODE的值并不正确.
  4. // 不过bootloader区不会很长, 因此只要在APP区读到END_OF_CODE不冲突就可以了.
  5. #define END_OF_CODE ((unsigned long)&_etext + ((unsigned long)&_edata - (unsigned long)&_sdata))

  6. #define PAGE_SIZE 2048    // for HD devices
  7. //#define PAGE_SIZE 1024     // for LD & MD devices

  8. //#define FLASH_SIZE ((*(unsigned long*)0x1ffff7cc) & 0xffff)   // for stm32f0xx
  9. #define FLASH_SIZE ((*(unsigned long*)0x1ffff7e0) & 0xffff)   // for stm32f10x

  10. //#define PAGE_MAIN (0x08000000 + (FLASH_SIZE - 3) * 1024)         // for LD & MD devices
  11. //#define PAGE_BACKUP (0x08000000 + (FLASH_SIZE - 2) * 1024)

  12. #define PAGE_MAIN (0x08000000 + (FLASH_SIZE - 6) * 1024)        // for HD devices
  13. #define PAGE_BACKUP (0x08000000 + (FLASH_SIZE - 4) * 1024)      // for HD devices

  14. #define MAIN_ADDR(x) (PAGE_MAIN + (x))
  15. #define BACKUP_ADDR(x) (PAGE_BACKUP + (x))
  16. #define LOAD_ADDR(x) (*(unsigned short*)MAIN_ADDR(x))
  17. #define LOAD_DATA(x) (*(unsigned short*)MAIN_ADDR((x) + 2))
  18. #define LOAD_BACKUP_ADDR(x) (*(unsigned short*)BACKUP_ADDR(x))
  19. #define LOAD_BACKUP_DATA(x) (*(unsigned short*)BACKUP_ADDR((x) + 2))

  20. #define MAX_DUMMY_ADDR (PAGE_SIZE / 8 * 3 - 1)      // LD & MD devices: 191

  21. extern int _etext, _sdata, _edata;

  22. /// @brief 取得第一个空地址
  23. /// @param None
  24. /// @retval 返回第一个空地址, 若不存在则返回-1
  25. static int GetFirstEmptyAddr(void)
  26. {
  27.     unsigned short i;
  28.     for(i = 0; i < PAGE_SIZE; i += 4) {
  29.         if(*(unsigned long*)MAIN_ADDR(i) == 0xffffffff)
  30.             return i;
  31.     }
  32.     return -1;  // Full
  33. }

  34. /// @brief 从后备页读取数据
  35. /// @param dummy_addr 伪地址
  36. /// @retval 读到的数据, 若未读到则返回-1 (此处应有更好的处理方式)
  37. static int ReadWordFromBackup(unsigned short dummy_addr) {
  38.     int addr = 1020;
  39.     while(addr >= 0) {
  40.         if(LOAD_BACKUP_ADDR(addr) == dummy_addr)
  41.             return LOAD_BACKUP_DATA(addr);
  42.         addr -= 4;
  43.     }
  44.     return -1;      // Not found
  45. }

  46. /// @brief 主存储页满, 利用后备页进行轮转
  47. /// @param None
  48. /// @retval None
  49. static void Rotate(void)
  50. {
  51.     FLASH_Unlock();
  52.     // 1. Erase Backup Page
  53.     FLASH_ErasePage(PAGE_BACKUP);
  54.     // 2. Copy Main Page to Backup Page. Add checksum later!
  55.     for(int i = 0; i < 1024; i += 4) {
  56.         FLASH_ProgramWord(BACKUP_ADDR(i), *(unsigned long*)MAIN_ADDR(i));   // full copy
  57.     }
  58.     // 3. Erase Main Page
  59.     FLASH_ErasePage(PAGE_MAIN);
  60.     // 4. Copy Backup Page to Main Page. Add Checksum Later!
  61.     for(int i = 0; i <= MAX_DUMMY_ADDR; i++) {
  62.         int data = ReadWordFromBackup(i);
  63.         if(data != -1)
  64.             FLASH_EEPROM_WriteWord(i, data);
  65.     }
  66.     FLASH_Lock();
  67. }

  68. /// @brief 写入16位字
  69. /// @param dummy_addr 伪地址
  70. /// @param data 16位数据
  71. /// @retval None
  72. void FLASH_EEPROM_WriteWord(unsigned short dummy_addr, unsigned short data)
  73. {
  74.     if(dummy_addr > MAX_DUMMY_ADDR) {
  75.         uprintf(USART_USB, "Address out of range!\n");
  76.         return;
  77.     }
  78.     int addr = GetFirstEmptyAddr();
  79.     if(addr == -1) {            // Page full, rotate needed
  80.         Rotate();
  81.         addr = GetFirstEmptyAddr();
  82.     }
  83.     unsigned org_data = FLASH_EEPROM_ReadWord(dummy_addr);
  84.     if(org_data == data)        // skip writing if data unchanged
  85.         return;

  86.     FLASH_Unlock();
  87.     FLASH_ProgramHalfWord(MAIN_ADDR(addr), dummy_addr);
  88.     FLASH_ProgramHalfWord(MAIN_ADDR(addr) + 2, data);
  89.     FLASH_Lock();
  90. }

  91. /// @brief 读取16位数据
  92. /// @param dummy_addr 伪地址
  93. /// @retval 读到的数据, 若未读到则返回0xffff
  94. unsigned short FLASH_EEPROM_ReadWord(unsigned short dummy_addr)
  95. {
  96.     int addr = GetFirstEmptyAddr();
  97. //    _dbg(); uprintf(USART_USB, "%d\n", addr);

  98.     if(addr == 0 || addr == -1)
  99.         return 0xffff;          // No data
  100.     while(addr >= 0) {
  101.         if(LOAD_ADDR(addr) == dummy_addr)
  102.             return LOAD_DATA(addr);
  103.         addr -= 4;
  104.     }
  105.     return 0xffff;              // Dummy_addr not found
  106. }

  107. /// @brief 读取全部数据, 仅用于测试
  108. /// @param None
  109. /// @retval None
  110. void FLASH_EEPROM_ReadAll(void)
  111. {
  112.     // todo
  113.     for(int i = 0; i < 1024; i += 4) {
  114.         uprintf(USART_USB, "%04d: %04x %04x  ", i,
  115.                 *(unsigned short*)MAIN_ADDR(i),
  116.                 *(unsigned short*)MAIN_ADDR(i + 2) );
  117.         if(i % 24 == 20)
  118.             uprintf(USART_USB, "\n");
  119.     }
  120. }

  121. /// @brief 写入数据
  122. /// @param addr 伪地址
  123. /// @param data 指向待写入数据缓冲区的指针
  124. /// @param num 需要写入的数据字节数
  125. /// @retval None
  126. void FLASH_EEPROM_WriteData(unsigned short addr, void* data, int num)
  127. {
  128. //    uprintf(USART_USB, "%04x %08x %d\n", addr, (unsigned long)data, num);
  129.     if(num % 2 != 0)
  130.         num++;
  131.     while (num > 0) {
  132. //        _dbg();
  133.         FLASH_EEPROM_WriteWord(addr, *(unsigned short*)data);
  134.         addr++;
  135.         data += 2;
  136.         num -= 2;
  137.     }
  138. }

  139. /// @brief 读取数据
  140. /// @param addr 伪地址
  141. /// @param data 指向待读取数据缓冲区的指针
  142. /// @param num 需要读取的数据字节数
  143. /// @retval None
  144. void FLASH_EEPROM_ReadData(unsigned short addr, void* data, int num)
  145. {
  146.     if(num % 2 != 0)
  147.         num++;
  148.     while(num > 0) {
  149.         *(unsigned short*)data = FLASH_EEPROM_ReadWord(addr);
  150.         addr++;
  151.         data += 2;
  152.         num -= 2;
  153.     }
  154. }

  155. /// @brief 初始化, 检查主存储页与代码页是否冲突
  156. /// @param None
  157. /// @retval None
  158. void FLASH_EEPROM_Config(void)
  159. {
  160.     uprintf(USART_USB, "%lu %08x\n", FLASH_SIZE, END_OF_CODE);
  161.     // Todo: flash config (Get base addr, ...)
  162.     if(END_OF_CODE >= PAGE_MAIN) {
  163.         uprintf(USART_USB, "Program code exceeds!\n");
  164.         while(1);
  165.     }
  166. }
复制代码

出0入0汤圆

发表于 2019-1-10 20:54:22 | 显示全部楼层
tomzbj 发表于 2019-1-10 17:54
用st官方的不就行了, 写N次才擦除一次
我用的:
flash_eeprom.h

不听看明白这段话

“// 在bootloader里只能读到bootloader区的结尾, 因此这时END_OF_CODE的值并不正确.
// 不过bootloader区不会很长, 因此只要在APP区读到END_OF_CODE不冲突就可以了.”

愿听你的详解。。。

出200入2554汤圆

发表于 2019-1-10 21:24:37 | 显示全部楼层
话说 ST 缺少内置 EEPROM 也都是历史问题了

出0入362汤圆

发表于 2019-1-10 21:48:03 | 显示全部楼层
kinsno 发表于 2019-1-10 20:54
不听看明白这段话

“// 在bootloader里只能读到bootloader区的结尾, 因此这时END_OF_CODE的值并不正确.

我这个是用倒数第三页作为主存储区, 倒数第二页作为后备区用来轮转 (最后一页可能会另作他用)。
所以在程序启动时要判断一下,实际有用的程序大小就是_etext加上_edata减去_sdata。如果.text和.data写到了倒数第三页, 则直接报错。
想想其实查一下倒数第三页是否全ff也就可以了。但是理论上确实有可能全ff但却是有用数据的情况,所以还是算了。

bootload一般也就几k,顶多十几k,肯定不会写到倒数第几页去(不然app往哪写),所以在bootloader里肯定不会报错。
一般应该也不会有在bootloader里写eeprom的需求,顶多读个参数之类,所以这里无所谓了。

出0入362汤圆

发表于 2019-1-10 21:52:28 | 显示全部楼层
t3486784401 发表于 2019-1-10 21:24
话说 ST 缺少内置 EEPROM 也都是历史问题了

可能是工艺问题?STM32L系列就都有

出200入2554汤圆

发表于 2019-1-10 22:00:46 | 显示全部楼层
tomzbj 发表于 2019-1-10 21:52
可能是工艺问题?STM32L系列就都有

早期的 ST 目测是工艺/专利有问题,导致没法内嵌 EEPROM,这点比起 ATMEL 差很多(AVR标配EEP)。
FLASH 模拟的 EEPROM,只能说是个补丁,本质上是损耗均衡算法。

不过要是 EEPROM 也用损耗均衡算法,就远不是 FLASH 模拟能赶上的了。

出0入0汤圆

发表于 2019-1-10 22:23:27 | 显示全部楼层
最好不要用内部flash存数据了,会导致cpu暂停长达 几十毫秒 数量级。
有可能导致中断丢失。

出0入362汤圆

发表于 2019-1-10 22:30:20 | 显示全部楼层
t3486784401 发表于 2019-1-10 22:00
早期的 ST 目测是工艺/专利有问题,导致没法内嵌 EEPROM,这点比起 ATMEL 差很多(AVR标配EEP)。
FLASH  ...

也就存储少量参数用,要存的东西多了还是得上外部eeprom
不过stm32f10x的i2c又不好用, 只能gpio模拟, 而且i2c eeprom写入还得延迟几个ms,也不爽

所以后来如果有外部spi flash,有文件系统的话,就直接在文件系统里写个文件来存储参数代替eeprom了。

出0入362汤圆

发表于 2019-1-10 22:32:33 | 显示全部楼层
meirenai 发表于 2019-1-10 22:23
最好不要用内部flash存数据了,会导致cpu暂停长达 几十毫秒 数量级。
有可能导致中断丢失。 ...

这个还好, 可以接受
有个大坑是如果用dma+dac读取flash里的波形数据然后输出, 写flash的暂停会导致输出波形相位混乱。
不过解决办法也简单, 把波形数据放在sram里就行了,写flash过程中波形不会中断。

出0入0汤圆

发表于 2019-1-10 22:49:43 | 显示全部楼层
tomzbj 发表于 2019-1-10 22:32
这个还好, 可以接受
有个大坑是如果用dma+dac读取flash里的波形数据然后输出, 写flash的暂停会导致输出 ...


奥,理解错了。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

出200入2554汤圆

发表于 2019-1-10 23:31:32 | 显示全部楼层
tomzbj 发表于 2019-1-10 22:30
也就存储少量参数用,要存的东西多了还是得上外部eeprom
不过stm32f10x的i2c又不好用, 只能gpio模拟,  ...

看来这个 i2c 不好用是实锤了,前阵子只是看到有人在说,猜测是:基本功能还行,抗干扰太差容易卡死。

看来 ST 还是欠一点,当初 atmel 卖给 PIC 的时候,ST 也只能眼巴巴瞅着

出0入0汤圆

 楼主| 发表于 2019-1-11 11:11:15 | 显示全部楼层
昨天程序经过测试发现在同时读写的情况下出现程序死机情况,因此有改进了一些,希望没有误导大家

#include "main.h"       

#define   QJ_BZ
#include "Global_Variable.h"

#include "stm32f4xx_it.h"
#include "stm32f4xx.h"
#include "stm32f4xx_flash.h"
#include "USART1.H"
#include "USART2.H"


unsigned char Timer_SendData_Flag;
unsigned char Timer_Collect_Flag;
unsigned char IWDG_Time_Conts;

int SCR1_Compensate;
int SCR2_Compensate;

unsigned char Rec_Flag;
unsigned char Rec_Buf[8];
///////////////////////////////////////////////////

unsigned int data[4] ={0x71,0x12,0x23,0x54};
unsigned int data1[4]={0x72,0x22,0x23,0x54};
unsigned int data2[4]={0x73,0x32,0x23,0x54};
unsigned int data3[4]={0x74,0x42,0x23,0x54};
unsigned int data4[4]={0x75,0x52,0x23,0x54};
unsigned int data5[4]={0x76,0x62,0x23,0x54};
unsigned int data6[4]={0x77,0x72,0x23,0x54};
unsigned int data7[4]={0x78,0x82,0x23,0x54};
unsigned int data8[4]={0x79,0x92,0x23,0x54};

////////////////////////////////////////////////////////////////////////////////////////

//////////////
//用户根据自己的需要设置
#define STM32_FLASH_SIZE 512                         //所选STM32的FLASH容量大小(单位为K)
#define STM32_FLASH_WREN 1  //使能FLASH写入(0,不是能;1,使能)
////////////////////////////////////////////////////////////////////////////////////////

//////////////
#if STM32_FLASH_SIZE<256
#define STM_SECTOR_SIZE 4096 //字节
#else
#define STM_SECTOR_SIZE        4096
#endif                 
//FLASH起始地址
#define STM32_FLASH_BASE 0x08000000         //STM32 FLASH的起始地址
//FLASH解锁键值


        u32 mUseHalfWord;//
        u32 mStartAddress;//

        u32 startAddress=(0x08000000+1000);
        u32 useHalfWord=1;
//读取指定地址的半字(16位数据)
//faddr:读地址(此地址必须为2的倍数!!)
//返回值:对应数据.
u16 ReadHalfWord(u32 faddr);
//WriteAddr:起始地址
//pBuffer:数据指针
//NumToWrite:半字(16位)数 ??
void Write_NoCheck(u32 WriteAddr,u16 *pBuffer,u16 NumToWrite) ;
//从指定地址开始写入指定长度的数据
//WriteAddr:起始地址(此地址必须为2的倍数!!)
//pBuffer:数据指针
//NumToWrite:半字(16位)数(就是要写入的16位数据的个数.)
void Write(u32 WriteAddr,u16 *pBuffer,u16 NumToWrite);


//从指定地址开始读出指定长度的数据
//ReadAddr:起始地址
//pBuffer:数据指针
//NumToWrite:半字(16位)数
void Read(u32 ReadAddr,u16 *pBuffer,u16 NumToRead) ;


u16 STMFLASH_BUF[STM_SECTOR_SIZE/2];//最多是2K字节
void STFLASH(uint32_t startAddress,u32 useHalfWord)
{
        if(startAddress%STM_SECTOR_SIZE!=0)//不是页的开始,将开始处设置为下一个页开始的地


                startAddress+=(STM_SECTOR_SIZE-(startAddress%STM_SECTOR_SIZE));
        mStartAddress=startAddress;
        mUseHalfWord=useHalfWord;
}

//读取指定地址的半字(16位数据)
//faddr:读地址(此地址必须为2的倍数!!)
//返回值:对应数据.

u16  ReadHalfWord(u32 faddr)
{
        return *(vu16*)faddr;
}
//WriteAddr:起始地址
//pBuffer:数据指针
//NumToWrite:半字(16位)数   
void Write_NoCheck(u32 WriteAddr,u16 *pBuffer,u16 NumToWrite)
{
       
        u16 i;
        for(i=0;i<NumToWrite;i++)
        {
                FLASH_ProgramHalfWord(WriteAddr,pBuffer[i]);
            WriteAddr+=2;//地址增加2.
        }  
}
//从指定地址开始写入指定长度的数据
//WriteAddr:起始地址(此地址必须为2的倍数!!)
//pBuffer:数据指针
//NumToWrite:半字(16位)数(就是要写入的16位数据的个数.)
void Write(u32 WriteAddr,u16 *pBuffer,u16 NumToWrite)
{
        u32 secpos;           //扇区地址
        u16 secoff;           //扇区内偏移地址(16位字计算)
        u16 secremain; //扇区内剩余地址(16位字计算)          
        u16 i;   
        u32 offaddr;   //去掉0X08000000后的地址
        if(WriteAddr<STM32_FLASH_BASE||(WriteAddr>=(STM32_FLASH_BASE

+1024*STM32_FLASH_SIZE)))return;//非法地址
        FLASH_Unlock();                                                //解锁
        offaddr=WriteAddr-STM32_FLASH_BASE;                //实际偏移地址.
        secpos=offaddr/STM_SECTOR_SIZE;                        //扇区地址  0~127 for

STM32F103RBT6
        secoff=(offaddr%STM_SECTOR_SIZE)/2;                //在扇区内的偏移(2个字节为基本单

位.)
        secremain=STM_SECTOR_SIZE/2-secoff;                //扇区剩余空间大小   
        if(NumToWrite<=secremain)secremain=NumToWrite;//不大于该扇区范围
        while(1)
        {        /*
                Read(secpos*STM_SECTOR_SIZE

+STM32_FLASH_BASE,STMFLASH_BUF,STM_SECTOR_SIZE/2);//读出整个扇区的内容
                for(i=0;i<secremain;i++)//校验数据
                {
                        if(STMFLASH_BUF[secoff+i]!=0XFFFF)break;//需要擦除            
                }
                if(i<secremain)//需要擦除
                {
                        FLASH_ErasePage(secpos*STM_SECTOR_SIZE+STM32_FLASH_BASE);//擦除

这个扇区
                        for(i=0;i<secremain;i++)//复制
                        {
                                STMFLASH_BUF[i+secoff]=pBuffer[i];          
                        }
                        Write_NoCheck(secpos*STM_SECTOR_SIZE

+STM32_FLASH_BASE,STMFLASH_BUF,STM_SECTOR_SIZE/2);//写入整个扇区  
                }else */Write_NoCheck(WriteAddr,pBuffer,secremain);//写已经擦除了的,直接

写入扇区剩余区间.                                   
                if(NumToWrite==secremain)break;//写入结束了
                else//写入未结束
                {
                        secpos++;                                //扇区地址增1
                        secoff=0;                                //偏移位置为0          
                           pBuffer+=secremain;          //指针偏移
                        WriteAddr+=secremain;        //写地址偏移          
                           NumToWrite-=secremain;        //字节(16位)数递减
                        if(NumToWrite>(STM_SECTOR_SIZE/2))secremain=STM_SECTOR_SIZE/2;//

下一个扇区还是写不完
                        else secremain=NumToWrite;//下一个扇区可以写完了
                }         
        };       
        FLASH_Lock();//上锁
}

//从指定地址开始读出指定长度的数据
//ReadAddr:起始地址
//pBuffer:数据指针
//NumToWrite:半字(16位)数
void Read(u32 ReadAddr,u16 *pBuffer,u16 NumToRead)
{
        u16 i;
        for(i=0;i<NumToRead;i++)
        {
                pBuffer[i]=ReadHalfWord(ReadAddr);//读取2个字节.
                ReadAddr+=2;//偏移2个字节.       
        }
}
const u8 TEXT_Buffer[]={"Flash_test"};

#define SIZE sizeof(TEXT_Buffer)                //数组长度
#define FLASH_SAVE_ADDR  0X0800FC00                //设置FLASH 保存地址(必须为偶数,且其值

要大于本代码所占用FLASH的大小+0X08000000)
u8 datatemp[SIZE];


///////////////////////////////////////////////////
int main(void)
{
         unsigned char sendconts,senddat[8];
         unsigned int tab1[4];
         SystemInit();
         USART1_Configuration(115200);
         NVIC_USART1_Configuration();
         
         //Write(FLASH_SAVE_ADDR,(u16*)TEXT_Buffer,SIZE);//写数据,第一次下载程序到32,

第二次注释掉此行,断电重新编译下载 //keil watch查看datatemp数组的数据正是之前写进去的数



               
                Write(FLASH_SAVE_ADDR,(u16*)data,4);
                Write(FLASH_SAVE_ADDR+100,(u16*)data1,4);
                Write(FLASH_SAVE_ADDR+200,(u16*)data2,4);
                Write(FLASH_SAVE_ADDR+300,(u16*)data3,4);
                Write(FLASH_SAVE_ADDR+400,(u16*)data4,4);
                Write(FLASH_SAVE_ADDR+500,(u16*)data5,4);
                Write(FLASH_SAVE_ADDR+600,(u16*)data6,4);
                Write(FLASH_SAVE_ADDR+700,(u16*)data7,4);
                Write(FLASH_SAVE_ADDR+800,(u16*)data8,4);
               
         while(1)
           {
                       
                         for(i=0;i<9;i++)
                         {
                                 Read(FLASH_SAVE_ADDR+i*100,(u16*)tab1,4);
                         senddat[2] = tab1[0];
                         senddat[3] = tab1[1];
                         senddat[4] = tab1[2];
                         senddat[5] = tab1[3];
                         senddat[6] = senddat[2]+senddat[3]+senddat[4]+senddat[5];
                         USART_Byte_Send(USART1, senddat[0]);
                         USART_Byte_Send(USART1, senddat[1]);
                         USART_Byte_Send(USART1, senddat[2]);
                         USART_Byte_Send(USART1, senddat[3]);
                         USART_Byte_Send(USART1, senddat[4]);
                         USART_Byte_Send(USART1, senddat[5]);
                         USART_Byte_Send(USART1, senddat[6]);
                         USART_Byte_Send(USART1, senddat[7]);
                         delay_ms(5000);                       
                         }
   }
}
   



出0入4汤圆

发表于 2019-1-11 13:46:31 | 显示全部楼层
mark.flash 损耗均衡算法

出140入115汤圆

发表于 2019-1-11 17:26:31 | 显示全部楼层
mark.flash 损耗均衡算法+1

出0入8汤圆

发表于 2019-1-12 07:28:23 来自手机 | 显示全部楼层
这个好…………

出0入0汤圆

发表于 2019-1-12 08:45:48 | 显示全部楼层
eeprom写flash 均衡算法
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-4-23 17:04

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表