STM32F103 IAP 实现远程OTA固件升级实战

STM32固件升级OTA 本文将详细介绍如何在STM32微控制器上实现基本OTA升级,涵盖从环境搭建、协议选择、固件打包、传输及更新流程等关键环节。 阅读详情

1. 什么是IAP和OTA?为什么需要它们?

大家好,我是老李,在嵌入式行业摸爬滚打十多年了,今天想和大家聊聊STM32F103的IAP远程升级实战。如果你曾经为设备固件更新需要拆机、接下载线而头疼,那么IAP技术绝对是你的救星。

IAP(In Application Programming)简单来说就是"在应用中编程",允许MCU在运行用户程序的同时对自身Flash进行编程。而OTA(Over The-Air)则是IAP的一种实现方式,通过无线通信进行远程升级。在实际项目中,我经常遇到设备安装在难以触及的位置,比如高空、密闭空间,这时候OTA就显得尤为重要。

STM32F103作为经典的Cortex-M3内核MCU,内置Flash支持自编程,这为IAP提供了硬件基础。通过串口结合YModem协议,我们可以实现稳定可靠的固件传输。我记得第一次实现这个功能时,那种"终于不用跑现场升级"的喜悦至今难忘。

2. 硬件准备与开发环境搭建

2.1 硬件选型与连接

要实现IAP功能,首先需要准备硬件平台。我推荐使用STM32F103C8T6最小系统板,也就是我们常说的"蓝板",它有64KB Flash和20KB RAM,完全足够IAP应用。

硬件连接很简单:

  • 串口1(PA9/PA10)用于程序调试和YModem通信
  • 预留一个GPIO(如PB0)作为进入Bootloader的触发引脚
  • 如果使用无线模块,可以连接串口2或SPI接口

我在实际项目中发现,最好预留一个LED指示灯(如PC13)和按键(如PA0),这样在调试Bootloader时会方便很多。当设备无法启动时,可以通过按键强制进入Bootloader模式。

2.2 开发环境配置

开发工具我习惯用STM32CubeMX + Keil MDK的组合,这也是大多数STM32开发者常用的环境。首先用STM32CubeMX生成Bootloader和App两个工程的基础代码,这样能确保底层配置的一致性。

关键配置步骤:

  1. 在CubeMX中使能USART1,配置为115200波特率
  2. 开启Flash读写功能(默认已开启)
  3. 为Bootloader工程设置正确的Flash起始地址(0x08000000)
  4. 为App工程设置偏移地址(如0x08004000)
// Bootloader的链接脚本配置
FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 16K
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 20K

// App工程的链接脚本配置  
FLASH (rx) : ORIGIN = 0x08004000, LENGTH = 48K
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 20K

3. Bootloader设计与实现详解

3.1 Bootloader的工作流程

Bootloader是IAP的核心,它需要完成以下几个关键任务:

  1. 上电后检查升级触发条件
  2. 与上位机建立通信,接收新固件
  3. 校验固件完整性
  4. 跳转到App程序执行

我设计的Bootloader流程是这样的:

void bootloader_main(void)
{
    // 初始化外设
    HAL_Init();
    SystemClock_Config();
    UART_Init();
    LED_Init();
    
    // 检查升级触发条件
    if(check_update_flag() || GPIO_ReadPin(BOOT_KEY_PIN) == 0)
    {
        start_ymodem_receive();
    }
    else
    {
        jump_to_app();
    }
}

在实际项目中,我建议为Bootloader预留16KB的Flash空间,这样既能满足功能需求,又不会占用太多应用空间。

3.2 YModem协议集成与优化

YModem协议是串口文件传输的经典协议,相比XModem,它支持批量传输和文件信息传递。我推荐使用开源ymodem.c/h,这个库稳定且易于集成。

YModem传输过程:

  1. 接收方发送'C'字符发起传输
  2. 发送方首先发送文件信息包(包含文件名和大小)
  3. 接收方确认后开始数据包传输
  4. 每个数据包1024字节,最后不足的用0x1A填充
  5. 传输完成后进行CRC校验

我在实现时增加了一些优化:

  • 超时重传机制:防止传输卡死
  • 断点续传:意外中断后可以从断点继续
  • 进度显示:通过LED或串口输出传输进度
