Controle de potência via PWM - ESP32

Controle de potência via PWM - ESP32 

A modulação por largura de pulso (PWM) é uma técnica amplamente utilizada em diversos meios, principalmente para controle de potência e velocidade. Neste tutorial, você aprenderá a configurar o PWM no ESP32 através do recurso LED PWM e fazer um LED "respirar" (fade) ou acender com metade do brilho.

[toc]

Pulse Width Modulation

Controle de potência via PWM - ESP32

Com o PWM, podemos controlar a tensão média em um componente, e por consequência a potência, como um LED, a velocidade de um motor DC ou até converter o sinal PWM criado (onda quadrada) para uma onda senoidal com a adição de alguns poucos itens.

As imagens (GIF) abaixo mostram o duty cycle variando, que altera a tensão média entregue ao componente. Em alguns casos como motores, também é preciso configurar corretamente a frequência de chaveamento e ter atenção ao nível de pico máximo aceito na alimentação, entretanto isso ficará de "lição de casa" para pesquisarem.

Controle de potência via PWM - ESP32
Brilho de LED com a variação do duty cycle
Controle de potência via PWM - ESP32
Tensão média com a variação do duty cycle

 


Mãos a obra - Variando o brilho do LED

Componentes necessários

Código do projeto

void setup()
{
	pinMode(2, OUTPUT);//Definimos o pino 2 (LED) como saída.

	ledcAttachPin(2, 0);//Atribuimos o pino 2 ao canal 0.
	ledcSetup(0, 1000, 10);//Atribuimos ao canal 0 a frequencia de 1000Hz com resolucao de 10bits.
	
}

void loop()
{
	for (int i = 0; i < 1024; i++)
	{
		ledcWrite(0, i);//Escrevemos no canal 0, o duty cycle "i".
		delay(2);
	}

	for (int i = 1023; i > 0; i--)
	{
		ledcWrite(0, i);
		delay(2);
	}
}

Colocando para funcionar

O código fará um "fade" no LED, dando a sensação de "respiração", aumentando e diminuindo o brilho gradativamente.


Entendendo a fundo

Software

-Função ledcAttachPin()

ledcAttachPin(PINO, CANAL);

Esta função apenas atribui um pino a um canal. Podemos escolher qualquer pino a qualquer canal, este vai de 0 a 15, totalizando 16 canais.

Cada canal é independente do outro, mas você também pode atribuir vários pinos a um mesmo canal.

Pino: Qualquer.

Canal: 0 - 15.

-Função ledcSetup()

ledcSetup(CANAL, FREQUENCIA, RESOLUCAO);

Esta função configura um canal para trabalhar a uma determinada frequência e resolução.

Canal: 0 - 15.

Frequência: 1 - 40MHz.

Resolução: 1 - 16 bits.

-Função ledcWrite()

ledcWrite(CANAL, DUTY CYCLE);

Esta função "escreve" o duty cycle ao canal. Lembramos que o valor colocado no parâmetro duty cycle não é em porcentagem e sim em decimal.

Exemplo: para um duty cycle de 50% com 10bits (2^10 = 1024) de resolução, devemos escrever 512.

Canal: 0 - 15.

Duty cycle: 0 - 100% (em decimal).


Indo além com PWM 

Tensão média

Podemos calcular a tensão média (V) entregue ao componente através de uma simples conta que relaciona o sinal HIGH com o duty cycle.

Sinal HIGH do ESP32 (Vcc): ~3.3V.

Duty cycle: 32%.

Ao efetuar a conta de 3.3*0.32, chegamos a conclusão que a tensão média (Vm) entregue será de 1.056V!

Vamos testar este código e verificar as tensões com um multímetro.

