STM32F103C8T6读写内部flash

发布者:学思者最新更新时间:2023-10-09 来源: elecfans关键字:STM32F103C8T6  读写  内部flash 手机看文章 扫描二维码
随时随地手机看文章

大家好,今天和大家分享一下STM32F103C8T6读写内部flash,关于103系列的单片机大家可以参考选项手册查看flash的容量。


一、芯片FLASH容量分类:

b3698f84-2115-11ec-82a8-dac502259ad0.png

可以看到我们今天介绍的这款芯片的flash大小是64K的,网上也有人说它可以支持到128K,但是官方给出的解释是前64K是有保证的,后面的无法保证,所以想要使用的小伙伴需要慎重。

现在芯片的flash大小我们知道了,下面就可以看看这个flash是怎么划分的了,通过芯片数据手册,我们能看到今天说的STM32F103C8T6是属于中等容量的设备。

既然是中等容量的设备了,那我们就来看看flash划分吧,在STM32的闪存编程手册中有这样一段话:按照不同容量,存储器组织成:

32个1K字节/页(小容量)128个1K字节/页(中容量)256个2K字节/页(大容量)

这段话怎么理解呢,就是告诉我们小容量的设备(内存是6K和32K)的设备是由1K字节每页组成的。

中容量的设备(内存是64K和128K)的设备是由1K字节每页组成的。大容量的设备(内存是256K、384K和512K)的设备是由2K字节每页组成的。

举个例子吧:

一个芯片的存储容量是64K,这64K是什么呢,就是64*1024个BYTE,一个BYTE是由8位0或1组成的,(比如0000 1111 这8个二进制数组成了一个字节,用十进制来说就是15)

小结一下:64K的flash可以存储64*1024个字节的数据。

咱们继续说,这64K的数据怎么划分,存储是按照页为单位进行存储的,一页1K的容量,也就说一页可以存储1024个字节。

一共是多少页?

答案是:64页,我们看一下官方是不是这么说的。

在闪存编程手册里确实是这么说的,所以我们刚才说是64页是正确的

二、 读写步骤:

上面我们知道了芯片是怎么分类的,下面我们就重点来讲解一下芯片是怎么读写的。

内部flash我们参照HAL库或者标准库,直接调用ST公司给我们封装好的库进行编程就可以了,这里我用的是标准库,有兴趣的小伙伴可以去看看HAL库。

是不是有小伙伴会疑问什么是标准库,什么是HAL库?

在这里给大家解释一下,这两个库都是ST公司,直接把寄存器封装成函数,供大家直接调用某一个函数,就可以完成各种寄存器的配置,不容大家直面芯片的寄存器,方便阅读和使用,因为每个函数的名称功能都是不一样的,在调用前可以参考函数的注释,在F0和F4的标准库里甚至有每个函数的用法,不知道为什么在F1的库里把使用步骤去掉了。

咱们继续,读写的话库函数分为:

/*------------ Functions used for all STM32F10x devices -----*/void FLASH_SetLatency(uint32_t FLASH_Latency);void FLASH_HalfCycleAccessCmd(uint32_t FLASH_HalfCycleAccess);void FLASH_PrefetchBufferCmd(uint32_t FLASH_PrefetchBuffer);void FLASH_Unlock(void);void FLASH_Lock(void);

FLASH_Status FLASH_ErasePage(uint32_t Page_Address);FLASH_Status FLASH_EraseAllPages(void);

FLASH_Status FLASH_EraseOptionBytes(void);FLASH_Status FLASH_ProgramWord(uint32_t Address, uint32_t Data);FLASH_Status FLASH_ProgramHalfWord(uint32_t Address, uint16_t Data);FLASH_Status FLASH_ProgramOptionByteData(uint32_t Address, uint8_t Data);FLASH_Status FLASH_EnableWriteProtection(uint32_t FLASH_Pages);FLASH_Status FLASH_ReadOutProtection(FunctionalState NewState);

