历史上的今天
返回首页

历史上的今天

今天是:2024年09月11日(星期三)

正在发生

2018年09月11日 | STM32中flash的读写详解

2018-09-11 来源:eefocus


一:对STM32内部FLASH写进行编程操作,需要遵循以下流程:

  1.FLASH解锁

  2.清除相关标志位

  3.擦除FLASH(先擦除后写入的原因是为了工业上制作方便,即物理实现方便)

  4.写入FLASH

  5.锁定FLASH

 

(1)获取状态:FLASH_Status FLASH_GetStatus(void);

返回值是通过枚举类型定义的。

 

 typedef enum

   FLASH_BUSY = 1,  //忙

   FLASH_ERROR_PG,  //编程错误

   FLASH_ERROR_WRP,  //写保护错误

   FLASH_COMPLETE,   //操作完成

   FLASH_TIMEOUT    //操作超时

 }FLASH_Status;

 

(2)FLASH_Unlock();//解锁函数(在对flash进行写操作前必须解锁)

(3)FLASH_ClearFlag();//清除所有已有标志

(4)擦除函数有3个:

FLASH_Status FLASH_ErasePage(uint32_t Page_Address);

FLASH_Status FLASH_EraseAllPages(void);

FLASH_Status FLASH_EraseOptionBytes(void);

 

(5)写函数:

FLASHStatus  FLASH_ProgramWord(uint32_t Address,uint32_t Data);//32位字写入函数

FLASHStatus  FLASH_ProgramHalfWord(uint32_t Address,uint32_t Data);//16位半字写入

FLASHStatus  FLASH_ProgramOptionByteData(uint32_t Address,uint32_t Data);//用户字节写入

 

int write_flash(u32 StartAddr,u16 *buf,u16 len)

{

    volatile FLASH_Status FLASHStatus;

u32 FlashAddr;

len=(len+1)/2;

FLASH_Unlock();//1.解锁函数(在对flash进行写操作前必须解锁)

    FLASH_ClearFlag(FLASH_FLAG_BSY | FLASH_FLAG_EOP | FLASH_FLAG_PGERR | FLASH_FLAG_WRPERR);//2.清除所有已有标志

FlashAddr=StartAddr;

FLASH_ErasePage(StartAddr);//3.擦除一个flash页面

    while(len--)

    {

 

      //FLASH_ProgramHalfWord为写入函数,返回值是flash的状态(5种)

      FLASHStatus = FLASH_ProgramHalfWord(FlashAddr,*buf++);

      if (FLASHStatus != FLASH_COMPLETE)  //FLASH_COMPLETE表示闪存完成

      {

        //printf("FLSH :Error %08X\n\r",FLASHStatus);

        return -1;

      }

      FlashAddr += 2;

    }

FLASH_Lock();

return 0;

}

 

二:FLASH 读取方法

 

    *(uint32_t *)0x8000000;//读一个字

  *(uint8_t *)0x8000000;//读一个字节;

  *(uint16_t *)0x8000000;//读半字;  

  举例:

  uint8_t data;

  data = *(uint8_t *)0x8000000;//就是读取FLASH中地址0x8000000处的数据

 

 

int read_flash(u32 StartAddr,u32 *buf,u16 len) //一次读一个字4字节

{

len=(len+3)/4;

while(len--)

        {

*buf=*(__IO uint32_t *)StartAddr;

                 StartAddr=StartAddr+4;

                 buf++;

}

        return 0;

}

 

三:几个有用的子函数

/*

功能:向指定地址写入数据

参数说明:addr: 写入的FLASH页的地址

          p:    被写入变量的地址(数组中的必须是uint8_t类型,元素个数必须是偶数)

          Byte_Num: 被写入变量的字节数(必须是偶数)

*/

  void FLASH_WriteByte(uint32_t addr , uint8_t *p , uint16_t Byte_Num)

  {

          uint32_t HalfWord;

          Byte_Num = Byte_Num/2;

          FLASH_Unlock();

          FLASH_ClearFlag(FLASH_FLAG_BSY | FLASH_FLAG_EOP | FLASH_FLAG_PGERR | FLASH_FLAG_WRPRTERR);

          FLASH_ErasePage(addr);

          while(Byte_Num --)

          {

                  HalfWord=*(p++);

                  HalfWord|=*(p++)<<8;

                  FLASH_ProgramHalfWord(addr, HalfWord);

                  addr += 2;

          }

          FLASH_Lock();

  }

 

  例:

  uint8_t data[100];

  FLASH_WriteByte(0x8000000 , data , 100);/*数组data的数据被写入FLASH中*/

 

