Componentes Eletronicos

Fonte Regulável com Arduino e Transistor

Eletrogate 6 de maio de 2021

Reguladores de tensão são fundamentais em circuitos eletrônicos onde haja uma etapa do circuito que funcione com um nível de tensão diferente ou dependendo do projeto o regulador de tensão pode servir também como uma referência.


Introdução

A energia elétrica se tornou algo essencial em nossa vida, e é difícil imaginar nossa vida hoje em dia sem ela. A energia elétrica se tornou algo básico em nossa sociedade assim como água e comida.

Sabemos que a energia elétrica precisa ser adequada para nossa demanda e que ela pode ser apresentada de formas diferentes: como em níveis, formas; podendo ser uma tensão alternada, uma tensão continua, tensão pulsada, etc. 

Existem várias características únicas para cada tipo de tensão, mas nesse post será abordado apenas o caso da tensão em corrente continua, ou apenas tensão continua.

Caso você tenha caído de paraquedas até aqui gostaria de te recomendar qualquer uma de nossas apostilas que terá uma seção somente sobre tensão, corrente e potência. Dá uma olhadinha e volte aqui.

Bom, sabendo disso, sabemos que existem vários circuitos que funcionam com níveis de tensão bem diferente. Por exemplo, é muito comum termos amplificadores de áudio e motores que funcionam com 24V ou 12V, mas também temos placa como Arduino que funcionam com 5V, e placas como o ESP-01 que funcionam com apenas com 3.3V

Bom, como existe essa discrepância da tensão que vários componentes em um projeto podem usar, para não termos que usar várias fontes diferentes em um mesmo projeto, usamos reguladores de tensão.

Reguladores de tensão convertem uma tensão em outra. Algum leitor pode ser tentado a pensar que um circuito como um divisor de tensão também funcionaria para essa função, mas estará equivocado.

Um circuito de divisor de tensão, como abordado nesse post, é útil apenas para sinais, que são informações em forma de tensão. Isso é, esse sinal de tensão não aciona nada, e a corrente associada é quase que desprezível. Por isso um divisor de tensão funciona para esse tipo de circuito.

Já no caso de circuitos que acionam coisas como motores, LEDs, etc, a corrente não é desprezível e a tensão no divisor de tensão não se manterá constante por a carga acionada se comportar como um resistor em paralelo. Por isso essa abordagem não funciona.

Existem diversos tipos de reguladores de tensão, e nesse post iremos aprender um pouco mais sobre eles e em como criar um regulador que pode ser programado com o Arduino.


Regulador Linear

Esse tipo de regulador é bastante conhecido e alguns modelos são bastante usados. Inclusive vai embarcado na placa Arduino um regulador de tensão linear.

Esse regulador ai (geralmente) é um AMS1117 de 5V. A função desse regulador é fazer com que o Arduino possa funcionar com uma fonte de 9V na entrada P4. Ele converte a tensão de 12 a 7V em 5V e faz com que o Arduino funcione sem queimar.

Os reguladores de tensão linear são muito usados porque são componentes bem simples, onde eles possuem 3 terminais, onde um é a tensão de entrada, outro o GND e no outro você vai ter a tensão de saída.

A vantagem dese tipo de regulador é que a tensão de saída é quase pura, onde as oscilações são quase desprezíveis. 

A principal desvantagem, no entanto, é que esse tipo de regulador é bastante ineficiente para fornecer correntes altas. Isso porque esse dispositivo funciona como uma espécie de resistor, dissipando em si mesmo a potência que seria jogada fora. Para dar um exemplo, basta pensar no seguinte cenário:

Você vai alimentar um servo com seu Arduino, e seu Arduino está ligado na tomada a uma fonte de 20V. O regulador de tensão irá garantir que o seu Arduino esteja funcionando com 5V e que o seu servo seja alimentando com 5V. No entanto, a corrente que o servo está demandando sairá da fonte, percorrerá o regulador de tensão e após isso ele vai entregar ao Arduino.

O regulador de tensão funcionará como um resistor de potência, onde ele vai absorver os 15V de diferença entre os 20V de entrada e os 5V de saída. Nessa abordagem a corrente que irá percorrer por ele será a mesma que a que o servo exige, que será em torno de 300mA. Com isso o regulador de tensão estará dissipando em si mesmo os 15V com uma corrente de 300mA. Isso  dá uma potência de 4,5W, que é uma potência bem alta (que é convertida em calor) no componente, o que pode gerar a queima ou ele entrar em modo de proteção (não funcionando corretamente). Nesse exemplo a fonte de alimentação está desperdiçando 75% da energia, no qual poderia estar sendo usada no Arduino.

Uma característica de reguladores de tensão linear é que a maioria deles são fixos, não podendo ser ajustados para uma tensão diferente da que o fabricante especificou. Caso queira adquirir um regulador desse tipo para o seu projeto, recomendo a família 78XX, como o 7805 e os reguladores da AMS1117. Eles são baratos e fáceis de encontrar.