void setup()
{
	pinMode(23, OUTPUT);//Definimos o pino 23 como saída.
	pinMode(22, OUTPUT);//Definimos o pino 22 como saída.
	pinMode(21, OUTPUT);//Definimos o pino 21 como saída.
	pinMode(19, OUTPUT);//Definimos o pino 19 como saída.

	ledcAttachPin(23, 0);//Atribuimos o pino 23 ao canal 0.
	ledcSetup(0, 1000, 10);//Atribuimos ao canal 0 a frequencia de 1000Hz com resolucao de 10bits.
	ledcWrite(0, 256);//Escrevemos um duty cycle de 25% no canal 0.

	ledcAttachPin(22, 1);//Atribuimos o pino 22 ao canal 1.
	ledcSetup(1, 1000, 10);//Atribuimos ao canal 1 a frequencia de 1000Hz com resolucao de 10bits.
	ledcWrite(1, 512);//Escrevemos um duty cycle de 50% no canal 1.

	ledcAttachPin(21, 2);//Atribuimos o pino 21 ao canal 2.
	ledcSetup(2, 1000, 10);//Atribuimos ao canal 2 a frequencia de 1000Hz com resolucao de 10bits.
	ledcWrite(2, 768);//Escrevemos um duty cycle de 75% no canal 2.

	ledcAttachPin(19, 3);//Atribuimos o pino 19 ao canal 3.
	ledcSetup(3, 1000, 10);//Atribuimos ao canal 3 a frequencia de 1000Hz com resolucao de 10bits.
	ledcWrite(3, 1023);//Escrevemos um duty cycle de 100% no canal 3.
}

void loop()
{

}

Testando este código e verificando o pino respectivo com um multímetro, podemos perceber que as contas são iguais ou próximas. Lembrando que o próprio multímetro tem sua faixa de precisão (erro), que neste caso é (+-0.5% + 3D com 1mV de resolução).

Todos os testes a seguir tem Vcc teórico de 3.3V, as imagens são as leituras do nosso multímetro.

Caso 1, 25% = 0.825V

25%

Caso 2, 50% = 1.65V

50%

Caso 3, 75% = 2.475V

75%

Caso 4, 100% = 3.3V

100%

Todos os valores lidos, mesmo estando próximos aos teóricos, há o erro do multímetro. Aplicando a formula de erro ao valor lido, todos os valores obtidos estão dentro da faixa tolerável de erro, ou seja, estão corretos!

Frequência X resolução

Um problema recorrente com alguns componentes é a frequência necessária de funcionamento. Motores por exemplo, é bastante usado entre 20kHz e 200kHz.

O recurso "LED PWM" do ESP32 é baseado em um clock de 80MHz, logo podemos fazer algumas contas básicas para se chegar a frequência máxima com a resolução escolhida.

Nos exemplos acima, foi usado uma frequência de 1kHz com 10bits de resolução, entretanto pode ser necessário o uso de uma frequência muito maior e a resolução é uma das barreiras para isso. Vamos fazer essa conta com os dados citados para chegar na frequência máxima (Fm).

A resolução deve ser em decimal e não "bits".

80MHz / 10bits

80000000 / 1024 = 78125Hz

A frequência máxima que conseguimos chegar com uma resolução de 10bits no ESP32 é de ~78kHz. Vamos testar!

Caso 1, 32kHz com 10bits

Caso 1

Caso 1.1, 80kHz com 10bits

Caso 1.1

Como feito nas contas, a frequência máxima realmente foi de ~78kHz para 10bits, mesmo atribuindo 80kHz no código. Agora vamos brincar com frequências mais altas deixando a resolução em 3bits e ver a frequência máxima.

80MHz / 3bits = Fm

80000000 / 8 = 10MHz

Caso 2, 2MHz com 3bits

Caso 2

Caso 2.1: 11MHz com 3bits

Caso 2.1

Novamente, as contas mostraram um máximo de 10MHz e mesmo atribuindo 11MHz, ficou limitado a 10MHz.


Considerações finais