// YModem接收处理核心代码
int32_t ymodem_receive(uint8_t *buf)
{
    uint8_t packet_data[PACKET_SIZE];
    uint32_t file_size = 0;
    uint32_t received_size = 0;
    
    // 发送'C'开始传输
    uart_send_byte('C');
    
    while(1)
    {
        // 接收数据包
        if(receive_packet(packet_data) == SUCCESS)
        {
            // 处理文件信息包
            if(is_file_info_packet(packet_data))
            {
                file_size = extract_file_size(packet_data);
                uart_send_byte(ACK);
                continue;
            }
            
            // 处理数据包
            memcpy(buf + received_size, packet_data, PACKET_1K_SIZE);
            received_size += PACKET_1K_SIZE;
            uart_send_byte(ACK);
            
            // 更新进度显示
            update_progress(received_size, file_size);
        }
    }
}

4. 应用程序设计与中断重映射

4.1 应用程序的地址配置

App程序需要做一些特殊配置才能与Bootloader协同工作。最重要的就是修改中断向量表偏移,否则中断无法正确响应。

在App工程的system_stm32f1xx.c中修改:

#define VECT_TAB_OFFSET  0x4000U  // 16KB Bootloader偏移

// 在SystemInit函数中设置向量表偏移
SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET;

在Keil中还需要修改链接配置:

  1. 打开Options for Target -> Linker
  2. 取消勾选"Use Memory Layout from Target Dialog"
  3. 编辑sct文件,修改Flash起始地址为0x08004000

4.2 中断处理注意事项

在IAP方案中,中断处理需要特别注意。Bootloader和App有各自的中断向量表,跳转时需要重新设置VTOR寄存器。

我遇到过一个坑:App中使能了某些外设中断,但在Bootloader中没有处理,导致从Bootloader跳转到App后中断无法正确响应。解决方案是在Bootloader中禁用所有外设中断:

void deinit_all_peripherals(void)
{
    __HAL_RCC_GPIOA_CLK_DISABLE();
    __HAL_RCC_GPIOB_CLK_DISABLE();
    __HAL_RCC_GPIOC_CLK_DISABLE();
    // 禁用其他外设时钟...
    
    NVIC_DisableIRQ(USART1_IRQn);
    NVIC_DisableIRQ(USART2_IRQn);
    // 禁用其他中断...
}

5. 固件升级全流程实战

5.1 生成可升级的Bin文件

Keil默认生成的是hex文件,我们需要将其转换为bin文件才能用于OTA升级。在Keil中有两种方法:

方法一:使用fromelf工具

  1. 打开Options for Target -> User
  2. 在After Build/Rebuild中勾选Run #1
  3. 输入命令:fromelf --bin --output=@L.bin !L

方法二:使用批处理文件 创建generate_bin.bat文件:

fromelf --bin --output=.\Output\app.bin .\Output\app.axf

我推荐第二种方法,因为更灵活,可以添加版本号等额外信息。

5.2 使用Xshell进行YModem升级

Xshell是常用的终端软件,内置YModem支持。升级步骤:

  1. 连接设备串口,波特率115200
  2. 设备启动时按下升级按键进入Bootloader模式
  3. 在Xshell中输入ymodem命令
  4. 选择要传输的bin文件
  5. 等待传输完成,设备自动重启

如果传输中断,可以检查以下几点:

  • 串口线是否接触良好
  • 波特率是否匹配
  • 是否有电磁干扰(建议使用屏蔽线)

5.3 升级验证与回退机制

升级完成后,Bootloader需要验证固件完整性才能跳转执行。我通常使用CRC32校验:

bool verify_firmware(uint32_t addr, uint32_t size)
{
    uint32_t calculated_crc = calculate_crc(addr, size - 4);
    uint32_t stored_crc = *(uint32_t*)(addr + size - 4);
    
    return (calculated_crc == stored_crc);
}

为了安全起见,我还实现了回退机制:

  • 保存两个版本的固件(当前和上一个)
  • 如果新固件验证失败,自动回退到旧版本
  • 记录升级日志,便于故障排查

6. 常见问题与调试技巧

6.1 内存分配问题

在IAP项目中,内存分配需要特别注意。Bootloader和App的RAM区域不能重叠,否则会导致数据损坏。