Reguladores Chaveados

Os reguladores chaveados são bem mais usados que os lineares. Por exemplo, nesse exato momento é muito provável que você esteja alguns reguladores chaveados e você nem saiba.

Dentro do carregador do seu celular, uma etapa da conversão entre a tensão da rede elétrica em 5V constante usa um regulador chaveado. Na fonte do notebook e fonte do computador também. Basicamente quase todas as fontes modernas utilizam uma etapa de regulação chaveada.

Os reguladores chaveados são interessantes porque eles são extremamente eficientes, onde quase nenhuma potência é dissipada no próprio regulador na hora da conversão. Em relação a um regulador linear ele pode ser até 98% mais eficiente, jogando pouquíssima energia fora em forma de calor.

Outra vantagem é que além da eficiência esses reguladores podem converter tensões menores para tensões maiores. Os conversores que regulam de uma tensão menor para uma maior são chamados de “Conversores Step Up”, e os que regulam de uma tensão maior para uma menor, são chamados de “Step-Down”.

Existem diversos tipos de circuitos que fazem esse tipo de regulação baseado em chaveamento. Os circuitos mais famosos são o DC/DC Buck, DC/DC Boost, e existe o circuito DC/DC Buck-Boost.

A desvantagem desse tipo de circuito é que a tensão na saída pode ser um pouco ruidosa. Isso significa que alguns circuitos que precisam de uma tensão constante e bem precisa, como circuitos de rádio, podem ter um pouco de problema com esse tipo de fonte, precisando de etapas de filtragem do ruído.

Uma característica interessante desses módulos é que geralmente eles podem ter a tensão de saída ajustada (mas podendo ser encontrado também versões onde a saída é fixa). Por serem reguladores que possuem uma tecnologia maior embarcada e são mais eficientes, geralmente o preço é mais elevado.

A Eletrogate comercializa esse tipo de regulador, sendo os mais famosos o regulador de tensão Step Down LM2596 e o Step Up XL6009E1.


Fonte de Tensão Regulável

Fontes de bancada são instrumentos primordiais para quase qualquer pessoa que trabalha com eletrônica. Isso porque muitas vezes precisamos configurar tensões específicas para testar circuitos específicos.

Exemplo de fonte de bancada

E entender como funciona um circuito desse pode ser bem interessante.

Todos os circuitos de fonte de bancada trabalham com sistemas de realimentação, que basicamente é um circuito que é capaz de medir a saída e tomar uma decisão na entrada levando em consideração a saída. Circuitos realimentados possuem algo que chamamos de “setpoint”, que nada mais é que uma referência de qual valor queremos na saída. Com base nessa referência que o circuito realimentado sabe qual o valor que deverá ter na saída.

Os circuitos realimentados é mais complexos que os sem realimentação, e para entender um circuito realimentado na prática é só pensar em um drone, como o que foi já abordado nesse blog. Quando você pede o drone para ficar em repouso, o circuito dele fica continuamente medindo o sinal do giroscópio e acelerômetro para deixar o drone parado independente do vento. Por isso, ele leva em consideração a saída em relação a entrada.

Para ficar mais claro, nesse exemplo do Drone, o setpoint (referência) é deixar o drone parado no ar, a saída é dada pelo sensor de acelerômetro e o giroscópio (que é estimada por esses sensores), e a entrada vai ser a potencia nos motores, que o circuito regula de acordo com a saída. Imagina se o drone não tivesse sensores para estimar o estado atual para ajustar na entrada (motores)? Com certeza nunca seria possível.

Bom, se você conseguiu entender até aqui, você já sabe o básico da teoria de controle, que é o que se estuda bastante no curso de Engenharia de Controle e Automação e outros. Só para formalizarmos, chamamos de controlador o circuito que mede a saída e ajusta a entrada de acordo com o setpoint (referência).

Existem diferentes tipos de controladores para fazer esse ajuste de qual valor deve ter a entrada em relação a saída, e os mais comuns são os controladores PID (que inclusive foi usado no Drone que montamos neste post). Os controladores PID tem esse nome porque possuem 3 partes, uma que é Proporcional, outra que é Integral e outra que é Derivativa. Juntando as primeiras letras de cada parte, temos PID.

De forma bastante simplificada, a parte proporcional é responsável por fazer com que a resposta da saída seja bem próxima à referência, mas nunca será exatamente igual. A parte integral faz com que a resposta seja exatamente igual a saída, uma vez que ele fica sempre somando os erros para aumentar a ação na saída até que a resposta seja igual. Já a ação derivativa é responsável por deixar o controlador mais rápido. 

Como eu disse, essa explicação é bastante simplificada e não condiz para todos os casos, uma vez que teoria de controle é um assunto bastante denso e um pouco abstrato. Mas para esse artigo basta saber o que faz a ação integral, que fica somando os erros da saída em relação a referência e garante que esses dois valores sejam iguais (isso não se aplica para todos os casos, okay? Mas se aplica para muitos casos).

