普冉(PUYA)单片机开发笔记(9): FLASH 读写

概述

单片机的 ROM 容量虽然不大,PY32F003 有 64K 字节的 ROM,但实际应用中会在 MCU 中存储持久化的数据,例如:在物联网应用中,需要把物模型持久化,作为非易失性数据,掉电了也要保存。这就要用到在 FLASH 保存这些数据。

PY32F003 支持 FLASH 读写。

PY32F003 的 FLASH 写入支持“按页写入”、“按扇区写入”和“全部写入”三种方式,实用中常会用到前两种方式。PY32F003 的 FLASH 页(Page)是一块 128 字节的 ROM 区域,可以直接寻址;扇区(Sector)是一块 4096 字节的 ROM 区域,可以直接寻址。

数据手册上列出了 FLASH 的可寻址空间和访问限制(后面有数据手册的截图)。

好啦,干货奉上 ;)

实现代码

老样子,以下几个步骤,就能搞好。

在 main.h 中声明 FLASH 读写的函数

/** ----------------------------------------------------------------------------
* @name   : uint32_t* Flash_Read(void);
* @brief  : 从预设的FLASH地址读取1页(128 Byte)的数据,保存在 data 中
* @param  : None.
* @retval : NULL 或者数据的首地址
* @remark : 
*** ----------------------------------------------------------------------------
*/
uint32_t* Flash_Read(uint16_t* buf_size);/** ----------------------------------------------------------------------------
* @name   : HAL_StatusTypeDef Flash_Write(uint32_t *data);
* @brief  : 从预设的FLASH地址写入1页(128Byte)的数据,data是要写入的数据
* @param  : [in] data: 要写入的数据指针.
* @param  : [in] data_size: 要写入的数据长度
* @retval : HAL_OK: 写入成功; 其它: 错误
* @remark : 上级函数必须检查操作返回值, 只有 HAL_OK 时才是有效数据
*** ----------------------------------------------------------------------------
*/
HAL_StatusTypeDef Flash_Write(uint32_t* data, const uint16_t data_size);

在 app_flash.c 中实现 FLASH 读写的函数