我建议的做法:

  • Bootloader使用RAM前半部分(如0x20000000-0x20000FFF)
  • App使用RAM后半部分(如0x20001000-0x20004FFF)
  • 在链接脚本中明确指定RAM区域

6.2 中断向量表跳转问题

跳转到App前,需要确保中断处理正确:

void jump_to_app(void)
{
    typedef void (*pFunction)(void);
    pFunction jump_to_application;
    uint32_t jump_address;
    
    // 检查栈顶地址是否合法
    jump_address = *(uint32_t*)(APP_ADDRESS + 4);
    jump_to_application = (pFunction)jump_address;
    
    // 禁用所有中断
    __disable_irq();
    
    // 设置主堆栈指针
    __set_MSP(*(uint32_t*)APP_ADDRESS);
    
    // 跳转到应用程序
    jump_to_application();
}

6.3 电源稳定性问题

在Flash编程过程中,电源稳定性至关重要。我遇到过因为电源波动导致Flash写入失败的情况。建议:

  • 增加电源滤波电容
  • Flash写入前检查电压是否正常
  • 写入失败时自动重试

7. 进阶优化与实战建议

7.1 增加安全加密功能

在生产环境中,固件安全非常重要。我建议增加以下安全措施:

  • 固件加密:使用AES等算法加密固件
  • 数字签名:验证固件来源合法性
  • 防回滚:防止降级到有安全漏洞的版本
bool verify_signature(uint8_t *firmware, uint32_t size)
{
    // 从固件末尾提取签名
    uint8_t *signature = firmware + size - SIGNATURE_SIZE;
    
    // 使用公钥验证签名
    return crypto_verify(firmware, size - SIGNATURE_SIZE, signature);
}

7.2 无线OTA实现

虽然本文重点介绍串口OTA,但同样的原理也适用于无线OTA。只需要将串口传输替换为无线传输即可:

  1. 使用Wi-Fi模块:通过ESP8266/ESP32实现HTTP固件下载
  2. 使用4G模块:通过MQTT协议接收固件更新
  3. 使用蓝牙:适合短距离无线更新

我在实际项目中常用ESP8266+HTTP的方式,成本低且稳定性好。关键是设计好断点续传机制,避免无线传输中断导致升级失败。

7.3 量产测试建议

在大规模生产中,IAP功能需要充分测试:

  1. 模拟各种异常情况:断电、信号中断、数据错误等
  2. 测试边界情况:最大固件大小、最小固件大小等
  3. 长期稳定性测试:连续升级100次以上验证可靠性

我建议编写自动化测试脚本,模拟各种升级场景,确保每个出厂设备都经过充分测试。

记得第一次部署到现场时,最好预留本地升级接口,万一无线升级出现问题还可以通过串口补救。实际项目中我还会在设备信息中记录固件版本和升级历史,方便远程排查问题。

STM32F103 IAP 实战:YModem协议下的OTA固件升级 本文详细介绍了STM32F103 IAP技术在YModem协议下的OTA固件升级实战方案。内容涵盖Bootloader设计、内存规划、YModem协议实现、固件校验及常见问题处理,为嵌入式开发者提供了一套完整可靠的无线升级解决方案,有效降低现场维护成本。 阅读详情

相关推荐

STM32 IAP实战:BootLoader与App分区设计与远程固件更新

本文详细介绍了STM32 IAP技术实现,重点讲解BootLoader与App分区的设计策略及远程固件更新流程。通过Flash分区管理、Ymodem传输协议、安全校验机制和故障恢复方案,确保工业设备固件升级的可靠性与安全性,为嵌入式系统远程维护提供完整解决方案。

7up55的博客 966

单片机通过WiFI进行OTA固件升级

STM32F103C8T6一共64K,FLASH一共64页,每页1K,bootloader分8K,FLAG分2K,APP1与APP2各27K,也就是我们的应用程序,编译出来不能超过27K的大小。这样,在烧录的时候,就可以直接烧录APP到0x08002000了。,将APP2的部分copy到APP1,copy完之后再清空FLAG区域的升级标志,然后重启,就会运行新的APP1也就是升级后的程序了。,最后一包接收完之后,就将FLAG区域的升级标志位设置为相应的标志数据,然后重启,就回到上面的升级流程了。

strongerHuang 779