Bom, fizemos essa tangente gigantesca só para falar que os circuitos de fonte de bancada possuem uma malha de controle porque eles precisam acertar o valor da tensão independente da corrente drenada. 

Se o circuito fosse em malha aberta ou malha fechada mas de ação apenas proporcional, faria com que o valor da tensão de alimentação fosse caindo a medida que a corrente drenada fosse aumentando. Um exemplo de uma fonte de tensão que funciona em malha aberta é uma bateria, onde a tensão dela reduz conforme a corrente de saída, porque ela opera sem nenhuma realimentação. Outro exemplo é um regulador de tensão linear 7805, que a tensão cai de acordo com a corrente dissipada.

Ao fazer um circuito com uma ação integradora, a gente contorna esse problema e garante que a tensão de saída sempre será igual a de referência, independente da corrente drenada.


Transistor

Que o transistor é o rei da eletrônica, todos nós sabemos disso, e dessa vez usaremos eles novamente em nosso projeto.

Um transistor pode ser usado de diversas formas em circuito eletrônico, mas um dos usos dele que é bem interessante é como um amplificador de corrente (No caso do transistor bipolar, okay?). 

Bom, para entender esse esquema de amplificador de corrente é bem simples. Todo mundo sabe que um transistor é um componente de 3 terminais, onde existe a base (B) o coletor (C)  e o emissor (E).

A gente pode dividir o transistor bipolar em dois componentes, onde um componente é formado por um diodo formado só pelos terminais da base e emissor, e o outro é como uma fonte de corrente, formada pelo Coletor e Emissor. Caso você não saiba o que é uma fonte de corrente, não se desespere, continue lendo.

A grande sacada aqui é que como dizemos, a Base e o Emissor formam um diodo, e todo diodo após uma tensão começa a conduzir corrente, e quanto maior a tensão nesse diodo maior a corrente que passa por ele. (assim como em um LED, que quanto maior a tensão maior o brilho que ele vai ter). Bom, essa corrente desse diodo formado pela Base e o Emissor que comanda a fonte de corrente do Coletor e o Emissor.

Quanto maior for a corrente do diodo formado entre a base e o emissor, maior a corrente entre o coletor e o emissor. Por que então chamamos de amplificador de corrente? É que a corrente que aparece no coletor e emissor é multiplicada por algumas dezenas de vezes em relação a do diodo. Por isso chamamos um transistor de multiplicador de corrente.

Para ficar claro, olhe esse GIF, ele faz uma relação com água, e ficará bem claro o que estou querendo dizer: Um pouco de água em um terminal controla um fluxo bem maior entre os outros dois.

Créditos: Make A Gif

Muito interessante né? Então, nosso circuito funcionará da seguinte forma: Vamos utilizar um sinal PWM do Arduino e passar esse sinal por um filtro resistor-capacitor. Esse filtro fará com que o sinal PWM, que é um sinal pulsado, vire um sinal de saída analógico mais ou menos constante. Esse capacitor irá fornecer a corrente da base do transistor, que é a corrente que controla a corrente de saída.

Como o sinal no capacitor é mais ou menos constante de acordo com o PWM, a corrente drenada no diodo formado pela base e emissor será mais ou menos constante e a corrente de saída também será mais ou menos constante. Como sabemos, a corrente quando percorre um resistor ela se transforma em tensão, logo, é fácil fazer essa conversão de corrente para tensão, só medir o sinal do resistor.

Uma vantagem de drenar essas correntes com um transistor é que existem transistores que são feitos para drenar altas correntes, caso tenha um dissipador adequado. A família de transistores TIP conseguem drenar correntes altíssimas, de até 5A, caso tenham um bom dissipador e estiver no modo de saturação.


Materiais Necessários para o Projeto Fonte Regulável com Arduino e Transistor

Bem, então sabendo de todo esse conhecimento sobre realimentação, propriedade de transistor, e muitas coisas que aprendemos aqui, já podemos colocar esses conceitos em prática.

Para fazer o projeto inicial, precisaremos somente de:

cta_cart


Abordagem Prática

A primeira montagem será para demonstrar como é simples montar esse projeto e controlar a tensão de algo utilizando apenas o Arduino.

Com a protoboard, monte o seguinte circuito:

É bem simples porque utiliza pouquíssimos componentes.

Para esse projeto precisaremos da biblioteca PID. Para isso, na Arduino IDE, abra o gerenciador de bibliotecas: “Ferramentas > Gerenciador de Bibliotecas”. A biblioteca é do Brett Beauregard.

O código que usaremos é o que está abaixo. Antes de enviar o código, com o auxílio de um multímetro, meça a tensão do pino de 5V da sua placa Arduino e insira o valor medido na variável VccMedido na 3a linha. Deixei um comentário no código também.

