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

ESP32开启BLE后analogWrite仅GPIO2可用,其他GPIO失效求助

ESP32开启BLE后仅GPIO2可使用PWM的解决方案

问题概述

ESP32 DEVKIT1开发板启用BLE库后,analogWrite仅能控制内置LED(GPIO2),其他GPIO无法实现PWM输出;尝试ESP32原生ledcWrite函数同样无效,但关闭BLE功能后,所有GPIO的PWM功能均正常工作。

问题原因

ESP32的BLE模块会占用特定的定时器和LEDC通道资源,默认的analogWrite实现或未手动配置的LEDC通道会与BLE的资源产生冲突,导致非GPIO2的引脚无法正常输出PWM信号。

解决方案

手动为需要PWM输出的GPIO分配独立的LEDC定时器和通道,避开BLE占用的资源(BLE通常占用定时器0及部分通道),具体步骤如下:

  • 为每个需要PWM的GPIO定义独立的LEDC定时器、通道和分辨率参数
  • 在setup函数中初始化LEDC定时器和通道
  • 使用ledcWrite替代analogWrite实现PWM输出

修改后的完整代码

#include <Wire.h>
#include <EEPROM.h>
#include <BLEDevice.h>
#include <BLEServer.h>
#include <BLEUtils.h>
#include <BLE2902.h>

#define BOARD_LED 2
#define GREEN_LED 16
#define SERVICE_UUID "4fafc201-1fb5-459e-8fcc-c5c9c331914b"
#define ACCELEROMETER_DATA_UUID "beb5483e-36e1-4688-b7f5-ea07361b26a8"
#define BOX_CHARACTERISTIC_UUID "f27b53ad-c63d-49a0-8c0f-9f297e6cc520"

// LEDC配置参数
#define LEDC_TIMER_0 0
#define LEDC_TIMER_1 1
#define LEDC_CHANNEL_0 0
#define LEDC_CHANNEL_1 1
#define LEDC_RESOLUTION 8  // 8位分辨率,对应PWM值范围0-255
#define LEDC_FREQ 5000     // PWM频率5kHz

BLECharacteristic *pStepDataCharacteristic;
BLECharacteristic *pLedStateCharacteristic;
BLECharacteristic *pPWMLedCharacteristic;

const size_t receivedArraySize = 2;
int receivedArray[receivedArraySize];
String boxValue = "";

const int MPU_ADDR = 0x68;
int16_t accelX, accelY, accelZ;

void ChangeLedState (int* dataFromMobileApp) {
  // 使用ledcWrite替代analogWrite
  ledcWrite(LEDC_CHANNEL_0, dataFromMobileApp[0]);
  ledcWrite(LEDC_CHANNEL_1, dataFromMobileApp[1]);
}

class MyServerCallbacks : public BLEServerCallbacks
{
  void onConnect(BLEServer *pServer)
  {
    Serial.println("Connected");
  }

  void onDisconnect(BLEServer *pServer)
  {
    Serial.println("Disconnected");
  }
};

class CharacteristicsCallbacks : public BLECharacteristicCallbacks
{
  void onWrite(BLECharacteristic *pCharacteristic)
  {
    stringToIntArray(pCharacteristic->getValue().c_str(), receivedArray, receivedArraySize);
    ChangeLedState(receivedArray);
    Serial.print("Value Written ");
    Serial.println(pCharacteristic->getValue().c_str());

    if (pCharacteristic == pLedStateCharacteristic)
    {
      boxValue = pCharacteristic->getValue().c_str();
      pLedStateCharacteristic->setValue(
        const_cast<char *>(boxValue.c_str())
      ); 
               
      pLedStateCharacteristic->notify();
    }
  }
};