FLASH_Status FLASH_UserOptionByteConfig(uint16_t OB_IWDG, uint16_t OB_STOP, uint16_t OB_STDBY);uint32_t FLASH_GetUserOptionByte(void);uint32_t FLASH_GetWriteProtectionOptionByte(void);

FlagStatus FLASH_GetReadOutProtectionStatus(void);FlagStatus FLASH_GetPrefetchBufferStatus(void);void FLASH_ITConfig(uint32_t FLASH_IT, FunctionalState NewState);FlagStatus FLASH_GetFlagStatus(uint32_t FLASH_FLAG);void FLASH_ClearFlag(uint32_t FLASH_FLAG);FLASH_Status FLASH_GetStatus(void);

FLASH_Status FLASH_WaitForLastOperation(uint32_t Timeout);

/*------------ New function used for all STM32F10x devices -----*/void FLASH_UnlockBank1(void);void FLASH_LockBank1(void);FLASH_Status FLASH_EraseAllBank1Pages(void);FLASH_Status FLASH_GetBank1Status(void);FLASH_Status FLASH_WaitForLastBank1Operation(uint32_t Timeout);

在这里就不一个一个的详细说了,我们说一下常用的就行

1. 解锁void FLASH_Unlock(void);

2. 上锁void FLASH_Lock(void);

3. 页擦除FLASH_Status FLASH_ErasePage(uint32_t Page_Address);

4. 半字写入FLASH_Status FLASH_ProgramHalfWord(uint32_t Address, uint16_t Data);

上面这4个函数就是我们最常用的。

下面说一下数据写入的步骤:

第一步:解锁。

第二步:判断写入的数据是否被擦除过,也就是判断写入的地址内存放的是不是0xFFFF 这里要重点说一下,为什么要判断是不是0xFFFF而不是判断是不是0xFF呢?因为我们每次写入数据都要写入半字,也就是两个字节的数据才行,而且写入的地址只能是2的整数倍,不能是奇数。这里大家注意一下。

第三步:写入数据 STM32F103C8T6只能按照半字的方式进行数据写入,写入前的数据必须是0XFFFF,因为FLASH数据写入,只能写0,不能写1,这也就是为什么我们要先确保写入前的数据是被擦除了的原因。

第四步:上锁。

第五步:验证写入是否正确。

其实第五步可以省略。

我们看看官方给的写入过程:

好了,其实是一样的。下面我就和大家来分享一下(百分之九十九参考的正点原子的例程)。

//不检查的写入//WriteAddr:起始地址//pBuffer:数据指针//NumToWrite:半字(16位)数 void STMFLASH_Write_NoCheck(u32 WriteAddr,u16 *pBuffer,u16 NumToWrite) { u16 i; for(i=0;i《NumToWrite;i++) { FLASH_ProgramHalfWord(WriteAddr,pBuffer); WriteAddr+=2;//地址增加2. } }

//从指定地址开始写入指定长度的数据//WriteAddr:起始地址(此地址必须为2的倍数!!)//pBuffer:数据指针//NumToWrite:半字(16位)数(就是要写入的16位数据的个数。)u16 STMFLASH_BUF[STM_SECTOR_SIZE/2];//最多是2K字节void STMFLASH_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) { STMFLASH_Read(((secpos*STM_SECTOR_SIZE)+STM32_FLASH_BASE),STMFLASH_BUF,STM_SECTOR_SIZE/2);//读出整个扇区的内容 for(i=0;i《secremain;i++)//校验数据// for(i=0;i《(STM_SECTOR_SIZE/2);i++)//校验数据 { if(STMFLASH_BUF[secoff+i]!=0XFFFF)break;//需要擦除 // if(STMFLASH_BUF!=0XFFFF)break;//需要擦除 } FLASH_ClearFlag(FLASH_FLAG_EOP | FLASH_FLAG_PGERR | FLASH_FLAG_WRPRTERR);