#include <PID_v1.h> // Inclusao da biblioteca do controlador

float VccMedido = 5; //A tensão medida no pino de 5V. Caso voce nao possua um multimetro, deixe 5.
float setpoint = 0;

int PIN_INPUT = A0;  // Pino de entrada do controlador PID, que irá servir como sensor
int PIN_OUTPUT = 5; // Pino de saída, que irá controlar o sistema

char resposta[25] = {"         "}; // String que recebe os dados seriais

double Setpoint, Input, Output, kp = 0, ki = 1, kd = 0; // Kp, Ki e Kd são os ajustes do controlador PID.

PID controlador (& Input, & Output, & Setpoint, kp, ki, kd, DIRECT);

void setup() {
  Serial.begin(9600);
  pinMode(PIN_INPUT, INPUT); // Inicializando o pino do sensor do controlador como entrada
  pinMode(PIN_OUTPUT, OUTPUT); // Inicializando como saída o pino do controlador da tensão.
  controlador.SetMode(AUTOMATIC); // Configura o controlador para funcionar em modo automático
  controlador.SetSampleTime(0); // Seta o controlador para ter a taxa de amostragem mais rápida possível.
  Serial.println("CLEARDATA");  // Limpa os dados das legendas do Plotter Serial
  Serial.println("Setpoint, Zero, Saida"); // Insere as legendas no Plotter Serial
}

void loop() {
  float Adc = VccMedido / 1023; //  ADC é a relação entre a tensão e os níveis ADC de 0 a 1023
  EscutaSerial(); // A função que irá ficar escutando a comunicação serial e irá inserir esses dados no vetor resposta
  Setpoint = setpoint / Adc; //Converte o Setpoint de Volts para níveis ADC (que é o que a placa entende)
  Input = analogRead(PIN_INPUT); //Carregando o valor do pino analógico para o controlador
  controlador.Compute(); // O controlador calcula qual deve ser a saída do pino PWM, para tudo ocorrer certo.
  analogWrite(PIN_OUTPUT, Output); //O pino de saída envia o sinal PWM que foi computado.
  imprimir(setpoint, 0,analogRead(A0)*Adc); // A função imprimir é um amontoado de "Serial.print"", só fizemos ela para facilitar.

}

void imprimir(float valor1, float valor2, float valor3) // A função recebe 3 parametros, e já imprime eles no formato correto.
{
  static int linha = 0;
  Serial.print(valor1);
  Serial.print(",");
  Serial.print(valor2);
  Serial.print(",");
  Serial.println(valor3);
}

void EscutaSerial() { // Função que recebe os dados do Plotter Serial e converte em um valor de Setpoint
  if (Serial.available() > 0) {
    byte leitura, i = 0;
    strcpy(resposta, "                  ");
    leitura = 255;
    while (leitura != 10) {
      if (Serial.available() > 0) {
        leitura = Serial.read();
        resposta[i] = (char)leitura;
        i++;
      }
    }
    i = 0;
  }
  setpoint = atof(strtok(resposta, " "));
}

Após o carregamento do código, abra o Serial Plotter (Ferramentas > Serial Plotter).

O resultado é este, onde você pode ver um gráfico da tensão no tempo, onde no canto inferior direito você pode digitar um valor de tensão, ex; 3.21, e o Arduino irá regular essa tensão na saída, como você pode ver no multímetro do vídeo abaixo:

No vídeo abaixo você vai ver o funcionamento com uma carga, que será um motor, e você vai ver que funciona bem da mesma forma:

Legal demais né? Mas será que dá melhorar? Claro que dá! Veremos abaixo um upgrade para esse projeto, com uma nova técnica para deixar mais precisa as medidas.


Turbinando o Projeto

Bom, o vídeo acima é muito legal, mas existe um problema nessa abordagem de cima, que é precisar ficar medindo a tensão de alimentação da placa Arduino. Talvez alguns leitores não entendam por que isso é necessário.

Caso alguém não saiba, o conversor ADC da placa Arduino, por padrão, tem como referência a tensão de alimentação, 5V, da placa. Isso é um problema porque raramente essa tensão permanesse em nível constante, por alguns fatores. Dentre esses fatores temos:

  • A alimentação da placa Arduino, caso esteja no USB, pode mudar a medida que outros dispositivos sejam conectados na porta USB. Isso porque seu computador começará a dividir a corrente com outros dispositivos e isso faz com que a tensão reduza. Por exemplo, a tensão na minha porta USB estava em 4.3V, mas quando plugo outras coisas chega a cair para 4.1V.
  • Mesmo que esteja usando uma tensão de 9V para alimentar a placa, e os 5V vindo do regulador de tensão do Arduino, essa tensão vai mudar de acordo com o consumo enérgico da placa Arduino. Quanto mais corrente demandar do regulador de tensão da placa, mais a tensão vai cair.

Por isso, o valor da tensão do pino de 5V sempre está sujeito a mudar, e quando a gente mede, não temos garantia nenhuma que esse valor do pino vai permanecer constante. Então, como resolver isso?