O PWM é extremamente útil em diversos projetos, permitindo o controle de potência, velocidade, brilho e até inversores (DC-AC) através da modulação da tensão. Apesar de parecer simples apenas "inverter o estado do pino", com frequências um pouco mais altas, não é qualquer microcontrolador que aguenta se manter com uma frequência estável ou se quer chegar em frequências acima de 10MHz. O ESP32 com 1bit de resolução nos permite chegar a 40MHz, dando uma vasta gama de possibilidades em aplicações.


Touch capacitivo - ESP32

Touch capacitivo com ESP32

Nesse tutorial aprenderemos a usar sensores de touch capacitivo em nossos projetos com o ESP32, que tem suporte nativo a este recurso incrível. Em vários projetos, precisamos adicionar botões ou algum tipo de sensor para toque (pressão); o mais usado por ser barato e fácil, é o Push Button, porem, alem de dar um aspecto "velho" ao projeto, pode gerar problemas mais frequentes como por exemplo Bounce. Para contornar estes problemas, usaremos o Touch capacitivo, que é o mesmo do seu celular moderno (Smartphone), ao mínimo toque, é detectado e executado tal tarefa.


Mãos à obra - Implementando um touch capacitivo no ESP32

Componentes necessários

Montando o projeto

A montagem é simples, apenas sendo necessário ligar o jumper ao GPIO4, ficara parecido com o nosso:

Touch capacitivo esp32

Programando

long lastms;//Váriavel para guardar o ultimo toque.

void setup()
{
    Serial.begin(9600);//Inicia a comunicação Serial para visualização dos valores do Touch.
    pinMode(LED_BUILTIN, OUTPUT);//Define o LED OnBoard como saída
    touchAttachInterrupt(4, led, 20);//Atribui uma função (led) quando for detectado um valor menor de (20) ao pino (4).
    lastms = 0;//Inicializa a váriavel em 0.

    //Para chegar a este valor usado (20), é necessário apenas ver os valores que aparece no Serial monitor,
    //toque o fio e veja qual sera o novo valor. Ao tocar, a tendencia do valor é aproximar-se de 0.
}


void loop()
{
    Serial.println(touchRead(4));//Mostra o valor do touch no monitor.
    delay(100);
}

void led()//função que foi atribuida para o evento do touch.
{
    if (millis() - lastms > 150)//Verifica se o ultimo toque faz mais de 150mS
    {
        digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN));//Inverte o estado do led.
        lastms = millis();//Salva o ultimo tempo em que foi tocado.
    }
}

Colocando para funcionar

Após o upload, podemos tocar na ponta do fio que perceberemos o LED invertendo seu estado. Se você manter tocado, verá que o LED ficará piscando, no intervalo de 150mS. Veja como ficou o nosso neste video:


Entendendo a fundo

Software

- Função de Interrupção touch -  touchAttachInterrupt()

touchAttachInterrupt(4, led, 20);

Esta função, atribui uma rotina de interrupção para quando for detectado um valor abaixo do definido para o pino. Neste caso, quando o ESP32 detectar um valor abaixo de 20 no pino 4, irá chamar a função led(). A nossa função led() apenas inverte o estado do led com um intervalo de tempo para que não pisque muito rápido.

Lembre-se que a função interrupção é como uma chamada telefônica. O controlador para tudo que está fazendo para atende-la.

- Função led()

A função led() é chamada através da interrupção no pino 4.

void led()//função que foi atribuida para o evento do touch.
{
    if (millis() - lastms > 150)//Verifica se o ultimo toque faz mais de 150mS
    {
        digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN));//Inverte o estado do led.
        lastms = millis();//Salva o ultimo tempo em que foi tocado.
    }
}

Sabemos que o processamento de um microcontrolador é muito mais rápido do que podemos interagir. Quando acionamos o touch, o ESP chamará milhares de vezes a interrupção que foi atribuída a função led(). Por isso é importante implementarmos uma maneira de fazer com que a iteração do LED ocorra apenas após um determinado tempo