/********************************************************************************* @file    app_flash.c* @brief   Application level Flash read/write/erase codes.******************************************************************************* @attention** Copyright (c) 2023 CuteModem Intelligence.* All rights reserved.** This software is licensed under terms that can be found in the LICENSE file* in the root directory of this software component.* If no LICENSE file comes with this software, it is provided AS-IS.********************************************************************************/#include "main.h"/* 定义用户数据在 FLASH 中存储的首地址, 这里指定了扇区号8, 页号256的首地址 */
#define FLASH_USER_START_ADDR 0x08007000
#define FLASH_USER_BUFF_SIZE  32/* 定义用户数据: 32*4=128 Bytes, 1 page */
uint32_t WD_BUF[FLASH_USER_BUFF_SIZE] = { 0 };
uint32_t RD_BUF[FLASH_USER_BUFF_SIZE] = { 0 };/** ----------------------------------------------------------------------------
* @name   : HAL_StatusTypeDef app_Flash_Erase(void);
* @brief  : 擦除从预设的FLASH地址的1页(128Byte)FLASH
* @param  : None.
* @retval : HAL_StatusTypeDef. 操作成功返回 HAL_OK, 错误返回错误码
* @remark : 上级函数必须检查操作返回值, 只有 HAL_OK 时才能继续操作
*** ----------------------------------------------------------------------------
*/
static HAL_StatusTypeDef app_Flash_Erase(void)
{uint32_t PAGEError = 0;FLASH_EraseInitTypeDef EraseInitStruct;EraseInitStruct.TypeErase   = FLASH_TYPEERASE_PAGEERASE;        // 擦写类型: 按页擦EraseInitStruct.PageAddress = FLASH_USER_START_ADDR;            // 擦写起始地址EraseInitStruct.NbPages  = sizeof(WD_BUF) / FLASH_PAGE_SIZE;    // 需要擦写的页数量if (HAL_FLASHEx_Erase(&EraseInitStruct, &PAGEError) != HAL_OK)  // 执行page擦除,PAGEError返回擦写错误的page,return HAL_ERROR;                                           // 返回0xFFFFFFFF, 表示擦写成功return HAL_OK;
}/** ----------------------------------------------------------------------------
* @name   : HAL_StatusTypeDef Local_Flash_Check_Blank(void);
* @brief  : 查空 FLASH 中已被擦除的地址
* @param  : None.
* @retval : HAL_StatusTypeDef. 操作成功返回 HAL_OK, 错误返回错误码
* @remark : 上级函数必须检查操作返回值, 只有 HAL_OK 时才能继续操作
*** ----------------------------------------------------------------------------
*/
static HAL_StatusTypeDef Local_Flash_Check_Blank(void)
{uint32_t addr = 0;while (addr < sizeof(WD_BUF)){if (0xFFFFFFFF != HW32_REG(FLASH_USER_START_ADDR + addr))return HAL_ERROR;addr += 4;}return HAL_OK;
}/** ----------------------------------------------------------------------------
* @name   : HAL_StatusTypeDef Local_Flash_Program(void);
* @brief  : 写预设地址的 FLASH
* @param  : None.
* @retval : HAL_StatusTypeDef. 操作成功返回 HAL_OK, 错误返回错误码
* @remark : 上级函数必须检查操作返回值, 只有 HAL_OK 时才能继续操作
*** ----------------------------------------------------------------------------
*/
static HAL_StatusTypeDef Local_Flash_Program(void)
{uint32_t flash_program_start = FLASH_USER_START_ADDR ;                 // flash写起始地址uint32_t flash_program_end = (FLASH_USER_START_ADDR + sizeof(WD_BUF)); // flash写结束地址uint32_t *src = (uint32_t *)WD_BUF;                                    // 数组指针while (flash_program_start < flash_program_end){if (HAL_FLASH_Program(FLASH_TYPEPROGRAM_PAGE, flash_program_start, src) != HAL_OK){return HAL_ERROR;}flash_program_start += FLASH_PAGE_SIZE; //flash 起始指针指向下一个 pagesrc += FLASH_PAGE_SIZE / 4;             //更新数据指针}return HAL_OK;
}/** ----------------------------------------------------------------------------
* @name   : HAL_StatusTypeDef Flash_Read(void);
* @brief  : 校验预设的FLASH地址开始的1页(128Byte)的数据
* @param  : None.
* @retval : HAL_StatusTypeDef. 操作成功返回 HAL_OK, 错误返回错误码。
* @remark : 上级函数必须检查操作返回值, 只有 HAL_OK 时才是有效数据
*** ----------------------------------------------------------------------------
*/
static HAL_StatusTypeDef Local_Flash_Verify(void)
{uint32_t addr = 0;while (addr < sizeof(WD_BUF)){if (WD_BUF[addr / 4] != HW32_REG(FLASH_USER_START_ADDR + addr)){return HAL_ERROR;}addr += 4;}return HAL_OK;
}/** ----------------------------------------------------------------------------
* @name   : Local_Flash_Print(const uint32_t* data, const uint16_t data_size);
* @brief  : 打印 data_size 个 data
* @param  : None.
* @retval : NULL 或者数据的首地址
* @remark : 
*** ----------------------------------------------------------------------------
*/
static void Local_Flash_Print(const uint32_t* data, const uint16_t data_size)
{printf("%d bytes of data in FLASH:\r\n", data_size*sizeof(uint32_t));for(int i = 0; i < data_size; i++){printf("0x%08X ", data[i]);if((i + 1) % 4 == 0) printf("\r\n");}printf("\r\n");
}/** ----------------------------------------------------------------------------
* @name   : uint32_t* Flash_Read(void);
* @brief  : 从预设的FLASH地址读取1页(128Byte)的数据,保存在 data 中
* @param  : None.
* @retval : NULL 或者数据的首地址
* @remark : 
*** ----------------------------------------------------------------------------
*/
uint32_t* Flash_Read(uint16_t* buf_size)
{uint32_t addr = 0;while (addr < sizeof(RD_BUF)){RD_BUF[addr / 4] = HW32_REG(FLASH_USER_START_ADDR + addr);addr += 4;}*buf_size = FLASH_USER_BUFF_SIZE;Local_Flash_Print((uint32_t*)(&RD_BUF[0]), *buf_size);return (uint32_t*)(&RD_BUF[0]);
}/** ----------------------------------------------------------------------------
* @name   : Flash_Write(uint32_t* data, const uint16_t data_size);
* @brief  : 从预设的FLASH地址写入1页(128Byte)的数据,data是要写入的数据
* @param  : [in] data, 一个 uint32_t 的数据缓冲区的首地址, 128字节
* @retval : HAL_HandleTypeDef. 操作成功返回 HAL_OK, 错误则返回错误码。
* @remark : 上级函数必须检查操作返回值, 只有 HAL_OK 时才是正确的操作
*** ----------------------------------------------------------------------------
*/
HAL_StatusTypeDef Flash_Write(uint32_t* data, const uint16_t data_size)
{HAL_StatusTypeDef res = HAL_BUSY;int i = 0;uint16_t w_size = data_size;if(data_size > FLASH_USER_BUFF_SIZE) w_size = FLASH_USER_BUFF_SIZE;for(i = 0; i < w_size; i++) WD_BUF[i] = data[i];for(i = w_size; i< FLASH_USER_BUFF_SIZE; i++) WD_BUF[i] = 0U;res = HAL_FLASH_Unlock(); // 解锁 FLASHif(res != HAL_OK ) return res;res = app_Flash_Erase();if(res != HAL_OK ) return res;res = Local_Flash_Check_Blank();if(res != HAL_OK ) return res;res = Local_Flash_Program();if(res != HAL_OK ) return res;res = Local_Flash_Verify();if(res != HAL_OK ) return res;res = HAL_FLASH_Lock();   // 锁定 FLASHif(res != HAL_OK ) return res;return HAL_OK;
}