if(i《secremain)//需要擦除// if(i《(STM_SECTOR_SIZE/2))//需要擦除 { FLASH_ClearFlag(FLASH_FLAG_EOP | FLASH_FLAG_PGERR | FLASH_FLAG_WRPRTERR); FLASH_ErasePage(secpos*STM_SECTOR_SIZE+STM32_FLASH_BASE);//擦除这个扇区 for(i=0;i《secremain;i++)//复制 { STMFLASH_BUF[i+secoff]=pBuffer; } STMFLASH_Write_NoCheck(secpos*STM_SECTOR_SIZE+STM32_FLASH_BASE,STMFLASH_BUF,STM_SECTOR_SIZE/2);//写入整个扇区 }else STMFLASH_Write_NoCheck(WriteAddr,pBuffer,secremain);

//写已经擦除了的,直接写入扇区剩余区间。 if(NumToWrite==secremain)break;//写入结束了 else//写入未结束 { secpos++; //扇区地址增1 secoff=0; //偏移位置为0 pBuffer+=secremain; //指针偏移 WriteAddr+=(secremain*2); //写地址偏移 NumToWrite-=secremain; //字节(16位)数递减 if(NumToWrite》(STM_SECTOR_SIZE/2)) { secremain=STM_SECTOR_SIZE/2;//下一个扇区还是写不完 } else { secremain=NumToWrite;//下一个扇区可以写完了 } } } FLASH_Lock();//上锁}

最终我们调用STMFLASH_Write()函数进行数据的写入,是不是有没看懂的小伙伴,我给大家解释一下写入的过程吧。

这个STMFLASH_Write()函数,是说给定一个写入的地址、数据和写入的个数,然后按照给定的地址开始写数据,注意红色字体。

写数据是怎么做的呢?

首先是整理一下写入的页地址和需要写入多少页,每一页写入的话起始地址是什么然后开始一页一页的写,当遇到跨页写入的时候,把第二页的地址写进去,写的个数继续写入就行。

还有一个地方很重要,就是我修改了库函数:

/** * [url=home.php?mod=space&uid=247401]@brief[/url] Programs a half word at a specified address. * [url=home.php?mod=space&uid=536309]@NOTE[/url] This function can be used for all STM32F10x devices. * @param Address: specifies the address to be programmed. * @param Data: specifies the data to be programmed. * @retval FLASH Status: The returned value can be: FLASH_ERROR_PG, * FLASH_ERROR_WRP, FLASH_COMPLETE or FLASH_TIMEOUT. */FLASH_Status FLASH_ProgramHalfWord(uint32_t Address, uint16_t Data){ FLASH_ClearFlag(FLASH_FLAG_EOP | FLASH_FLAG_PGERR | FLASH_FLAG_WRPRTERR);

FLASH_Status status = FLASH_COMPLETE; /* Check the parameters */ assert_param(IS_FLASH_ADDRESS(Address));#ifdef STM32F10X_XL /* Wait for last operation to be completed */ status = FLASH_WaitForLastOperation(ProgramTimeout);

if(Address 《 FLASH_BANK1_END_ADDRESS) { if(status == FLASH_COMPLETE) { /* if the previous operation is completed, proceed to program the new data */ FLASH-》CR |= CR_PG_Set; *(__IO uint16_t*)Address = Data; /* Wait for last operation to be completed */ status = FLASH_WaitForLastBank1Operation(ProgramTimeout);

/* Disable the PG Bit */ FLASH-》CR &= CR_PG_Reset; } } else { if(status == FLASH_COMPLETE) { /* if the previous operation is completed, proceed to program the new data */ FLASH-》CR2 |= CR_PG_Set; *(__IO uint16_t*)Address = Data; /* Wait for last operation to be completed */ status = FLASH_WaitForLastBank2Operation(ProgramTimeout);

/* Disable the PG Bit */ FLASH-》CR2 &= CR_PG_Reset; } }#else /* Wait for last operation to be completed */ status = FLASH_WaitForLastOperation(ProgramTimeout); if(status == FLASH_COMPLETE) { /* if the previous operation is completed, proceed to program the new data */ FLASH-》CR |= CR_PG_Set; *(__IO uint16_t*)Address = Data;

/* Wait for last operation to be completed */ status = FLASH_WaitForLastOperation(ProgramTimeout); /* Disable the PG Bit */ FLASH-》CR &= CR_PG_Reset; } #endif /* STM32F10X_XL */ /* Return the Program Status */ return status;}