Uma forma de fazer isso é usar um contador de tempo com o auxilio da função millis(), uma variável auxiliar e um IF.

  1.  A função millis() conta o tempo em milissegundos desde que o ESP32 foi ligado.
  2.  A variável auxiliar armazena o valor do millis() da ultima vez que houve alteração do estado do LED
  3. A condicional IF compara o tempo atual do millis() com o tempo armazenado na variável auxiliar, se for maior que o tempo escolhido, ele entra na rotina do IF, altera o estado do LED e novamente armazena o novo tempo de millis().

Ou seja: Essa rotina subtrai o tempo atual com o anterior, e se for maior que 150mS, irá inverter o LED e salvar o novo tempo. Dessa forma, só invertemos o estado do LED depois que passou 150ms da ultima mudança de estado.

Veja que se você ficar com o dedo pressionado o tempo todo, teremos o LED ligando e desligando de 150ms em 150ms.

Você poderia usar delay() também, mas o problema é que o delay mantem o microcontrolador parado contando o tempo enquanto esse tipo de rotina implementada permite que o controlador continue com a execução das outras tarefas.

Por isso essa função condicional é bastante usada para atribuir intervalos entre as ações, uma alternativa saudável para o delay().

- Função de leitura do touch

touchRead(4)

Esta função, retorna o valor do pino (Threshold). Este valor pode váriar de acordo do lugar de ESP32. Em nossos testes, ao plugar o ESP32 na Protoboard, o valor foi de 84 para 60. Os valores quando não estamos tocando ficaram em média de 60, e ao tocar, aproximou-se de 0.

Por isso definimos 20 na função anterior, pois ao tocar, o valor aproxima-se de 0, então colocando 20, teremos certeza que foi um toque e chamamos a função para inverter o LED.

- Uma outra forma de implementar o touch

Veja que você poderia implementar a leitura no seu programa sem usar a interrupção. Usando um IF na função loop por exemplo.

void loop()
{
    Serial.println(touchRead(4));//Mostra o valor do touch no monitor.
    delay(100);

    if(touchRead(4) < 20) //verifica se o valor lido é menor que 20
    {
      if (millis() - lastms > 150)//Verifica se o ultimo toque faz mais de 150mS
        {
          digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN));//Inverte o estado do led.
          lastms = millis();//Salva o ultimo tempo em que foi tocado.
        }
    }
}

O programa todo ficaria assim:

long lastms;//Váriavel para guardar o ultimo toque.

void setup()
{
    Serial.begin(9600);//Inicia a comunicação Serial para visualização dos valores do Touch.
    pinMode(LED_BUILTIN, OUTPUT);//Define o LED OnBoard como saída
    lastms = 0;
}

void loop()
{
    Serial.println(touchRead(4));//Mostra o valor do touch no monitor.
    delay(100);

    if(touchRead(4) < 20) //verifica se o valor lido é menor que 20
    {
      if (millis() - lastms > 150)//Verifica se o ultimo toque faz mais de 150mS
        {
          digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN));//Inverte o estado do led.
          lastms = millis();//Salva o ultimo tempo em que foi tocado.
        }
    }
}

Hardware

Antes do touch capacitivo entrar em uso continuo em celulares, o touch era resistivo, sendo necessário tocar a tela com certa pressão para que fosse detectado o toque. Já o touch capacitivo, é mais sensível e permitindo um manuseio mais fácil da tela. Veja a imagem representando o touch capacitivo:

Touch capacitivo esp32 1

Quando você toca no fio ou tela, há uma troca de elétrons entre as partes, e com isso, permite o nosso sistema detecta-lo.


Desafio

O desafio desta vez, é que você monte um teclado matricial com o touch do ESP32 para digitar uma senha por exemplo.

teclado matricial


Fechamento

