You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Arduino IDE开发ESP8266 NodeMCU时OTA下载文件是否需要CRC校验?

ESP8266 OTA升级CRC校验必要性及实现方案

一、CRC校验的必要性

非常有必要,核心原因如下:

  • 网络传输过程中的丢包、错包、信号干扰都可能导致下载的bin文件出现字节错误,一旦烧录错误的固件会直接导致设备变砖,只能有线重刷
  • ESP8266自带的Updater类默认只做最基础的写入校验,不会校验整个固件的完整性,无法识别传输过程中产生的整体数据偏差
  • CRC32校验实现简单,资源占用极低,对ESP8266这类资源有限的MCU非常友好,额外开销可以忽略

二、具体实现步骤

前置准备

首先需要在服务端提前计算好待升级bin文件的CRC32值,两种常见实现方式:

  • 本地打包固件时用工具计算后和bin文件一起存到服务器,或者直接存在bin文件的末尾固定位置
  • 服务器收到固件上传请求时自动计算CRC32,提供单独的接口给设备查询对应版本固件的CRC值

设备端代码实现

可以直接用ESP8266核心库自带的CRC32类,不需要额外安装第三方库,实现逻辑如下:

  1. 升级前先请求服务端获取对应固件的目标CRC32值
  2. 下载固件的同时逐块计算当前接收数据的CRC32值
  3. 固件下载完成后对比计算得到的CRC和服务端下发的CRC,一致才调用Updater.end()提交烧录,不一致就丢弃本次下载的固件,触发重试逻辑

核心代码示例

#include <ESP8266WiFi.h>
#include <ESP8266HTTPClient.h>
#include <WiFiClient.h>
#include <Updater.h>
#include <CRC32.h>

const char* ssid = "你的WiFi名称";
const char* password = "你的WiFi密码";
// 固件下载地址
const char* firmwareUrl = "http://你的服务器地址/firmware.bin";
// 固件CRC32查询地址
const char* crcUrl = "http://你的服务器地址/firmware_crc";

CRC32 crc;

void setup() {
  Serial.begin(115200);
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("WiFi连接成功");

  doOTA();
}

void doOTA() {
  WiFiClient client;
  HTTPClient http;
  
  // 第一步:获取目标CRC值
  uint32_t targetCrc = 0;
  if(http.begin(client, crcUrl)) {
    int httpCode = http.GET();
    if(httpCode == HTTP_CODE_OK) {
      targetCrc = strtoul(http.getString().c_str(), NULL, 16);
      Serial.printf("获取到目标CRC32: 0x%X\n", targetCrc);
    }
    http.end();
  }

  if(targetCrc == 0) {
    Serial.println("获取CRC失败,取消升级");
    return;
  }

  // 第二步:下载固件并计算CRC
  if(http.begin(client, firmwareUrl)) {
    int httpCode = http.GET();
    if(httpCode == HTTP_CODE_OK) {
      int firmwareSize = http.getSize();
      Serial.printf("固件大小: %d字节\n", firmwareSize);

      if(Updater.begin(firmwareSize)) {
        WiFiClient* stream = http.getStreamPtr();
        uint8_t buf[128];
        size_t bytesRead;
        crc.reset();

        while (http.connected() && stream->available()) {
          bytesRead = stream->readBytes(buf, sizeof(buf));
          // 计算CRC
          crc.update(buf, bytesRead);
          // 写入升级分区
          Updater.write(buf, bytesRead);
        }

        uint32_t calculatedCrc = crc.finalize();
        Serial.printf("计算得到的CRC32: 0x%X\n", calculatedCrc);

        if(calculatedCrc == targetCrc) {
          if(Updater.end()) {
            Serial.println("升级成功,即将重启");
            ESP.restart();
          } else {
            Serial.printf("升级失败: %s\n", Updater.getErrorString());
          }
        } else {
          Serial.println("CRC校验不匹配,丢弃固件");
          Updater.abort();
        }
      } else {
        Serial.println("升级分区初始化失败");
      }
    }
    http.end();
  }
}

void loop() {

}

注意事项

  • 服务端计算CRC32的时候要和ESP8266的CRC32类使用相同的多项式,默认都是0x04C11DB7,只要没有手动修改就不会有匹配问题
  • 如果不想单独做CRC查询接口,也可以把固件的CRC32值放在bin文件的最后4个字节,设备下载完所有数据后,先取最后4个字节作为目标CRC,再计算前面所有数据的CRC对比即可
  • 校验失败后可以做最多3次重试,避免偶发的网络波动导致升级失败

内容的提问来源于stack exchange,提问作者Tushar Yadav

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.15 00:27:04