说明:

  1. 参考厂家的数据手册,选择 FLASH 地址空间的最后一个扇区( Sector 8)的第一页作为存储区域。通过 #define FLASH_USER_START_ADDR 0x08007000 进行定义,同时定义 FLASH_USER_BUFF_SIZE 为 32,把这个页占满。
  2. 定义写数据缓冲区(WD_BUF )和读数据缓冲区(RD_BUF)变量,缓冲区长度设置为 128 字节:32 个 uint32_4 类型整数,占用 FLASH 容量等于 32 X 4 = 128。
  3. 完成“擦写”、“查空”、“编程(写入)”和“校验” 4 个函数的编码。
  4. 写了一个测试用的格式化打印函数。以上这五个函数是 FLASH 操作的底层函数,对上级调用 FLASH 读写功能的函数不必可见,因此都定义成了 static 类型。
  5. 完成 Flash_Read 函数。直接访问预定义的 FLASH 内存空间首地址开始的一页数据,存放在缓冲区 RD_BUF 中,Flash_Read 函数返回 RD_BUF 的首地址。
  6. 完成 Flash_Write 函数。FLASH 写的顺序是“解锁 --> 擦除 --> 查空 --> 写入 --> 校验 --> 锁定”,本文采取了全部检查的方式进行写操作,只要中间任何一步出错就返回。如果“信得过” MCU 的话,“查空”这一步可以省区。

在 main.c 中完成调用