void stringToIntArray(const String& inputString, int* intArray, size_t arraySize) {
  char buffer[10];

  size_t bufferIndex = 0;
  size_t arrayIndex = 0;

  for (size_t i = 0; i < inputString.length(); i++) {
    char currentChar = inputString.charAt(i);
    if (isdigit(currentChar) || currentChar == '-') {
      buffer[bufferIndex++] = currentChar;
    } else if (currentChar == ',' || i == inputString.length() - 1) { 
      buffer[bufferIndex] = '\0';
      intArray[arrayIndex++] = atoi(buffer);
      bufferIndex = 0;
    }
  }
}

void readAccelerometerData() {
  Wire.beginTransmission(MPU_ADDR);
  Wire.write(0x3B);
  Wire.endTransmission(false);
  Wire.requestFrom(MPU_ADDR, 6, true);

  accelX = Wire.read() << 8 | Wire.read();
  accelY = Wire.read() << 8 | Wire.read();
  accelZ = Wire.read() << 8 | Wire.read();
}

void setup() {
  Wire.begin();
  Serial.begin(9600);
  Wire.beginTransmission(MPU_ADDR);
  Wire.write(0x6B);
  Wire.write(0);
  Wire.endTransmission(true);
  delay(2000);

  // 初始化LEDC定时器
  ledcSetup(LEDC_CHANNEL_0, LEDC_FREQ, LEDC_RESOLUTION);
  ledcSetup(LEDC_CHANNEL_1, LEDC_FREQ, LEDC_RESOLUTION);
  // 将通道绑定到对应GPIO
  ledcAttachPin(BOARD_LED, LEDC_CHANNEL_0);
  ledcAttachPin(GREEN_LED, LEDC_CHANNEL_1);

  BLEDevice::init("Step-Sense");
  
  BLEServer *pServer = BLEDevice::createServer();
  pServer->setCallbacks(new MyServerCallbacks());
  BLEService *pService = pServer->createService(SERVICE_UUID);
  delay(100);

  pStepDataCharacteristic = pService->createCharacteristic(
  ACCELEROMETER_DATA_UUID,
  BLECharacteristic::PROPERTY_READ |
  BLECharacteristic::PROPERTY_WRITE |
  BLECharacteristic::PROPERTY_NOTIFY |
  BLECharacteristic::PROPERTY_INDICATE
  );

  pLedStateCharacteristic = pService->createCharacteristic(
      BOX_CHARACTERISTIC_UUID,
      BLECharacteristic::PROPERTY_READ |
      BLECharacteristic::PROPERTY_WRITE |
      BLECharacteristic::PROPERTY_NOTIFY |
      BLECharacteristic::PROPERTY_INDICATE
  );

  pStepDataCharacteristic->addDescriptor(new BLE2902());

  pService->start();

  BLEAdvertising *pAdvertising = pServer->getAdvertising();
  pAdvertising->start();
  Serial.println("BLE device is ready to be connected");

  pStepDataCharacteristic->setValue("[0,0,0]");
  pStepDataCharacteristic->setCallbacks(new CharacteristicsCallbacks());

  pLedStateCharacteristic->setValue("0");
  pLedStateCharacteristic->setCallbacks(new CharacteristicsCallbacks());

  Serial.println("Waiting for a client connection to notify...");

  // 无需再调用pinMode,ledcAttachPin已完成配置
}

void loop() {
  readAccelerometerData();
  String strToSend = "[";
  strToSend += accelX;
  strToSend += ",";
  strToSend += accelY;
  strToSend += ",";
  strToSend += accelZ;
  strToSend += "]";

  pStepDataCharacteristic->setValue(strToSend.c_str());
  pStepDataCharacteristic->notify();
  delay(50);
}

说明

  • 手动指定了LEDC的定时器和通道,避免与BLE占用的资源冲突(这里使用了定时器0和1,通道0和1,可根据实际情况调整)
  • 8位分辨率确保PWM值范围为0-255,与原analogWrite的参数范围一致,无需修改手机端传入的数据
  • ledcAttachPin会自动将GPIO配置为输出模式,无需额外调用pinMode

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.04 03:02:03