A melhor abordagem é o próprio Arduino conseguir estimar a sua tensão de alimentação, e durante a execução ele vai atualizando esse valor de tensão para nós. Isso garante que caso a tensão de alimentação mude, ele vai corrigir esse valor e sempre corrigir a conversão de ADC para Volts.

A estratégia que eu usei é utilizar o pino de 3.3V. Esse pino é bem interessante de usar porque ele vem de um regulador de tensão linear que não está sendo usado nesse projeto. A regulação de linha de um regulador de tensão sem carga é sempre muito boa.

O regulador de 3.3V é alimentado pelo pino de 5V do Arduino, esse regulador varia muito pouco a tensão de saída (que é os 3.3V), algo quase desprezível, se a entrada (os 5V) variar. Então nossa estratégia será explorar o pino de 3.3V.

Só tem um detalhe: apesar de a tensão nesse pino ser constante mesmo que a alimentação oscile, vai existir um ruído na medição da tensão desse pino, pelo menos no Arduino Nano. Isso porque os 3.3V vem do chip conversor USB-Serial.

Mas ruído não é mais um problema para nós, porque aprendemos nesse post sobre filtros digitais como resolver esse tipo de problema.

A única diferença do filtro que usaremos em relação aos filtros mostrados lá, é que nosso filtro precisa ser preciso mas não pode demorar muito para convergir para o valor correto. Por isso usaremos um filtro onde ele começa com a quantidade de amostras igual a 1, e irá incrementando as amostras a cada chamada até chegar em 100 amostras. Dessa forma o filtro começa ultra rápido mas bem impreciso, mas vai ficando mais preciso e lento.

Não tem problema o filtro ser lento, porque não temos expectativas para a tensão de 3.3V mudar, por isso o filtro por ser bem lento e preciso. O filtro utilizado será do tipo IIR, por não precisar gastar memória do processador. Caso você não esteja entendendo essa discussão sobre filtros, recomendo demais ir no post sobre filtros digitais.

Para concluir a discussão, o valor de 3.3V não oscila, mas também não é exatamente 3.3V. Você precisará medir uma vez esse valor com um multímetro para calibrar, e inserir no código. Mas após isso você não precisará medir mais (somente caso você mudar de placa Arduino no projeto). No meu caso, o pino de 3.3V mediu uma tensão de 3.46V, mas que fica constante com diferentes tensões em 5V.

Bem, agora tendo uma medida bem precisa sobre valor da alimentação, poderemos estimar quanto cada nível ADC equivale em Volts.

Bom, para turbinar ainda mais o projeto, imagino que ter que controlar a tensão pelo computador nem sempre é viável, porque muitas vezes precisaremos que esse projeto seja mais portátil. Por isso, projetei o uso de um encoder incremental e implementei a visualização através de um display Oled.

Isso deixa o projeto muito mais elegante e prático.

Materiais Necessários para o Projeto Fonte Regulável com Arduino e Transistor Turbinado

Talvez você tenha a disposição um encoder diferente, mas não se preocupe, eles são equivalentes, como visto na imagem abaixo:

A nova montagem será da seguinte forma:

Um upgrade a mais para esse projeto é utilizar um dissipador de calor no transistor. O meu, que você vai ver no vídeo abaixo, foi retirado de sucata. Mas você pode encontrar um dissipador de forma bem simples. O dissipador vai te permitir drenar mais corrente no transistor, e assim você vai ter uma fonte mais parruda.

Para o novo código você vai precisar de ter novas bibliotecas. Essas bibliotecas novas são as seguintes a “Adafruit GFX” e “Adafruit SSD1306”:

Após a instalação das bibliotecas, carregue o código abaixo. Como o código é bem grande, tentei deixar o máximo comentado possível.

/* INCLUSÃO DAS BIBLIOTECAS */
#include <PID_v1.h> // Inserindo a biblioteca para realizar o controle da tensão
#include <Wire.h>   // Inserindo a biblioteca para realizar a comunicação I2C                     
#include <Adafruit_GFX.h> // Biblioteca de efeitos visuais
#include <Adafruit_SSD1306.h> // Biblioteca do módulo OLED utilizado.

/* DEFINIÇÃO DAS VARIÁVEIS E CONSTANTES RESPONSÁVEIS PELA CONFIGURAÇÃO*/
#define VccMax 5  // Definindo qual a tensão máxima que o módulo pode regular
#define Qtd_Amostras_3v3 100    // Quantidade de amostras do filtro (ver o post sobre filtros)
#define Intervalo_Amostragem 1 // definindo o intervalo de amostragem em ms.
float Calibracao3v3 = 3.3;    // A tensão medida no pino de 3.3V. IMPORTANTE: Caso você não tenha um multimetro para medir, deixe o valor em 3.3V.