/*

功能:从指定地址读取数据

参数说明:addr 从FLASH中读取的地址

          p    读取后要存入变量的地址(数组中的必须是uint8_t类型)

          Byte_Num 要读出的字节数

*/

  void FLASH_ReadByte(uint32_t addr , uint8_t *p , uint16_t Byte_Num)

  {

    while(Byte_Num--)

    {

     *(p++)=*((uint8_t*)addr++);

    }

  }

  例:

  uint8_t data[101];

  FLASH_ReadByte(0x8000001 , data , 101);/*FLASH中的数据被读入数组data中*/

hardware_conf.h中:

//64 flash

#define  ADDRESS_START_ADDR     ((u32)0x0800EC00)//59:存储域名和端口号

#define  TIME_START_ADDR        ((u32)0x0800F000)//60:存储时间

#define  KEYS_START_ADDR  ((u32)0x0800F400)//61:存储各种key

#define  MACHINEID_START_ADDR ((u32)0x0800F800)//62:存储机器码

#define  VERSION_START_ADDR   ((u32)0x0800FC00)//63:存储版本号

 

main()中:

//获取flash内容

void getFlash()

{

      /*读取机器码*/

    u8 machineId[19]="";

    read_flash(MACHINEID_START_ADDR, (u32 *) machineId, 19);

    strncpy(MachineID_Default, machineId, 18);

    

    /*读取时间*/   

    u8 times[20]="";

    read_flash(TIME_START_ADDR, (u32 *) times, 20);

    

    char timeKey[2]="";

    strncpy(timeKey, times, 1);

 

    

    /*读取keys*/

    u8 out_data[220];

    read_flash(KEYS_START_ADDR, (u32 *) out_data, 220);

  }

    

//写各种key到flash

int getAllMessage() 

{

    char in_data[220];

    //下面是falsh需要存储的变量

    sprintf(in_data, "%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s",isFisrt,community_code,address,swipe,code_overtime,myKey1,Private_Key,check_pw);

    if(strlen(in_data)==96&&in_data[0]=='N' &&in_data[1]=='\n'&&in_data[63]=='\n'&&in_data[65]=='\n'&&in_data[69]=='\n'&&in_data[75]=='\n'&&in_data[82]=='\n'&&in_data[89]=='\n')

    {

      write_flash(KEYS_START_ADDR, (u16 *) in_data, 220);

      ACCLOG("write keys success\n");

      return 1;

    }else{

      ACCLOG("write keys fail...\n");

      return 0;

    }

}


推荐阅读

史海拾趣

Diamond SA公司的发展小趣事

随着全球对环保和可持续发展的关注度不断提高,Diamond SA公司也积极响应这一趋势。他们致力于开发环保型电子产品和技术解决方案,减少对环境的影响。同时,公司还积极参与各种环保活动和公益事业,推动整个电子行业的绿色发展。这些努力不仅提升了公司的社会形象和声誉,也为公司的长期发展奠定了坚实的基础。

EEMB Co Ltd公司的发展小趣事

为了适应公司业务的快速发展和满足市场需求的不断增长,EEMB集团于2017年在汉川市修建了新工厂。新工厂占地面积120亩,使用面积达27000平方米,配备了先进的生产设备和技术。一期工程全面投入生产后,公司的产能得到了显著提升,能够更好地满足客户的订单需求。同时,新工厂的建成也进一步提升了公司的生产效率和产品质量。

EMLSI公司的发展小趣事

