Lendo sensores analógicos em Deep Sleep com ULP - ESP32

Leitura de sensores analógicos pelo ADC com ULP

Neste tutorial, aprenderemos a ler um sensor analógico através do ADC no ESP32 em Deep Sleep, utilizando o ULP. Esse método de leitura, permite uma economia de bateria gigantesca, já que não precisamos acordar o microcontrolador para efetuar a leitura, situação na qual o gasto é bem maior do que quando mesmo procedimento é feito pelo ULP.

Figura 1 - ULP.

[toc]

kit robotica educacional com Arduino ESP ou Microbit

Por que utilizar?

Imagine que em seu projeto portátil, é preciso ler o sensor de temperatura a cada 30 segundos e para isso, logicamente, precisamos acordar o microcontrolador para efetuar essa tarefa, entretanto, o consumo do ESP32 nesse caso seria de 40mA apenas para ler o sensor. Com o ULP, podemos fazer essa leitura em Deep Sleep e o consumo enquanto o ULP está funcionando não passaria de 150uA, com uma média de consumo dependendo do duty cycle do ULP. Com isso, economizaríamos nesse caso de 150uA (100% duty cycle), aproximadamente 270x mais bateria do que se acordássemos o microcontrolador para essa mesma tarefa.

É fácil perceber o aumento incrível na duração da bateria que poderia ser obtido apenas ao usar o ULP para ler o sensor, as aplicações desse guerreiro são muito grandes, mas o foco é para Sleep.

Se você ainda não conhece o ULP, clique aqui para ver a introdução sobre este incrível coprocessador de baixo consumo presente no ESP32.


Mãos a obra - Lendo um sensor de temperatura em Deep Sleep

Componentes necessários

Códigos do projeto

- Main code (C ou C++), responsável pela programação do ESP32 em si.

#include <C:/msys32/ESP32/ESP32/components/arduino/cores/esp32/Arduino.h>
#include <C:/msys32/ESP32/esp-idf/components/driver/include/driver/rtc_io.h>
#include <C:/msys32/ESP32/esp-idf/components/driver/include/driver/adc.h>
#include <C:/msys32/ESP32/esp-idf/components/ulp/ulp.c>
#include <C:/msys32/ESP32/ESP32/build/main/ulp_main.h>
extern "C"
{
#include <C:/msys32/ESP32/esp-idf/components/esp32/include/esp_clk.h>
}
//Pode ser preciso arrumar os diretorios das bibliotecas
//Pode ser preciso remover o "extern 'C'{}" e definir a biblioteca fora dele, alguns usuarios relatam erro sem o uso do extern

extern const uint8_t ulp_main_bin_start[] asm("_binary_ulp_main_bin_start");
extern const uint8_t ulp_main_bin_end[] asm("_binary_ulp_main_bin_end");
void ulp();


extern "C" void app_main()
{
	initArduino();//inicia configuracoes do arduino, caso nao use o Arduino component, remova essa linha
	pinMode(2, OUTPUT);

	if (esp_sleep_get_wakeup_cause() == ESP_SLEEP_WAKEUP_ULP)//se o wakeup for por causa do ULP, tomara alguma atitude
	{
		digitalWrite(2, 1);
		delay(500);
		digitalWrite(2, 0);
	}
	else//se nao, iniciara o ULP
	{
		ulp();//configura e inicializa o ulp
	}
	

	esp_sleep_enable_ulp_wakeup();//habilita o wakeup pelo ULP
	esp_deep_sleep_start();//entra em deep sleep eterno
}




void ulp()
{
	adc1_config_channel_atten(ADC1_CHANNEL_4, ADC_ATTEN_11db);
	adc1_config_width(ADC_WIDTH_12Bit);
	adc1_ulp_enable();
	//configura o ADC1 #4 (GPIO32) para 3.3V 12bit e atribui o uso ao ULP
	
	ulp_set_wakeup_period(0, 10000000);//ativa o timer de wakeup do ULP apos cada HALT para 10seg

	ulp_load_binary(0, ulp_main_bin_start, (ulp_main_bin_end - ulp_main_bin_start) / sizeof(uint32_t));//carrega os arquivos
	ulp_run((&ulp_main - RTC_SLOW_MEM) / sizeof(uint32_t));//inicia o ULP
}

- ULP code (Assembly .S), responsável pela programação do ULP em si.

#include "soc/soc_ulp.h"
#include "soc/rtc_io_reg.h"
#include "soc/sens_reg.h"
#include "soc/rtc_cntl_reg.h"


.bss//secao das variaveis


.text//secao do codigo


	.global main
	main:

		move r0, 0//r0 = 0
		move r1, 0//r1 = 0
		stage_rst//stage_cnt = 0

		leitura:
			stage_inc 1//stage_cnt++
			adc r1, 0, 4+1//r1 = leitura ADC GPIO32
			add r0, r0, r1//r0 = r0+r1
			jumps leitura, 4, lt//loop responsavel pelas leituras, equivale a um FOR()

		rsh r0, r0, 2//calcula a media das 4 leituras r0 = r0/4
		jumpr wakeup, 496, ge//se a media da leitura que esta em r0 for maior ou igual que 496 (40 graus celsius), acorda o mcu
		halt//coloca o ULP em sleep e ativa o timer de wakeup (definido com 10 segundos no main code)

	wakeup:
		wake//acorda o mcu
		halt

Entendendo a fundo

Software

leitura:
			stage_inc 1
			adc r1, 0, 4+1
			add r0, r0, r1
			jumps leitura, 4, lt

		rsh r0, r0, 2
		jumpr wakeup, 496, ge
		halt

A parte interessante e diferente do código é justamente a leitura do canal ADC, nós poderíamos fazer mais simples sem utilizar uma estrutura de repetição FOR(), entretanto, é sempre interessante fazer uma média de leituras (inclusive com delay's) para evitar ruídos e coisas do tipo. Já ensinamos a fazer o laço FOR() no tutorial introdutório do ULP.

  1. É feito a leitura do canal ADC no GPIO32 4x e a cada leitura, o valor é somado no registrador R0.
  2. Após as 4 leituras precisamos tirar a média entre eles, entretanto, não há mnemônicos simples para divisão como "DIV". Usaremos os operadores de BitWise (RSH - Right Shift Bit) para dividir o valor por 4. Por causa da divisão facilitada com o RSH na base 2 (2, 4, 8, 16...), também faremos uma quantidade de leituras na base 2.

Não se esqueça de conferir o Set de Instruções do ULP nas referências em caso de dúvidas.

-Mnemônico ADC

adc r1, 0, 4+1

Efetua a leitura do ADC no GPIO32 e atribui o valor ao registrador R1.

O segundo e terceiro operador (parâmetro) deste mnemônico se refere a tabela abaixo, onde:

Segundo operador: Controlador ADC (ADC1 = 0 ou ADC2 = 1). Usamos "0" pois o GPIO32 faz parte do ADC1.

Terceiro operador: MUX+1. O GPIO32 esta descrito como "...CH4", logo foi usado seu canal+1 (4+1).

Figura 2 - Pinagem MUX do ADC.

-Mnemônico RSH

rsh r0, r0, 2

O Right Shift Bit foi usado para calcular a média das 4 leituras. Lembre-se que os valores decimais (após a vírgula) são excluídos, restando apenas os inteiros.

-Mnemônico JUMPR

jumpr wakeup, 496, ge

Esse é o nosso "IF a moda antiga", que pula para a label "wakeup" se o valor do ADC for maior ou igual que 496. Ocasionando no Wake up do ESP32 pelo ULP.

Pelo fato de operações aritméticas não serem tão simples neste Assembly do ULP, em vez da condicional (jumpr) que faz o wake up do ESP32 usar valores como 32°C, onde é preciso efetuar varias contas, usaremos o valor direto do ADC que economiza processamento e tempo. O valor 496 no ADC com o LM35 equivale a 40°C .

Mais informações sobre o LM35 podem ser vistas clicando aqui.


Considerações finais

Mesmo que as aplicações do ULP estejam voltadas a Sleep, podemos usa-lo até com o ESP32 ligado, para por exemplo ler o canal ADC enquanto o ESP32 faz outra tarefa em que não se possa "perder tempo" lendo os lentos canais de ADC. Também é possível criar funções ISR para criar interrupções entre ULP e Main Core, deixando a brincadeira em um nível muito mais sério e interessante.


Desafios

O desafio desta vez é criar a rotina de interrupção citada acima (ISR) para uma comunicação extremamente rápida e eficiente entre ULP e Main Core. Você pode procurar no datasheet sobre o registrador (bit) que o comando WAKE do ULP ativa quando o ESP32 não esta em Sleep e criar a ISR.

Referências

http://esp-idf.readthedocs.io/en/latest/api-guides/ulp_instruction_set.html

https://portal.vidadesilicio.com.br/ultra-low-power-coprocessor-ulp-esp32/


Ultra Low Power coprocessor (ULP) - ESP32

Ultra Low Power coprocessor 

Neste tutorial, você irá aprender a instalar e usar o incrível ULP do ESP32, uma ferramenta extremamente poderosa e útil em projetos portáteis onde se faz o uso de baterias. Para programar o ULP, você vai precisar dos seguintes itens que não serão ensinados aqui:

  • Conhecimento em Assembly e registradores.
  • ESP-IDF instalada.

Deixaremos todas referencias sobre esses itens e os do tutorial ,como por exemplo, instalação do ULP, ao fim do tutorial.

[toc]

kit robotica educacional com Arduino ESP ou Microbit

O que é o ULP e como funciona?

Ultra Low Power coprocessor (ULP) - ESP32
Figura 1 - Coprocessador

O ULP é um coprocessador que podemos utilizar no ESP32 como um terceiro processador, entretanto, este foi projetado para uso em Deep Sleep, visto que seu consumo é extremamente baixo (150uA). Com ele, podemos fazer por exemplo, leituras de sensores ADC e a partir disso, acordar o MCU para tomar alguma decisão mais complexa, como enviar o dado para um banco de dados. Também é possível utilizar I2C e manipular os GPIO do RTC Domain.

Este pequeno processador acessa a região da memória chamada RTC_SLOW_MEM (8kB), onde é armazenado seu código ASM e também variáveis globais que são compartilhadas entre todos processadores. Com essas variáveis, podemos fazer a comunicação entre o ULP e os processadores principais (Main Core). Lembre-se que essas variáveis são mantidas entre os Deep Sleep's, então podemos guardar valores nessa região para usar após o Wake-UP.

O ULP contém 4 registradores de 16bit para uso geral (R0, R1, R2, R3) e mais um registrador de 8bit especifico para contagens (STAGE_CNT), como em loops com FOR(). Para programa-lo ,utilizamos a linguagem Assembly, uma linguagem de baixo nível extremamente rápida, eficiente e econômica em  termos de memória, mas não em linhas (hehehe).

Principais aplicações do ULP

  • Monitorar sensores digitais ou analógicos em Deep Sleep ocasionando um aumento gigantesco no tempo de duração de uma bateria.
  • Ajudar no processamento principal, caso necessário um poder de processamento maior.
  • Efetuar tarefas secundárias, como manipulação de GPIO's, sensores, criação de ISR's e etc, enquanto o Main Core faz uma tarefa pesada ou Time Sensitive.

Mãos a obra - Piscando um LED com o ULP em Assembly com um ESP32

Instalando o Core do ULP na ESP-IDF

Antes de sair usando o ULP loucamente, precisamos instalar os arquivos do Core (arquivos do sistema) para que o ULP funcione e seja compilado corretamente pelo Assembler da IDF (GNU) e após a instalação, precisamos ativa-lo e atribuir uma memória (ao mesmo), no "menuconfig".Para realizar estes procedimentos, siga os passos a seguir:

Se você ainda não tem a ESP-IDF instalada, instale-a antes de prosseguir: https://portal.vidadesilicio.com.br/instalando-esp-idf-no-windows-esp32/

1-) Baixe o .ZIP que contem os arquivos já prontos para serem colocados na IDF: https://github.com/espressif/binutils-esp32ulp/wiki