STM32F103实战指南:基于HAL库的IAP固件远程升级方案

本文详细介绍了基于STM32F103和HAL库的IAP固件远程升级方案,涵盖Bootloader设计、Flash分区、通信协议优化及安全机制等关键技术。通过实战案例解析,帮助开发者实现可靠的远程升级功能,提升工业设备维护效率。特别适合需要OTA升级的嵌入式系统开发者参考。

weixin_29168813的博客 227

计算机考试怎么改主题,职称计算机《WindowsXP》考点:设置桌面主题

职称计算机《WindowsXP》考点:设置桌面主题导语:微软最初发行了家庭版和专业版两个版本,家庭版的消费对象是家庭用户,专业版则在家庭版的基础上添加了新的为面向商业的设计的网络认证、双处理器等特性。下面是相关内容。考点1 设置桌面主题该考点是必考的知识点,通常情况下会考核设置指定的桌面主题,有时会单独出题,有时也会在其他知识点中涉及,要求考生务必熟练掌握。利用【控制面板】和桌面快捷方式可以设置桌...

weixin_34664632的博客 848

【STM32F103C8T6 串口 OTA升级】

STM32F103C8T6 OTA升级教程

qq_48519157的博客 1029

基于STM32的远程升级IAP完整实现方案

经过这一番深度剖析,你现在应该明白,一个工业级的STM32 OTA系统不仅仅是“接收+写入”那么简单。它应该是:🔹可靠的传输层:YModem确保每一帧都不丢;🔹安全的存储层:IAP配合双区备份,不怕断电;🔹可信的验证机制:数字签名杜绝恶意固件;🔹清晰的分层架构:模块解耦,易于扩展;🔹完善的错误恢复:自动回滚,永不“变砖”。这才是真正能上产品的OTA方案。💬 最后一句真心话:技术没有新旧之分,只有适不适合。

weixin_30951515的博客 1077

STM32 通过 WIFI 实现远程 OTA 升级:探索与实践

整个升级过程涉及到用户程序、BootLoader 以及自建服务器之间的协同工作。用户程序负责定时与云端交互获取升级信息,BootLoader 则在检测到升级标志后执行实际的下载和写入操作。

2504_94301232的博客 928

基于STM32F103的2G远程OTA升级实战项目

随着物联网设备在工业、家居和远程监测等领域的广泛应用,传统通过JTAG/SWD接口进行本地烧录的固件更新方式已难以满足大规模部署下的运维需求。STM32系列MCU基于ARM Cortex-M内核,支持应用内编程(IAP)技术,为实现远程固件升级(OTA)提供了硬件基础。通过集成2G通信模块,可在无Wi-Fi或以太网覆盖的场景下,构建低成本、广域网接入的OTA系统。该方案不仅提升了设备维护效率,还显著降低了现场人工操作成本。

weixin_31163455的博客 507

STM32项目中一种在线升级/应用升级OTA-IAP设计方案

STM32 OTA-IAP设计方案 OTA是Over-the-Air的简写,即空中下载技术,通过网络远程给用户进行系统更新和升级。IAP是In Application Programming的简写,IAP是用户自己的程序在运行过程中对User Flash的部分区域进行烧写,目的是为了在产品发布后可以方便地通过预留的通信口对产品中的固件程序进行更新升级。IAP主要包括BootLoader和应用程序两...

健忘16的博客 1万+

【 Git学习记录(三)】推荐四款主流的Git代码托管平台 —— GitHub、GitLab、Gitee、Coding

了解过Git之后,作为一个程序猿最基本的,你还需要了解目前主流的在线代码托管平台,并至少选择其中一款在平时开发中使用。这里特别介绍以下四款: 国外平台 GitHub —— 全球最流行的代码托管平台 GitLab —— 基于git的仓库管理程序 国内平台 Gitee —— 开源中国旗下的代码托管平台 Coding —— 支持社交元素的代码托管平台 一. GitHub 链接地址:https://github.com/ GitHub目前是全球最流行的代码托管平台(别称:全球最大的同性交友.

JZevin的博客 6094

Depth Anything 3实战:如何用DINOv2 Transformer一键生成3D高斯点云?

