ESP32 ESC BRUSHLESS
Posted: Wed Nov 19, 2025 4:48 am
Code: Select all
#ifdef __cplusplus
extern "C"
#endif
#include "esp_adc_cal.h"
#include "driver/ledc.h"
#define PWM_HZ 25000
#define PWM_BITS 8
#define A_PWM 0 // # U
#define B_PWM 1 // # V
#define C_PWM 2 // # W
#define A_HIGH 25
#define B_HIGH 26
#define C_HIGH 27
#define A_LOW 14
#define B_LOW 12
#define C_LOW 13
#define A_BEMF 35
#define B_BEMF 34
#define C_BEMF 39
#define POT_SPEED 36
unsigned int TIMER_STEP = 1000; // 1000 DEFAULT // EM ms # TEMPO ENTRE ZERO CROSS RISING E ZERO CROSS FALLING ??????
uint8_t PWM_VALUE = 100; // 39,215% (DE 50KHZ) OU DE 255 # 30392,5 KHZ DE 50KHZ # 1.294V DE 3.3V
uint16_t FAIL_COUNTER = 0; // CONTADOR DE FALHAS
int SEQUENCE_STEP = 0; // SEQUÊNCIA DE STEPS
byte BEMF_ON = 0; // INTERRUPÇOES DE BEMF DESABILITADAS
unsigned long TIMER = 0;
const byte POLES = 14; // NR DE IMÃS NO MOTOR
int POT_VALUE_READ = 0;
//=====================================================================================
//================================= INTERRUPÇÕES BEMF =================================
//=====================================================================================
void ICACHE_RAM_ATTR A_BEMF_FALLING(){ // FALLING A
FAIL_COUNTER = 0; // COLOCA O CONTADOR DE FALHAS EM "0"
byte j = 0; // VARIÁVEL "j" QUEBRA O LOOP EM CASO DE FALHA AO SAIR SEM INTERRUPÇÃO.
for(byte i = 0; i < 30; i++){ // 30 = DEBOUNCE COUNT, SE A BOBINA CAIU NA BORDA FALLING, MAS NÃO FORMOU ARCO,
if(digitalRead(A_BEMF)) // ESPERA ATÉ QUE O ARCO TERMINE, OU SEJA, ATÉ QUE O IMÃ ESTEJA CENTRALIZADO.
i -= 1;
j++;
if(j > 500)
break;
}
BLDC_MOVE(); // ENERGIZA AS BOBINAS DE ACORDO COM A PRÓXIMA SEQUÊNCIA DE STEPS
SEQUENCE_STEP++; // INCREMENTA A CONTAGEM DE STEPS EM "1" PARA SE PREPARAR PARA A PRÓXIMA INTERRUPÇÃO
//-------------------------------------------------------------------------------------
if(SEQUENCE_STEP > 6) // SE A SEQUÊNCIA DE STEPS FOR MAIOR QUE 6,
SEQUENCE_STEP = 1; // REINICIA CONTAGEM
}
//-------------------------------------------------------------------------------------
//*************************************************************************************
//*************************************************************************************
void ICACHE_RAM_ATTR A_BEMF_RISING(){
FAIL_COUNTER = 0;
byte j = 0;
for(byte i = 0; i < 30; i++){
if(!digitalRead(A_BEMF))
i -= 1;
j++;
if(j > 500)
break;
}
BLDC_MOVE();
SEQUENCE_STEP++;
//-------------------------------------------------------------------------------------
if(SEQUENCE_STEP > 6)
SEQUENCE_STEP = 1;
}
//************************************************************************************************
//************************************************************************************************
void ICACHE_RAM_ATTR B_BEMF_FALLING(){
FAIL_COUNTER = 0;
byte j = 0;
for(byte i = 0; i < 30; i++){
if(digitalRead(B_BEMF))
i -= 1;
j++;
if(j > 500)
break;
}
BLDC_MOVE();
SEQUENCE_STEP++;
//-------------------------------------------------------------------------------------
if(SEQUENCE_STEP > 6)
SEQUENCE_STEP = 1;
}
//*************************************************************************************
//*************************************************************************************
void ICACHE_RAM_ATTR B_BEMF_RISING(){
FAIL_COUNTER = 0;
byte j = 0;
for(byte i = 0; i < 30; i++){
if (!digitalRead(B_BEMF))
i -= 1;
j++;
if(j > 500)
break;
}
BLDC_MOVE();
SEQUENCE_STEP++;
//-------------------------------------------------------------------------------------
if(SEQUENCE_STEP > 6)
SEQUENCE_STEP = 1;
}
//*************************************************************************************
//*************************************************************************************
void ICACHE_RAM_ATTR C_BEMF_FALLING(){
FAIL_COUNTER = 0;
byte j = 0;
for(byte i = 0; i < 30; i++){
if(digitalRead(C_BEMF))
i -= 1;
j++;
if(j > 500)
break;
}
BLDC_MOVE();
SEQUENCE_STEP++;
//-------------------------------------------------------------------------------------
if(SEQUENCE_STEP > 6)
SEQUENCE_STEP = 1;
}
//*************************************************************************************
//*************************************************************************************
void ICACHE_RAM_ATTR C_BEMF_RISING(){
FAIL_COUNTER = 0;
byte j = 0;
for(byte i = 0; i < 30; i++){
if(!digitalRead(C_BEMF))
i -= 1;
j++;
if(j > 500)
break;
}
BLDC_MOVE();
SEQUENCE_STEP++;
//-------------------------------------------------------------------------------------
if(SEQUENCE_STEP > 6)
SEQUENCE_STEP = 1;
}
//=====================================================================================
//================================= COMUTAÇÕES DAS BOBINAS ============================
//=====================================================================================
void BH_CL(){
digitalWrite(A_LOW, LOW);
digitalWrite(B_LOW, LOW);
digitalWrite(C_LOW,HIGH);
ledcWrite(A_PWM,0);
ledcWrite(B_PWM,PWM_VALUE);
ledcWrite(C_PWM,0);
if(BEMF_ON == 0){
detachInterrupt(B_BEMF);
detachInterrupt(C_BEMF);
attachInterrupt(A_BEMF, A_BEMF_FALLING, FALLING);
}
}
//*************************************************************************************
//*************************************************************************************
void CH_BL(){
digitalWrite(A_LOW, LOW);
digitalWrite(B_LOW,HIGH);
digitalWrite(C_LOW, LOW);
ledcWrite(A_PWM,0);
ledcWrite(B_PWM,0);
ledcWrite(C_PWM,PWM_VALUE);
if(BEMF_ON == 0){
detachInterrupt(B_BEMF);
detachInterrupt(C_BEMF);
attachInterrupt(A_BEMF, A_BEMF_RISING, RISING);
}
}
//*************************************************************************************
//*************************************************************************************
void CH_AL(){
digitalWrite(A_LOW,HIGH);
digitalWrite(B_LOW, LOW);
digitalWrite(C_LOW, LOW);
ledcWrite(A_PWM,0);
ledcWrite(B_PWM,0);
ledcWrite(C_PWM,PWM_VALUE);
if(BEMF_ON == 0){
detachInterrupt(A_BEMF);
detachInterrupt(C_BEMF);
attachInterrupt(B_BEMF, B_BEMF_FALLING, FALLING);
}
}
//*************************************************************************************
//*************************************************************************************
void AH_CL(){
digitalWrite(A_LOW, LOW);
digitalWrite(B_LOW, LOW);
digitalWrite(C_LOW,HIGH);
ledcWrite(A_PWM,PWM_VALUE);
ledcWrite(B_PWM,0);
ledcWrite(C_PWM,0);
if(BEMF_ON == 0){
detachInterrupt(A_BEMF);
detachInterrupt(C_BEMF);
attachInterrupt(B_BEMF, B_BEMF_RISING, RISING);
}
}
//*************************************************************************************
//*************************************************************************************
void AH_BL(){
digitalWrite(A_LOW, LOW);
digitalWrite(B_LOW,HIGH);
digitalWrite(C_LOW, LOW);
ledcWrite(A_PWM,PWM_VALUE);
ledcWrite(B_PWM,0);
ledcWrite(C_PWM,0);
if(BEMF_ON == 0){
detachInterrupt(A_BEMF);
detachInterrupt(B_BEMF);
attachInterrupt(C_BEMF, C_BEMF_FALLING, FALLING);
}
}
//*************************************************************************************
//*************************************************************************************
void BH_AL(){
digitalWrite(A_LOW,HIGH);
digitalWrite(B_LOW,LOW);
digitalWrite(C_LOW,LOW);
ledcWrite(A_PWM,0);
ledcWrite(B_PWM,PWM_VALUE);
ledcWrite(C_PWM,0);
if(BEMF_ON == 0){
detachInterrupt(A_BEMF);
detachInterrupt(B_BEMF);
attachInterrupt(C_BEMF, C_BEMF_RISING, RISING);
}
}
//*************************************************************************************
//*************************************************************************************
//*************************************************************************************
//*************************************************************************************
//*************************************************************************************
//*************************************************************************************
void BLDC_MOVE(){ // FUNÇÃO DE COMUTAÇÃO DAS BOBINAS
switch (SEQUENCE_STEP){ // A FUNÇÃO QUE ENERGIZA AS BOBINAS E PREPARA AS INTERRUPÇOES DE ACORDO COM A SEQUÊNCIA DE STEPS
case 1: AH_BL(); break;
case 2: AH_CL(); break;
case 3: BH_CL(); break;
case 4: BH_AL(); break;
case 5: CH_AL(); break;
case 6: CH_BL(); break;
default: break;
}
}
//=====================================================================================
//=================================== COMUTAÇÃO INICIAL ===============================
//=====================================================================================
void INITIAL_COMUTATION(){ // 800000 = TESTE LENTO VISÍVEL
TIMER_STEP = 8000; // 8000us = 8ms // 125 HZ # A COMUTAÇÃO DAS BOBINAS É INICIADA EM INTERVALOS DE 8ms
SEQUENCE_STEP = 0; // SEQUÊNCIA DE STEPS DEFINIDO COMO "0"
while(TIMER_STEP > 1000){ // 1000us = 1ms // ENQUANTO INTERVALO DE COMUTAÇÃO FOR MAIOR QUE 1ms (1 KHZ)
SEQUENCE_STEP++; // INCREMENTA SEQUENCIA DE STEPS EM 1
if(SEQUENCE_STEP > 6) // SE A SEQUÊNCIA DE STEPS FOR MAIOR QUE 6...
SEQUENCE_STEP = 1; // REINICIA A CONTAGEM.
BLDC_MOVE(); // CONTINUA PARA O PRÓXIMO STEP
delayMicroseconds(TIMER_STEP); // DELAY ENTRE UM STEP E OUTRO
TIMER_STEP -= 1000; // SUBTRAI (1000)DE TIME_STEP (8000) AYÉ CHEGAR A 1000
}
}
//=====================================================================================
//=================================== GIRO DO MOTOR ===================================
//=====================================================================================
void MOTOR_SPINNER(){
int POT_VALUE = analogRead(POT_SPEED); // O VALOR LIDO NO POTENCIÔMETRO É PROPORCIONAL AO VALOR DO PWMM, (0-4095) # (0-255)
PWM_VALUE = POT_VALUE / 16; // PWM_VALUE = # (4096 / 256 = 16) # (16 / 16 = 1)
if(PWM_VALUE < 5)PWM_VALUE = 15; // É GARANTIDO QUE O VALOR PWM NÃO FIQUE ABAIXO DE 20,(PARA QUE O MOTOR NÃO PARE)
FAIL_COUNTER++; // CONTADOR DE FALHAS USADO PARA BLOQUEAR SE O MOTOR ESTIVER TRAVADO POR QUALQUER MOTIVO
if(FAIL_COUNTER > 250){ // ESTE CONTADOR DE FALHAS É ZERADO SEMPRE QUE OCORRER UMA INTERRUPÇÃO, SE O CONTADOR FOR > QUE 200,
FAIL_COUNTER = 0; // ZERA O CONTADOR DE STEPS
BEMF_ON = 1; // BEMF HABILITADO
detachInterrupt(A_BEMF); // INTERRUPÇÕES DE BEMF DEABILITADAS...
detachInterrupt(B_BEMF); // INTERRUPÇÕES DE BEMF DESABILITADAS...
detachInterrupt(C_BEMF); // INTERRUPÇÕES DE BEMF DESABILITADAS...
PWM_VALUE = 30; // INICIA O MOTOR COM PWM EM 20
INITIAL_COMUTATION(); // ...E A COMUTAÇÃO É REALIZADA NOVAMENTE NO MODO MOTOR DE PASSO (SEM INTERRUPÇÕES).
BEMF_ON = 0; // BEMF DESABILITADAS
SEQUENCE_STEP = 6;
attachInterrupt(digitalPinToInterrupt(A_BEMF), A_BEMF_RISING, RISING);
}
}
//=====================================================================================
//==================================== VOID SETUP =====================================
//=====================================================================================
void setup(){
Serial.begin(115200);
pinMode(A_HIGH, OUTPUT);
pinMode(B_HIGH, OUTPUT);
pinMode(C_HIGH, OUTPUT);
pinMode(A_LOW, OUTPUT);
pinMode(B_LOW, OUTPUT);
pinMode(C_LOW, OUTPUT);
pinMode(A_BEMF, INPUT_PULLUP);
pinMode(B_BEMF, INPUT_PULLUP);
pinMode(C_BEMF, INPUT_PULLUP);
ledcAttachPin(A_HIGH, A_PWM);
ledcAttachPin(B_HIGH, B_PWM);
ledcAttachPin(C_HIGH, C_PWM);
ledcSetup(A_PWM, PWM_HZ, PWM_BITS);
ledcSetup(B_PWM, PWM_HZ, PWM_BITS);
ledcSetup(C_PWM, PWM_HZ, PWM_BITS);
//=====================================================================================
//==================================== VOID LOOP ======================================
//=====================================================================================
void loop() {
MOTOR_SPINNER();
}