有幸被选中参加STM32U0开发板的评测活动。原打算把一个智能坐垫的项目移植过来试一试功耗能不能降到更低。但无奈手头杂事太多,一再耽搁,今天小编通知我活动截至时间到了,也没来得及完成最终的实际功耗测试,索性功能移植的差不多了,就把移植过程中的一些记录拿来分享一下。
先来个开箱视频把,早就录好了。
然后就是移植过程中的一些记录。我是第一次接触STM32 的开发,原本一直在搞Arduino下的ESP32开发,所以这次是从头开始学习STM32开发的,所以记录一下移植过程。本次移植涉及到了RTC,串口、Flash以及低功耗等部分。
先说一下我的开发环境,我用的STM32Cube IDE开发。参考B站教程 。全网最完整最干练的CubeMX、CubeIDE STM32开发教程 拥抱高效Cube开发方式【3.1】—Kevin带你读《STM32Cube高效开发教程基础篇》_哔哩哔哩_bilibili
先来介绍下开发板的特点。
如下代码是把printf重定向到LUART1
/* USER CODE BEGIN Includes */
#include<stdio.h>
#include<string.h>
/* USER CODE END Includes */
/* Private variables ---------------------------------------------------------*/
UART_HandleTypeDef hlpuart1;
/* USER CODE BEGIN PV */
#ifdef __GNUC__
#define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
#else
#define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
#endif
PUTCHAR_PROTOTYPE
{
//同样USART2改为你的串口
HAL_UART_Transmit_IT(&hlpuart1, (uint8_t*)&ch,1);
return ch;
}
/* USER CODE END PV */
因为板卡上带有ST-LINK,用的是USART2或LPUART1(二选一),所以把printf重定向到LPUART1串口。
在IDE生成的代码中插入如下内容:
首先,您需要在 main.c 文件中的 USER CODE Includes 中包含 “stdio.h” 以使用 printf。
/* USER CODE BEGIN Includes */
#include <stdio.h>
/* USER CODE END Includes */
以下代码将编译器将标准输出连接到 printf 的 UART。
/* Private variables ---------------------------------------------------------*/
UART_HandleTypeDef hlpuart1;
/* USER CODE BEGIN PV */
#ifdef __GNUC__
#define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
#else
#define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
#endif
PUTCHAR_PROTOTYPE
{
//同样USART2改为你的串口
HAL_UART_Transmit_IT(&hlpuart1, (uint8_t*)&ch,1);
return ch;
}
/* USER CODE END PV */
上图为每1秒触发一次中断
导航到此处
函数 __weak void HAL_RTCEx_WakeUpTimerEventCallback(RTC_HandleTypeDef *hrtc)
是可以重新实现的,在main.c
文件中重新定义此函数。
/* USER CODE BEGIN 0 */
void HAL_RTCEx_WakeUpTimerEventCallback(RTC_HandleTypeDef *hrtc){
//中断处理程序
}
/* USER CODE END 0 */
以上函数在RTC唤醒后打印当前的日期和时间
/* USER CODE BEGIN WHILE */
RTC_TimeTypeDef sTime;
RTC_DateTypeDef sDate;
while (1)
{
HAL_RTC_GetTime(&hrtc, &sTime, RTC_FORMAT_BIN);
HAL_RTC_GetDate(&hrtc, &sDate, RTC_FORMAT_BIN);
printf(date_str,"%4d-%02d-%02d %02d:%02d:%02d\r\n",2000 + sDate.Year, sDate.Month, sDate.Date,sTime.Hours,sTime.Minutes,sTime.Seconds);
}
#include <time.h>
/* USER CODE BEGIN PFP */
int32_t stm32_rtc_readtimestamp(const RTC_TimeTypeDef rTime,const RTC_DateTypeDef rDate){
struct tm tm_new;
tm_new.tm_sec = rTime.Seconds;
tm_new.tm_min=rTime.Minutes;
tm_new.tm_hour=rTime.Hours - 8;
tm_new.tm_mday=rDate.Date;
tm_new.tm_mon=rDate.Month-1;
tm_new.tm_year=rDate.Year+100;
return mktime(&tm_new);
}
/* USER CODE END PFP */
int32_t timeStamp;
while (1)
{
......
timeStamp = stm32_rtc_readtimestamp(sTime,sDate);
printf("timestamp = %ld",timeStamp);
}
得到时间戳后,可以使用在线工具进行验证:时间戳(Unix timestamp)转换工具 - 在线工具。
将我们自己的时间戳输入进去,即可得到北京时间,以此进行验证。也可以将我们需要转换的时间输入进去,转换得到时间戳。
开启LPUART1,并修改针脚到PA2和PA3,这两个针脚可以直接通过开发板的Typec的虚拟串口访问。
开启LPUART2,并修改针脚到PC0和PC1,这两个针脚用于和蓝牙模块通讯。
开启串口中断
以下代码写入while中
HAL_GPIO_ReadPin(KEY_GPIO_Port, KEY_Pin);
if(GPIO_PIN_RESET == HAL_GPIO_ReadPin(KEY_GPIO_Port, KEY_Pin)){ //是否为低电平,按下为低电平
HAL_Delay(10);//软件消抖
if(GPIO_PIN_RESET == HAL_GPIO_ReadPin(KEY_GPIO_Port, KEY_Pin)){
HAL_GPIO_TogglePin(LD4_GPIO_Port, LD4_Pin);//小灯翻转
while(HAL_GPIO_ReadPin(KEY_GPIO_Port, KEY_Pin) == GPIO_PIN_RESET){}
}
}
在利用RTC闹钟唤醒standby模式中,需要关注的问题有:
1.关于功耗控制,需要对不使用的IO口进行漏电流的控制,因此,最好将没有使用的IO口都配置为模拟输入状态。
2.利用RTC闹钟进行唤醒时,需要注意闹钟中断触发后,中断标识是否被清除,否则,standby模式很可能在进入后立马退出。
3.如果要在退出standby模式后,RTC时钟需要继续按照设定的时间计时,需要通过后备寄存器来判断单片机是否是第一次启动。
运行 > 睡眠 > 停止 > 待机。
其中运行模式与睡眠模式功耗为mA级,停止模式与待机模式为uA级,其中待机最小可以达到<5uA。
如何进入?
睡眠模式:
执行WFI或WFE指令可以使MCU进入睡眠状态。
停止模式:
在以下条件下执行WFI或WFE指令:
1、设置Cortex-M3系统控制寄存器中的SLEEPDEEP位;
2、清除电源控制寄存器(PWR_CR)中的PDDS位 进入;
3、通过设置PWR_CR中LPDS位选择电压调节器的模式;
待机模式:
在以下条件下执行WFI或WFE指令:
1、设置Cortex-M3系统控制寄存器中的SLEEPDEEP位;
2、设置电源控制寄存器(PWR_CR)中的PDDS位;
3、清除电源控制/状态寄存器(PWR_CSR)中的WUF位;
如何退出?
睡眠模式:
如果是执行WFI指令进入睡眠模式,任意一个外设中断都能将系统从睡眠模式唤醒。如果是执行WFE指令进入睡眠模式,一旦发生唤醒事件时,微处理器都将从睡眠模式退出。
停止模式:
如果是执行WFI进入停止模式,任一外部中断线为中断模式可以唤醒。如果是执行WFE进入停止模式。任一外部中断线为事件模式可以唤醒。
待机模式:
待机模式唤醒只有4种:外部复位、IWDG复位、WKUP引脚上的上升沿或RTC闹钟事件的上升沿。并且从待机唤醒后,除了电源控制/状态寄存器,所有寄存器被复位。唤醒后的代码执行等同于复位后的执行。
在利用RTC闹钟唤醒standby模式中,需要关注的问题有:
1.关于功耗控制,需要对不使用的IO口进行漏电流的控制,因此,最好将没有使用的IO口都配置为模拟输入状态。参见针脚设置
2.利用RTC闹钟进行唤醒时,需要注意闹钟中断触发后,中断标识是否被清除,否则,standby模式很可能在进入后立马退出。
3.如果要在退出standby模式后,RTC时钟需要继续按照设定的时间计时,需要通过后备寄存器来判断单片机是否是第一次启动。
/* USER CODE BEGIN 0 */
void sys_enter_standby_mode(void)
{
GPIO_AnalogState_Config(); //禁用GPIO
__HAL_RCC_PWR_CLK_ENABLE(); // 使能PWR时钟
HAL_PWR_EnableBkUpAccess();
HAL_PWR_EnterSTANDBYMode(); //进入待机模式
}
/* USER CODE END 0 */
static void MX_RTC_Init(void)
{
......
/* USER CODE BEGIN RTC_Init 1 */
HAL_PWR_EnableBkUpAccess();
/* USER CODE END RTC_Init 1 */
......
......
/* USER CODE BEGIN Check_RTC_BKUP */
if(HAL_RTCEx_BKUPRead(&hrtc,RTC_BKP_DR1) != 0xA5A5) //判断后备寄存器是否被赋值
{
/* USER CODE END Check_RTC_BKUP */
/** Initialize RTC and set the Time and Date
*/
......
......
......
/* USER CODE BEGIN RTC_Init 2 */
HAL_RTCEx_BKUPWrite(&hrtc, RTC_BKP_DR1, 0xA5A5); //这里就是将这个寄存器的标志设为刚才的那个值,下次掉电后就不会进入到这里来
}
else
{
if (HAL_RTCEx_SetWakeUpTimer_IT(&hrtc, 0, RTC_WAKEUPCLOCK_CK_SPRE_16BITS, 0) != HAL_OK)
{
Error_Handler();
} /* RTC的中断配置初始化以及启动 */
}
/* USER CODE END RTC_Init 2 */
}
这个函数主要是为了在低功耗状态下,尽量控制IO上不必要的漏电流产生。在进入待机模式前调用。
/* USER CODE BEGIN 2 */
void GPIO_AnalogState_Config(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
/*Set all GPIO in analog state to reduce power consumption*/
__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE();
__HAL_RCC_GPIOC_CLK_ENABLE();
GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Pin = GPIO_PIN_All;
HAL_GPIO_Init(GPIOA,&GPIO_InitStruct);
HAL_GPIO_Init(GPIOB,&GPIO_InitStruct);
HAL_GPIO_Init(GPIOC,&GPIO_InitStruct);
__HAL_RCC_GPIOA_CLK_DISABLE();
__HAL_RCC_GPIOB_CLK_DISABLE();
__HAL_RCC_GPIOC_CLK_DISABLE();
}
/* USER CODE END 2 */
上ST-LINKUtility 查看flash占用情况
本器件地址为0x08000000 到 0x0803EED0
可以从0x08020000 开始进行写入。本MCU仅支持双位操作。
int d1 =0;
int d2 =0;
uint32_t flashwriteaddr = 0x08020000; //定义写入数据的地址
uint32_t pageError = 0;
uint64_t flashwritedata = u32_to_u64(946657215,946658888);//0x386CD7BE00000002;//要写入的数据,必须得是双字64bit
FLASH_EraseInitTypeDef flash_erase; //定义一个结构体变量,里面有擦除操作需要定义的变量
HAL_FLASH_Unlock(); //第二步:解锁
flash_erase.TypeErase = FLASH_TYPEERASE_PAGES; //擦除类型是“Page Erase”
flash_erase.Page = 64; //擦除第16页
flash_erase.NbPages = 1; //一次性擦除2页,可以是任意页
HAL_FLASHEx_Erase(&flash_erase,&pageError); //第三步:参数写好后调用擦除函数
HAL_FLASH_Program(FLASH_TYPEPROGRAM_DOUBLEWORD, flashwriteaddr, flashwritedata);//第四步:写入数据
HAL_FLASH_Lock(); //第五步:上锁
d1 = *(__IO uint32_t *)flashwriteaddr; //读出flash中的数据
d2 = *(__IO uint32_t *)(flashwriteaddr+4); //地址偏移+4
printf("read data:%d %d\r\n",d2,d1);
HAL_Delay(200);
/**
* 通过位操作实现2个uint32_t合并为uint64_t
*/
uint64_t u32_to_u64(uint32_t d1,uint32_t d2){
//先将uint32_t的a转为uint64_t,此时a前面32位都是0,然后左移32位,此时右32位为0,最后加上uint32_t类型的b,填充右32位的0
return (uint64_t)(((uint64_t)d1) << 32) + d2;
}
以下是开发板载的mcu的分页表。
//STM32u0的FLASH大小为256KB,只有128个页
#define ADDR_FLASH_PAGE_0 ((uint32_t)0x08000000) /* Base @ of Page 0, 2 Kbytes */
#define ADDR_FLASH_PAGE_1 ((uint32_t)0x08000800) /* Base @ of Page 1, 2 Kbytes */
#define ADDR_FLASH_PAGE_2 ((uint32_t)0x08001000) /* Base @ of Page 2, 2 Kbytes */
#define ADDR_FLASH_PAGE_3 ((uint32_t)0x08001800) /* Base @ of Page 3, 2 Kbytes */
#define ADDR_FLASH_PAGE_4 ((uint32_t)0x08002000) /* Base @ of Page 4, 2 Kbytes */
#define ADDR_FLASH_PAGE_5 ((uint32_t)0x08002800) /* Base @ of Page 5, 2 Kbytes */
#define ADDR_FLASH_PAGE_6 ((uint32_t)0x08003000) /* Base @ of Page 6, 2 Kbytes */
#define ADDR_FLASH_PAGE_7 ((uint32_t)0x08003800) /* Base @ of Page 7, 2 Kbytes */
#define ADDR_FLASH_PAGE_8 ((uint32_t)0x08004000) /* Base @ of Page 8, 2 Kbytes */
#define ADDR_FLASH_PAGE_9 ((uint32_t)0x08004800) /* Base @ of Page 9, 2 Kbytes */
#define ADDR_FLASH_PAGE_10 ((uint32_t)0x08005000) /* Base @ of Page 10, 2 Kbytes */
#define ADDR_FLASH_PAGE_11 ((uint32_t)0x08005800) /* Base @ of Page 11, 2 Kbytes */
#define ADDR_FLASH_PAGE_12 ((uint32_t)0x08006000) /* Base @ of Page 12, 2 Kbytes */
#define ADDR_FLASH_PAGE_13 ((uint32_t)0x08006800) /* Base @ of Page 13, 2 Kbytes */
#define ADDR_FLASH_PAGE_14 ((uint32_t)0x08007000) /* Base @ of Page 14, 2 Kbytes */
#define ADDR_FLASH_PAGE_15 ((uint32_t)0x08007800) /* Base @ of Page 15, 2 Kbytes */
#define ADDR_FLASH_PAGE_16 ((uint32_t)0x08008000) /* Base @ of Page 16, 2 Kbytes */
#define ADDR_FLASH_PAGE_17 ((uint32_t)0x08008800) /* Base @ of Page 17, 2 Kbytes */
#define ADDR_FLASH_PAGE_18 ((uint32_t)0x08009000) /* Base @ of Page 18, 2 Kbytes */
#define ADDR_FLASH_PAGE_19 ((uint32_t)0x08009800) /* Base @ of Page 19, 2 Kbytes */
#define ADDR_FLASH_PAGE_20 ((uint32_t)0x0800A000) /* Base @ of Page 20, 2 Kbytes */
#define ADDR_FLASH_PAGE_21 ((uint32_t)0x0800A800) /* Base @ of Page 21, 2 Kbytes */
#define ADDR_FLASH_PAGE_22 ((uint32_t)0x0800B000) /* Base @ of Page 22, 2 Kbytes */
#define ADDR_FLASH_PAGE_23 ((uint32_t)0x0800B800) /* Base @ of Page 23, 2 Kbytes */
#define ADDR_FLASH_PAGE_24 ((uint32_t)0x0800C000) /* Base @ of Page 24, 2 Kbytes */
#define ADDR_FLASH_PAGE_25 ((uint32_t)0x0800C800) /* Base @ of Page 25, 2 Kbytes */
#define ADDR_FLASH_PAGE_26 ((uint32_t)0x0800D000) /* Base @ of Page 26, 2 Kbytes */
#define ADDR_FLASH_PAGE_27 ((uint32_t)0x0800D800) /* Base @ of Page 27, 2 Kbytes */
#define ADDR_FLASH_PAGE_28 ((uint32_t)0x0800E000) /* Base @ of Page 28, 2 Kbytes */
#define ADDR_FLASH_PAGE_29 ((uint32_t)0x0800E800) /* Base @ of Page 29, 2 Kbytes */
#define ADDR_FLASH_PAGE_30 ((uint32_t)0x0800F000) /* Base @ of Page 30, 2 Kbytes */
#define ADDR_FLASH_PAGE_31 ((uint32_t)0x0800F800) /* Base @ of Page 31, 2 Kbytes */
#define ADDR_FLASH_PAGE_32 ((uint32_t)0x08010000) /* Base @ of Page 32, 2 Kbytes */
#define ADDR_FLASH_PAGE_33 ((uint32_t)0x08010800) /* Base @ of Page 33, 2 Kbytes */
#define ADDR_FLASH_PAGE_34 ((uint32_t)0x08011000) /* Base @ of Page 34, 2 Kbytes */
#define ADDR_FLASH_PAGE_35 ((uint32_t)0x08011800) /* Base @ of Page 35, 2 Kbytes */
#define ADDR_FLASH_PAGE_36 ((uint32_t)0x08012000) /* Base @ of Page 36, 2 Kbytes */
#define ADDR_FLASH_PAGE_37 ((uint32_t)0x08012800) /* Base @ of Page 37, 2 Kbytes */
#define ADDR_FLASH_PAGE_38 ((uint32_t)0x08013000) /* Base @ of Page 38, 2 Kbytes */
#define ADDR_FLASH_PAGE_39 ((uint32_t)0x08013800) /* Base @ of Page 39, 2 Kbytes */
#define ADDR_FLASH_PAGE_40 ((uint32_t)0x08014000) /* Base @ of Page 40, 2 Kbytes */
#define ADDR_FLASH_PAGE_41 ((uint32_t)0x08014800) /* Base @ of Page 41, 2 Kbytes */
#define ADDR_FLASH_PAGE_42 ((uint32_t)0x08015000) /* Base @ of Page 42, 2 Kbytes */
#define ADDR_FLASH_PAGE_43 ((uint32_t)0x08015800) /* Base @ of Page 43, 2 Kbytes */
#define ADDR_FLASH_PAGE_44 ((uint32_t)0x08016000) /* Base @ of Page 44, 2 Kbytes */
#define ADDR_FLASH_PAGE_45 ((uint32_t)0x08016800) /* Base @ of Page 45, 2 Kbytes */
#define ADDR_FLASH_PAGE_46 ((uint32_t)0x08017000) /* Base @ of Page 46, 2 Kbytes */
#define ADDR_FLASH_PAGE_47 ((uint32_t)0x08017800) /* Base @ of Page 47, 2 Kbytes */
#define ADDR_FLASH_PAGE_48 ((uint32_t)0x08018000) /* Base @ of Page 48, 2 Kbytes */
#define ADDR_FLASH_PAGE_49 ((uint32_t)0x08018800) /* Base @ of Page 49, 2 Kbytes */
#define ADDR_FLASH_PAGE_50 ((uint32_t)0x08019000) /* Base @ of Page 50, 2 Kbytes */
#define ADDR_FLASH_PAGE_51 ((uint32_t)0x08019800) /* Base @ of Page 51, 2 Kbytes */
#define ADDR_FLASH_PAGE_52 ((uint32_t)0x0801A000) /* Base @ of Page 52, 2 Kbytes */
#define ADDR_FLASH_PAGE_53 ((uint32_t)0x0801A800) /* Base @ of Page 53, 2 Kbytes */
#define ADDR_FLASH_PAGE_54 ((uint32_t)0x0801B000) /* Base @ of Page 54, 2 Kbytes */
#define ADDR_FLASH_PAGE_55 ((uint32_t)0x0801B800) /* Base @ of Page 55, 2 Kbytes */
#define ADDR_FLASH_PAGE_56 ((uint32_t)0x0801C000) /* Base @ of Page 56, 2 Kbytes */
#define ADDR_FLASH_PAGE_57 ((uint32_t)0x0801C800) /* Base @ of Page 57, 2 Kbytes */
#define ADDR_FLASH_PAGE_58 ((uint32_t)0x0801D000) /* Base @ of Page 58, 2 Kbytes */
#define ADDR_FLASH_PAGE_59 ((uint32_t)0x0801D800) /* Base @ of Page 59, 2 Kbytes */
#define ADDR_FLASH_PAGE_60 ((uint32_t)0x0801E000) /* Base @ of Page 60, 2 Kbytes */
#define ADDR_FLASH_PAGE_61 ((uint32_t)0x0801E800) /* Base @ of Page 61, 2 Kbytes */
#define ADDR_FLASH_PAGE_62 ((uint32_t)0x0801F000) /* Base @ of Page 62, 2 Kbytes */
#define ADDR_FLASH_PAGE_63 ((uint32_t)0x0801F800) /* Base @ of Page 63, 2 Kbytes */
#define ADDR_FLASH_PAGE_64 ((uint32_t)0x08020000) /* Base @ of Page 64, 2 Kbytes */
#define ADDR_FLASH_PAGE_65 ((uint32_t)0x08020800) /* Base @ of Page 65, 2 Kbytes */
#define ADDR_FLASH_PAGE_66 ((uint32_t)0x08021000) /* Base @ of Page 66, 2 Kbytes */
#define ADDR_FLASH_PAGE_67 ((uint32_t)0x08021800) /* Base @ of Page 67, 2 Kbytes */
#define ADDR_FLASH_PAGE_68 ((uint32_t)0x08022000) /* Base @ of Page 68, 2 Kbytes */
#define ADDR_FLASH_PAGE_69 ((uint32_t)0x08022800) /* Base @ of Page 69, 2 Kbytes */
#define ADDR_FLASH_PAGE_70 ((uint32_t)0x08023000) /* Base @ of Page 70, 2 Kbytes */
#define ADDR_FLASH_PAGE_71 ((uint32_t)0x08023800) /* Base @ of Page 71, 2 Kbytes */
#define ADDR_FLASH_PAGE_72 ((uint32_t)0x08024000) /* Base @ of Page 72, 2 Kbytes */
#define ADDR_FLASH_PAGE_73 ((uint32_t)0x08024800) /* Base @ of Page 73, 2 Kbytes */
#define ADDR_FLASH_PAGE_74 ((uint32_t)0x08025000) /* Base @ of Page 74, 2 Kbytes */
#define ADDR_FLASH_PAGE_75 ((uint32_t)0x08025800) /* Base @ of Page 75, 2 Kbytes */
#define ADDR_FLASH_PAGE_76 ((uint32_t)0x08026000) /* Base @ of Page 76, 2 Kbytes */
#define ADDR_FLASH_PAGE_77 ((uint32_t)0x08026800) /* Base @ of Page 77, 2 Kbytes */
#define ADDR_FLASH_PAGE_78 ((uint32_t)0x08027000) /* Base @ of Page 78, 2 Kbytes */
#define ADDR_FLASH_PAGE_79 ((uint32_t)0x08027800) /* Base @ of Page 79, 2 Kbytes */
#define ADDR_FLASH_PAGE_80 ((uint32_t)0x08028000) /* Base @ of Page 80, 2 Kbytes */
#define ADDR_FLASH_PAGE_81 ((uint32_t)0x08028800) /* Base @ of Page 81, 2 Kbytes */
#define ADDR_FLASH_PAGE_82 ((uint32_t)0x08029000) /* Base @ of Page 82, 2 Kbytes */
#define ADDR_FLASH_PAGE_83 ((uint32_t)0x08029800) /* Base @ of Page 83, 2 Kbytes */
#define ADDR_FLASH_PAGE_84 ((uint32_t)0x0802A000) /* Base @ of Page 84, 2 Kbytes */
#define ADDR_FLASH_PAGE_85 ((uint32_t)0x0802A800) /* Base @ of Page 85, 2 Kbytes */
#define ADDR_FLASH_PAGE_86 ((uint32_t)0x0802B000) /* Base @ of Page 86, 2 Kbytes */
#define ADDR_FLASH_PAGE_87 ((uint32_t)0x0802B800) /* Base @ of Page 87, 2 Kbytes */
#define ADDR_FLASH_PAGE_88 ((uint32_t)0x0802C000) /* Base @ of Page 88, 2 Kbytes */
#define ADDR_FLASH_PAGE_89 ((uint32_t)0x0802C800) /* Base @ of Page 89, 2 Kbytes */
#define ADDR_FLASH_PAGE_90 ((uint32_t)0x0802D000) /* Base @ of Page 90, 2 Kbytes */
#define ADDR_FLASH_PAGE_91 ((uint32_t)0x0802D800) /* Base @ of Page 91, 2 Kbytes */
#define ADDR_FLASH_PAGE_92 ((uint32_t)0x0802E000) /* Base @ of Page 92, 2 Kbytes */
#define ADDR_FLASH_PAGE_93 ((uint32_t)0x0802E800) /* Base @ of Page 93, 2 Kbytes */
#define ADDR_FLASH_PAGE_94 ((uint32_t)0x0802F000) /* Base @ of Page 94, 2 Kbytes */
#define ADDR_FLASH_PAGE_95 ((uint32_t)0x0802F800) /* Base @ of Page 95, 2 Kbytes */
#define ADDR_FLASH_PAGE_96 ((uint32_t)0x08030000) /* Base @ of Page 96, 2 Kbytes */
#define ADDR_FLASH_PAGE_97 ((uint32_t)0x08030800) /* Base @ of Page 97, 2 Kbytes */
#define ADDR_FLASH_PAGE_98 ((uint32_t)0x08031000) /* Base @ of Page 98, 2 Kbytes */
#define ADDR_FLASH_PAGE_99 ((uint32_t)0x08031800) /* Base @ of Page 99, 2 Kbytes */
#define ADDR_FLASH_PAGE_100 ((uint32_t)0x08032000) /* Base @ of Page 100, 2 Kbytes */
#define ADDR_FLASH_PAGE_101 ((uint32_t)0x08032800) /* Base @ of Page 101, 2 Kbytes */
#define ADDR_FLASH_PAGE_102 ((uint32_t)0x08033000) /* Base @ of Page 102, 2 Kbytes */
#define ADDR_FLASH_PAGE_103 ((uint32_t)0x08033800) /* Base @ of Page 103, 2 Kbytes */
#define ADDR_FLASH_PAGE_104 ((uint32_t)0x08034000) /* Base @ of Page 104, 2 Kbytes */
#define ADDR_FLASH_PAGE_105 ((uint32_t)0x08034800) /* Base @ of Page 105, 2 Kbytes */
#define ADDR_FLASH_PAGE_106 ((uint32_t)0x08035000) /* Base @ of Page 106, 2 Kbytes */
#define ADDR_FLASH_PAGE_107 ((uint32_t)0x08035800) /* Base @ of Page 107, 2 Kbytes */
#define ADDR_FLASH_PAGE_108 ((uint32_t)0x08036000) /* Base @ of Page 108, 2 Kbytes */
#define ADDR_FLASH_PAGE_109 ((uint32_t)0x08036800) /* Base @ of Page 109, 2 Kbytes */
#define ADDR_FLASH_PAGE_110 ((uint32_t)0x08037000) /* Base @ of Page 110, 2 Kbytes */
#define ADDR_FLASH_PAGE_111 ((uint32_t)0x08037800) /* Base @ of Page 111, 2 Kbytes */
#define ADDR_FLASH_PAGE_112 ((uint32_t)0x08038000) /* Base @ of Page 112, 2 Kbytes */
#define ADDR_FLASH_PAGE_113 ((uint32_t)0x08038800) /* Base @ of Page 113, 2 Kbytes */
#define ADDR_FLASH_PAGE_114 ((uint32_t)0x08039000) /* Base @ of Page 114, 2 Kbytes */
#define ADDR_FLASH_PAGE_115 ((uint32_t)0x08039800) /* Base @ of Page 115, 2 Kbytes */
#define ADDR_FLASH_PAGE_116 ((uint32_t)0x0803A000) /* Base @ of Page 116, 2 Kbytes */
#define ADDR_FLASH_PAGE_117 ((uint32_t)0x0803A800) /* Base @ of Page 117, 2 Kbytes */
#define ADDR_FLASH_PAGE_118 ((uint32_t)0x0803B000) /* Base @ of Page 118, 2 Kbytes */
#define ADDR_FLASH_PAGE_119 ((uint32_t)0x0803B800) /* Base @ of Page 119, 2 Kbytes */
#define ADDR_FLASH_PAGE_120 ((uint32_t)0x0803C000) /* Base @ of Page 120, 2 Kbytes */
#define ADDR_FLASH_PAGE_121 ((uint32_t)0x0803C800) /* Base @ of Page 121, 2 Kbytes */
#define ADDR_FLASH_PAGE_122 ((uint32_t)0x0803D000) /* Base @ of Page 122, 2 Kbytes */
#define ADDR_FLASH_PAGE_123 ((uint32_t)0x0803D800) /* Base @ of Page 123, 2 Kbytes */
#define ADDR_FLASH_PAGE_124 ((uint32_t)0x0803E000) /* Base @ of Page 124, 2 Kbytes */
#define ADDR_FLASH_PAGE_125 ((uint32_t)0x0803E800) /* Base @ of Page 125, 2 Kbytes */
#define ADDR_FLASH_PAGE_126 ((uint32_t)0x0803F000) /* Base @ of Page 126, 2 Kbytes */
#define ADDR_FLASH_PAGE_127 ((uint32_t)0x0803F800) /* Base @ of Page 127, 2 Kbytes */
本帖最后由 nengzhi 于 2024-6-3 17:38 编辑
感谢楼主的评测分享,这一章内容非常多呀,期待您的最终作品程现!