大家能看出来吗?就是红色字体部分,增加了一个每次写入前清除所有异常状态。为什么添加这个呢?

因为,如果你写入的数据的地址没有擦除,你就写入的话会导致异常状态的发生,而这个异常状态时要手动清除的,如果你没有清除这个异常状态,而继续写入数据的话,那么你后面写入任何数据都会报错,均写不进去,所以我在这里增加了一个异常状态清除,如果前面写入的数据报错了,不会影响我接下来的数据写入。

这里大家就清除为什么了吧。

写数据会了,那么再说一下读数据,其实这里读数据要比外部flash读取容易的多,我们直接读取地址,返回的就是地址存放的数据,是不是很简单。

看下面的函数:

//读取指定地址的半字(16位数据)//faddr:读地址(此地址必须为2的倍数!!)//返回值:对应数据.u16 STMFLASH_ReadHalfWord(u32 faddr){ return *(vu16*)faddr; }//从指定地址开始读出指定长度的数据//ReadAddr:起始地址//pBuffer:数据指针//NumToWrite:半字(16位)数void STMFLASH_Read(u32 ReadAddr,u16 *pBuffer,u16 NumToRead) { u16 i; for(i=0;i《NumToRead;i++) { pBuffer=STMFLASH_ReadHalfWord(ReadAddr);//读取2个字节。 ReadAddr+=2;//偏移2个字节。 }}

有没有很开心,读写数据就是这么简单就完成了。


关键字:STM32F103C8T6  读写  内部flash 引用地址:STM32F103C8T6读写内部flash

上一篇:LinkedInSTM32F4时钟系统初始化的程序代码分享
下一篇:通过STM32的C8t6获取DHT11的温湿度数据

推荐阅读最新更新时间:2024-11-14 08:15