在电子行业中,产品质量是企业生存和发展的关键。EMLSI公司深知这一点,因此始终将品质管理放在首位。公司建立了严格的质量管理体系,从原材料采购到产品生产的每一个环节都进行严格把关。同时,EMLSI还注重与客户的沟通和反馈,及时解决客户在使用过程中遇到的问题。这种对品质的执着追求让EMLSI赢得了客户的信任和忠诚。

Hong Kong X'Tals Ltd公司的发展小趣事
确保电源电压在LM122的允许范围内(4.5~40V),以避免损坏芯片。
Global Power Technologies Group公司的发展小趣事
可以将不规则的输入脉冲整形为具有固定宽度和幅度的输出脉冲。
DILABS公司的发展小趣事

面对数字化浪潮的冲击,DILABS积极拥抱变革。他们加大了对人工智能、物联网等前沿技术的研发投入,推动公司向数字化转型。同时,DILABS还积极参与行业标准的制定和推广工作,为电子行业的未来发展贡献自己的力量。展望未来,DILABS将继续秉承创新、品质、环保和数字化的理念,为全球客户提供更加优质、高效的电子产品和服务。

问答坊 | AI 解惑

protel99se教程

学习PROTEL99se必备…

查看全部问答>

基于AT89S52单片机的LED点阵显示屏控制系统的设计.PDF

基于AT89S52单片机的LED点阵显示屏控制系统的设计.PDF…

查看全部问答>

2440开发板,液晶显示800*600问题

液晶显示问题。我买了快开发板,本来是1024*768分辨率的,根据网上资料,修改成800*600,但是整个WINDOWS界面只显示了屏幕的左上角,其他WINDOWS CE程序一切正常,不知道如何是好,希望各位能给电帮助。…

查看全部问答>

网络开发笔记6_伪动态网页

一 为什么说是伪动态     做网站的人知道动态网页常用的开发语是ASP.net、JSP、PHP。而这里我们是没法用上的,我们用的是cgi文件。   二 什么是CGI        Common Gate Interface(通用网关 ...…

查看全部问答>

STM8关于LIN总线的请教

大家好!      小弟现在遇到一个奇怪的问题。      硬件测试环境:板子是STM8S208,板子上有两个LIN接口,一个做主机,一个做从机,用一条串口线将两个口连接起来通信。       ...…

查看全部问答>

关于申请租借TI仿真器的问题

近几天一直在TI网站上瞎转悠,深为它的器件性能所引,在我提交的电源方案中(还没有完善)决定使用它的Piccolo CPU : _TMS320f28035,它可以由一块CPU担任所设想的从PFC到输出部分的、全部分的功率控制。     然而,搞这个没有个仿真器 ...…

查看全部问答>

如何使用 CCS 建一个 M3 的工程

如何使用 CCS 建一个 M3 的工程,一直在用 MDK,最近不得不熟悉 CCS ,不知道 CCS 要怎么建工程呢? 找到一个 PDF ,按照里边的步骤还是能编译,而且很慢,这样的工具怎么用呢? [ 本帖最后由 Study_Stellaris 于 2011-12-5 16:00 编辑 ]…

查看全部问答>

OMAPL138开发板无法连接上PC

在CCS3.3的开发环境下,拿TDS560仿真器连接omapl138的板子,在reset_TDS560USB_plus时出现如下错误:C:\\CCStudio_v3.3\\cc\\bin>dbgjtag -f brddat\\ccbrd0.dat -rv ------------------------------------------------------------------------ ...…

查看全部问答>

BeagleBone试用第一周 底板PCB--今天终于决定把板子拿去制了。到底如何不管他。

今天终于决定把板子拿去制了。到底如何不管他。 时间要紧。有错就改嘛。反正还是好同志。 希望大家支持,阿莫那里要求插孔都加大0.15MM 所以我的孔画的比较大。 有关硬件的资料: [ 本帖最后由 damiaa 于 2012-9-28 16:27 编辑 ...…

查看全部问答>

编译出错

Building configuration: project - Debug Updating build tree... Linking Error[e16]: Segment CSTACK (size: 0x32 align: 0x1) is too long for segment definition. At least 0x19 more bytes needed. The problem occurred while proces ...…

查看全部问答>