代码
File: STM8S208MB_Flash_Op.c
/*
@file: STM8S208MB_Flash_Op.c
@brief: 读写Flash
@data: 2023-04-14
@author: ArcherQAQ
*/
#include "STM8S208MB_Flash_Op.h"
#include "stdio.h"
u8 dataBuf[] = {0xFF, 0xFF}; // 写入Flash的数据
u8 Rec_Buf[100] = {0x00}; // 接收读取的数据, 设有100个元素
/*
/*
@brief: 读写Flash
@data: 2023-04-14
@author: ArcherQAQ
*/
#include "STM8S208MB_Flash_Op.h"
u8 dataBuf[] = {0xFF, 0xFF}; // 写入Flash的数据
u8 Rec_Buf[100] = {0x00}; // 接收读取的数据, 设有100个元素
/*
@brief 参考数据手册Flash的Memory access security system部分实现写入Flash功能
@param Addr: Flash中需要被写入的地址
@param Buf: 需要写入的数据buffer
@return None
*/
// High density的stm8s的Flash地址范围为0x00 8000 ~ 0x02 7FFF即20个bit所以这里用u32来存放地址
void Flash_WriteNByte(u32 Addr, u8 *Buf)
{
u8 i = 0;
// 解锁Main Program area,连续往FLASH_PUKR写入两个MASS keys(查看Flash的MASS部分)
// 该两个keys会与硬件keys值比对
// 如果相同则解锁
FLASH_PUKR = 0x56;
FLASH_PUKR = 0xAE;
// 成功解锁后IAPSR寄存器的PUL(Program memory Unlocked Flag)会置位
// 表示Flash解锁,允许写
while (!(FLASH_IAPSR | (1 << 1)))
{
};
// 将Buf中的数据写入经过PointerAttr修饰的指针变量
for (i = 0; i < sizeof(Buf); i++)
{
*(PointerAttr u8*)Addr = Buf[i];
Addr++;
}
// 完成写操作后重新给Flash上锁,防止Flash的内容corrupution
// 通过软件清空FALSH_IAPSR的PUl即可将Flash重新上锁
FLASH_IAPSR &= ~(1 << 1);
}
/*
@brief 参考数据手册Flash的Memory access security system部分实现读取Flash功能
@param Addr: Flash中需要被读取的地址
@param Len: 需要读的地址的长度
@param Rec_Buf: 接收返回字节的缓存数组
@return None
*/
void Flash_ReadNByte(u32 Addr, u16 Len, u8 *Rec_Buf)
{
u8 i;
for(i = 0; i < Len; i++)
{
Rec_Buf[i] = *(PointerAttr u8*)Addr; // 将读到相应地址的字节返回给Rec_Buf
Addr++; // Addr地址+1
}
}
File: STM8S208MB_Flash_Op.h
/*
@file: STM8S208MB_Flash_Op.h
@brief: 读写Flash
@data: 2023-04-14
@author: ArcherQAQ
*/
#ifndef __STM8S208MB_FLASH_OP_H__
#define __STM8S208MB_FLASH_OP_H__
#include "iostm8s208mb.h"
#include "STM8S208MB_General.h"
/*
@note: 坑中坑,stm8s中普通指针变量的长度只有16bit
但是Flash中的地址能最大能到地址为0x02 7FFF的内存单元
这就意味着使用类型为u8*的指针变量无法指向64K(2^16)以后的地址单元
然后通过在官方库函数查看 void FLASH_ProgramByte (uint32_t Address, uint8_t Data)
函数,发现其通过 PointerAttr 标识来解锁Flash访问空间的限制
可通过 printf("%d\n", sizeof(PointerAttr u8*)); 验证,输出为3
表示被PointerAttr修饰的u8*型指针变量长度为3个字节
*/
/*!< Used with memory Models for code higher than 64K */
#define FAR __far
#define PointerAttr FAR
#define FLASH_ADDR 0x27FF1 // 需要操作的Flash地址
void Flash_WriteNByte(u32 Addr, u8 *Buf);
void Flash_ReadNByte(u32 Addr, u16 Len, u8 *Rec_Buf);
#endif
File: STM8S208MB_General.h
/*
* @file: STM8S208MB_General.h
* @brief: STM8S208MB项目通用头文件
* @date: 2023-04-11
* @author: ArcherQAQ
*/
#ifndef __STM8S208MB_General_H__
#define __STM8S208MB_General_H__
/*************************包含头文件*******************************/
/*************************常用数据类型定义*************************/
/*!< Signed integer types */
typedef signed char int8_t;
typedef signed short int16_t;
typedef signed long int32_t;
/*!< Unsigned integer types */
typedef unsigned char uint8_t;
typedef unsigned short uint16_t;
typedef unsigned long uint32_t;
/*!< STM8 Standard Peripheral Library old types (maintained for legacy purpose) */
typedef int32_t s32;
typedef int16_t s16;
typedef int8_t s8;
typedef uint32_t u32;
typedef uint16_t u16;
typedef uint8_t u8;
/************************通用函数声明*************************/
void CLK_Init(void); // 时钟初始化函数
void delay(u16 cnt); // 延迟函数声明
#endif
File: mian.c
#include "iostm8s208mb.h"
#include "STM8S208MB_General.h"
#include "STM8S208MB_Flash_Op.h"
int main( void )
{
CLK_Init(); // 设置时钟为内部16MHz高速时钟
delay(200);// 延时系统时钟稳定
extern u8 dataBuf[];
extern u8 Rec_Buf[];
Flash_WriteNByte(FLASH_ADDR, dataBuf);
Flash_ReadNByte(FLASH_ADDR, 2, Rec_Buf);
while(1)
{
u8 i;
for(i = 0; i < 2; i++)
{
printf("第%d个读到的字节为:0x%.2x\r\n", i + 1, Rec_Buf[i]);
printf("\r\n");
printf("\r\n");
}
delay(100);
}
}
功能验证
连续在0x27FF1、0x27FF2地址中写入0xFF
连续读0x27FF1、0x27FF2两个地址
需要注意的一些点捏:)
-
u8*类型的无符号指针变量,在IAR中长度为16个bit,即2个字节;然而在VSCode中测试为32个bit,即4个字节
这说明数据类型的长度跟平台和编译器是有关联的,不能根据刻板印象来决定数据的类型,不确定数据类型的长度,则用
sizeof()
打印一下其具体占用多少个字节 -
如果不用
PointerAttr
来修饰u8* 类型指针变量的话,这就意味着,其指向的地址范围为:0x0000 ~ 0xFFFF,即64k的地址大小。开始写的时候没意识到这点,直接就用u8* 类型指针变量来存放了大于64k的地址。例子中读写的地址分别为0x27FF1和0x27FF2,这两个地址明显大于0xFFFF的,将其强行存进16位长度的u8*类型指针变量,显然会发生截断的情况如将0x27FF1放进16位长度的u8*类型指针变量,结果为0x7FF1,这显然不是我们需要访问的地址