/********************************************************************************* @file    main.c* @brief   Main program entry.******************************************************************************* @copyright** Copyright (c) 2023 CuteModem Intelligence.* All rights reserved.** This software is licensed under terms that can be found in the LICENSE file* in the root directory of this software component.* If no LICENSE file comes with this software, it is provided AS-IS.********************************************************************************//* Private includes*/
#include "main.h"
#include <stdio.h>
/* Private define ------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
struct Student_t {uint32_t pri_id;char stu_id[13];char name[25];uint8_t grade;uint8_t class;char performance[17];
};/* Private function prototypes -----------------------------------------------*/
/* Private user code ---------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*//**
* -------------------------------------------------------------------------
* @file   : int main(void)
* @brief  : main函数
* @param  : 无
* @retval : 无限循环,无返回值
* @remark : 
* -------------------------------------------------------------------------
*/
int main(void)
{HAL_Init();             // systick初始化SystemClock_Config();   // 配置系统时钟GPIO_Config();if(USART_Config() != HAL_OK) Error_Handler();         printf("[SYS_INIT] Debug port initilaized.\r\n");printf("\r\n+---------------------------------------+""\r\n|        PY32F003 MCU is ready.         |""\r\n+---------------------------------------+""\r\n         10 digits sent to you!          ""\r\n+---------------------------------------+""\r\n");HAL_Delay(0);if (DBG_UART_Start() != HAL_OK) Error_Handler();HAL_Delay(0);struct Student_t stu1, stu2;uint16_t stu_rec_size = sizeof(stu1);uint16_t data_size = 0;uint32_t* flash_data = Flash_Read(&data_size);stu2 = *((struct Student_t *)flash_data);printf("Previous saved student profile: %d bytes \r\n""  Primary ID = %d\r\n""  Student ID = '%s'\r\n""        Name = '%s'\r\n""       Grade = %d\r\n""       Class = %d\r\n"" Performance = '%s'\r\n", data_size * 4,stu2.pri_id, stu2.stu_id, stu2.name, stu2.grade, stu2.class,stu2.performance);memset(&stu1, 0, sizeof(stu1));stu1.pri_id = 24506;strcpy(stu1.stu_id, "CSTU-2020-02");strcpy(stu1.name, "Zhang Lao 4");stu1.grade = 2;stu1.class = 11;strcpy(stu1.performance,"A+A-B+B++");printf("Current student profile: %d bytes.\r\n"" Primary ID = %d\r\n"" Student ID = '%s'\r\n""       Name = '%s'\r\n""      Grade = %d\r\n""      Class = %d\r\n"" Performance = '%s'\r\n", stu_rec_size,stu1.pri_id, stu1.stu_id, stu1.name, stu1.grade, stu1.class,stu1.performance);if(Flash_Write((uint32_t*)(&stu1), stu_rec_size) != HAL_OK ) {printf("Data updating error.\r\n");Error_Handler();}while (1){ BSP_LED_Toggle(LED3);HAL_Delay(500);}
}/**
* -------------------------------------------------------------------------
* @brief  : void Error_Handler(void)
* @detail : 错误陷阱函数,提示错误,然后死循环
* @param  : 无
* @retval : 无
* @remark : 
* -------------------------------------------------------------------------
*/
void Error_Handler(void)
{Debug_Info("[__ERROR_] System halt.");while (1) {}
}#ifdef USE_FULL_ASSERT
/*** @brief  Reports the name of the source file and the source line number*         where the assert_param error has occurred.* @param  file: pointer to the source file name* @param  line: assert_param error line source number* @retval None*/
void assert_failed(uint8_t *file, uint32_t line)
{/* User can add his own implementation to report the file name and line number,tex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
}
#endif /* USE_FULL_ASSERT */

说明:

  1. 首先定义了一个简单的“学生档案”的结构体,结构体的尺寸不能超过128字节。考虑到可能的“四字节”对齐,这个结构体的尺寸不一定等于各个元素尺寸的算术和,需要使用 sizeof() 运算符事先打印一下这个结构体的尺寸。
  2. 然后是和以前的实验相同的时钟选择、LED 和串口的初始化。
  3. 从 FLASH 中读取上一次写入的数据(uint32_t*),使用强制类型转换,得到学生档案结构体的数据,并打印出来。
  4. 更新这个结构体一些元素的数值,使用强制类型转换,重新写入 FLASH。

实验结果

利用主程序的顺序,用硬代码方式修改第3步的数据,观察打印结果。如果修改了数据,在下一次编译运行时可以看到打印信息的相应变化。连续两次运行,然后 RESET 一次,运行结果如下所示:第二次编译前,将该学生的评分从“A+A-B+B+”修改成了“A+A-B+B++”(多了一个+号),可以看出数据已经更新。

[SYS_INIT] Debug port initilaized.+---------------------------------------+
|        PY32F003 MCU is ready.         |
+---------------------------------------+10 digits sent to you!          
+---------------------------------------+
1234567890
128 bytes of data in FLASH:
0x00005FBA 0x55545343 0x3230322D 0x32302D30 
0x61685A00 0x4C20676E 0x34206F61 0x00000000 
0x00000000 0x00000000 0x0B020000 0x2D412B41 
0x2B422B42 0x00000000 0x00000000 0x00000000 
0x0800331C 0x00000001 0x0800331C 0x08000469 
0x08002852 0x21000000 0x2000032C 0x2000032C 
0x00000040 0x00000000 0x0000015C 0x2000032C 
0x200007F0 0x200007F1 0x00000001 0x08001FE5 Previous saved student profile: 128 bytes Primary ID = 24506Student ID = 'CSTU-2020-02'Name = 'Zhang Lao 4'Grade = 2Class = 11Performance = 'A+A-B+B+'
Current student profile: 64 bytes.Primary ID = 24506Student ID = 'CSTU-2020-02'Name = 'Zhang Lao 4'Grade = 2Class = 11Performance = 'A+A-B+B+'
[SYS_INIT] Debug port initilaized.+---------------------------------------+
|        PY32F003 MCU is ready.         |
+---------------------------------------+10 digits sent to you!          
+---------------------------------------+
1234567890
128 bytes of data in FLASH:
0x00005FBA 0x55545343 0x3230322D 0x32302D30 
0x61685A00 0x4C20676E 0x34206F61 0x00000000 
0x00000000 0x00000000 0x0B020000 0x2D412B41 
0x2B422B42 0x00000000 0x00000000 0x00000000 
0x0800331C 0x00000001 0x0800331C 0x08000469 
0x08002852 0x21000000 0x2000032C 0x2000032C 
0x00000040 0x00000000 0x0000015C 0x2000032C 
0x200007F0 0x200007F1 0x00000001 0x08001FE5 Previous saved student profile: 128 bytes Primary ID = 24506Student ID = 'CSTU-2020-02'Name = 'Zhang Lao 4'Grade = 2Class = 11Performance = 'A+A-B+B+'
Current student profile: 64 bytes.Primary ID = 24506Student ID = 'CSTU-2020-02'Name = 'Zhang Lao 4'Grade = 2Class = 11Performance = 'A+A-B+B++'
[SYS_INIT] Debug port initilaized.+---------------------------------------+
|        PY32F003 MCU is ready.         |
+---------------------------------------+10 digits sent to you!          
+---------------------------------------+
1234567890
128 bytes of data in FLASH:
0x00005FBA 0x55545343 0x3230322D 0x32302D30 
0x61685A00 0x4C20676E 0x34206F61 0x00000000 
0x00000000 0x00000000 0x0B020000 0x2D412B41 
0x2B422B42 0x0000002B 0x00000000 0x00000000 
0x0800331C 0x00000001 0x0800331C 0x08000469 
0x08002852 0x21000000 0x2000032C 0x2000032C 
0x00000040 0x00000000 0x0000015C 0x2000032C 
0x200007F0 0x200007F1 0x00000001 0x08001FE5 Previous saved student profile: 128 bytes Primary ID = 24506Student ID = 'CSTU-2020-02'Name = 'Zhang Lao 4'Grade = 2Class = 11Performance = 'A+A-B+B++'
Current student profile: 64 bytes.Primary ID = 24506Student ID = 'CSTU-2020-02'Name = 'Zhang Lao 4'Grade = 2Class = 11Performance = 'A+A-B+B++'

总结

  • 读写 PY32F003 的 FLASH 很简单,利用 HAL 库,按照规定的顺序(解锁-擦除-查空-写入-校验-锁定)操作即可完成 FLASH 的写入。FLASH 解锁要顺序地使用既定的两个标志字。
// Defined in py32f003x8.h
#define FLASH_KEY1_Msk                    (0x45670123UL << FLASH_KEY1_Pos)     /*!< 0x45670123 */
#define FLASH_KEY1                        FLASH_KEY1_Msk                       /*!< Flash program erase key1 */
#define FLASH_KEY2_Pos                    (0U)
#define FLASH_KEY2_Msk                    (0xCDEF89ABUL << FLASH_KEY2_Pos)     /*!< 0xCDEF89AB */
#define FLASH_KEY2                        FLASH_KEY2_Msk                       /*!< Flash program erase key2: used with FLASH_PEKEY1// Defined in py32f0xx_hal_flash.c
/*** @brief  Unlock the FLASH control register access.* @retval HAL Status*/
HAL_StatusTypeDef HAL_FLASH_Unlock(void)
{HAL_StatusTypeDef status = HAL_OK;if (READ_BIT(FLASH->CR, FLASH_CR_LOCK) != 0x00U){/* Authorize the FLASH Registers access */WRITE_REG(FLASH->KEYR, FLASH_KEY1);WRITE_REG(FLASH->KEYR, FLASH_KEY2);/* verify Flash is unlock */if (READ_BIT(FLASH->CR, FLASH_CR_LOCK) != 0x00U){status = HAL_ERROR;}}return status;
}
  • FLASH 读操作时不需要 Unlock/Lock,可以当作“普通”的内存访问读取 FLASH 相应地址的数据。
#define HW32_REG(ADDRESS) (*((volatile unsigned int *)(ADDRESS)))
  • FLASH 写必须被视为一个完整的过程,五个步骤要完整地、顺序地执行,不能中断,要不的话会导致系统卡死。在主程序的循环中运行 FLASH 写操作时,如果还有其它定时器中断服务程序也要执行 FLASH 写操作的话,要用类似互斥量的方式防止某一个正在进行的 FLASH 写操作的过程被中断(FLASH 读写过程中卡死的情况还是不少的,有兴趣的可以多看一点数据手册的第4章中的内容)。

探索性的开发,差错难免。谬误之处,欢迎在评论区批评指正。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/223983.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

1845_emacs中一个中文乱码问题分析解决

Grey 全部学习内容汇总&#xff1a;GitHub - GreyZhang/editors_skills: Summary for some common editor skills I used. 1845_emacs中一个中文乱码问题分析解决 曾经有一次放弃过我自己的emacs配置&#xff0c;一个原因就是中文的支持。感觉我的配置跟其他人的配置显得有些…

深度学习(生成式模型)——ADM:Diffusion Models Beat GANs on Image Synthesis

文章目录 前言基础模型结构UNet结构Timestep Embedding关于为什么需要timestep embedding global attention layer 如何提升diffusion model生成图像的质量Classifier guidance实验结果 前言 在前几篇博文中&#xff0c;我们已经介绍了DDPM、DDIM、Classifier guidance等相关的…

leetcode做题笔记2415. 反转二叉树的奇数层

给你一棵 完美 二叉树的根节点 root &#xff0c;请你反转这棵树中每个 奇数 层的节点值。 例如&#xff0c;假设第 3 层的节点值是 [2,1,3,4,7,11,29,18] &#xff0c;那么反转后它应该变成 [18,29,11,7,4,3,1,2] 。 反转后&#xff0c;返回树的根节点。 完美 二叉树需满足…

【STM32单片机】旋转太空人设计

文章目录 一、功能简介二、软件设计三、实验现象联系作者 一、功能简介 本项目使用STM32F103C8T6单片机控制器&#xff0c;使IIC OLED液晶等。 主要功能&#xff1a; 系统运行后&#xff0c;OLED显示动画界面。 二、软件设计 /* 作者&#xff1a;嗨小易&#xff08;QQ&#x…

vue中实现PDF文件流预览

代码示例 <template><div class"print"><div v-if"!viewShow" class"opt-box"><div style"height: 700px; overflow: auto;"><el-table :data"tableData" border><el-table-column prop…

HTML基础标签

但实际上无论声明为中文还是英文都可以写&#xff0c;中文/英文 主要是浏览器在进行调用翻译功能的时候&#xff0c;会按照声明的语言来进行翻译。 标签语义&#xff1a; 标签的属性一般都是在第一个标签中定义该标签效果所拥有的属性。 即标签的作用是什么 <>标签功能…

CSS——标准流、浮动、Flex布局

1、标准流 标准流也叫文档流&#xff0c;指的是标签在页面中默认的排布规则&#xff0c;例如&#xff1a;块元素独占一行&#xff0c;行内元素可以一行显示多个。 2、浮动 作用&#xff1a;让块元素水平排列 属性名&#xff1a;float 属性值&#xff1a; left&#xff1a;…

做为一个产品经理带你详细了解--动态面板的使用

&#x1f4da;&#x1f4da; &#x1f3c5;我是bing人&#xff0c;一个在CSDN分享笔记的博主。&#x1f4da;&#x1f4da; &#x1f31f;在这里&#xff0c;我要推荐给大家我的专栏《Axure》。&#x1f3af;&#x1f3af; &#x1f680;无论你是编程小白&#xff0c;还是有一…

卫星影像5天一更新的地图网站

如果全球影像每5天一更新&#xff0c;并集多种地图数据源于一体的PB级海量地图数据该怎样去管理呢&#xff1f; 这是当我了解到SOAR网站之后&#xff0c;思考过的一个问题。 全球最大的在线地图网站 在SOAR的官方网站&#xff0c;据称它是世界上最大的在线地图网站。 它是集…

如何远程访问Axure RP制作的本地web站点实现协同办公

文章目录 前言1.在AxureRP中生成HTML文件2.配置IIS服务3.添加防火墙安全策略4.使用cpolar内网穿透实现公网访问4.1 登录cpolar web ui管理界面4.2 启动website隧道4.3 获取公网URL地址4.4. 公网远程访问内网web站点4.5 配置固定二级子域名公网访问内网web站点4.5.1创建一条固定…

深入理解Java关键字volatile

前置知识-了解以下CPU结构 如下图所示&#xff0c;每个CPU都会有自己的一二级缓存&#xff0c;其中一级缓存分为数据缓存和指令缓存&#xff0c;这些缓存的数据都是从内存中读取的&#xff0c;而且每次都会加载一个cache line&#xff0c;关于cache line的大小可以使用命令cat…

stm32与Freertos入门(二)移植FreeRTOS到STM32中

简介 注意&#xff1a;FreeRTOS并不是实时操作系统&#xff0c;而是分时复用的&#xff0c;只不过切换频率很快&#xff0c;感觉上是同时在工作。本次使用的单片机型号为STM32F103C8T6,通过CubeMX快速移植。 一、CubeMX快速移植 1、选择芯片 打开CubeMX软件&#xff0c;进行…

(独白)我为什么选择了计算机行业?

为什么可能很简单&#xff0c;但为什么的为什么就有点长了。就当作讲故事吧 在高中毕业后选择专业时&#xff0c;和大多数人一样&#xff0c;我根本不知道要选择什么专业&#xff0c;更不知道哪个专业发展前景好&#xff0c;哪个专业好就业。在当时比较火的专业我记得应该是土…

使用广播星历进行 GPS 卫星位置的计算

目录 1.计算卫星运动的平均角速度 n 2.计算观测瞬间卫星的近地点角 3.计算偏近点角 4.计算真近点角 f 5.计算升交角距 6.计算摄动改正项 7.进行摄动改正 8.计算卫星在轨道面坐标系中的位置 9.计算观测瞬间升交点的经度 L 10.计算卫星在瞬时地球坐标系中的位置 11.…

JDK21+HADOOP3.2.2+Windows安装步骤

哈哈哈 最近转战大数据这块了&#xff0c;分享一下hadoop3.2.2的安装步骤 借鉴了不少大佬的文章&#xff0c;如有雷同&#xff0c;都是大佬们的 1.JDK安装 我选择的是JDK21 以下是下载网址和截图&#xff0c;这个没有太多的&#xff0c;一般下载最新的就可以 JDK: Java Down…

SQL数列

SQL数列 1、数列概述2、SQL数列2.1、简单递增序列2.2、等差数列2.3、等比数列3、SQL数列的应用3.1、连续问题3.2、多维分析1、数列概述 数列是最常见的数据形式之一,实际数据开发场景中遇到的基本都是有限数列。常见的数列例如:简单递增序列、等差数列、等比数列等 SQL如何实…

Helplook VS Salesforce:哪个知识库更好?

对于组织来说&#xff0c;选择一个合适的平台来管理在线知识库可能是一个具有挑战性的任务。而Salesforce的知识管理功能可以帮助组织更好地管理和分享他们的知识&#xff0c;从而更好地为客户提供服务。这是一种将知识管理集成到CRM平台中的方法&#xff0c;可以简化知识共享和…

vue el-cascader组件change失效以及下拉框不消失的问题

文章目录 1.前言2. 碰到的问题3. 如何解决这两个问题 1.前言 最近项目上用到el-cascader这个组件,需要可以选第一级菜单&#xff0c;也需要可以选第二级菜单&#xff0c;点击完成之后需要关闭下拉框。其实功能比较简单&#xff0c;找了很多资料&#xff0c;没有找到合适的方案…

分类预测 | GASF-CNN格拉姆角场-卷积神经网络的数据分类预测

分类预测 | GASF-CNN格拉姆角场-卷积神经网络的数据分类预测 目录 分类预测 | GASF-CNN格拉姆角场-卷积神经网络的数据分类预测分类效果基本描述模型描述程序设计参考资料 分类效果 基本描述 1.GASF-CNN格拉姆角场-卷积神经网络的数据分类预测&#xff08;完整源码和数据) 2.自…

音乐制作软件Ableton Live 11 mac功能特点

Ableton Live 11 mac是一款数字音频工作站软件&#xff0c;用于音乐制作、录音、混音和现场演出是一款流行的音乐制作软件。 Ableton Live 11 mac特点和功能 Comping功能&#xff1a;Live 11增加了Comping功能&#xff0c;允许用户在不同的录音轨道上进行多次录音&#xff0c;…