Figura 2 - Download do Core.

2-) Abra o .ZIP, acesse a pasta "esp32ulp-elf-binutils" e dentro dessa haverá outras tres pastas, copie-as para dentro do diretório "\msys32\mingw32\" da sua IDF.

Figura 3 - Copiando os arquivos do ULP pra IDF.

Já instalamos os arquivos, agora precisamos adicionar algumas linhas ao "component.mk" da pasta do seu projeto. Você precisa fazer os passos abaixo para todos projetos que pretende usar o ULP.

Você deve usar os diretórios do seu projeto.

3-) Abra o arquivo "component.mk" que se encontra na pasta "main" do seu projeto com o bloco de notas ou similar.

Figura 4 - Component.mk.

4-) Adicione o seguinte trecho ao arquivo:

ULP_APP_NAME ?= ulp_$(COMPONENT_NAME)
ULP_S_SOURCES = $(COMPONENT_PATH)/ulp/ulp.S
ULP_EXP_DEP_OBJECTS := main.o
include $(IDF_PATH)/components/ulp/component_ulp_common.mk
Figura 5 - Trecho adicionado ao mk.

5-) Abra o mingw32, vá ao diretório do seu projeto e use o "make menuconfig" para habilitar o ULP. No nosso caso, para ir ao diretório do projeto com o mingw32 é "cd /esp32/esp32".

Figura 6 - Abrindo o diretório.

Vá em "component config > esp32 specific" e habilite-o. Ao habilitar, aparecerá uma opção de configurar a memória reservada ao ULP, deixaremos o padrão por enquanto (512B).

Figura 7 - Habilitando o ULP.

Salve e saia do "menuconfig".

6-) Na pasta "main" do seu projeto, crie uma pasta "ulp" e dentro dessa, crie um arquivo "ulp.S".

Nota: você pode criar e editar (programar) o arquivo "ulp.S" com o bloco de notas caso não tenha uma IDE como Visual Studio (usada no tutorial).

Esses nomes precisam ser iguais ao trecho adicionado no "componente.mk".

Ultra Low Power coprocessor (ULP) - ESP32
Figura 8 - Arquivo do ULP.

Após a criação desse arquivo, podemos finalmente programar o incrível ULP. Esse arquivo é onde iremos programar o Assembly à ele.

Haverão dois códigos, um para o Main Core (main.c ou main.cpp) e outro pro ULP (ulp.S). O que faremos é basicamente atribuir o código Assembly ao trecho da memória RTC_SLOW_MEM e liga-lo. Após isso, o ESP32 entrará em Deep Sleep enquanto o ULP piscará um LED para mostrar funcionamento. Não se esqueça de ler o "Entendendo a fundo" que há explicações sobre o código Assembly e o funcionamento do ULP.

Estamos usando a ESP-IDF com Arduino component, isso nos permite usar tanto as bibliotecas do Arduino quanto da IDF. Se você usar a IDF sem o Arduino component, o código ficará praticamente igual, mudando apenas alguns detalhes como a alteração de extern "C" void app_main()  para void app_main() , em caso de dúvidas, comente!

Componentes necessários

  • 1x - ESP32 (Usaremos o NodeMCU32).
  • 1x - LED (Usaremos o LED Onboard).

Código do projeto

main.cpp

#include <C:/msys32/ESP32/ESP32/components/arduino/cores/esp32/Arduino.h>
#include <C:/msys32/ESP32/esp-idf/components/driver/include/driver/rtc_io.h>
#include <C:/msys32/ESP32/esp-idf/components/ulp/ulp.c>
#include <C:/msys32/ESP32/ESP32/build/main/ulp_main.h>
//Pode ser preciso arrumar os diretorios das bibliotecas

extern const uint8_t ulp_main_bin_start[] asm("_binary_ulp_main_bin_start");
extern const uint8_t ulp_main_bin_end[] asm("_binary_ulp_main_bin_end");

void ulp();

extern "C" void app_main()
{
	initArduino();//Inicia algumas configuracoes do Arduino Core, se voce nao usa Arduino component, apague essa linha
	ulp();//carrega e inicia o ULP

	ESP.deepSleep(1800000000);//entra em deep sleep
}

void ulp()
{
	rtc_gpio_init(GPIO_NUM_2);//inicia o GPIO2 no RTC DOMAIN
	rtc_gpio_set_direction(GPIO_NUM_2, RTC_GPIO_MODE_OUTPUT_ONLY);//Define o GPIO2 como saida

	ulp_load_binary(0, ulp_main_bin_start, (ulp_main_bin_end - ulp_main_bin_start) / sizeof(uint32_t));//Carrega o binario do codigo assembly na memoria
	ulp_run((&ulp_main - RTC_SLOW_MEM) / sizeof(uint32_t));//Inicia o ULP
}

ulp.S

#include "soc/soc_ulp.h"
#include "soc/rtc_io_reg.h"
#include "soc/sens_reg.h"
#include "soc/rtc_cntl_reg.h"


.bss//Variaveis sao declaradas dentro da secao .bss


.text//O codigo é feito dentro da secao .text

	.global main
	main://O codigo e iniciado aqui, equivale ao void setup()

		

	jump loop//Isso nao e necessario, mas foi colocado para organizacao
 
	loop:
		
		WRITE_RTC_REG(RTC_GPIO_OUT_W1TS_REG, RTC_GPIO_OUT_DATA_W1TS_S+12, 1, 1)//GPIO2 HIGH
		stage_rst
		1: stage_inc 1
		wait 32000
		jumps 1b, 125, lt//delay 500ms
		

		WRITE_RTC_REG(RTC_GPIO_OUT_W1TC_REG, RTC_GPIO_OUT_DATA_W1TC_S+12, 1, 1)//GPIO2 LOW
		stage_rst
		1: stage_inc 1
		wait 32000
		jumps 1b, 125, lt//delay 500ms

		
		jump loop//volta ao inicio do loop

Colocando para funcionar

Após programar, basta dar upload para o ESP32 pelo próprio mingw32 e a mágica irá acontecer.

Ultra Low Power coprocessor (ULP) - ESP32
GIF - Blink.

Entendendo a fundo

ULP

Apesar de termos apresentado apenas uma ideia sobre o ULP, devemos entender que este é muito mais complexo que isso devido ao fato de ter como aplicação alvo o Deep sleep.

Algumas características do ULP:

  • Clock (pode ser alterado e calibrado): 8.5MHz ±7%.
  • Memória: RTC_SLOW_MEM com 8kB.
  • Timer de Wake-UP (pode ser desativado): 150kHz.
  • 4 Registradores de 16bit (R0-R3).
  • 1 Registrador de 8bit (STAGE_CNT).
  • Funciona tanto nos modos de operações normais até Deep sleep.
  • Capacidade de fazer leituras de sensores analógicos/digitais externos, I2C e vários outros itens.

Funcionamento e dicas do ULP

O ULP é um coprocessador FSM (Finite state machine) que podemos usar para praticamente qualquer objetivo, entretanto é preciso tomar alguns cuidados como o timer de Wake-UP. Esse timer que vem por padrão ativado, serve para acordar o ULP periodicamente após encontrar o comando HALT no código Assembly. No nosso exemplo não foi usado HALT para encerrar o código do ULP pois usamos ele em um loop infinito. Se você não tomar cuidado esse comando e esquecer o timer ativado (é possível desativa-lo para garantir o funcionamento em certos casos), provavelmente o ULP não irá funcionar da forma que você espera.

Após o binário ser carregado e o ULP iniciado pelo código principal, o ULP irá iniciar a execução do código na label "main" que foi definida no ulp_run() , a partir desse ponto, será executado linha após linha até encontrar o comando HALT ou cair em um loop infinito como mostrado nesse tutorial.

Ao usar o comando WAKE o ESP32 irá acordar e executar todo o código novamente do começo, isso pode gerar problemas com o ulp_run() uma vez que o ULP já esta em execução e será reiniciado, para isso você deve adicionar uma condicional de Wake-UP que verifica o motivo do ESP32 ter acordado e caso não tenha sido pelo ULP, deve ter sido queda de energia ou similares, logo, precisamos inicia-lo novamente.

Toda explicação de funcionamento do ULP, comandos do Assembly, registradores e etc, estão na referencia técnica do ESP32 que se encontra no fim do tutorial.

Software

ulp.S

-Macro WRITE_RTC_REG()

WRITE_RTC_REG(RTC_GPIO_OUT_W1TC_REG, RTC_GPIO_OUT_DATA_W1TC_S+12, 1, 1)//GPIO2 LOW

Essa macro escreve um valor no registrador, sendo bem parecido com o tutorial que já fizemos sobre: Manipulando os registradores do ESP32, Porem, é usado os registrador do RTC Domain, por isso ativamos os pino 12 do RTC, que equivale ao GPIO2.

-Delay em Assembly

stage_rst
1: stage_inc 1
wait 32000
jumps 1b, 125, lt//delay 500ms

O blink faz com que o LED fique 500ms acesso e 500ms apagado, mas como que isso foi feito? Foi usado os ciclos do clock do ULP que é por padrão 8.5MHz ±7%, vamos arredondar para 8MHz ou seja, a cada 1 segundo, o clock irá oscilar 8 milhões de vezes. Pensando nisso, podemos calcular a quantidade de ciclos necessário para efetuar um delay.

Para fazer o delay, iremos usar 3 itens que nos ajudarão a "pular" ciclos do clock, fazendo com que o processador fique em espera:

  • NOP (No Operation): pula 1 ciclo do clock.
  • WAIT X: equivale a usar vários NOP's, limite de 65535.
  • Registrador: guardará um valor auxiliar na contagem.

Veja os passos para efetuar o delay de 500ms no Assembly do ULP com o registrador STAGE_CNT:

1-) Segundos * clock = ciclos para pular

0.5 * 8000000 = 4000000

2-) Cada WAIT pode conter no máximo 65535, que não é nem perto do que precisamos (4000000), logo, vamos utilizar uma variável (registrador) auxiliar que irá se comportar igual ao FOR(). Será usado WAIT 32000, mas você pode escolher qualquer um desde que esteja dentro dos limites.

ciclos para pular / wait = total de operações do loop

4000000 / 32000 = 125 operações

Agora, basta fazer um FOR() em Assembly para que se assemelhe a isso:

for (int i = 0; i < 125; i++)
{
    //blabla
}

Usaremos o registrador STAGE_CNT que é indicado para contagens:

stage_rst//Reseta o registrador (STAGE_CNT = 0)
1: stage_inc 1//Incrementa o registrador em +1 (STAGE_CNT++)
wait 32000//Equivale a 32000 NOP's
jumps 1b, 125, lt//Pula para label "1before" enquanto o registrador for menor que 125

Considerações finais

Infelizmente pelo ESP32 ainda não "cair em uso" aqui no Brasil, só encontramos informações de fora e principalmente no Datasheet. Espero que com esse "ponta pé inicial" mais pessoas comecem a postar materiais sobre ULP, uma vez que as aplicações para esse pequeno campeão que não encontramos em qualquer lugar são gigantescas e muito importantes em projetos portáteis, onde permite o processamento de informações enquanto todo o resto do microcontrolador permanece em Sleep para economia da bateria. Bons estudos e aproveite essa ferramenta extraordinária.

Se você já conseguiu usar o ULP, veja este tutorial para leitura de sensores analógicos ou digitais em Deep Sleep com o ULP no ESP32.

https://portal.vidadesilicio.com.br/lendo-sensores-analogicos-deep-sleep-ulp-esp32/

Referencias

https://esp-idf.readthedocs.io/en/v3.0-rc1/api-guides/ulp.html

https://esp-idf.readthedocs.io/en/v3.0-rc1/api-guides/ulp_instruction_set.html

http://espressif.com/sites/default/files/documentation/esp32_technical_reference_manual_en.pdf

https://portal.vidadesilicio.com.br/instalando-esp-idf-no-windows-esp32/