本文详细介绍了Depth Anything 3(DA3)模型如何利用DINOv2 Transformer架构,实现从单张或多视角图像一键生成高质量3D高斯点云。DA3通过统一的深度-射线表示和自适应注意力机制,简化了传统复杂的3D重建流程,并可直接微调用于3D高斯渲染,为图形学、CV和内容创作领域提供了高效的端到端解决方案。

postgres8guard的博客 722

STM32F103系列程序升级解决方案:IAP升级、OTA升级及多App备份切换防变砖技术

ABM开发板FreeRTOS版APP源码(APPV3.0)基于Cortex-M3架构与FreeRTOS内核,构建了一套功能完整、可配置、高可靠的嵌入式实时系统解决方案。其底层模块提供了处理器核心操作与启动支持,FreeRTOS内核实现了任务调度、通信同步等核心功能,可满足工业控制、智能硬件等领域的实时性与可靠性需求。开发者可基于此源码,通过配置与扩展任务逻辑,快速适配具体应用场景,降低嵌入式实时系统的开发难度与周期。

YCxPYEdDlF的博客 1956

Win10 / Win11 启用 Hyper-V 虚拟机详细教程(图文+命令行全攻略)

摘要:本文详细介绍Windows10/11系统启用Hyper-V虚拟化平台的方法,包含专业版/企业版的图形界面和PowerShell命令行操作,以及家庭版通过脚本强制启用的特殊方案。内容涵盖版本支持对比、操作步骤图解、常见问题解答和性能优化建议,帮助开发者快速搭建虚拟化环境进行多系统测试。附微软官方文档参考链接和详细操作示意图。

ElioXu 7083

STM32F103 IAP 在线升级OTA

MCU 设备上的 OTA 升级可理解为 IAP (In Application Programming) 技术

DongJayYet的博客 1471

基于轻量级神经网络MobileNet V2的水果识别种类算法研究

本文阐述了一种基于轻量级卷积神经网络MobileNet V2的水果分类与识别算法研究。为了最大限度地促进机械收获,需要一个检测系统,它可以让我们识别不同类别的水果。一个相对未开发的想法是使用深度学习和人工智能算法,不仅可以检测水果的种类,还可以检测水果是否成熟。这可以证明是有利可图的,因为它可以提供作物生长状况以及成熟和未成熟果实的个体数量,以及决定是否是收获时间的有用信息。第一步对数据进行了预处理,数据预处理技术在众多的深度学习计算中起到了重要作用。

qq_43556680的博客 1641

Blazor Session设置

微软官方封装了一些浏览器的操作,其中就有Session的操作的封装ProtectedSessionStorage 微软文档因为我们知道,依赖注入的生命周期是Singleton程序Scoped网页:刷新,url直接跳转都会重置。Transient路由C# Blazor 学习笔记(10):依赖注入但是没有一个和浏览器绑定的生命周期。即浏览器关闭才会退出。这个是后端无法获取的,因为后端根本不知道浏览器何时关闭。这个只能用浏览器自带的缓存。

qq_44695769的博客 1788

基于STM32F103/GD32F103的远程升级之旅

STM32远程升级 GD32 STM32 IAP/OTA升级 bootloader源码 app源码基于stm32f103/GD32f103系列附详细手册一份配套软件:两个(串口上位机软件和服务器端软件)提供基础说明文档!提供其他相关的详细资料。文件压缩包大小800多M,基于移远EC20、ec200系列模块的FTP服务器远程升级功能最近在研究基于STM32F103以及GD32F103系列芯片的远程升级功能,和大家分享一下这个超有趣的项目。

Q68823886的博客 1491

飞塔防火墙之Link Monitor

Link Monitor类似于SLA,飞塔防火墙线路质量探测的一个功能。

weixin_41903258的博客 2410

STM32F103-IAP代码升级

IAP 代码升级介绍

jcf5832的博客 1669

华为OD机试E卷 -猜字谜(Java & Python& JS & C++ & C )

小王设计了一个简单的猜字谜游戏,游戏的谜面是一个错误的单词,比如nesw,玩家需要猜出谜底库中正确的单词。猜中的要求如下:请你写一个程序帮忙在谜底库中找到正确的谜底。谜面是多个单词,都需要找到对应的谜底,如果找不到的话,返回”not found”

算法大师! 3488

qtcreator使用远程服务器编译代码