Hoje você aprendeu a usar esta íncrivel função que ESP32 nos dá. Com ela, é possível deixar nosso projetos extremamente modernos e bonitos. Alem disto, você também pode usa-lo em conjunto com o ULP para acordar o ESP32 de Deep-Sleep, viabilizando projetos portáteis e vestíveis. Se houver alguma sugestão, dúvida ou crítica, comente abaixo que iremos te responder.


conhecendo ESP32

Conhecendo o ESP32

Conhecendo o ESP32

Vamos conhecer mais a respeito do incrível "irmão mais novo" do nosso querido ESP8266, o ESP32. Este novo microcontrolador da Espressif é uma melhoria do seu antecessor, com mais poder de processamento (Triple core), memória e novos recursos, incluindo Bluetooth e sensores de touch capacitivo. Veja abaixo uma lista de características do ESP32.

Figura 1 - NodeMCU 32-S
Figura 1 - NodeMCU 32-S

Características do ESP-WROOM32

  • Processador principal: LX6 32-bit Dual-core, operando 2-240 MHz.
  • Processador secundário: ULP (Ultra Low Power coprocessor) 8MHz e consome 150uA.
  • FLASH: 4MB.
  • RAM: 520kB.
  • GPIO: 34, com 3.3V e 12mA.
  • ADC: 18, com resolução de 12-bit.
  • DAC: 2, com resolução 8-bit.
  • WiFi: 2,4 GHz, 802.11 b/g/n.
  • Bluetooth: Bluetooth Low Energy v4.2 (BLE).
  • Acelerador via hardware para encriptações, hash e afins. (AES, RSA, SHA e ECC).
  • True Random Number Generator (TRGN).
  • 4 Timers de 64-bit.
  • 4 Watchdogs.
  • 10 Sensores de Touch Capacitivo.
  • 1  Sensor de temperatura interno.
  • 1 Sensor de efeito Hall.

O ULP é um processador de baixo consumo que pode ser usado até em Deep Sleep, e com isso, conseguimos acordar o micro controlador das mais diversas formas, como por exemplo dados na Serial, informação de algum sensor ou os próprios sensores de toque capacitivo. Vários erros que aconteciam com o ESP8266 foram corrigidos e/ou melhorados, por exemplo, as tarefas de background, interrupções, yield() e watchdogs. Ainda é cedo para dizer (no momento) se foram corrigidos totalmente ou apenas melhorados para que gerem menos inconvenientes.

Podemos programa-lo de diversas formas, inclusive na Arduino IDE. Porem, a inclusão das funções do ESP32 ainda está atrasada em relação a esp-IDF, há varias funções que ainda não foram portadas para o Core do Arduino, a principal até o momento, é o Bluetooth, que ainda não é possível usufruir corretamente. Se você precisa usar o Bluetooth ou alguma função que ainda não foi incluída à Arduino IDE, sugerimos que use a esp-IDF.

Chega de papo e vamos programar esta belezinha, o nosso novo brinquedo. Iremos usar a Arduino IDE por já estarmos familiarizado com os comandos e funções.


Instalando o ESP32 na Arduino IDE

Instalando o Python no seu computador

Talvez seja necessário a instalação do Python em sua maquina caso ainda não tenha instalado. Se você já programou o ESP8266, provavelmente já tem o Python instalado e não precisara instalar novamente.

- Baixando o instalador do Python