int Leitura_3v3 = 0; // Variavel global que é chamada em várias funções e faz a leitura em níveis ADC da tensão de 3.3V.
int PIN_INPUT = A0, PIN_OUTPUT = 5; // Declaração dos pinos de saida e entrada do controlador.

double Setpoint, Input, Output, // Cariáveis que serão computadads no controlador
       kp = 0, ki = 1, kd = 0;  // Os parametros do controlador PID.

#define SCREEN_WIDTH 128                  // OLED display largura, em pixels
#define SCREEN_HEIGHT 32                  // OLED display altura, em pixels

#define OLED_RESET -1                     // Pino de reset

/* INSERINDO OS OBJETOS PARA REALIZAR O CONTROLE DO DISPLAY E DO CONTROLADOR*/
PID controlador (& Input, & Output, & Setpoint, kp, ki, kd, DIRECT); // Declaração do objeto controlador PID.
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);   //Criando o objeto para controlar o display

/*CONFIGURAÇÃO DAS VARIÁVEIS PARA CONTROLAR O ENCODER*/
static int pinA = 2;                      //Pino para interrupção interna do Enconder
static int pinB = 3;                      //Pino para interrupção interna do Enconder
volatile byte aFlag = 0;                  //PinA detectando apenas a borda de subida
volatile byte bFlag = 0;                  //PinB como borda de subida na detecção
volatile int8_t encoderPos = 0;             //Posição atual do Encoder, que pode variar de 0 a 9
volatile byte prevEncoderPos = 0;         //Variavel para armazenar o valor anterior, para saber se o encoder foi girado.
volatile byte reading = 0;                //Armazena o valor dos pinos de interrupção

const byte buttonPin = 4;                 //Pino do botão do encoder
byte oldButtonState = HIGH;               //Armazena o antigo estado do botão
const unsigned long debounceTime = 10;    //Delay para evitar erros na leitura do botão
unsigned long buttonPressTime;            //Tempo que o botão foi pressionado para debounce

void setup() {
  Serial.begin(9600); // Iniciando a comunicacao serial para ver a tensão no Plotter Serial
  pinMode(PIN_INPUT, INPUT); // Inicializando o pino do sensor do controlador como entrada
  pinMode(PIN_OUTPUT, OUTPUT); // Inicializando como saída o pino do controlador da tensão.

  if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C))     //Inicia o display
  {
    Serial.println(F("SSD1306 a inicialização falhou"));   //Verifica se a conexão com o display falhou
    for (;;);                                         //Caso falhou, vai entrar em um loop infinito para não continuar
  }
  display.clearDisplay();      //A inicialização do display foi bem sucedida, então limpa o display
  display.setTextColor(SSD1306_WHITE);                //Setando a cor do texto para branco

  pinMode(pinA, INPUT_PULLUP);                        //Seta PinA como entrada PULLUP,para não precisar do resistor.
  pinMode(pinB, INPUT_PULLUP);                        //Seta PinB como entrada PULLUP,para não precisar do resistor.
  attachInterrupt(0, PinA, RISING);                   //Inicia a rotina de interrupção dos pinos de rotação do encoder
  attachInterrupt(1, PinB, RISING);
  pinMode (buttonPin, INPUT_PULLUP);                  //Seta o botão como entrada PULLUP,para não precisar do resistor.

  controlador.SetMode(AUTOMATIC); // Configura o controlador para funcionar em modo automático
  controlador.SetSampleTime(0); // Seta o controlador para ter a taxa de amostragem mais rápida possível.
  Serial.println("CLEARDATA"); // Limpa os dados das legendas do Plotter Serial
  Serial.println("Setpoint, Zero, Saida"); // Insere as legendas no Plotter Serial
  Leitura_3v3 = analogRead(A1);  // Leitura do valor ADC referente a 3.3V, onde aqui é o valor bruto que ainda será filtrado
  Amostragem(); // Chamando a função que atualiza o valor do filtro.
}


void loop() {

  float setpoint = 0, Adc = 0; // Setpoint recebe o valor que deve ser ajustado na saída, e ADC qual é a relação entre a tensão e os níveis ADC de 0 a 1023
  setpoint = Tensao(); // Tensao é a função responsável por converter o valor selecionado no display em um valor de tensão float
  Adc = Calibracao3v3 / filtro3v3(0); // Essa função ADC vai fazer a relação entre s níveis ADC e tensão, dividindo o valor da calibração pelo nível ADC filtrado
  // É importante ser filtrado porque não haverá qaquel
  Leitura_3v3 = analogRead(A1);  // Faz a leitura de 3.3V para atualizar no filtro.

  Amostragem(); // Essa é a função que fará a amostragem no tempo que determinamos no intervalo de amostragem que definimos na segunda linha de código.

  Setpoint = (int)(setpoint / Adc); // Converte o valor do setpoint (minusculo, que é em volts) em níveis ADC, pela relação feita pela variável 'Adc'

  Input = analogRead(PIN_INPUT); //O controlador lendo a entrada da porta analógica, que é a saída do transistor
  controlador.Compute(); // O controlador calcula qual deve ser a saída do pino PWM, para tudo ocorrer certo.
  analogWrite(PIN_OUTPUT, Output); //O pino de saída envia o sinal PWM que foi computado.
  imprimir(setpoint, 0, analogRead(A0)*Adc); // A função imprimir é um amontoado de "Serial.print"", só fizemos ela para facilitar.
}

