STM32 BootLoader 刷新项目 (十一) Flash写操作-命令0x57

STM32 BootLoader 刷新项目 (十一) Flash写操作-命令0x57

1. 引言

嵌入式系统中,BootLoader 是设备启动的第一部分代码,负责硬件初始化和主程序加载。在 STM32F407 中,BootLoader 的另一重要功能是支持应用程序的在线升级,这需要用到 Flash 写操作。本文详细介绍如何实现这一功能。

1.1 Flash Write命令的应用场景

在嵌入式设备中,固件更新和管理是实现产品生命周期内功能扩展与问题修复的重要手段,而 BootLoader 的 Flash Write 命令就是固件更新流程的核心之一。

  1. 固件在线升级
    BootLoader 的主要功能是加载主程序,但为了支持在线升级,它需要实现对 Flash 的擦除和写入功能。通过网络(如 WiFi、以太网)或串行接口(如 UART、CAN),将新固件下载到设备中并写入 Flash,完成程序的更新。

  2. 分区存储管理
    在复杂的应用中,可能会使用 Flash 的不同分区存储多个固件版本或配置文件。Flash Write 命令可用于将新版本的固件写入备用分区,并在验证后切换到新的固件运行。

  3. 设备参数或日志存储
    除了固件,Flash 写命令还可用于存储一些需要长期保存的数据,如设备参数、运行日志等。相比 EEPROM,Flash 提供更大的存储空间和更快的读写速度。


1.2 Flash Write命令的作用

Flash Write 命令作为 BootLoader 的核心功能模块,直接决定了系统的升级能力和稳定性,其作用主要包括以下几点:

  1. 支持固件安全升级
    通过 Flash Write 命令,新的固件数据可以被可靠地写入到指定的 Flash 区域,完成固件升级任务。

  2. 提高系统稳定性和安全性
    在升级过程中,Flash Write 命令结合校验机制可确保数据完整性和准确性,避免因写入错误导致设备崩溃。

  3. 实现高效的存储操作
    Flash Write 命令封装了 Flash 写操作的底层细节,让开发者无需关注复杂的硬件接口配置,只需调用接口完成数据存储。

  4. 与擦除操作结合使用
    Flash 写命令通常和擦除命令配合工作,确保写入新数据前清空目标区域,避免残留数据干扰。


2. STM32F407 Flash 简介

2.1 Flash介绍

STM32F407 芯片采用 Cortex-M4 内核,内置 Flash 存储用于程序和数据存储。STM32F407 的 Flash 大小为 512KB,分为若干个扇区(Sector),每个扇区的大小并不相同:

  • 扇区 0 到 3:16KB 每扇区
  • 扇区 4:64KB
  • 扇区 5 到 11:128KB 每扇区
扇区编号起始地址大小
00x0800000016 KB
10x0800400016 KB
20x0800800016 KB
30x0800C00016 KB
40x0801000064 KB
5-110x08020000 开始每扇区128 KB

在进行 Flash 写入时,需注意:

分区结构
Flash 存储器分为多个扇区,每个扇区可以独立擦除和写入,大小从 16 KB 到 128 KB 不等。

支持字节、半字、字写入
Flash 写入操作的基本单位是 字(word, 32 bits),并且地址需要 4 字节对齐。

支持电压范围宽
Flash 支持的工作电压范围为 2.7V 至 3.6V。

操作速度
Flash 写操作较慢,通常需要几个微秒到几百微秒。

image-20241114070535836

2.2 BootLoader Flash划分

由下图可以看出本BootLoader的Flash的划分,其中划给BootLoader为32KB,从0x0800 0000-0x0800 7FFF,占用Sector 0-1两个段。App应用程序占用0x0800 8000-0x080F FFFF,总共10个Sector。

image-20241114070819942

下面是BootLoader的跳转过程,关于具体的跳转过程,可以参考上一篇文章: STM32 BootLoader 刷新项目 (九) 跳转指定地址-命令0x55

image-20241114230528904

image-20241114230647450

2.3 STM32F407 Flash 写入的原理

2.3.1 Flash 的存储机制

