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
相关产品推荐
相关产品推荐