Entre em   ( https://www.python.org/downloads/ )   e Baixe o Python 2.7.XX

- Instalando o Python

Abra o instalador e siga até a terceira tela. Na terceira tela ative a opção "Add Python.exe to Path" clicando em "Will be installed on local hard drive" e termine a instalação.

 

Instalando o Driver (Core) do ESP32 na IDE Arduino

1 - Baixe o ZIP do ESP32, disponível no site do GitHub. ( https://github.com/espressif/arduino-esp32 )

 

2- Extraia os arquivos dentro da pasta Arduino/hardware/espressif/esp32/ , que se encontra em seu HD. Ficara igual o nosso:

 

3- Vá em esp32/tools e execute o arquivo GET.exe . Irá começar o download de novos arquivos e isso pode demorar um pouco. Ao fim, a janela se fechara automaticamente.

 

4- Abra a Arduino IDE, e veja se as placas do ESP32 estão disponíveis para seleção.

 

5- Plugue seu ESP32 no computador e espere a instalação automática do driver CP2102. Alguns usuários relatam que não foi possível a instalação automática, sendo necessário a instalação manualmente do driver CP2102. Após a instalação do driver, selecione a porta COM respectiva do seu ESP32, se estiver em duvida qual seja, desconecte o ESP32 do computador e veja quais portas estão ativas, agora conecte novamente e veja a porta que apareceu.


Mãos à obra

Componentes necessários

Programando

Iremos fazer o primeiro upload para nossa placa com o clássico Blink. O Blink é um código para piscar LEDs de forma bem simples. Na placa NodeMCU há um LED OnBoard que iremos piscar, então não é preciso usar um LED externo. Caso você queira usar um LED externo, não se esqueça de alterar os pinos no código.

Código do projeto

void setup()
{
    pinMode(LED_BUILTIN, OUTPUT);//Habilita o LED onboard como saída.
}

void loop()
{
    digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN));//Faz o LED piscar (inverte o estado).
    delay(250);//espera 250mS para inverter o estado do LED.
}

Colocando para funcionar

Após o upload do código, nosso micro controlador começara a piscar, veja o nosso:

ESP32


Entendendo a fundo

Software

- Função Setup

void setup()
{
    pinMode(LED_BUILTIN, OUTPUT);//Habilita o LED onboard como saída.
}

A função de Setup do Arduino é feita da mesma forma, ao ligar/resetar o micro controlador, esta função é executada uma unica vez, por isso o nome "setup", referenciando uma função que configure nosso micro controlador. Normalmente as configurações iniciais, como por exemplo definição de pino (Input/Output) só é necessária ser feita uma vez, logo, adicionamos ela ao setup. Diferentemente do Loop, que é aonde nosso código é executado infinitamente.

- Função pinMode

pinMode(LED_BUILTIN, OUTPUT);//Habilita o LED onboard como saída.

A função pinMode(pino, estado) é usada para definir qual o estado de um pino do micro controlador, no caso, iremos controlar um LED, então foi declarado OUTPUT, para que possamos alterar o nivel lógico do pino (LOW ou HIGH).

- Função digitalWrite

digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN));//Faz o LED piscar (inverte o estado).

A função digitalWrite(pino, estado) é usada para "escrever" um valor no pino do micro controlador. Você pode usar LOW e HIGH, para acender ou apagar um LED, ligar ou desligar motores e etc. Também foi usado a função digitalRead(pino) que faz a leitura do atual estado do pino, e após pegar este valor, nós invertemos com a exclamação " ! ", que se encontra antes da função digitalRead(). Fazendo isto, nós sempre iremos alternar o estado do LED, ou seja, se esta ligado, desligamos; e se esta desligado, ligamos.

- Função Delay

delay(250);//espera 250mS para inverter o estado do LED.

A função delay(mS) é usada para adicionar um tempo entre as tarefas. Se ela não for usada, o LED irá piscar muito rapidamente, impossibilitando a visualização. Logo, usamos 250mS para que possamos ver o LED piscando lentamente.


Fechamento

Então chegamos ao fim de mais um tutorial, aprendemos a instalar e dar o primeiro upload neste incrivel micro controlador. Nos proximos tutoriais, iremos ensinar sobre como dividir tarefas entre os 2 processadores, permitindo assim, que você rode 2 códigos ao mesmo tempo.

Você também pode optar por instalar a ESP-IDF, um ambiente completo de desenvolvimento pro ESP32 que suporta todas configurações e features do microcontrolador: https://portal.vidadesilicio.com.br/instalando-esp-idf-no-windows-esp32/

Se houver dúvidas ou sugestões, fique à vontade para comentar!