Instalando a ESP IDF no Windows - ESP32

Instalando a ESP IDF no Windows - ESP32

Neste tutorial, vamos aprender a instalar a Toolchain juntamente com a ESP IDF, que é um ambiente completo de desenvolvimento pro ESP32, onde é suportado todas features, opções e configurações sobre o microcontrolador, permitindo que o ESP32 se encaixe perfeitamente nos mais variados projetos, desde simples até industriais!

[toc]

O que é a ESP IDF e quais são os pontos fortes?

Normalmente chamada apenas de IDF, podemos dizer que esta engloba todos os conjuntos de API's e configurações do ESP32. Já a Toolchain (mingw32) consiste em uma ferramenta que compila e constrói o código que escrevemos juntamente com as configurações escolhidas no "menuconfig". Por fim, ESP IDF é o conjunto de bibliotecas feitas pro ESP32.

Os principais pontos a serem levados em consideração para você trocar a Arduino IDE ou outra, pela IDF são:

  • Suporte a todas features, incluindo Bluetooth, Flash Encryption e Secure Boot (itens importantes para quem pretende criar e vender produtos).
  • Configuração total do sistema, como por exemplo eFuses, clock, watchdog's, timer's, memória dinâmica para WiFi e até tempo de Wake-UP após Deep sleep.

Mãos a obra - Testando a ESP IDF

Instalando a Toolchain e ESP IDF

Usaremos alguns diretórios padrões para instalação, você pode optar por escolher qualquer nome e local, mas tome cuidado ao seguir o tutorial "ao pé da letra".

1-) Faça o download da Toolchain em: http://esp-idf.readthedocs.io/en/latest/get-started/windows-setup.html

Figura 1 - Download Toolchain.

2-) Abra o .ZIP e copie a pasta "msys32" para a raiz do seu HD "C:\".

Figura 2 - Copiando a pasta.

3-) Faça o download do .ZIP da ultima release que encontrar, nesse caso é a 3.0-rc1: https://github.com/espressif/esp-idf/releases

Nota: há outras maneiras de baixar a IDF, como pelo próprio Toolchain. Caso precise de outros métodos, veja as referencias.

Figura 3 - Download da IDF.

4-) Crie uma pasta chamada "ESP32" na raiz da "msys32" que você copiou no passo 2. Logo em seguida, abra o .ZIP do passo 3, copie a pasta dentro desse novo diretório "ESP32" e renomeie para "esp-idf". Ficara parecido com: "C:\msys32\ESP32\esp-idf"

Figura 4 - Pasta renomeada.

5-) Precisamos adicionar uma variável à Toolchain que guardará o diretório da pasta "esp-idf", sem isso não funcionará corretamente.

Vá no diretório "C:\msys32\etc\profile.d" copie e cole qualquer script (extensão .SH), fazendo com que o arquivo fique duplicado.

Figura 5 - Duplicando um script.

Renomeie este script duplicado para "export_idf_path" e abra-o com algum editor de texto como bloco de notas e apague tudo o que estiver escrito. Escreva essa nova e única linha que indica ao Toolchain o diretório da esp-idf que instalamos:

export IDF_PATH="C:\msys32\ESP32\esp-idf"

Figura 6 - export_idf_path editado para o caminho da esp-idf.

Finalmente instalamos todo o ambiente de programação e desenvolvimento do ESP32 no Windows, agora vamos copiar a pasta de algum exemplo da IDF para que seja nosso local de trabalho.

Vamos copiar a pasta do projeto "hello world" que se encontra em "C:\msys32\ESP32\esp-idf\examples\get-started\" no mesmo local que nossa pasta "esp-idf" e renomeá-la "esp32".

Figura 6 - Pasta hello world a ser copiada.
Figura 7 - Hello world copiado e renomeado.

Pronto! Podemos usufruir de todas features e configurações do ESP32. Se você não souber usar o painel da IDF, logo abaixo em "Entendendo a fundo", explicaremos como usar a IDF para compilar e configurar seus projetos.

Componentes necessários

Código do projeto

Não iremos programar nada! Apenas dar upload do antigo "hello world"  que copiamos logo acima, veja abaixo em "Entendendo a fundo" como dar upload do código ao ESP32 pelo painel da IDF.

Colocando para funcionar

Após o upload do código e ver o monitor, já temos algumas informações sobre o nosso microcontrolador.

Figura 8 - IDF MONITOR.

Entendendo a fundo

IDF

Para dar upload dos códigos, ver o "Serial monitor", editar configurações do Bootloader e etc, precisamos usar o painel (CMD) da IDF.

Antes de mostrarmos alguns comandos da IDF, vamos configurar o nosso projeto ESP32 (antigo hello world) para que o upload seja feito e vejamos funcionando.

1-) Abra o programa "mingw32" que se encontra em "C:\msys32\", abra a pasta do projeto com "cd /esp32/esp32" e abra o menu de configurações com "make menuconfig"

Figura 9 - Abrindo a pasta do projeto e configurando.

Aqui é o paraíso do ESP32, onde conseguimos configurar praticamente tudo desse microcontrolador, desde clock até alocação de memórias dinâmicas e Watchdog.

Precisamos escolher a porta COM em que seu ESP32 está plugado no computador, você encontra isso em "Gerenciador de dispositivos" no Windows, o nosso está na porta COM8.

2-) Vá em "Serial flasher config" e altere a "Default serial port" para sua porta COM, o nosso será COM8. Você também pode alterar a velocidade de upload caso seu conversor suporte, normalmente é o CP2102 que suporta até a opção "921600".

Aconselhamos fortemente que se você pretende usar o ESP32 para algo comercial ou projeto sério, leia e configure todas as opções do ESP32 corretamente para seu projeto, você pode ver a ajuda de cada configuração apertando "H" e nas referencias.

Agora que configuramos a porta COM correta para upload, salve e saia do menuconfig.

3-) Digite "make flash monitor" para que comece a compilação do seu código, isso pode demorar MUITO toda vez que você altera o menuconfig, pois o Toolchain recompila todos os componentes, entretanto, após a primeira compilação depois da alteração do menuconfig, não demora mais que 60 segundos.

A dica para acelerar essa primeira compilação é usar todos os núcleos do seu processador. É indicado usar o numero de núcleos + 1. Nosso computador tem 4 núcleos, então vamos usar o seguinte comando: "make flash monitor -j5", isso deixa a compilação extremamente mais rápida.

Nosso código será finalmente enviado ao ESP32 e automaticamente após o termino, será aberto o "Serial monitor" que mostrará algumas informações sobre seu microcontrolador.

A partir daqui você já pode aproveitar a IDF, também existem alguns comandos interessantes e únicos:

  • make help: mostra todos os comandos da IDF e o que fazem.
  • make: mostra alguns comandos de compilação e endereços dos binários.
  • make flash: da upload do código ao ESP32.
  • make monitor: abre o "Serial monitor".
  • make clean: apaga a pasta BUILD do projeto.
  • make erase_flash: apaga toda a FLASH do ESP32, incluindo seções de memória não volátil como NVS, FAT e EEPROM.
  • make size: mostra o tamanho dos binários como o uso da FLASH e RAM.

Considerações finais

A ESP-IDF é um prato cheio pra quem pretende se aprofundar no ESP32 desde motivos profissionais ou educacionais, uma vez que este é barato e confiável até para aplicações industriais, diferente do ESP8266.

Você ainda pode usar bibliotecas do Arduino como a WiFi, Serial e WiFiClient em vez das originais da IDF, isso é chamado de "Arduino component", onde podemos usar tanto as bibliotecas e funções do Arduino, quanto da IDF. Para isso, precisará alterar algumas coisas da pasta do seu projeto que são ensinadas aqui: https://github.com/espressif/arduino-esp32/blob/master/docs/esp-idf_component.md

Referencias

http://esp-idf.readthedocs.io/en/latest/get-started/windows-setup.html

http://esp-idf.readthedocs.io/en/latest/get-started/index.html

http://esp-idf.readthedocs.io/en/latest/get-started/add-idf_path-to-profile.html

https://github.com/espressif/arduino-esp32/blob/master/docs/esp-idf_component.md


manipulando registradores esp32

Manipulando os registradores - ESP32

Registradores - ESP32

Com o sucesso gigantesco do ESP32 que veio para bater de frente dos PIC32 e STM32, ganhando em alguns aspectos como velocidade, não podemos deixar de lado a manipulação de registradores que não estavam presentes, de maneira fácil, no ESP8266. Neste tutorial, vamos aprender a manipular os registradores de porta (GPIO) do ESP32 de forma simples para efetuar um Blink extremamente compacto e o mais rápido possível.

[toc]

O que são registradores em um microcontrolador?

São pequenos endereços de memória que nos permitem, via software, controlar pinos, processos, interrupções e coisas do tipo de forma extremamente eficiente. Podemos dizer que isso se assemelha ao assembly, visto que é um dos itens de mais baixo nível que conseguimos controlar diretamente pelo código e com isso temos uma eficiente forma de programação em questão de velocidade e confiança.

O ESP32 conta com centenas de registradores de 32bits para que possamos manipular com eficiência todo o hardware disponível, todas as informações estão disponíveis no Datasheet que estará ao fim deste tutorial.

Observação importante: em alguns casos de registradores como o correspondente ao famoso "pinMode()" que declara um pino como saída por exemplo, há mais de um registrador que faz essa mesma tarefa e também mais formas de escrever ou ler registradores, entretanto, sobre os registradores, usaremos os registradores atômicos, que nos garantem a escrita ordenada em um ambiente Triple-Core.

 


Mãos a obra - Piscando um LED através da manipulação de registradores

Componentes necessários

Código do projeto

void setup()
{
	REG_WRITE(GPIO_ENABLE_REG, BIT2);//Define o GPIO2 como saída
}

void loop()
{
	REG_WRITE(GPIO_OUT_W1TS_REG, BIT2);//GPIO2 HIGH (set)
        delay(250);
	REG_WRITE(GPIO_OUT_W1TC_REG, BIT2);//GPIO2 LOW (clear)
        delay(250);
}

Colocando para funcionar


Entendendo a fundo

Software

Quem esta acostumado com registradores pode estranhar esse jeito de manipula-los, parecendo muito mais fácil do que em outros microcontroladores. A verdade é que "REG_WRITE" é uma macro para facilitar a manipulação dos registradores que é definida no arquivo "soc.h", lá você também encontra macros como REG_READ que é usada para leitura de registradores, REG_SET_FIELD e etc.

Os três registradores usados são:

  • GPIO_ENABLE_REG (Figura 1): Registrador que habilita o GPIO(0-31) como saída.
  • GPIO_OUT_W1TS_REG (Figura 2): Registrador que define o GPIO(0-31) em HIGH (Vcc). (SET)
  • GPIO_OUT_W1TC_REG (Figura 3): Registrador que define o GPIO(0-31) em LOW (GND). (CLEAR)

 

Figura 1 - GPIO_ENABLE_REG

 

Figura 2 - GPIO_OUT_W1TS_REG

 

Figura 3 - GPIO_OUT_W1TC_REG

 

Uma forma bem comum de se utilizar registradores para pinos, é a manipulação direta (nesse caso a 32 bits, logo, 32 pinos) de uma única vez em uma linha! Com isso é possível economizar varias linhas e também deixar o código mais rápido. Se você pretende definir dois pinos como saída, a sentença ficará dessa forma (serve para os outros registradores também):

REG_WRITE(GPIO_ENABLE_REG, BIT2 + BIT4);//Define o GPIO2 e GPIO4 como saída

Esses são os registradores básicos para manipular um pino de saída, se você pretende ler pinos de entrada, terá que usar outros registradores que estão detalhados no Datasheet.

 

Observação: alguns registradores não estão com os nomes definidos nos arquivos do ESP32, logo, você não conseguirá manipular o registrador pelo nome (igual feito acima com GPIO_ENABLE_OUT e etc). Para manipular os registradores que não estão definidos, é necessário pegar o endereço do registrador na memória que se encontra no Datasheet. Veja como ficaria a manipulação sem o nome definido:

 

Figura 4 - Endereço dos registradores.
REG_WRITE(0x3ff44020, BIT2);//Define o GPIO2 como saída

while (1)
{
	REG_WRITE(0x3ff44008, BIT2);//GPIO2  = HIGH
	delay(250);
	REG_WRITE(0x3ff4400C, BIT2);//GPIO2 = LOW
	delay(250);
}

 


Considerações finais

Manipulando diretamente os registradores, conseguimos fazer tarefas com uma extrema velocidade e confiança, sendo necessária para vários projetos. Leia bem o Datasheet se você pretende dominar este incrível microcontrolador e boa sorte com os registradores.

Referências

Todos os registradores, informações e detalhes sobre o ESP32 se encontram nesse Datasheet:

http://espressif.com/sites/default/files/documentation/esp32_technical_reference_manual_en.pdf


Lendo dados do Google planilhas com ESP - Banco de dados

Lendo dados do Google planilhas com ESP - Banco de dados

No tutorial Banco de dados com Google planilhas com ESP, aprendemos a enviar dados para o Google Planilhas. Entretanto, para fazer justo ao nome "banco de dados", também precisamos recuperar dados da planilha para manipula-los ou até criar comandos de controle pela planilha, que permitirá, por exemplo, ativar atuadores ou ler dados que colocamos na planilha. Dessa forma, neste tutorial iremos aprender como ler os dados do Google Planilhas através de um ESP.

[toc]

Configurações iniciais - Requisitando dados do Google planilhas

O processo necessário para adquirir dados da planilha é quase o mesmo em relação ao método de envio (GET), entretanto para fazer isso, precisamos obter uma chave secreta. Esta chave faz o papel de "senha", para que ninguém consiga ler seus dados sem ela.

Atenção: Há maneiras mais seguras, como restringir o acesso da chave ou usar autenticador. Será mostrado o método mais simples.

Passo 1-) Entre na plataforma de gerenciamento de API's da Google: https://console.developers.google.com/apis , crie um novo projeto e de um nome qualquer.

Este projeto será apenas para "guardar" sua chave com a respectiva API, neste caso, Google planilhas.

Figura 1 - Criando um projeto de API.

 

Passo 2-) Vá em "Credenciais" e crie uma "Chave de API"

Figura 2 - Criando a Chave de API.

 

Figura 3 - Chave de API.

 

Feche a janela e a partir de agora, já temos nossa chave necessária para requisição de dados (e futuramente, altera-los).

 

Passo 3-) Volte para a página inicial do Google APIs, clique em "Biblioteca", selecione "Google Sheets API" e "Ativar"

Figura 4 - Ativando a API.

 

 

 

Terminamos de criar nossa chave e ativa-la, agora podemos manipular qualquer planilha que tenhamos salvo no Google Drive!


Mãos a obra - Lendo o Google planilhas

Componentes necessários

Código do projeto

Atenção: é necessário que você use os dados da sua planilha e faça uma alteração na mesma, explicaremos logo abaixo.

#include <ESP8266WiFi.h>

WiFiClientSecure cl;//Cria um cliente seguro (para ter acesso ao HTTPS)
String textFix = "GET /v4/spreadsheets/12IYuWdV0aJa8mQPhsR5C6AVEwZufyC05wufTrTJsSg/values/";
String key = "?key=IzaSyDmot3XwHfsNhqeuKdINMYxpyFK4cY";//Chave de API
//Essas Strings serao auxiliares, para nao precisar ficar re-escrevendo toda hora


void setup()
{
    Serial.begin(115200);//Inicia a comunicacao serial
    WiFi.mode(WIFI_STA);//Habilita o modo estaçao
    WiFi.begin("SUA REDE", "SUA SENHA");//Conecta na sua rede
    delay(3000);//Espera um tempo para se conectar no WiFi

}

void loop()
{

    if (cl.connect("sheets.googleapis.com", 443) == true)//Tenta se conectar ao servidor do Google APIs na porta 443 (HTTPS)
    {
        String toSend = textFix;//Atribuimos a String auxiliar na nova String que sera enviada
        
        toSend += "C2:C4";//Os valores que queremos ler da planilha. Para uma única célula, use algo como "A2"; para ler varios, use algo como "A1:C4".
        toSend += key;//Adicionamos a chave na String
        toSend += " HTTP/1.1";//Completamos o metodo GET para nosso formulario.

        cl.println(toSend);//Enviamos o GET ao servidor-
        cl.println("Host: sheets.googleapis.com");//-
        cl.println();//-
			

        Serial.println("Dado recebido:\n");//Mostra no Serial Monitor todo o pacote recebido.-
        Serial.print(cl.readString());//-
        cl.stop();//Encerramos a conexao com o servidor.
    }
    else
    {
        Serial.println("Erro ao se conectar");
    }
	

    delay(5000);

}

Ajustando o código para sua planilha

Antes de testar, precisamos alterar os dados do código para os seus dados e também compartilhar o link da sua planilha. Sem isso não irá funcionar!

Lembrando: altere apenas os dados destacados, o restante é necessário para funcionamento correto.

Passo 1-) Vá no começo do código e altere a chave (destacada) por sua chave.

Figura 5 - Alterando a Chave de API.

 

Passo 2-) Ainda nesta parte, altere o ID com o da planilha que você deseja obter os dados. Para isso vá em seu Google Drive, entre na planilha e pegue o ID:

Neste caso, vamos pegar a própria planilha criada na primeira parte do material.

configurando o google planilhas - banco de dados

Figura 6 - Alterando o ID da planilha.

 

Se você testar o código, verá que não temos permissão para acessar o banco de dados no Google planilhas. Isso acontece pois nossa "Chave de API" precisa estar com o link público (Qualquer pessoa com o link pode visualizar). Você pode contornar isso usando os Autenticadores ou adicionando Emails confiáveis ao sistema. Usaremos o mais simples para didática e fácil entendimento. Veja a saída do Serial monitor:

Figura 7 - Serial Monitor: Erro de permissão ao acessar o banco de dados no Google Planilhas

 

Passo 3-) Para deixar o link público, vá na sua planilha e siga os passos:

  • 1-) Clique em "Compartilhar" no canto superior direito.
  • 2-) Clique em "Avançado".

 

  • 3-) Clique em "Alterar...".

 

  • 4-) Clique em "Ativado: qualquer pessoa com link" e salve.

Colocando para funcionar

Agora podemos testar e já estará funcionando!

lendo as células do google planilhas - banco de dados com ESP
Figura 8 - Serial Monitor: Resposta de um grupo de células do nosso banco de dados no Google Planilhas

 

Veja que o pedido foi de um grupo de células, neste caso, C2:C4. Isso significa que iremos receber os dados das células C2,C3 e C4 em ordem da respectiva chamada.


Entendendo a fundo

Software

- String auxiliar (textFix)

String textFix = "GET /v4/spreadsheets/12IYuWdV0aJa8mQPhsR5C6AVEwZufyC05wufTrTJsSg/values/";

Basicamente é onde colocamos o ID da nossa planilha, você deve alterar para o ID de sua planilha!

- String auxiliar (key)

String key = "?key=IzaSyDmot3XwHfsNhqeuKdINMYxpyFK4cY";//Chave de API

Esta outra String, é onde atribuímos nossa Chave de API, você deve alterar para sua Chave de API.

- Obtenção dos dados

toSend += "C2:C4";

Aqui fica a grande jogada, onde conseguimos pegar células individuais, ou grupos de células. Vamos a um breve resumo.

Nossa planilha:

Banco de dados no Google Planilhas
Nosso banco de dados no Google Planilhas

 

Célula individual: Imagine que você precisa do valor da célula C2("Vida").

toSend += "C2";

 

Grupo de células: Imagine que você precisa do valor de um grupo de células, neste caso C2, C3 e C4 ("Vida", "De", "Silicio").

toSend += "C2:C4";

 

Podemos ver a resposta do Google ao pedido C2:C4 no Serial Monitor:

Lendo o banco de dados no Google planilhas
Lendo o banco de dados no Google planilhas

 

Você pode estar se perguntando: "Como vou usar essa String cheia de 'lixo' ?"

Este será o desafio de vocês! Futuramente criaremos um tutorial sobre manipulação de Strings. Mas aqui vai uma dica, procure sobre estes comandos em programação:

Com elas, você é capaz de pegar partes e caracteres específicos da String e ainda criar protocolos de mensagens para uma comunicação efetiva.


Desafio

Tente pegar apenas o valor que você queria da planilha. Você irá usar os dois comandos citados acima para "limpar" a String recebida pelo Google e assim tornando-a útil para o uso no microcontrolador.

Fechamento

Agora que você consegue obter valores da planilha, pode usar dados da planilha para algum processamento interno ou criar comandos de controle através da planilha! As possibilidades são muitas e depende de você. Boa sorte.

Referências

  • https://developers.google.com/sheets/guides/concepts
  • https://developers.google.com/sheets/guides/values

Banco de dados com Google planilhas com ESP32 / ESP8266

Banco de dados com Google planilhas - ESP

O Google planilhas é um "Excel online", que te permite criar tabelas e coisas do tipo, online, sem a necessidade de instalar no seu computador. Podemos compartilhar essa tabela para outras pessoas visualizarem ou edita-las. Nesse tutorial aprenderemos como usar o Google Planilhas para criar um banco de dados online, gratuito e simples, visto que não precisamos ter um servidor dedicado à hospedar o serviço. Esta primeira parte será ensinado apenas a enviar os dados usando um ESP.

[toc]

Banco de dados

Banco de dados é um conjunto de dados, normalmente relacionados entre si, como por exemplo: dados de clientes, LOG de temperaturas e coisas similares. Normalmente são dados organizados por colunas e linhas (matriz/tabela) para fácil entendimento por nós.

Poderíamos usar MySQL ou Firebase, que nos permite criar banco de dados de forma eficiente e confiável, entretanto,  é preciso ter um servidor apenas para hospedar seu banco de dados sempre disponível.

Você pode ler mais sobre Banco de dados e o uso do MySQL no tutorial: Arduino e MySQL – Registrando temperatura em um banco de dados usando o Shield Ethernet W5100

O Google planilhas oferece uma solução simples e gratuita para o armazenamento dos dados coletados. Podemos criar essas tabelas em conjunto do Google Forms, para enviar os dados dos nossos sensores, clientes e etc., sem a necessidade de um computador ou servidor pago hospedando o banco de dados, já que a Google se encarrega totalmente do serviço.

Obtendo os recursos necessários

Para usar esse incrível recurso precisaremos de uma conta no Google, e com ela criaremos dois arquivos, um de Planilha e outro Form.

Iremos através do formulário, enviar dados para a planilha (os dados do formulário irão para a planilha).

Passo 1-) Vá ao seu Google Drive e crie uma Planilha.

Passo 2-) Altere o nome da sua planilha para ser de fácil identificação nos próximos passos.

Figura 3 - Alterando o nome da planilha.
Figura 3 - Alterando o nome da planilha.

Passo 3-) Volte no Drive e crie um formulário.

Passo 4-) Altere o titulo do seu formulário para o desejado, e configure as perguntas.

Na planilha, os títulos das perguntas serão as colunas, e as respostas serão as linhas. Usaremos a opção "Resposta curta", que permite adicionar números e textos pequenos.

Passo 5-) Vá em "Respostas", vamos atribuir o formulário à planilha criada anteriormente. Clique nas "três bolinhas", e "Selecionar destino da resposta".

Passo 6-) Selecione a planilha desejada e estará pronto para receber nossos dados.

Agora, nosso formulário esta pronto para receber os dados e automaticamente transmitir para a planilha.

Para testar o formulário, clique no "Olho" ao canto superior direito, para abrir o link do formulário.

Figura 7 - Abrindo o link do formulário.
Figura 7 - Abrindo o link do formulário.

Após digitar o numero e clicar em "Enviar", será mostrado o aviso que a resposta foi registrada.

Figura 8 - Resposta enviada.
Figura 8 - Resposta enviada.

Agora, volte à sua Planilha, e veja que os resultados já estão aparecendo!

A coluna "Carimbo de data/hora" é preenchida automaticamente pelo sistema do Google, poupando imenso trabalho e requisitos do nosso sistema, dispensando até mesmo RTCs. A outra coluna "Numero" é o titulo da nossa pergunta, e a linha é a resposta que inseri.

Figura 9 - Resposta do formulário na planilha.
Figura 9 - Resposta do formulário na planilha.

Agora que aprendemos a utilizar o formulário em conjunto com a planilha, precisamos apenas integrar no Microcontrolador.


Mãos à obra

Componentes necessários

Conheça um pouco mais sobre ESP:

Código do projeto

Atenção: Não copie e cole o código inteiro, precisamos fazer algumas alterações no link utilizado. Será explicado logo abaixo em "Entendendo a fundo".

Caso esteja usando o ESP32, altere as bibliotecas removendo a ESP8266WiFi.h e incluindo as bibliotecas WiFi.h e WiFiClientSecure.h

Alguns usuário relatam erro com as versões mais novas do core esp8266 (quando você instala pelo menu (ferramentas > placa > gerenciar placas). A solução é instalar e usar a versão 2.4.0

// Código Banco de dados com Google planilhas com ESP - Vida de Silício

#include <ESP8266WiFi.h> 
// Alterar a linha anterior por #include <WiFi.h> se estiver usando ESP32
// #include <WiFiClientSecure.h> // Incluir esta biblioteca se estiver usando ESP32

WiFiClientSecure client;//Cria um cliente seguro (para ter acesso ao HTTPS)
String textFix = "GET /forms/d/e/1FAIpQLSdm6M_0mTVx_LKHLB1J3u_hjaag_hBtMfDHQlTIKe0EoatfsQ/formResponse?ifq&entry.717212213=";
//Essa String sera uma auxiliar contendo o link utilizado pelo GET, para nao precisar ficar re-escrevendo toda hora


void setup()
{
    Serial.begin(115200);//Inicia a comunicacao serial
    WiFi.mode(WIFI_STA);//Habilita o modo estaçao
    WiFi.begin("SUA REDE", "SUA SENHA");//Conecta na rede
    
    delay(2000);//Espera um tempo para se conectar no WiFi

}


void loop()
{
    if (client.connect("docs.google.com", 443) == 1)//Tenta se conectar ao servidor do Google docs na porta 443 (HTTPS)
    {
        String toSend = textFix;//Atribuimos a String auxiliar na nova String que sera enviada
        toSend += random(0, 501);//Adicionamos um valor aleatorio
        toSend += "&submit=Submit HTTP/1.1";//Completamos o metodo GET para nosso formulario.

        client.println(toSend);//Enviamos o GET ao servidor-
        client.println("Host: docs.google.com");//-
        client.println();//-
        client.stop();//Encerramos a conexao com o servidor
        Serial.println("Dados enviados.");//Mostra no monitor que foi enviado
    }
    else
    {
        Serial.println("Erro ao se conectar");//Se nao for possivel conectar no servidor, ira avisar no monitor.
    }

    delay(5000);
}

Colocando para funcionar

Após a editar o código com as suas informações, tudo irá funcionar corretamente. Veja como ficou o nosso, enviando valores aleatórios para nossa planilha a cada ~5 Segundos.


Entendendo a fundo

Precisamos fazer algumas alterações para o funcionamento do sistema com sua planilha. Sem isso, você irá enviar dados para nossa planilha de teste! (hehe)

Passo 1-)  Abra seu formulário (Figura 7).

Passo 2-) Copie todo o link entre "docs.google.com" e "/viewform". Salve isso em algum lugar, já iremos utilizar.

O nosso ficou "/forms/d/e/1FAIpQLSdm6M_0mTVx_LKHLB1J3u_hjaag_hBtMfDHQlTIKe0EoatfsQ".

Passo 3-)  Clique com o direito no "Input Text Box" e "inspecionar elemento".

Passo 4-) Agora, iremos pegar o nome desse Input Text Box.

O nosso é "entry.717212213".

Agora, devemos alterar esses dois valores no código, pois são os valores da sua planilha, e no código demonstrado de exemplo, foi utilizado nossos dados.

Obs: Altere apenas as partes destacadas, o restante é necessário para o correto funcionamento.

Atualização por contribuição do leitor Anselmo:

Caso tenha dificuldade em encontrar os entry, bastar seguir os seguintes passos:

    1. Clique no formulário com o botão direito do mouse e selecione "Exibir código fonte da pagina" (Ctrl+U);
    2. Agora pesquise pelo nome do campo inserido no formulário usando a ferramenta de pesquisa do navegador (Ctrl+F);
    3. No final do código vai encontra algo parecido com:  FB_PUBLIC_LOAD_DATA_ = [null,[null,[[490158642,"nome do campo",null,0,[[12345678,null,0,null,[[1,9,[""];
    4. O entry vai ser o numero após o colchete “12345678”,
    5. Inclua "entry." antes do número, fincando “entry.12345678”;
    6. Se você tiver outros campos, os outros entry do formulário vão estar na sequencia.

Exemplo: Campo do formulário: Teste var 1

    • Procure por “Teste var” (Ctrl+F);
    • No final do código vai encontra algo parecido com: "teste var 1",null,0,[[278629525,null,0,null,[[1,9,[""]
    • Copie o número após o colchete “278629525”
    • basta agora incluir "entry." antes do número , ficando “entry.278629525”

 

Passo 5-) Vá no começo do código e altere esta parte destacada, pelo que você copiou no item 2.

Esta parte é o "ID/KEY" do seu formulário, cada formulário tem o seu.

Passo 6-) Nessa mesma parte do código, altere essa outra parte destacada, pelo valor copiado no item 4.

Se você tiver mais de uma entrada para dados, a String ficaria por exemplo:

"GET /forms/d/e/1FAIpQLSdm6M_0mTVx_LKHLB1J3u_hjaag_hBtMfDHQlTIKe0EoatfsQ/formResponse?ifq&entry.717212213=123&entry.312212717=1234"

Os dados em negrito são os dados que você adicionaria, sendo de sensores, temperatura e etc.

Se você quiser testar com nossa planilha, sinta-se livre. Entretanto, é permitido apenas a visualização. Link da nossa planilha.

Software

- String auxiliar

String textFix = "GET /forms/d/e/1FAIpQLSdm6M_0mTVx_LKHLB1J3u_hjaag_hBtMfDHQlTIKe0EoatfsQ/formResponse?ifq&entry.717212213=";

Essa String textFix é uma auxiliar para nao precisar ficar reescrevendo toda hora, desde que essa parte é FIXA. O único valor que iremos alterar é após o  igual "=", que será o valor enviado à planilha.

- Função WiFiClient::connect()

if (client.connect("docs.google.com", 443) == 1)

Precisamos antes de enviar o método GET, se conectar no servidor. Essa função se conecta à URL (IP), na porta desejada.

- Corpo restante do GET

String toSend = textFix;//Atribuimos a String auxiliar na nova String que sera enviada
toSend += random(0, 501);//Adicionamos um valor aleatorio
toSend += "&submit=Submit HTTP/1.1";//Completamos o metodo GET para nosso formulario.

client.println(toSend);//Enviamos o GET ao servidor-
client.println("Host: docs.google.com");//-
client.println();//-
client.stop();//Encerramos a conexao com o servidor
Serial.println("Dados enviados.");//Mostra no monitor que foi enviado

Após a conexão com o servidor, adicionamos um valor aleatório na String final à ser enviada, e também terminamos o restante do necessário a ser enviado.


Desafio

Foi demonstrado apenas o envio de uma variável para a planilha, entretanto em qualquer projeto pode ser necessário o envio de diversas. Faça as alterações necessárias, adicionando os novos "Input Text Box" e tente enviar varias variáveis para sua planilha!

Fechamento

Em diversos projetos precisamos enviar dados ou guarda-los para analise, e um banco de dados como SQL pode ser desnecessário, uma vez que precisamos de um servidor para hospedar o banco de dados; com este método é possível facilmente criar seu banco de dados online, compartilhar com amigos e etc.

Na parte 1 foi mostrado apenas o procedimento para envio dos dados, entretanto, podemos precisar pegar valores da tabela para uso. Já a parte 2, você aprenderá como ler os valores da planilha para manipulação de dados ou até criar comandos de controle para o MCU: Lendo dados do Google planilhas com ESP – Banco de dados

Referências

  • https://developers.google.com/sheets/api/guides/values

Multiprocessamento - ESP32

Multiprocessamento com ESP32

As vezes é necessário que façamos o uso de sistemas multicores para as mais diversas finalidades, como por exemplo, fazer verificações de dados pela Serial, I2C ou sensores, enquanto o outro processador (Core) faz uma outra atividade em que não possa ser interrompida ou seja indesejado esse tipo de ação. Aprenderemos o que é multiprocessamento e usaremos o incrível ESP32 que tem ao todo três cores, para criar dois LOOP(), permitindo que você rode dois códigos ao mesmo tempo!

Lembrando: O terceiro core do ESP32 é um ULP, que é apenas programado em Assembly. Também é possível programa-lo para as mais diversas finalidades. Será mostrado apenas a programação do core principal.

Para conhecer mais sobre o ESP32 você pode conferir nosso tutorial: Conhecendo o ESP32

[toc]

Computação paralela - Multiprocessamento

computação paralela - Multiprocessamento
computação paralela - Multiprocessamento

Computação paralela é um assunto extremamente complicado, porem podemos simplificar de um método prático:

Você tem um supermercado com um caixa e em horários de pico, o caixa não é rápido suficiente para atender os clientes, então é necessário contratar outro funcionário que fique em outro caixa, fazendo assim que a velocidade de espera seja até 50% menor. (será atendido o dobro de clientes em relação a apenas um caixa)

Um sistema computacional paralelo, permite realizar diversos cálculos (tarefas, algoritmos, etc) simultaneamente. Há diversas maneiras de se paralelizar um código que é normalmente escrito em sequência: em bit, instrução, de dado ou de tarefa. O método mais simples é por exemplo dividir um FOR() pela metade a atribuir cada metade em cores diferentes, diminuindo o tempo de execução em até 50%. Apesar de parecer ser extremamente útil, há inúmeros problemas relacionados, como condição de corrida: o acesso simultâneo da mesma variável pode gerar erros em cálculos ou se o próprio calculo for dependentes de outros resultados, a paralelização disto é inconveniente, uma vez que utilizar semáforos para sincronizar as tarefas (exclusão mutua), pode ser mais lento que o simples código em sequencial. A questão à se pensar com uso de semáforos para sincronia de processos, deve ser analisada com o grau de granulação, uma vez que o uso excessivo de semáforos, pode deixar o processo mais lento que o código sequencial (single core).


Mãos à obra

Componentes necessários

Código do projeto

int tempo;//Variavel que armazena o tempo.

void setup()
{
	Serial.begin(115200);//Inicia a comunicaçao serial
	pinMode(2, OUTPUT);//Define o led Onboard como saída


	Serial.printf("\nsetup() em core: %d", xPortGetCoreID());//Mostra no monitor em qual core o setup() foi chamado
	xTaskCreatePinnedToCore(loop2, "loop2", 8192, NULL, 1, NULL, 0);//Cria a tarefa "loop2()" com prioridade 1, atribuída ao core 0
	delay(1);
}

void loop()//O loop() sempre será atribuído ao core 1 automaticamente pelo sistema, com prioridade 1
{
	Serial.printf("\n Tempo corrido: %d", tempo++);
	delay(1000);//Mantem o processador 1 em estado ocioso por 1seg
}

void loop2(void*z)//Atribuímos o loop2 ao core 0, com prioridade 1
{
	Serial.printf("\nloop2() em core: %d", xPortGetCoreID());//Mostra no monitor em qual core o loop2() foi chamado
	while (1)//Pisca o led infinitamente
	{
		digitalWrite(2, !digitalRead(2));
		delay(100);
	}
}

Colocando para funcionar

Podemos observar tanto no Serial Monitor quanto no ESP32, o funcionamento esperado do código. Enquanto o core 1 faz a contagem do tempo e espera 1seg para repetir a mensagem (o que o deixa em IDLE [travado]), o core 0 pisca o led, mostrando que um não interfere no outro.


Entendendo a fundo

Software

-Função xTaskCreatePinnedToCore()

xTaskCreatePinnedToCore(loop2, "loop2", 8192, NULL, 1, NULL, 0);

Esta função cria uma tarefa e atribuí a um especifico processador. O FreeRTOS pode definir automaticamente em qual core a tarefa será rodada, para isto, use xTaskCreate() (Mais informações no site FreeRTOS).

Neste caso, criamos a tarefa loop2, com "tamanho" de 8192 Bytes (words), nenhum parâmetro, prioridade 1 e atribuída ao core 0.

Vamos esclarecer os parâmetros em ordem (da esquerda à direita):

xTaskCreatePinnedToCore(pxTaskCodepcNameusStackDepthpvParametersuxPrioritypxCreatedTaskxCoreID)

pxTaskCode: Ponteiro para a tarefa, apenas o nome da tarefa.   loop2.

pcName: O nome (String) da tarefa (entre aspas), é usado para facilitar o debug.   "loop2".

usStackDepth: O tamanho de Stack reservada à tarefa, mais informações clique aqui.   8192.

pvParameters: O valor a ser passado para a tarefa no momento de criação. Nossa tarefa não precisa de parâmetros, então:   NULL.

uxPriority: A prioridade da tarefa. É comum se usar 1 para tarefas simples, já que funções de delay (IDLE) tem prioridade 0.   1.

Se duas tarefas com mesma prioridade estiverem na fila, a primeira da fila irá ser executada e depois a próxima. Caso uma tarefa com prioridade 1 esteja na fila, porém uma tarefa com prioridade 2 também, será executado a tarefa com prioridade 2 e depois as outras.

pxCreatedTask: Valor opcional caso seja necessário manipulação das tarefas (Handle).   NULL.

xCoreID: Atribuí a tarefa a um core especifico.   0.

Observações:

  • Se você por exemplo criar dois loops, ao chamar uma subrotina (função), ela será executada no core em que foi chamada.
  • Caso você não crie uma tarefa "infinita", será necessário deletar a tarefa com xTaskDelete().
  • No caso do loop2() criado, é necessário o uso de pelo menos delay(1) dentro do loop, para que o Task Watchdog não seja ativado. Há maneiras de contornar isso, mas precisa fazer alterações no BootLoader.

-Função xPortGetCoreID()

xPortGetCoreID()

Esta função retorna o core em que a tarefa esta sendo executada.


Fechamento

A computação paralela se mostra útil quando necessário alto poder computacional ou monitoramento de itens específicos. Este assunto é gigantesco, complicado e intrigante, foi mostrado apenas o básico sobre o assunto; se você quer se aprofundar mais, veja os PDFs que foram citados no começo.

Dúvidas? Sugestões? Críticas? Comente abaixo!

 


Comunicação Wireless TCP com ESP (Parte 2)

Comunicação Wireless TCP com ESP

Daremos inicio a segunda parte do nosso material sobre comunicações Wireless. No tutorial anterior, foi abordado sobre o protocolo UDP, que não é orientado à conexão. Desta vez, vamos aprender sobre o protocolo TCP, este por sua vez, é orientado à conexão, que nos garante a entrega de mensagens, ordenação do recebimento/envio, etc. O código aqui apresentado irá funcionar tanto para ESP8266 quanto para o ESP32, já que a diferença é mínima e funciona da mesma forma.

 

[toc]

Protocolo TCP

TCP (Transmission Control Protocol) é um protocolo para transmissão de dados voltado à conexão, ou seja, permite que as maquinas se comuniquem e gerenciem o estado atual da conexão com seus clientes e servidores. Uma característica importante do TCP é seu gerenciamento do status da rede e os dados, com isto, podemos saber se o dado enviado foi realmente entregue ao destinatário, também garante a entrega ordenada das informações sem que haja colisões e perdas inperceptíveis. Muitas aplicações usam o TCP para efetuar suas comunicações, sendo amplamente usado em todo tipo de situação, ao contrario do UDP que por não ser orientado à conexão, pode gerar erros em nossos sistemas.


Mãos à obra

Componentes necessários

Obs: Você pode usar qualquer aplicativo ou programa para transmitir os pacotes TCP. Nós usaremos o primeiro encontrado na Play Store para ser fácil de vocês encontrarem caso queiram usar também. Link do TCP Client na Play Store

Código do projeto

#ifdef ESP8266//Se estiver usando ESP8266, automáticamente irá adicionar as bibliotecas do ESP8266.
#include <ESP8266WiFi.h>
#include <WiFiServer.h>
#elif defined ESP32//Se estiver usando ESP32, fara a mesma operaçao.
#include <WiFi.h>
#endif

WiFiServer sv(555);//Cria o objeto servidor na porta 555
WiFiClient cl;//Cria o objeto cliente.


void setup()
{
    Serial.begin(115200);//Habilita a comm serial.

    WiFi.mode(WIFI_AP);//Define o WiFi como Acess_Point.
    WiFi.softAP("NodeMCU", "");//Cria a rede de Acess_Point.

    sv.begin();//Inicia o servidor TCP na porta declarada no começo.
}

void loop()
{
    tcp();//Funçao que gerencia os pacotes e clientes TCP.
}

void tcp()
{
    if (cl.connected())//Detecta se há clientes conectados no servidor.
    {
        if (cl.available() > 0)//Verifica se o cliente conectado tem dados para serem lidos.
        {
            String req = "";
            while (cl.available() > 0)//Armazena cada Byte (letra/char) na String para formar a mensagem recebida.
            {
                char z = cl.read();
                req += z;
            }

            //Mostra a mensagem recebida do cliente no Serial Monitor.
            Serial.print("\nUm cliente enviou uma mensagem");
            Serial.print("\n...IP do cliente: ");
            Serial.print(cl.remoteIP());
            Serial.print("\n...IP do servidor: ");
            Serial.print(WiFi.softAPIP());
            Serial.print("\n...Mensagem do cliente: " + req + "\n");

	    //Envia uma resposta para o cliente
            cl.print("\nO servidor recebeu sua mensagem");
            cl.print("\n...Seu IP: ");
            cl.print(cl.remoteIP());
            cl.print("\n...IP do Servidor: ");
            cl.print(WiFi.softAPIP());
            cl.print("\n...Sua mensagem: " + req + "\n");
			
        }
    }
    else//Se nao houver cliente conectado,
    {
        cl = sv.available();//Disponabiliza o servidor para o cliente se conectar.
        delay(1);
    }
}

Colando para funcionar

Devo lembrar que o IP padrão do ESP em modo Acess_Point é 192.168.4.1

1-) Precisamos nos conectar na rede WiFi criada pelo micro controlador.

2-) Logo, iremos adicionar o servidor com seu IP e PORTA no aplicativo. Lembre-se que você pode usar qualquer aplicativo ou programa de computador para isso.

 

3-) Após incluir os dados do servidor no aplicativo, podemos conectar-se e enviar os dados.

 

 

Obs: Também há dados disponíveis no Serial monitor, que o micro controlador escreveu, olhe como ficou.


Entendendo a fundo

Software

-Função WiFiClient::connected()

if (cl.connected())//Detecta se há clientes conectados no servidor.
{

}

Esta função retorna se há cliente conectado em nosso servidor. Também irá retornar que há clientes até que todos dados sejam lidos do buffer, se não, continuará aparecendo clientes conectados até que todos dados sejam lidos.

-Função WiFiClient::available()

if (cl.available() > 0)//Verifica se o cliente conectado tem dados para serem lidos.
{

}

Esta função, retorna a quantidade de bytes disponiveis para a leitura no buffer do cliente. Pode ser usada para detectar se há dados, e também para efetuar a leitura byte a byte do buffer, afim de montar a String final.

-Função WiFiClient::print()

cl.print();

Usada para enviar a String para o cliente. Há várias maneiras de mandar uma informação para o cliente, desde write(), printf() até print() e println().

-Função WiFiServer::available()

cl = sv.available();//Disponabiliza o servidor para o cliente se conectar.

Esta função, obtem um cliente que esta conectado ao servidor e tem dados disponiveis para a leitura. Pode ser entendida a grosso modo que diz ao cliente que há um servidor disponivel para enviar dados.


Desafio

O desafio desta vez, é tentar conectar multiplos clientes ao mesmo tempo em seu servidor. Este código não permite isto, então faça alterações e estude sobre as bibliotecas usadas para permitir multiplas conexões!

Fechamento

Neste tutorial, você aprendeu a efetuar uma troca simples de mensagens entre o Cliente (nosso celular) e o Servidor (ESP), pode ser usada de mesma forma para comunicação entre dois micro controladores. Na parte 3 deste material, aplicaremos as aulas passadas em um aplicativo em Android ou PC para se comunicar com nosso ESP8266/32. Não se esqueça de comentar sobre duvidas, elogios e criticas! Também aceitamos sugestões sobre a terceira parte deste material.

 


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!


Protocolo de tempo NTP com ESP

Protocolo de tempo NTP com ESP

É comum que em projetos de automação e robótica seja necessário saber a hora correta, para marcar a hora em que uma ação ocorreu ou até para ativar sensores em certo horário. Vamos aprender a adicionar um RTC (Real Time Clock - Relógio de tempo Real) ao ESP sem precisar de um hardware externo, como por exemplo um DS1307 ou do DS3231. Para isso, usaremos o NTP que só precisa de uma conexão com a internet o que é facilmente resolvido quando o assunto é projetos com ESP e IoT.

 

Sobre o NTP

Do Wikipédia:

O NTP é um protocolo para sincronização dos relógios dos computadores baseado no protocolo UDP sob a porta 123, para sincronização do relógio de um conjunto de computadores em redes de dados com latência variável. O NTP permite manter o relógio de um computador com a hora sempre certa e com grande exatidão.

O NTP serve tanto para atualizar e também manter os horários e datas sincronizadas entre dispositivos. Não há muitas explicações sobre isto, porém caso queira aprender mais sobre o NTP, clique AQUI ou AQUI.

 

 

Digamos que você tem uma rede de sensores, e precisa que eles liguem as 20h da noite, as melhores alternativas para isto, são um RTC externo/interno ou até o NTP caso haja conexão com a internet. Para o exemplo deste tutorial, acenderemos o LED Onboard de acordo com o horário que iremos definir. Com o NTP, também é possível arrumar a data e hora de um RTC externo que esteja errado!

Download da biblioteca NTPClient

Neste GIF, é mostrado o funcionamento do exemplo deste tutorial, no qual o LED foi acionado as 19:23:30.

ESP8266
FIG 1 - Projeto do tutorial - ESP8266

Mãos à obra

Componentes necessários

Montando o projeto

Nesse projeto usaremos apenas a placa NodeMCU. Usaremos o LED que já vem na placa ligado ao Pino D4 para fazer nossa experiência. Também funciona com ESP32.

Código do projeto

Não se esqueça de alterar as credenciais do WiFi e usar o fuso horário correto. Também altere para o horário que desejar, como o tutorial foi feito as 19:23, usamos este valor.

#include <NTPClient.h>//Biblioteca do NTP.
#include <WiFiUDP.h>//Biblioteca do UDP.
#include <ESP8266WiFi.h>//Biblioteca do WiFi.

WiFiUDP udp;//Cria um objeto "UDP".
NTPClient ntp(udp, "a.st1.ntp.br", -3 * 3600, 60000);//Cria um objeto "NTP" com as configurações.

#define led D4//Define o LED ao pino D4.

String hora;//Váriavel que armazenara o horario do NTP.

void setup()
{
   Serial.begin(9600);//Inicia a comunicação serial.

   pinMode(led, OUTPUT);//Define o pino como saida.
   digitalWrite(led, 1);//Apaga o LED.

   WiFi.mode(WIFI_STA);
   WiFi.begin("SUA REDE", "SUA SENHA");//Conecta ao WiFi.
   delay(2000);//Espera a conexão.

   ntp.begin();//Inicia o NTP.
   ntp.forceUpdate();//Força o Update.
}

void loop()
{
   hora = ntp.getFormattedTime();//Armazena na váriavel HORA, o horario atual.
   Serial.println(hora);//Printa a hora já formatada no monitor.

   if (hora == "19:23:30")//Se a hora atual for igual à que definimos, irá acender o led.
   {
      digitalWrite(led, 0);//Acende
   }

   delay(1000);//Espera 1 segundo.
}

Entendendo a fundo

Software

-Declarando o objeto

NTPClient ntp(udp, "a.st1.ntp.br", -3 * 3600, 60000);//Cria um objeto "NTP" com as configurações.

Aqui é criado o objeto NTP com os seguintes parâmetros:

  1. Objeto UDP.
  2. Servidor do NTP, Acesse ESTE link para ver os servidores brasileiros disponíveis.
  3. Fuso horário multiplicado por segundos, apenas altere o fuso horário se for necessário.
  4. intervalo de updates para atualização da hora, é necessário para manter a hora correta. O padrão é 1 Minuto.

 

-Função NTPClient::begin() e forceUpdate()

ntp.begin();//Inicia o NTP.

ntp.forceUpdate();//Força o Update.

Iniciamos o NTP e também forçamos o update para certificar de que a hora esteja certa.

-Salvando a hora atual

hora = ntp.getFormattedTime();//Armazena na váriavel HORA, o horario atual.

Esta função ntp.getFormattedTime() retorna uma string com a hora atual, contendo HH:MM:SS. Salvamos isto na nossa String hora

Também é possível pegar os dados separados ou até o dia. Veja as funções da biblioteca!

-Acionando o LED com a hora

if (hora == "19:23:30")//Se a hora atual for igual à que definimos, irá acender o led.
{
   digitalWrite(led, 0);//Acende
}

Caso a variável que contem a hora atual seja igual à definida, neste caso é 19:23:30, acenderá o LED.


Desafio

O desafio desta vez, é manter o LED aceso entre intervalos de tempo, por exemplo das 13h até as 16h. Para isto, pode-se usar a boa e velha lógica booleana ou a função constrain() do arduino. Boa sorte!

Considerações finais

A implementação deste simples protocolo pode ser de grande ajuda e utilidade em seus projetos que tenham conexão com a Internet. Dúvidas? Sugestões? Críticas? Comente abaixo!


Comunicação Wireless UDP com ESP (Parte 1)

Comunicação Wireless UDP com ESP

Neste material, iremos aprender a fazer uma comunicação Wireless UDP entre dois ESP8266 para transmissão de informações. O grande diferencial do ESP é sua comunicação Wireless com suporte a WiFi, então nada mais justo que aprender a usar isto. Lembrando que este código também funciona para o ESP32.

 

[toc]

Protocolo UDP

O protocolo UDP, da camada de transporte, nos permite de forma rápida e descomplicada, o envio de informações através da rede. A simplicidade de usar o UDP é compensada ao fato de não ser uma comunicação orientada à conexão, como por exemplo o TCP, logo, não há garantia que os pacotes sejam recebidos de forma ordenada ou se quer sejam recebidos. Usa-lo para aplicações simples é recomendado, já que não são dados críticos; a perda de pacotes (improvável, porém possa acontecer) não é tão prejudicial ao sistema. Iremos transmitir de um Cliente para um Host.

Esta comunicação simples pode ser feita para transmitir dados até um banco de dados em um computador ou informações para outros Micro controladores. As aplicações são as mais diversas e variadas possíveis, novamente, o limite é sua imaginação.

Lembre-se, serão dois ESP8266, um cliente e outro host. Os dois códigos estarão logo abaixo!

Veja como é rápido o processo de envio e recebimento dos dados. O cliente pisca quando envia o pacote e o host  pisca após receber o pacote, é tão rápido que os dois parecem piscar juntos:

 


Mãos à obra

Componentes necessários

 

Hardware

Acenderemos o LED_BUILTIN do NodeMCU para indicar a transmissão de dados. Este LED OnBoard, está conectado ao pino D4 do NodeMCU.

Código do projeto

Cliente

#include <ESP8266WiFi.h>//Biblioteca do WiFi.
#include <WiFiUdp.h>//Biblioteca do UDP.

WiFiUDP udp;//Cria um objeto da classe UDP.
long x;//Variavel para ser enviada.

void setup()
{
   pinMode(D4, OUTPUT);//Habilita o LED onboard como saida.
   digitalWrite(D4, 1);//Desliga o LED.

   WiFi.mode(WIFI_STA);//Define o ESP8266 como Station.
}

void loop()
{
   connect();//Sub-rotina para conectar-se ao host.

   send();//Sub-rotina para enviar os dados ao host.

   delay(500);//Aguarda meio segundo.
}

void connect()//Sub-rotina para verificar a conexao com o host.
{
   if (WiFi.status() != WL_CONNECTED)//Caso nao esteja conectado ao host, ira se conectar.
   {
      WiFi.begin("NodeMCU", "");//Conecta à rede do host.
      delay(2000);//Espera ate que a conexao seja feita.
   }
}

void send()//Sub-rotina para enviar dados ao host.
{
   if (WiFi.status() == WL_CONNECTED)//Só ira enviar dados se estiver conectado.
   {
      x = random(0, 1000);//Gera um numero aleatorio entre 0 e 1000.
      udp.beginPacket("192.168.4.1", 555);//Inicializa o pacote de transmissao ao IP e PORTA.
      udp.println(x);//Adiciona-se o valor ao pacote.
      udp.endPacket();//Finaliza o pacote e envia.

      digitalWrite(D4, 0);//-
      delay(5);//-
      digitalWrite(D4, 1);//Pisca o led rapidamente apos enviar.
   }
   else//Caso nao esteja com uma conexao estabelicida ao host, piscara lentamente.
   {
      digitalWrite(D4, 0);
      delay(250);
      digitalWrite(D4, 1);
   }
}

 

Host

#include <ESP8266WiFi.h>//Biblioteca do WiFi.
#include <WiFiUdp.h>//Biblioteca do UDP.

WiFiUDP udp;//Cria um objeto da classe UDP.

String req;//String que armazena os dados recebidos pela rede.

void setup()
{
   pinMode(D4, OUTPUT);//Habilita o LED onboard como saida.
   digitalWrite(D4, 1);//Desliga o LED.

   Serial.begin(115200);//Habilita a comunicaçao serial para a string recebida ser lida no Serial monitor.

   WiFi.mode(WIFI_AP);//Define o ESP8266 como Acess Point.
   WiFi.softAP("NodeMCU", "");//Cria um WiFi de nome "NodeMCU" e sem senha.
   delay(2000);//Aguarda 2 segundos para completar a criaçao do wifi.

   udp.begin(555);//Inicializa a recepçao de dados UDP na porta 555
}

void loop()
{
   listen();//Sub-rotina para verificar a existencia de pacotes UDP.
}

void listen()//Sub-rotina que verifica se há pacotes UDP's para serem lidos.
{
   if (udp.parsePacket() > 0)//Se houver pacotes para serem lidos
   {
       req = "";//Reseta a string para receber uma nova informaçao
       while (udp.available() > 0)//Enquanto houver dados para serem lidos
       {
           char z = udp.read();//Adiciona o byte lido em uma char
           req += z;//Adiciona o char à string
       }

       //Após todos os dados serem lidos, a String estara pronta.

       Serial.println(req);//Printa a string recebida no Serial monitor.

       digitalWrite(D4, 0);//-
       delay(5);//-
       digitalWrite(D4, 1);//Pisca o LED rapidamente apos receber a string.
    }
}

 

Entendendo a fundo

Software

Recomendamos que vocês a leiam esta referência sobre WiFi, praticamente todos comandos disponíveis estão explicados AQUI.

Cliente

 

-Enviando dados para o destino

udp.beginPacket("192.168.4.1", 555);//Inicializa o pacote de transmissao ao IP e PORTA.
udp.println(x);//Adiciona-se o valor ao pacote.
udp.endPacket();//Finaliza o pacote e envia.

Nesta parte, usamos 3 funções do UDP, entre elas estão:

-Função WiFiUDP::beginPacket()

udp.beginPacket("192.168.4.1", 555);

Estamos enviando o pacote para o IP "192.168.4.1" que é o IP padrão do host no ESP8266, na porta 555.

 

-Função WiFiUDP::println()

udp.println(x);

Adicionamos o valor da variável X ao pacote.

 

-Função WiFiUDP::endPacket()

udp.endPacket();

Por ultimo, fechamos o pacote para finalmente ser enviado ao destino.

 

Para melhor entendimento, veja esta figura:

 

  • Vermelho = beginPacket();
  • Verde = print();
  • Azul = endPacket();

 


Host

 

-Função WiFiUDP::parsePacket()

udp.parsePacket();

Esta função faz a verificação de novos dados no buffer. Se houver dados novos para serem lidos, a função irá retornar um numero maior que zero.


Desafio

O desafio agora é você fazer uma mensagem de retorno para quem enviou uma mensagem ao host, por exemplo, quando o cliente 1 enviar dados ao host, o host responda "OK". Também faça um Print do IP de quem foi recebido o dado. Na referencia do WiFi (citado acima), há os comandos necessários!

 

Finalizando

Com a possibilidade de comunicação entre dispositivos pelo WiFi ou Wireless Ponto-a-Ponto, podemos fazer projetos muito legais e redes de dispositivos para se comunicarem. Não se esqueça de ver a parte 2 do material, sobre TCP! Dúvidas? Sugestões? Críticas? Comente abaixo!


Servidor WEB com ESP - NodeMCU

Servidor WEB com NodeMcu - ESP

Vamos aprender à criar um Servidor WEB usando HTML e TCP/IP em nosso pequeno ESP8266 ou ESP32. Para essa experiência usaremos o NodeMcu, mas daremos as instruções para você fazer o mesmo projeto com o ESP32. Um servidor web é, como o nome sugere, um servidor de informações que serão fornecidas pelo MCU através da internet ou até LAN. Podemos acessar estes dados em computadores, celulares ou outros MCU's, e também enviar informações e instruções para o MCU.

Http servidor web

Aplicação prática

Acionar LEDs, motores, luzes, ventiladores, etc. Você terá uma interface HMI (Interface Homem-Máquina) e com isso, conseguirá manipular seu sistema das mais diversas formas. Ver status de funcionamento de sensores ou atuadores, as possibilidades são muitas, depende de você. Mostraremos apenas o básico, o controle de um LED por botão, porém, após você entender o funcionamento deste sistema, conseguira fazer muitas coisas!

Para este projeto, você verá o básico necessário para implementar com sucesso um acionamento (transmissão de dados SITE->MCU).

TCP

O protocolo TCP/IP (Transmission Control Protocol) é um protocolo para transmissão orientado à conexão, ou seja, permite que as maquinas se comuniquem e gerenciem o estado atual da transmissão.

Uma característica muito importante sobre o TCP é seu gerenciamento do status da rede e os dados, com isto, podemos saber se o dado enviado foi realmente entregue ao destinatário, também garante a entrega ordenada das informações sem que haja colisões e perdas imperceptíveis.

De um jeito mais fácil, TCP será nosso “Caminhão”, que irá levar as informações até o navegador de quem acessar nosso IP.


HTML

HTML é uma linguagem de marcação utilizada em sites da WEB e são interpretadas pelos navegadores (http request). Quando o usuário se conectar ao IP do ESP pelo navegador, o mesmo irá enviar os dados no formato do HTML via TCP e com isso, após o navegador receber os dados, irá mostrar a página web!

Clique aqui para ver mais Informações sobre HTML


Mãos à obra

Componentes necessários

Hardware

Vamos acender o LED_BUILTIN do NodeMCU, este LED OnBoard, está conectado ao pino D4 do NodeMCU.

NodeMcu trabalhando como servidor web

Código do projeto

Não se esqueça de colocar suas credenciais do WiFi na linha 14 para o funcionamento do código!

#include <ESP8266WiFi.h>//Biblioteca que gerencia o WiFi.
#include <WiFiServer.h>//Biblioteca que gerencia o uso do TCP.

WiFiServer servidor(80);//Cria um objeto "servidor" na porta 80 (http).
WiFiClient cliente;//Cria um objeto "cliente".

String html;//String que armazena o corpo do site.

void setup()
{
   Serial.begin(9600);//Inicia comunicaçao Serial.

   WiFi.mode(WIFI_STA);//Habilita o modo STATION.
   WiFi.begin("SUA REDE", "SUA SENHA");//Conecta no WiFi (COLOQUE O NOME E SENHA DA SUA REDE!).

   Serial.println(WiFi.localIP());//Printa o IP que foi consebido ao ESP8266 (este ip que voce ira acessar).
   servidor.begin();//Inicia o Servidor.

   pinMode(D4, OUTPUT);//Define o LED_BUILTIN como Saida.
}

void loop()
{
   http();//Sub rotina para verificaçao de clientes conectados.
}

void http()//Sub rotina que verifica novos clientes e se sim, envia o HTML.
{
   cliente = servidor.available();//Diz ao cliente que há um servidor disponivel.

   if (cliente == true)//Se houver clientes conectados, ira enviar o HTML.
   {
      String req = cliente.readStringUntil('\r');//Faz a leitura do Cliente.
      Serial.println(req);//Printa o pedido no Serial monitor.

      if (req.indexOf("/LED") > -1)//Caso o pedido houver led, inverter o seu estado.
      {
         digitalWrite(D4, !digitalRead(D4));//Inverte o estado do led.
      }

      html = "";//Reseta a string.
      html += "HTTP/1.1 Content-Type: text/html\n\n";//Identificaçao do HTML.
      html += "<!DOCTYPE html><html><head><title>ESP8266 WEB</title>";//Identificaçao e Titulo.
      html += "<meta name='viewport' content='user-scalable=no'>";//Desabilita o Zoom.
      html += "<style>h1{font-size:2vw;color:black;}</style></head>";//Cria uma nova fonte de tamanho e cor X.
      html += "<body bgcolor='ffffff'><center><h1>";//Cor do Background

      //Estas linhas acima sao parte essencial do codigo, só altere se souber o que esta fazendo!

      html += "<form action='/LED' method='get'>";//Cria um botao GET para o link /LED
      html += "<input type='submit' value='LED' id='frm1_submit'/></form>";

      html += "</h1></center></body></html>";//Termino e fechamento de TAG`s do HTML. Nao altere nada sem saber!
      cliente.print(html);//Finalmente, enviamos o HTML para o cliente.
      cliente.stop();//Encerra a conexao.
   }
}

Entendendo a fundo

Software

-Função WiFiServer::available()

cliente = servidor.available();

Aqui, estamos dizendo ao cliente que há um servidor disponível para conexão.

-Detectando clientes conectados

if (cliente == true){}

Com esta condicional, é verificado a existência de clientes conectados no ESP, e se sim, enviará o HTML para o cliente.

-Enviando a estrutura do HTML

cliente.print(html);

Após a criação da estrutura do HTML, precisamos enviar para o cliente. É feito com um simples print().

-Fechando conexão

cliente.stop();

Após o envio do HTML, encerramos a conexão pois não é necessário se manter conectado.


Foi usado um botão do tipo SUBMIT para fazer uma requisição GET ao Host, para entender melhor como funcionam os botoes no HTML, veja ESTE tutorial.

Fechamento

Com a possibilidade de receber e enviar dados pela internet, nossos horizontes ficam bem amplos. Podemos tanto controlar o MCU para por exemplo acionar o portão da garagem, ou descobrir se esta chovendo com sensores e etc. Dúvidas? Sugestões? Críticas? Comente abaixo!


Controlando seu projeto usando Telegram

Controlando seu projeto usando Telegram - ESP

Controlando seu projeto com Telegram

Imagine uma automação ou projeto que permite você “conversar” com seu Microcontrolador (MCU) e também receber comandos, parece difícil, mas é bem simples. Aprenderemos a usar o Telegram para criar automações e projetos das mais diversas possibilidades e utilidades que estabelece uma comunicação amigável com o MCU. Para essa experiência usaremos o NodeMCU 8266, mas você pode fazer com outros ESPs, tal como os da linha ESP8266 e o ESP32.

 

[toc]

O Telegram

Podemos fazer desde simples controles de LEDs, ou até uma automação residencial controlada pelo Telegram, já que os BOTs permitem controle total de informações.

 

Usaremos o Telegram pois nos permite criar “BOTs”. Estes BOT's, são como robôs virtuais e com eles, conseguimos criar uma interface IHM (Interface Homem-Máquina). Este método, permite o fluxo de informações de ambos sentidos (Input e Output), então conseguimos controlar o sistema e também ser notificado pelo sistema.

 

Criando seu Bot no Telegram

1-) Pesquise pelo "BotFather" no menu de pesquisa do Telegram, entre nele e clique em "Começar ou Reiniciar".

 

 

 

2-) Pelo BotFater podemos criar novos Bots, configura-los e muito mais. Para criar, faça:

  1. Digite "/newbot".
  2. Digite o nome do seu novo Bot.
  3. Digite o usuário do Bot com a terminação "bot".

 

3-) Logo após a criação, o BotFater enviará uma mensagem com o link do Bot e logo abaixo o Token do Bot. Você pode clicar neste link para abrir a conversa com seu Bot ou pode pesquisa-lo futuramente.

Você precisa desse Token para inserir no código!

 

Mãos a obra

Componentes necessários

Para este projeto, usaremos o ESP8266 (versão NodeMCU). Entretanto, pode ser feito igualmente com o ESP32, sendo necessário alguns pequenos ajustes.

  • 1x – ESP8266. (Usaremos o NodeMCU).
  • 1x – Telegram no Celular.
  • 1x - LED. (Usaremos o LED OnBoard da placa).

- Biblioteca utilizada

Clique AQUI para ir a pagina de download da biblioteca "UniversalTelegramBot" utilizada.

Alguns usuários relatam erro com a biblioteca "ArduinoJson".  Caso aconteça com você, será necessário instalar a biblioteca na Arduino IDE.

Para isso vá em "Gerenciador de bibliotecas", procure pela biblioteca "ArduinoJson", instale-a e reinicie a Arduino IDE.

- Código do projeto

Não se esqueça de alterar as credenciais do WiFi e também o Token do seu Bot. Sem isso não irá funcionar.

Vários usuários relatam erro com a versão 2.5 do esp8266 (core) instalado na Arduino IDE, que é resolvido instalando a 2.4.0.

 

#include <ESP8266WiFi.h>
#include <WiFiClientSecure.h>
#include <UniversalTelegramBot.h>
#define BOTtoken "135924:AAErDKEJaQpEnqs_xj35asdGQ5kK6dQet4"//Define o Token do *seu* BOT

WiFiClientSecure client;
UniversalTelegramBot bot(BOTtoken, client);

String id, text;//Váriaveis para armazenamento do ID e TEXTO gerado pelo Usuario
unsigned long tempo;

void setup()
{
   pinMode(D4, OUTPUT);//LED conectado à saida
   WiFi.mode(WIFI_STA);//Define o WiFi como Estaçao
   connect();//Funçao para Conectar ao WiFi
}

void loop()
{
   if (millis() - tempo > 2000)//Faz a verificaçao das funçoes a cada 2 Segundos
   {
      connect();//Funçao para verificar se ainda há conexao
      readTel();//Funçao para ler o telegram
      tempo = millis();//Reseta o tempo
   }
}

void connect()//Funçao para Conectar ao wifi e verificar à conexao.
{
   if (WiFi.status() != WL_CONNECTED)//Caso nao esteja conectado ao WiFi, Ira conectarse
   {
      WiFi.begin("SUA REDE", "SUA SENHA");//Insira suas informaçoes da rede
      delay(2000);
   }
}

void readTel()//Funçao que faz a leitura do Telegram.
{
   int newmsg = bot.getUpdates(bot.last_message_received + 1);

   for (int i = 0; i < newmsg; i++)//Caso haja X mensagens novas, fara este loop X Vezes.
   {
      id = bot.messages[i].chat_id;//Armazenara o ID do Usuario à Váriavel.
      text = bot.messages[i].text;//Armazenara o TEXTO do Usuario à Váriavel.
      text.toUpperCase();//Converte a STRING_TEXT inteiramente em Maiuscúla.

      if (text.indexOf("ON") > -1)//Caso o texto recebido contenha "ON"
      {
         digitalWrite(D4, 0);//Liga o LED
         bot.sendMessage(id, "LED ON", "");//Envia uma Mensagem para a pessoa que enviou o Comando.
      }

      else if (text.indexOf("OFF") > -1)//Caso o texto recebido contenha "OFF"
      {
         digitalWrite(D4, 1);//Desliga o LED
         bot.sendMessage(id, "LED OFF", "");//Envia uma Mensagem para a pessoa que enviou o Comando.
      }

      else if (text.indexOf("START") > -1)//Caso o texto recebido contenha "START"
      {
         bot.sendSimpleMessage(id, id, "");//Envia uma mensagem com seu ID.
      }

      else//Caso o texto recebido nao for nenhum dos acima, Envia uma mensagem de erro.
      {
         bot.sendSimpleMessage(id, "Comando Invalido", "");
      }
   }

}

Colocando para funcionar

Após a criação do BOT e upload do código, podemos ver funcionando. Veja o BOT respondeu como o esperado aos comandos:

 


Entendendo a fundo

Software

-Função UniversalTelegramBot::sendMessage()

bot.sendMessage(id, "LED OFF", "");

Com esta função, é feito o envio da mensagem para o determinado ID (referente ao ID de quem enviou a mensagem ao Bot). Logo ao iniciar seu BOT, automaticamente é enviado uma mensagem "/START", e nosso sistema irá responder com o seu ID do Telegram; você pode usar isso para aceitar apenas comandos de seu ID.

 

-Variável id

id = bot.messages[i].chat_id;

Toda vez que o Bot receber um novo update (mensagem), irá armazenar o ID da pessoa que enviou a mensagem na variável id.

 

-Variável text

text = bot.messages[i].text;

Toda vez que o Bot receber um novo update (mensagem), irá armazenar o texto na variável text.

 

A biblioteca do Telegram permite mais opções interessantes, como por exemplo obter o horário em que a mensagem foi enviada ao Bot! Dê uma olhada na referência da biblioteca.

 

-Função UniversalTelegramBot::getUpdates()

int newmsg = bot.getUpdates(bot.last_message_received + 1);

Esta função faz a verificação de novas mensagens, sempre será lido da última (mais recente), para a primeira (mais antiga) mensagem no buffer do Bot. Isto será feito até que se tenha lido todas as mensagens disponíveis então tome cuidado para não travar ou atrasar o resto do seu código!


Desafio

Qualquer pessoa que adicionar seu Bot (basta pesquisar), pode enviar comandos e controla-lo. Você terá que criar algum tipo de “cadeado” para aceitar apenas comandos de pessoas autorizadas. Cada usuário no Telegram tem um ID, então você pode usar isso à seu favor e fazer o sistema aceitar apenas comandos de algumas pessoas.

Fechamento

Podemos facilmente incluir este controle com o Telegram em diversos projetos, permitindo que o mesmo seja controlado à distancia e até mesmo que você seja notificado, como por exemplo um alarme para sua casa que mande mensagem para seu celular ao detectar movimento. As aplicações são imensas, dependendo apenas da sua criatividade. Dúvidas? Sugestões? Críticas? Comente!