我并没有找到很好的windows上可以用的rsync工具,最后是装了wsl来调用rsync同步到代码后,在用ssh调用linux命令来编译的。安装wsl安装ubuntu启动wsl然后把windows里的ssh文件证书和配置复制到wsl里同时config的key目录需要改一下,这样就可以登录服务器了然后在home目录创建build.sh进行远程编译。

习惯就好zz的专栏 1384

【固件升级】之IAP(二)

在系统编程,可借助MCU厂商预置的Bootloader 实现通过板载UART或USB接口烧录代码,比如STM32存储映射Code分区中的System memory可以预置厂商的Bootloader,让MCU支持通过UART下载(不限于UART,具体由厂商预置Bootloader实现而定);Step7:将接受到的升级数据包存入APPB区,并将相关升级参数存入Parameter区,若接收数据完成,固件检验通过则写入Parameter区升级标志,并进入 Step8。而ICP编程就是以SWD接口进行的。

Longrun的博客 2290

android 蓝牙通讯demo

android 下蓝牙通讯demo,实现了发现蓝牙,使能蓝牙,通过蓝牙发送消息。

STM32F103_Bootloader程序开发01 - 什么是IAP?跟OTA有什么关系?

IAP,中文一般称为“应用程序内编程”或“在应用中自编程”。本质含义:MCU 在运行用户代码(App或Bootloader)时,通过自身的代码(而不是用外部编程器/仿真器)来擦写和更新片上 Flash 内容。典型的应用场景:在系统上线后,通过串口、CAN、USB、以太网等接口下载新固件,并写入指定Flash区,完成固件升级。实际场景:工程师用串口工具将固件下载到MCU,MCU通过IAP代码将固件烧写到App区。OTA,直译就是“空中下载”或者“远程升级”。

wallace89的博客 1575

Probability and Statistics - 4th edition

Probability and Statistics - 4th edition

win10 跳过U8环境检测的IE WebControls.rar

win10 安装u8的时候 提示IE WebControls 不通过,这个工具可以欺骗u8的检查。 跳过U8环境检测的IE WebControls。提示导入失败后,重新检测通过。

STM32F103 Bootloader远程升级固件

本文详解如何在STM32F103上构建Bootloader实现远程固件升级,涵盖启动流程、Flash操作、IAP技术及串口通信协议设计,支持断点续传与安全校验,助力智能设备远程维护。

weixin_30021053的博客 509

怀旧版电脑GBC模拟器

再现原版GBC掌机的界面,电脑运行连游戏界面都一样大小,很怀旧,很真实,(英文版)强烈推荐,很小的文件,很难才找到的。

stm32 IAP升级 OTA升级 野外设备远程升级 自建FTP服务器升级 多App备份 切换

ABM开发板FreeRTOS版APP源码(APPV3.0)基于Cortex-M3架构与FreeRTOS内核,构建了一套功能完整、可配置、高可靠的嵌入式实时系统解决方案。其底层模块提供了处理器核心操作与启动支持,FreeRTOS内核实现了任务调度、通信同步等核心功能,可满足工业控制、智能硬件等领域的实时性与可靠性需求。开发者可基于此源码,通过配置与扩展任务逻辑,快速适配具体应用场景,降低嵌入式实时系统的开发难度与周期。

zWLzTRxDJb的博客 702

STM32 IAP升级 OTA远程升级方案及自建FTP服务器实现多App备份与切换,防止单片机变砖

它把“单个 32 bit 变量”抽象成“最多 24 个独立事件位”,通过“位或、位与、位清除、位等待”四种原子语义,让多个任务可以以“任意位匹配”或“全位匹配”方式聚合/等待事件,从而替代传统“多个二值信号量”方案,减少 RAM 占用与上下文切换次数。通过以上机制,事件组在仅消耗 28 字节 RAM(StaticEventGroup_t)的前提下,即可替代传统“N 个信号量 + M 次同步”方案,显著降低资源占用与 CPU 负载,是 FreeRTOS 高内聚、低耦合设计哲学的典型体现。

2504_94300644的博客 1576
上一篇: 跨越平台:在Linux环境下高效开发TouchGFX的实战指南
下一篇: 超越GIF:OLED屏幕的动态内容显示技术与优化策略
ruby5
博客等级 码龄15年 29粉丝 893原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值