void Amostragem() { // Essa função verifica se o tempo de amostragem  selecionado ocorreu
  static unsigned long timer1 = 0; // A variável que irá contar o útimo
  if ((abs(millis() - timer1)) > (int)(Intervalo_Amostragem)) { // Caso o tempo de amostragem tenha ocorrido, ele envia 1 para a função de filtro de media movel
    //Dessa forma a função sabe que é para atualizar o valor de saída para um novo valor filtrado
    filtro3v3(1);
  }
}

void imprimir(float valor1, float valor2, float valor3){ // A função recebe 3 parametros, e já imprime eles no formato correto.
  Serial.print(valor1);
  Serial.print(",");
  Serial.print(valor2);
  Serial.print(",");
  Serial.println(valor3);
}

float filtro3v3(bool atualiza_saida) { //O filtro aqui tem uma pequena mudanca em relacao ao filtro apresentado no post dedicado ao assunto
  //Esse filtro ele possui precisão variável. Ele começa bem impreciso e rápido, e vai mudando para impreciso e lento.
  //Isso porque não é esperado que o sinal de 3.3V mude com o tempo, por isso o filtro precisa começar bem rápido, para que atinja o valor esperado e vá corrigindo a precisão lá.
  static short Qtd_Amostras_Aux = 1;
  static float Saida_Filtro = 0;

  if (atualiza_saida == 0) return ((double)Saida_Filtro);

  else {
    Saida_Filtro += (float)(Leitura_3v3 - Saida_Filtro) / (float)Qtd_Amostras_Aux;
    Qtd_Amostras_Aux = constrain((Qtd_Amostras_Aux + 1), 0, Qtd_Amostras_3v3);
  }
}

float Tensao(){ // Essa funcao converte as mudanças no encoder e transforma em um valor de tensão.
  static float tensao = 0, aux; // Todas as variáveis são do tipo static porque o valor da tensão é salvo nessa função.
  static byte pos = 0; // A posição do digito que estamos digitando, correspondendo as casas decimais
  static bool button = false; // 
  if (encoderPos != 0) { // Encoder Pos é uma variável global que diz se o encoder foi para a direita ou esquerda. ele recebe -1 ou 1 se o encoder teve um acréscimo de movimentação.
   aux = tensao + encoderPos * pow(10, -(pos)); //A lógica é bem simples. Se o encoder teve um acrescimo, ele vai somar com a tensão que já existe 1x10^(-pos). Caso seja negativo, faz -1. Esse valor de 1 ou -1 são justamente os salvos na variável do encoder.
   // A variavel auxiliar é usada porque precisa passar por uma comparação para ver se a tensão selecionada é válida
    if ((aux >= -0.0001) and (aux <= (VccMax))) { // Esse IF é somente para evitar bugs de selecionar tensão menor que 0 e maior que a tensão máxima permitida.
      tensao = aux; // Se passou por esse IF, a tensão é válida e a tensão auxiliar passa a ser o valor da tensão final.
    }
    encoderPos = 0; // Faz com que a variável que sente a mudança do encoder retorne a 0, indicando que o encoder está parado agora.
  }
  ImprimeDisplay(tensao, pos); // Após isso simprime no display OLED o valor selecionado. A variavel de posição é chamada para colocar corretamente onde ficara a indicação de seleção.

  byte buttonState = digitalRead (buttonPin); // Aqui começa a verificação se o botão foi pressionado, para selecionar o algarismo correto.
  if (buttonState != oldButtonState) // Isso quer dizer que o botão foi pressionado
  {
    if (millis () - buttonPressTime >= debounceTime)      //Rotina para debounce
    {
      buttonPressTime = millis ();                        //Registra o tempo em que o botão foi pressionado
      oldButtonState =  buttonState;                      //Registra o antigo estado do botão
      if (buttonState == LOW)
      {
        pos = (pos + 1) % 3;  // Isso garante que a posição volta para o 0 depois do 2.
      }
    }
  }
  return ((float)tensao); // No final de tudo essa funcao retorna o valor da tensão que selecionamos.
}

void ImprimeDisplay(float tensao, byte pos) { // Funcao para imprimir no Display o valor da tensao junto com o traçado que indica qual o algarismo que está sendo mexido.
  display.setTextSize(2);                                   //Imprime as informações na tela size
  display.clearDisplay();                                   //Limpa o display

  display.setCursor(30, 10);                                //Seta o posição do texto
  display.print((float)abs(tensao));                        // Imprime a tensão no display
  display.println("V"); // E insere esse V no final para indicar Volts

  switch (pos) {     // Imprimindo o underline baseado em qual posição do algarismo escolhido está.
    case 0: display.setCursor(30, 15);
      break;

    case 1: display.setCursor(53, 15);
      break;

    case 2: display.setCursor(65, 15);
      break;
  }
  display.println("_");
  display.display(); //Atualiza o display
}

void PinA()                               //Rotina para tratar a interrupção causada pelo encoder rotativo PinA.
{
  cli();                                  //Pare as interrupções para que seja lido o valor nos pinos
  reading = PIND & 0xC;                   //Lê todos os oito valores dos pinos e remove todos, exceto os valores de pinA e pinB
  if (reading == B00001100 && aFlag)      //Checa se temos os dois os pinos em HIGH e se estavamos esperando uma borda ascendente deste pino
  {
    encoderPos = 1;                     //Volta para o 9 antes do 0
    bFlag = 0;                            //Reseta as flags para o próximo turno
    aFlag = 0;
  }
  else if (reading == B00000100)          //Sinaliza que estamos esperando o PinB realizar a transição para a rotação
    bFlag = 1;
  sei();                                  //Reinicia as interrupções
}

void PinB()                               //Rotina para tratar a interrupção causada pelo encoder rotativo PinB.
{
  cli();                                  //Pare as interrupções para que seja lido o valor nos pinos
  reading = PIND & 0xC;                   //Lê todos os oito valores dos pinos e remove todos, exceto os valores de pinA e pinB
  if (reading == B00001100 && bFlag)      //Checa se temos os dois os pinos em HIGH e se estavamos esperando uma borda ascendente deste pino
  {
    encoderPos = -1;
    bFlag = 0;                            //Reseta as flags para o próximo turno
    aFlag = 0;
  }
  else if (reading == B00001000)          //Sinaliza que estamos esperando o PinA realizar a transição para a rotação
    aFlag = 1;
  sei();                                   //Reinicia as interrupções
}

E o resultado, como você pode conferir abaixo, ficou muito legal!


Limitações

É muito legal ter aprendido como fazer um regulador de tensão com o Arduino de forma bem simples, mas esse projeto tem algumas limitações que precisam ser ditas:

  • A tensão, mesmo que regulada, sempre tem um ripple associado. Ele nunca tem a tensão de saída tão pura, a tensão de saída se assemelha mais a uma tensão de um circuito chaveado tradicional. Por isso, circuitos sensíveis podem não funcionar tão bem
  • Apesar de ser um circuito que funciona por PWM, é uma fonte que utiliza a caracteristica de uma fonte linear na sua eficiencia. Muita potencia é dissipada no transistor e transformada em calor. Por isso é necessário que o transistor tenha um dissipador caso você queira drenar correntes maiores que 500mA.
  • O projeto até permite utilizar fontes maiores, mas o perigoso é que se caso a leitura analógica da tensão de saída falhe por algum motivo, seja por mal contato, ou jumper rompido, o controlador irá enviar um sinal de controle cada vez maior e a tensão de saída será próxima a tensão da fonte. Quando a leitura analógica voltar, o seu arduino irá ler a tensão da fonte (que pode ser uma fonte de 9V, por exemplo), que fará a porta ser danificada, ou até mesmo a placa Arduino. Por isso, caso queira fazer isso, é necessário implementar um circuito de proteção para que a tensão de saída seja sempre no máximo 5V.

Conclusão

Nesse post aprendemos bastante sobre transistores, reguladores de tensão e outros conceitos.

Fique ligado no blog porque esse post vai servir como base direta para artigos bem interessantes que serão publicados em breve.

Caso a leitura tenha sido útil para você, e você deseja mais dicas como esta, nos siga no instagram @eletrogate. Lá você vai encontrar muitos conteúdos como este.

Se você caiu de paraquedas e não conhece o blog da Eletrogate, te recomendo a visitar outros posts. Temos vários outros posts muito ricos de informação.

Caso tenha ficado alguma dúvida ou queira fazer um elogio, não se esqueça de utilizar o campo dos comentários.

Muito obrigado por ter lido até aqui e até a próxima!


Sobre o Autor


Gustavo Nery

Cursando Engenharia de Controle e Automação pela UFMG. Apaixonado por eletrônica, computação e tecnologias na área de sistemas embarcados. Nos tempos livres me divido entre desenvolver pesquisa na universidade, adquirir novos conhecimentos e estar com a família.


Eletrogate

6 de maio de 2021

A Eletrogate é uma loja virtual de componentes eletrônicos do Brasil e possui diversos produtos relacionados à Arduino, Automação, Robótica e Eletrônica em geral.

Conheça a Metodologia Eletrogate e Lecione um Curso de Robótica nas Escolas da sua Região!

Eletrogate Robô

Cadastre-se e fique por
dentro de novidades!