艾迈斯半导体剥离NFC和RFID读写器产品线
2016年8月3日,全球领先的高性能传感器和模拟解决方案供应商艾迈斯半导体(ams AG,SIX股票代码:AMS)今日宣布向意法半导体(NYSE:STM)出售其NFC和RFID读写器IP、技术和产品线,成交金额为7930万美元现金(约7150万欧元)以及取决于未来获利能力及经营成果的高达3700万美元的款项。通过此次交易,艾迈斯半导体在成为全球传感器解决方案领先供应商的道路上更进一步。艾迈斯半导体将保留其传感器相关NFC / RFID标签业务和相关设计专长以创建无线物联网传感器解决方案并支持即将到来的传感器新发展。 此次交易是艾迈斯半导体实现其传感器解决方案战略的重要组成部分,公司正积极努力管理其现有技术及产品以达成该目标。交易
[传感器]
使用I2C读写EEPROM流程总结
1、配置I/O端口,确定并配置I2C的模式,使能GPIO和I2C时钟 2、写 1)检测SDA是否空闲 2)按I2C协议发出起始信号 3)发出7位器件地址和写模式 4)要写入的存储区首地址 5)用页写入方式或字节写入方式写入数据 6)发送I2C通信结束信号 3、读 1)检测SDA是否空闲 2)按照I2C协议发出起始信号 3)发出7位器件地址和写模式 4)发出要读写的存储区首地址 5)重发起始信号 6)发出7位器件地址和读模式 7)接收数据 类似写操作,每个操作之后都要检测“事件”是否成功
[单片机]
【MPC5744P】内部Flash读写
MPC5744P内部Flash相当大,除了存储代码,多余的空间还可以另作它用,例如参数存储,故障存储,当然,Bootloader也是依赖于Flash读写。 内部Flash的结构请参考上一篇关于Flash结构及启动原理的说明:https://blog.csdn.net/u010875635/article/details/85162135 读取:一次读取256位。 擦除:一次擦除一个block,无论是16KB、32KB、64KB抑或256KB 编程:内置flash存储可以通过word(32bits)或者double words(64bits)寻址编程,多个word或double words填充编程页缓存(256bit
[单片机]
【MPC5744P】<font color='red'>内部</font><font color='red'>Flash</font><font color='red'>读写</font>
STM32CubeMX GPIO模拟I2C读写M24C64
一、先了解一下硬件的连接,I2C_SDA和I2C_SCL分别接STM32的PB9、PB6 二、粗阅一下M24C64的数据手册,得知器件地址和存储器地址,器件地址是8bit,而存储器地址是16bit 三、下面是M24C64的写时序 四、下面是M24C64的读时序 五、下面是程序编写流程 六、看看时序参数 七、好啦!需要的知识点差不多都提到了开始搬砖 1、用STM32CubeMX配置生成工程,并打开工程。(具体怎么用这个软件这里不讲) 2、在我的工程里是这样配置的 《1》配置USART3,用打印读出来的数据与写入的是否一致 《2》配置PB6、PB9为开漏输出模式,配置如下: void MX_GPIO_Init(void)
[单片机]
STM32CubeMX GPIO模拟I2C<font color='red'>读写</font>M24C64
射频芯片MFRC522在读写器终端中的应用设计
在此主要叙述以STC89C52单片机为核心的脉动真空灭菌器控制系统的设计,给出了系统的实现原理、硬件组成及相应的软件设计。在灭菌过程中,采用Fuzzy—PID混和算法对温度进行非线性控制。利用该系统的智能化软件可方便地实现对脉动真空灭菌器的自动化控制。该系统在消毒灭菌的过程中,可以实时显示参数和图形化显示灭菌过程,还可以储存所需要的所有参数及打印等功能,同时还采取了软、硬件抗干扰措施。实验表明该系统提高了灭菌器的控制精度,功能齐全且实用性强,可以安全运行,实现了灭菌器的自动化工作过程。 现在人们生活水平提高了,人们更加的关注医疗灭菌消毒。在90年代中期,国内研制了_种新型灭菌设备——脉动真空灭菌系统。该系统采用了先进的
[单片机]
射频芯片MFRC522在<font color='red'>读写</font>器终端中的应用设计
基于AS3990芯片的UHF手持读写器设计
1.引言 无线射频技术RFID(radio frequency identification)是20 世纪90 年代兴起的一种非接触的自动识别技术,利用其射频信号空间传播的特性——通过空间耦合(交变磁场或电磁场)实现无接触信息传递,并通过所传递的信息来实现对被识别物体的自动识别。识别过程不需要物理接触,不需要人工管理即可完成标签信息的写入和读取。采用RFID 技术,可以一次性实现对多个目标以及运动目标的识别。此外,电子标签是可读写的,能储存大量信息,安全性保密性强,并且不怕外部灰尘、污渍等,具有较强的环境适应能力。正是由于具有这些其它识别方式不具备的优势,RFID 技术在物流、运输、交通、生产、防伪等领域有着广泛的应用和巨大的
[单片机]
基于AS3990芯片的UHF手持<font color='red'>读写</font>器设计
【STM8S】 FLASH与EEPROM读写操作
以下为FLASH操作: #include flash.h #include stm8s_flash.h void Flash_Write_bytes(uint32_t Address , uint8_t * DataBuff,uint16_t length) { uint16_t Count=0; for( Count=0 ; Count length ; Count++ ) { FLASH_ProgramByte_User(Address+Count,DataBuff ); } } void FLASH_ProgramByte_User(uint32_t Address, uint8_t
[单片机]
DS18B20读写程序
#include reg51.h //包含单片机寄存器的头文件 #include intrins.h //包含_nop_()函数定义的头文件 #define uchar unsigned char #define uint unsigned int sbit date=P3^7; unsigned char code table ={0x3f, 0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07, 0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79, 0x71,0x80,0xc0}; uchar falg; uint c,temp; void delay(u
[单片机]
小广播
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件
更多往期活动

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved