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

ESP32开启WiFi时analogRead(A10)失效的固件修复方案咨询

解决ESP32 WiFi与ADC2引脚冲突的固件方案

你的问题是ESP32的ADC2引脚(GPIO4/A10)与WiFi硬件资源冲突导致读取失败,由于板子已量产无法更换引脚,完全可以通过固件修改来规避这个问题——核心思路是临时暂停WiFi射频模块,完成ADC读取后再恢复WiFi功能,以下是具体实现方案和代码修改示例:

冲突原因说明

ESP32的ADC2模块与WiFi/蓝牙射频共享同一组硬件总线,当WiFi处于活跃状态时,射频会独占这部分资源,导致ADC2无法正常采样,返回固定值0。这是硬件层面的资源限制,只能通过固件调度来规避。

可行的固件修改方案

1. 调整读取逻辑:中断标记+主任务处理

由于WiFi操作不能在中断上下文执行(会导致系统崩溃或死锁),需要把ADC读取的逻辑从定时器中断移到主任务中:

  • 定时器中断仅负责标记需要读取电池电量
  • 主loop中检测到标记后,执行WiFi暂停→ADC读取→WiFi恢复的流程

2. WiFi暂停与恢复的实现

使用WiFi.mode()函数临时关闭WiFi,读取完成后恢复之前的WiFi模式。需要注意保存当前WiFi状态,避免恢复后无法重连。

3. 代码修改示例

基于你提供的代码,修改后的完整代码如下(关键修改处已标注):

#include <WiFi.h>

#define LED_BUILTIN 2

#define LEVEL1 25           // Level1 : GPIO 25 of ESP32
#define LEVEL2 26           // Level2 : GPIO 26 of ESP32
#define LEVEL3 27           // Level3 : GPIO 27 of ESP32
#define LEVEL4 14           // Level4 : GPIO 14 of ESP32

#define VBUS_DETECT 12       //GPIO 13

#define BATTERY_READ A10      //GPIO 4(A10) : Analog READ PIN for the battery voltage

#define BATTERY_0   1950         // ADC value for Battery 0%  - 1950
#define BATTERY_25  2303         // ADC value for Battery 25% - 2200
#define BATTERY_50  2400         // ADC value for Battery 50% - 2275
#define BATTERY_75  2410         // ADC value for Battery 75% - 2310
#define BATTERY_100 2850         // ADC value for Battery 100%  2850

int LEVELS[4] = {25, 26, 27, 14};
int batSensorValue = 0;  // value read from the pot
int full_charged = 0;
hw_timer_t *Timer0_Cfg = NULL;
int prevBatIndex = 0;
int batTimerCount = 0;
int gSensorValue = 0;
int adjustedSensorValue = 0;
int functionalSensorValue = 0;
uint8_t sensorBuffer = 4;
bool chargeFlashFlag = 0;
bool needReadBattery = false; // 新增:标记需要读取电池电量
wifi_mode_t prevWiFiMode;     // 新增:保存暂停前的WiFi模式

int getLevelIndex(int value) {
  switch (value) {
    case 0 ... BATTERY_25 - 1:
      return 1;
    case BATTERY_25 ... BATTERY_50 - 1:
      return 2;
    case BATTERY_50 ... BATTERY_75 - 1:
      return 3;
    case BATTERY_75 ... BATTERY_100 - 1:
      return 4;  
    default:
      return 5;
  }
}

void IRAM_ATTR Timer0_ISR() {
  batTimerCount++;
  
  // 仅标记需要读取,不再在中断中执行ADC读取
  if(batTimerCount >= 10) {
    needReadBattery = true;
    batTimerCount = 0;
  }
}

// 新增:电池电量读取与处理函数
void readAndProcessBattery() {
  // 保存当前WiFi模式
  prevWiFiMode = WiFi.getMode();
  
  // 暂停WiFi
  WiFi.mode(WIFI_OFF);
  
  // 多次读取取平均值(原逻辑的10次采样)
  gSensorValue = 0;
  for(int i=0; i<10; i++) {
    batSensorValue = analogRead(BATTERY_READ);
    gSensorValue += batSensorValue;
    delay(10); // 短延迟保证采样稳定
  }
  
  // 恢复WiFi模式
  WiFi.mode(prevWiFiMode);
  // 如果之前是STA模式,尝试重连(防止暂停导致断开)
  if(prevWiFiMode == WIFI_STA && !WiFi.isConnected()) {
    WiFi.reconnect();
  }
  
  // 原有的数据处理逻辑
  int vbusStatus = digitalRead(VBUS_DETECT);
  adjustedSensorValue = (vbusStatus == 1 ? ((gSensorValue/10)-58) : (gSensorValue/10));
  
  if (  (BATTERY_0 - sensorBuffer) <= adjustedSensorValue && adjustedSensorValue <= (BATTERY_0 + sensorBuffer) ||
        (BATTERY_25 - sensorBuffer) <= adjustedSensorValue && adjustedSensorValue <= (BATTERY_25 + sensorBuffer) ||
        (BATTERY_50 - sensorBuffer) <= adjustedSensorValue && adjustedSensorValue <= (BATTERY_50 + sensorBuffer) ||
        (BATTERY_75 - sensorBuffer) <= adjustedSensorValue && adjustedSensorValue <= (BATTERY_75 + sensorBuffer) ||
        (BATTERY_100 - sensorBuffer) <= adjustedSensorValue && adjustedSensorValue <= (BATTERY_100 + sensorBuffer) )
  {
    functionalSensorValue = adjustedSensorValue + sensorBuffer + 1;
  }
  else functionalSensorValue = adjustedSensorValue; 

  int levelIndex = getLevelIndex(functionalSensorValue);
  full_charged = (levelIndex == 5) ? 1 : 0;

  Serial.print("levelIndex = ");
  Serial.println(levelIndex);
  Serial.print("sensor = ");
  Serial.println(adjustedSensorValue);
  
  // LED控制逻辑
  if(prevBatIndex > vbusStatus) {
    prevBatIndex = 0;
    return;
  }

  for(int i = 0; i < 4; i++) {
    digitalWrite(LEVELS[i], i < levelIndex ? HIGH : LOW);
  }  

  if(full_charged == 0 && vbusStatus == 1 && chargeFlashFlag == 0)  {
    digitalWrite(LEVELS[levelIndex-1], !digitalRead(LEVELS[levelIndex-1]));
  }

  if (vbusStatus == 1) chargeFlashFlag = (chargeFlashFlag+1)%2;

  prevBatIndex = vbusStatus;
  gSensorValue = 0;
}

void setup() {
  Serial.begin(115200);
  
  WiFi.begin();

  pinMode(LEVEL1, OUTPUT);
  pinMode(LEVEL2, OUTPUT);
  pinMode(LEVEL3, OUTPUT);
  pinMode(LEVEL4, OUTPUT);
  pinMode(VBUS_DETECT, INPUT);

  Timer0_Cfg = timerBegin(0, 80, true);
  timerAttachInterrupt(Timer0_Cfg, &Timer0_ISR, true);
  timerAlarmWrite(Timer0_Cfg, 100000, true); // 100ms触发一次
  timerAlarmEnable(Timer0_Cfg);
}

void loop() {
  // 检查是否需要读取电池电量
  if(needReadBattery) {
    needReadBattery = false;
    readAndProcessBattery();
  }
  delay(100);
}

关键注意事项

  • WiFi暂停时间:整个读取过程仅需几十毫秒,对WiFi连接的影响极小,用户几乎感知不到
  • 重连逻辑:如果WiFi在暂停时处于连接状态,恢复后需要调用WiFi.reconnect()确保重新连接
  • 采样时机:如果你的设备有大量WiFi数据传输,可以选择在传输间隙读取,进一步降低影响
  • 备选方案:也可以尝试使用ESP-IDF原生的adc2_get_raw()函数,该函数会尝试获取ADC2使用权,失败时返回错误,但这种方式在WiFi活跃时成功率较低,不如暂停WiFi可靠

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.02 19:14:58