STM32F407 的 Flash 是基于浮栅晶体管(Floating Gate Transistor)技术的非易失性存储器。其基本存储原理如下:

  1. 写入数据
    写入操作通过向 Flash 单元中的浮栅施加高压,将电子注入其中,从而改变其电导状态。
  2. 擦除数据
    Flash 擦除是将目标扇区内的所有单元恢复到初始状态(全为 1),需要通过高电压释放浮栅中的电子。
  3. 对齐限制
    Flash 地址必须以 4 字节对齐进行写入,否则写入会失败。
2.3.2 Flash 写操作流程

STM32F407 的 Flash 写入操作由以下几个步骤组成:

  1. 解锁 Flash 控制器
    写操作前需要解锁 Flash 控制器,通过设置 KEY1KEY2 寄存器完成解锁。解锁后才能对 Flash 进行写入或擦除。
  2. 配置 Flash 操作类型
    STM32F4 提供了 HAL 库的函数,如 HAL_FLASH_Program,开发者可以选择写入的类型(例如 32 位字写入)。
  3. 执行写入操作
    将目标地址和要写入的数据传递给 Flash 控制器,控制器根据设定的地址和数据完成写入。
  4. 锁定 Flash 控制器
    为了避免意外修改 Flash 内容,写操作完成后需锁定 Flash 控制器。

3. 实现 Flash 写操作的Demo代码讲解

在 STM32F407 中,Flash 写入功能由其内部存储器控制器支持,开发者可利用 HAL 库实现简单高效的操作。以下是实现 Flash Write 的核心步骤及示例代码。

3.1 硬件与软件

  • STM32F407 开发板
  • STM32CubeIDE 或 Keil uVision
  • ST-Link 调试器

3.2 配置和解锁 Flash

在进行任何 Flash 写入操作前,需解锁 Flash 控制器,以允许写入。示例如下:

#include "stm32f4xx_hal.h"// 解锁Flash控制器以允许写入操作
void Flash_Unlock(void) {if (HAL_FLASH_Unlock() != HAL_OK) {// 错误处理:解锁失败}
}

3.3 实现写入单个数据的函数

写入单个 uint32_t 数据到 Flash 指定地址:

HAL_StatusTypeDef Flash_WriteWord(uint32_t address, uint32_t data) {Flash_Unlock();  // 解锁Flash// 写入一个32位数据到指定地址HAL_StatusTypeDef status = HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, address, data);HAL_FLASH_Lock();  // 写入完成后立即上锁return status;  // 返回操作状态
}

3.4 实现写入多组数据的函数

实际应用中,往往需要一次性写入一组数据。以下是实现批量写入的代码:

HAL_StatusTypeDef Flash_WriteData(uint32_t startAddress, uint32_t *data, uint32_t length) {Flash_Unlock();  // 解锁FlashHAL_StatusTypeDef status = HAL_OK;// 循环写入数据for (uint32_t i = 0; i < length; i++) {status = HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, startAddress + (i * 4), data[i]);if (status != HAL_OK) {break;  // 如果写入失败,退出循环}}HAL_FLASH_Lock();  // 写入完成后立即上锁return status;  // 返回写入状态
}

3.5 Flash 写入前的擦除操作

在写入新数据前,需确保目标区域已擦除,避免数据冲突。以下是实现扇区擦除的代码:

HAL_StatusTypeDef Flash_EraseSector(uint32_t sector) {FLASH_EraseInitTypeDef eraseInitStruct;uint32_t sectorError;Flash_Unlock();  // 解锁Flash// 配置擦除参数eraseInitStruct.TypeErase = FLASH_TYPEERASE_SECTORS;  // 按扇区擦除eraseInitStruct.Sector = sector;                     // 目标扇区eraseInitStruct.NbSectors = 1;                       // 擦除数量eraseInitStruct.VoltageRange = FLASH_VOLTAGE_RANGE_3; // 电压范围:2.7V - 3.6V// 执行擦除操作HAL_StatusTypeDef status = HAL_FLASHEx_Erase(&eraseInitStruct, &sectorError);HAL_FLASH_Lock();  // 上锁Flashreturn status;  // 返回擦除状态
}

3.6 综合示例:实现 BootLoader 中的 Flash 写命令

以下是将上述功能整合的一个完整示例:

void Flash_WriteExample(void) {uint32_t testData[3] = {0x12345678, 0xABCDEF01, 0x98765432};  // 示例数据// 擦除目标扇区(扇区5)if (Flash_EraseSector(FLASH_SECTOR_5) == HAL_OK) {printf("Sector erased successfully.\n");}// 写入数据到目标地址if (Flash_WriteData(0x08020000, testData, 3) == HAL_OK) {printf("Data written successfully.\n");}
}

3.7 Write Flash的步骤总结

3.7.1 解锁 Flash

解锁 Flash 控制器的步骤:

  1. 写入解锁密钥 0x456701230xCDEF89AB 到 Flash 解锁寄存器(FLASH->KEYR)。
  2. 确保 Flash 未处于写保护状态。
3.7.2 擦除扇区

写入前需先擦除目标扇区。擦除过程如下:

  1. 配置擦除模式和目标扇区。
  2. 设置擦除启动位(FLASH_CR_STRT)。
  3. 等待擦除完成(检查 FLASH_SR_BSY 位)。
3.7.3 写入数据
  1. 将要写入的数据和目标地址传递给 HAL_FLASH_Program 函数。
  2. 写入完成后,Flash 控制器会自动校验数据完整性。
  3. 若写入失败,会通过状态寄存器返回错误码。
3.7.4 上锁 Flash

写入完成后,设置 FLASH_CR_LOCK 位以锁定 Flash 控制器。

4. 0x57命令介绍–Flash擦除

在本篇文章,我们的主要是介绍0x57的命令,这个命令主要是在BootLoader中写指定Flash Sector的命令。

通过上位机发送7+X+4 Byte的数据,其中第1 Byte为整个数据的长度,第2Byte为指令码,第3-6 Byte为要写入Flash的基地址,第7 Byte是写入数据X的长度,第8-(8+X) Byte为写入数据的值,9+X Byte为前7+X Byte的CRC校验值,上位机通过串口UART发送给下位机,下位机回复地址是否写入成功的标志。

image-20241118072458838

下面是发送命令过程中上位机与BootLoader之间的交互。

image-20241114230607647

5. Flash写-命令程序设计

以下是代码的详细解析和逐行注释,包括函数的含义和执行过程。主要描述了 BootLoader 中的 BL_MEM_WRITE 命令的实现细节,如何从主机接收命令并写入 Flash。


主函数:接收命令并处理

void bootloader_uart_read_data(void)
{uint8_t rcv_len=0;printmsg_Host("BL_DEBUG_MSG: Receive CMD\n\r"); // 向主机打印调试信息,表示已准备好接收命令while (1){// 关闭指示灯,表示正在等待命令HAL_GPIO_WritePin(LED2_GPIO_Port, LED2_Pin, GPIO_PIN_RESET);// 清空接收缓冲区,避免数据残留影响memset(bl_rx_buffer, 0, 200);// 读取命令包的第一个字节,这是命令包的长度字段HAL_UART_Receive(C_UART, bl_rx_buffer, 1, HAL_MAX_DELAY);// 提取长度字段rcv_len = bl_rx_buffer[0];// 根据长度字段,接收整个命令包HAL_UART_Receive(C_UART, &bl_rx_buffer[1], rcv_len, HAL_MAX_DELAY);// 根据命令包的第二个字节(命令代码),选择处理函数switch(bl_rx_buffer[1]){case BL_GET_VER: // 获取 BootLoader 版本号bootloader_handle_getver_cmd(bl_rx_buffer);break;case BL_GET_HELP: // 获取支持的命令列表bootloader_handle_gethelp_cmd(bl_rx_buffer);break;case BL_GET_CID: // 获取芯片 IDbootloader_handle_getcid_cmd(bl_rx_buffer);break;case BL_GET_RDP_STATUS: // 获取读保护状态bootloader_handle_getrdp_cmd(bl_rx_buffer);break;case BL_GO_TO_ADDR: // 跳转到指定地址执行代码bootloader_handle_go_cmd(bl_rx_buffer);break;case BL_FLASH_ERASE: // 擦除 Flash 指定区域bootloader_handle_flash_erase_cmd(bl_rx_buffer);break;case BL_MEM_WRITE: // 写入 Flashbootloader_handle_mem_write_cmd(bl_rx_buffer);break;default: // 无效命令处理printmsg("BL_DEBUG_MSG:Invalid command code received from host \n");break;}}
}

命令处理函数:BL_MEM_WRITE

void bootloader_handle_mem_write_cmd(uint8_t *pBuffer)
{uint8_t write_status = 0x00; // 写入状态初始化uint8_t payload_len = pBuffer[6]; // 从命令包中提取有效载荷长度uint32_t mem_address = *((uint32_t *)(&pBuffer[2])); // 提取目标内存地址printmsg("BL_DEBUG_MSG:bootloader_handle_mem_write_cmd\n");// 计算命令包的总长度uint32_t command_packet_len = bl_rx_buffer[0] + 1;// 从命令包末尾提取主机发送的 CRC32 校验值uint32_t host_crc = *((uint32_t *)(bl_rx_buffer + command_packet_len - 4));// 校验 CRC32 数据完整性if (!bootloader_verify_crc(&bl_rx_buffer[0], command_packet_len - 4, host_crc)){printmsg("BL_DEBUG_MSG:checksum success !!\n");// 校验通过后向主机发送 ACK 应答bootloader_send_ack(pBuffer[0], 1);printmsg("BL_DEBUG_MSG: mem write address : %#x\n", mem_address);// 验证目标内存地址是否合法if (verify_address(mem_address) == ADDR_VALID){printmsg("BL_DEBUG_MSG: valid mem write address\n");// 关闭指示灯,表示开始写入HAL_GPIO_WritePin(LED2_GPIO_Port, LED2_Pin, GPIO_PIN_RESET);// 执行实际的写入操作write_status = execute_mem_write(&pBuffer[7], mem_address, payload_len);// 打开指示灯,表示写入完成HAL_GPIO_WritePin(LED2_GPIO_Port, LED2_Pin, GPIO_PIN_SET);// 将写入状态反馈给主机bootloader_uart_write_data(&write_status, 1);}else{printmsg("BL_DEBUG_MSG: invalid mem write address\n");write_status = ADDR_INVALID; // 地址无效// 向主机反馈地址无效状态bootloader_uart_write_data(&write_status, 1);}}else{printmsg("BL_DEBUG_MSG:checksum fail !!\n");// 校验失败,发送 NACK 应答bootloader_send_nack();}
}

实际写入函数

uint8_t execute_mem_write(uint8_t *pBuffer, uint32_t mem_address, uint32_t len)
{uint8_t status = HAL_OK; // 写入状态初始化为成功// 解锁 Flash 模块,允许写入HAL_FLASH_Unlock();// 按字节逐个写入数据到指定地址for (uint32_t i = 0; i < len; i++){// 写入 Flash 的核心函数,支持字节写入status = HAL_FLASH_Program(FLASH_TYPEPROGRAM_BYTE, mem_address + i, pBuffer[i]);}// 写入完成后锁定 Flash,防止误操作HAL_FLASH_Lock();return status; // 返回写入状态
}

流程说明:

  1. 使用 HAL_FLASH_Unlock 解锁 Flash 控制器,获取操作权限。
  2. 逐字节写入数据到指定地址。
  3. 写入完成后调用 HAL_FLASH_Lock 重新锁定控制器。

7. 实战演练

下面是上位机的命令菜单,通过在终端调用Python脚本,然后在终端输入下位机连接的串口号,即可进入命令界面,目前可支持如下命令:

image-20240713104433991

输入写入命令的操作,然后在输入写入App的基地址。

image-20241118074802777

写入过程中:

image-20241118074826562


写入完成

image-20241118074841971

在上述整个写入的过程,上位机和MCU之间一直发送数据,如下图所示,一直发送每一个地址要写入的数据。

image-20241118075028466

后面关于上位机的内容,我单独出一期进行讲解,这里主要讲解MCU侧的操作。

8. 总结

本文详细介绍了在 STM32F407 上实现 Flash 写入的完整步骤,包括解锁、写入单个数据、多组数据及扇区擦除的实现方法。通过上述代码和测试方法,您可以为系统增加可靠的固件升级能力。

欢迎留言交流!如有疑问或建议,请随时反馈。

9. 系列文章

STM32 BootLoader 刷新项目 (一) STM32CubeMX UART串口通信工程搭建

STM32 BootLoader 刷新项目 (二) 方案介绍

STM32 BootLoader 刷新项目 (三) 程序框架搭建及刷新演示

STM32 BootLoader 刷新项目 (四) 通信协议

STM32 BootLoader 刷新项目 (五) 获取软件版本号-命令0x51

STM32 BootLoader 刷新项目 (六) 获取帮助-命令0x52

STM32 BootLoader 刷新项目 (七) 获取芯片ID-0x53

STM32 BootLoader 刷新项目 (八) 读取Flash保护ROP-0x54

STM32 BootLoader 刷新项目 (九) 跳转指定地址-命令0x55

[STM32 BootLoader 刷新项目 (十) Flash擦除-命令0x56](STM32 BootLoader 刷新项目 (十) Flash擦除-命令0x56-CSDN博客)

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

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

Spring IoC——针对实习面试

目录 Spring IoC谈谈你对Spring IoC的理解IoC和DI有区别吗&#xff1f;IoC&#xff08;控制反转&#xff09;DI&#xff08;依赖注入&#xff09;IoC与DI的区别 什么是Spring Bean&#xff1f;作用域有哪些&#xff1f;Bean是线程安全的吗&#xff1f;说一下Spring Bean的生命周…

【H2O2|全栈】MySQL的云端部署

目录 前言 开篇语 准备工作 MySQL移除 为什么需要移除&#xff1f; 移除操作 Yum仓库 yum简介 rpm安装 yum库安装 MySQL安装 使用yum安装 开机自启动 检查运行状态 MySQL配置 初始密码 ​编辑登录 修改root密码 退出MySQL 字符集配置 结束语 前言 开篇语…

数据结构-二叉平衡树

一.平衡二叉树 二叉搜索树插入的次序不同导致不同的深度和平均查找长度ASL 左右子树高度差不超过绝对值1的二叉搜索是二叉平衡树 二.平衡二叉树的调整 在右子树的右子树上的插入做RR插入 把被破坏节点的右子树变成跟节点并把这个右子树的左子树挂载到原来被破坏的结点的右子树…

【PCIE716-0】基于PCIe总线架构的XC7Z100 FPGA高性能实时信号处理平台

板卡概述 PCIE716-0是一款基于PCIe总线架构的XC7Z100 FPGA高性能实时信号处理平台。该平台采用Xilinx的ZYNQ SOC系列产品XC7Z100作为主处理器。 该平台的PL端具有1个FMC&#xff08;HPC&#xff09;接口&#xff0c;1路PCIe x8主机接口&#xff0c;支持1路UART串口、支持1组6…

从0开始的数据结构速过——番外(1)

目录 尝试 思考与架构设置 编写&#xff01; 一些额外知识的补充 可变参数模板 std::common_type std::forward 这是《数据结构从0开始》的一个番外。实际上是介绍一下一些现代C的写法。这里以快速构建std::array作为契机来说明一下一些现代C的语法。 尝试 我们在这里呢…

Day10_CSS过度动画

Day10_CSS过度动画 背景 : PC和APP项目我们已经开发完毕, 但是再真正开发的时候有些有些简易的动态效果我们可以使用CSS完成 ; 本节课我们来使用CSS完成基础的动画效果 今日学习目标 CSS3过度CSS3平面动态效果CSS3动画效果案例 1. CSS3过渡 ​ 含义 :过渡指的是元素从一种…

如何制作代购系统的客服支持模块

在代购系统中&#xff0c;客服支持模块是维护用户满意度和忠诚度的关键环节。一个有效的客服支持模块不仅可以解决用户的疑问和问题&#xff0c;还可以收集用户反馈&#xff0c;用于改进服务和产品。本文将详细介绍如何制作一个代购系统的客服支持模块&#xff0c;包括前端界面…

【unity小技巧】一些unity3D灯光的使用与渲染及性能优化方案

文章目录 天空盒反射配置太阳耀斑眩光烘培光照烘培光照时弹出错误&#xff0c;记得勾选模型下面的选择阴影项目配置光源模型模型shader的问题 全局光照混合光照模式混合照明模式减性照明模式Shadowmask照明模式间接烘焙照明模式 环境光遮罩灯光探针反射探针技术关闭反射探针可以…

Spring Boot汽车资讯:科技与汽车的对话

5系统详细实现 5.1 管理员模块的实现 5.1.1 用户信息管理 汽车资讯网站的系统管理员可以管理用户&#xff0c;可以对用户信息修改删除审核以及查询操作。具体界面的展示如图5.1所示。 图5.1 用户信息管理界面 5.1.2 汽车品牌管理 系统管理员可以汽车品牌信息进行添加&#xf…

go 学习网站,go例子 go demo go学习视频

1. 代码例子&#xff1a; Go by Example 2. b站 视频&#xff1a; 尚硅谷视频&#xff1a; 004_尚硅谷_程序的基本概念_哔哩哔哩_bilibili 3. go技术文档&#xff1a; fmt Go语言中文文档

记录下,用油猴Tampermonkey监听所有请求,绕过seesion

油猴Tampermonkey监听所有请求&#xff0c;绕过seesion 前因后果脚本编写 前因后果 原因是要白嫖一个网站的接口&#xff0c;这个接口的页面入口被隐藏掉了&#xff0c;不能通过页面调用&#xff0c;幸好之前有想过逆向破解通过账号密码模拟登录后拿到token&#xff0c;请求该…

网络安全:我们的安全防线

在数字化时代&#xff0c;网络安全已成为国家安全、经济发展和社会稳定的重要组成部分。网络安全不仅仅是技术问题&#xff0c;更是一个涉及政治、经济、文化、社会等多个层面的综合性问题。从宏观到微观&#xff0c;网络安全的重要性不言而喻。 宏观层面&#xff1a;国家安全与…

多账号登录管理器(淘宝、京东、拼多多等)

目录 下载安装与运行 解决什么问题 功能说明 目前支持的平台 功能演示 登录后能保持多久 下载安装与运行 下载、安装与运行 语雀 解决什么问题 多个账号的快捷登录与切换 功能说明 支持多个电商平台支持多个账号的登录保持支持快捷切换支持导入导出支持批量删除支持…

浅谈网络 | 二层到三层

目录 物理层到MAC层第一层&#xff08;物理层&#xff09;第二层&#xff08;数据链路层&#xff09;局域网 交换机与VLAN生成树协议VLAN ICMP与pingICMP 协议的格式 网关静态路由是什么&#xff1f; 路由协议如何配置策略路由&#xff1f;动态路由算法动态路由协议 物理层到MA…

c++ 后端

基础知识 1. 指针、引用2. 数组3. 缺省参数4. 函数重载5. 内联函数6. 宏7. auto8. const9. 类和对象10. 类的6个默认成员函数11. 初始化列表12. this指针13. C/C的区别14. C 三大特性15. 结构体内存对齐规则16. explicit17. static18. 友元类、友元函数19. 内部类20. 内存管理&…

汽车资讯新趋势:Spring Boot技术解读

5系统详细实现 5.1 管理员模块的实现 5.1.1 用户信息管理 汽车资讯网站的系统管理员可以管理用户&#xff0c;可以对用户信息修改删除审核以及查询操作。具体界面的展示如图5.1所示。 图5.1 用户信息管理界面 5.1.2 汽车品牌管理 系统管理员可以汽车品牌信息进行添加&#xf…

【C++】vector

一、vector的介绍及使用 1.1 vector的介绍 vector的底层与string相似都是顺序表形式管理数组&#xff0c;本质上来说string就可以归入到vector里面&#xff0c;但是在实际使用中&#xff0c;字符有很多自身独有的接口设计需要&#xff0c;因此string被单独拿出来设计。在前面s…

uniapp Uview上传图片组件Upload会自动刷新

背景 最近在做跑团小程序&#xff0c;马上接近尾声了&#xff0c;今天新增一个团长增加活动页面&#xff1a; 然后一切准备就绪&#xff0c;发现了一个问题&#xff0c;当选择上传图片后&#xff0c;页面会自动刷新&#xff0c;把之前填写的信息全部重置了。奇怪了&#xff0c…

软件测试之缺陷管理

一、软件缺陷的基本概念 1、软件缺陷的基本概念主要分为&#xff1a;缺陷、故障、失效这三种。 &#xff08;1&#xff09;缺陷&#xff08;defect&#xff09;&#xff1a;存在于软件之中的偏差&#xff0c;可被激活&#xff0c;以静态的形式存在于软件内部&#xff0c;相当…

数字资产与大健康领域的知识宝藏:高效知识库搭建策略

在数字化时代&#xff0c;大健康领域的企业积累了丰富的数字资产&#xff0c;这些资产如同一座待挖掘的金矿&#xff0c;蕴含着巨大的价值。高效搭建知识库&#xff0c;能够将这些数字资产转化为企业竞争力。 数字资产与大健康领域知识宝藏 数字资产在大健康领域包括患者数据…