domingo, 19 de agosto de 2018

Arduino PWM e ADC

Conversor AD


O ATmega328P apresenta internamente um conversor AD de 10 bits. Um conversor AD permite a leitura de um valor analógico e converter esse valor em número binário. Dessa forma, podemos fazer leituras de valores analógicos entre 0 e 5 V com os pinos de A0-A5 do Arduino. 

Um aspecto importante que deve ser levado em conta sobre um ADC é a sua resolução, no caso do Arduino (ATmega328P), temos um conversor de 10 bits e, em geral, usamos uma tensão de referência de 5 V. Dessa forma, para o cálculo da resolução, temos: 

$R=\frac{V_{REF}}{2^{N}}$ 

$R=\frac{5}{2^{10}}$ 

$R=\frac{5}{1024}$ 

$R=0.0048828125$ 

$R=4.88 mV$

A resolução informa a variação que será detectada pelo conversor, assim, se quisermos ler uma tensão de 4.8 mV, teremos uma leitura de 0, essa leitura só será maior que 0 quando a tensão lida for maior que 4.88 mV. Para uma tensão de 2.5 V, podemos calcular a saída do conversor, por:

$V_{ADC}=\frac{V_{IN}}{R}$

$V_{ADC}=\frac{2.5}{4.88m}$

$V_{ADC}=512.295$

$V_{ADC}=512$

Como 2.5 V é a metade de 5 V, temos uma saída de 512 no conversor, que é a metade de 1024.

Para o exemplo a seguir, utilizaremos o pino A0 do Arduino para ler a tensão no terminal central de um potenciômetro de 10 kΩ (outros valores também servirão). Um potenciômetro é uma resistência variável, apresenta três terminais e ao utilizarmos os três terminais, criamos um divisor de tensão. Para isso, um terminal deve ser ligado ao pino de GND do Arduino, o terminal central a um pino analógico (A0) e o último terminal ao pino de 5 V. Dessa forma, ao variamos a resistência, mudamos a tensão que será lida.

Utilizaremos o Monitor Serial do IDE do Arduino (atalho: Ctrl + Shift + M) para a apresentação dos resultados. Ligue o potenciômetro como na imagem a seguir: 

Figura 1. Conversor AD 

Conecte o Arduino ao computador, upload o seguinte código e abra o monitor serial:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
uint8_t pinPot = 0; // Potenciometro no pino A0
uint16_t ADCpot = 0; // Variável para armazenar o valor lido

void setup() 
{
  Serial.begin(9600); // Configura o monitor, baudrate = 96000
}

void loop() 
{
  ADCpot = analogRead(pinPot);   // Lê e armazena em ADCpot
  Serial.print("Valor lido = "); // Imprime no monitor a string
  Serial.println(ADCpot);        // Imprime no monitor o valor de ADCpot
  delay(1000);                   // Delay de 1000 ms, 1 s
}

Varie a resistência do potenciômetro e observe os resultados no Monitor Serial. Bastante legal, não é?

Linha 6 temos a função que configura a comunicação com o Monitor Serial, Serial.begin(9600), 9600 é o baudrate, que é taxa de transmissão de dados (informações por segundo). Outros valores de baudrate poderiam ser usados, mas o valor deve ser igual ao do Monitor Serial. Para enviamos os dados que serão impressos no Monitor Serial, usamos as funções Serial.print() ou Serial.println(), onde na segunda ocorre um pulo para a próxima linha. Entre os parênteses colocamos o argumento que desejamos enviar, podendo ser uma string (cadeia de caracteres) ou um número. 

O Monitor Serial é uma ferramenta muito útil, podendo ser utilizado para imprimir variáveis, e assim, é possível comprovar se o valor é, realmente, o valor esperado ou testar a entrada de execução em um if. Dessa forma, é possível testar o funcionamento do código. Além disso, o Monitor Serial pode ser utilizado para enviar dados para o Arduino. No exemplo a seguir utilizaremos o Monitor Serial para controlar o LED do Arduino ligado ao pino 13.

Conecte o Arduino ao seu computador e upload o seguinte código:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
uint8_t ledPin = 13;  // LED do pino 13
char state = 0; // Variável do tipo char para armazenar caracteres

void setup()   
{
  Serial.begin(9600); // Configura a comunicação serial
}
 
void loop()
{
  while(Serial.available()==0); // Espera o recebimento de dados
  
  state = Serial.read(); // Lê dado do teclado e armazena em state
    
  switch(state)
  {
    case '1': // Caso o dado seja 1, ativa o LED
      Serial.println("LED ON");
      digitalWrite(ledPin, HIGH); 
      Serial.println("..."); 
      break;
    
    default:  // Caso seja qualquer outro dado, desativa o LED
      Serial.println("LED OFF");
      digitalWrite(ledPin, LOW); 
      Serial.println("..."); 
      break;
  }
}

Ao se pressionar a tecla 1 do teclado, o LED acenderá, caso seja pressionado qualquer outra tecla, o LED apagará. Para isso usamos a função switch, ela recebe um argumento e o testa usando cases, caso o teste do case seja verdadeiro, todas as funções dentro dele serão executadas, no final de cada case existe um break, o uso dele é necessário para que a sequência de execução saia do switch, caso contrário, os próximos cases também serão executados sem a realização dos testes. A função switch é bem parecida com a if else, dependendo da situação o uso de uma pode ser melhor que o uso da outra. No final de todos os cases, pode ser utilizado o default, que será executado caso nenhum dos cases sejam executados, dessa forma, ao se pressionar qualquer tecla que não seja a 1, o LED será desligado.

PWM


Os pinos do Arduino que apresentam o símbolo (~) podem ser usados para gerar um sinal PWM (Pulse Width Modulation). O PWM é um sinal periódico, onde é possível controlar o tempo em que o sinal fica em nível lógico alto durante um período. Em outras palavras, é um sinal retangular de largura controlada. 

O duty cycle (ciclo de trabalho) representa a relação entre o período em nível lógico alto dividido pelo período total, temos assim:

$Duty=\frac{T_{ON}}{T}$

$Duty_{\%}=\frac{T_{ON} \times100}{T}$

A imagem a seguir, mostra três sinais PWM com diferentes duty cycle:

Figura 2. Sinal PWM

Os três sinais PWM apresentam o mesmo período, mas com diferentes duty cycle. O PWM possui muitas aplicações, uma delas é o controle da tensão média em uma carga, com isso, podemos controlar a luminosidade de um LED ou a velocidade de um motor variando–se apenas o duty cycle.  No próximo exemplo iremos variar a luminosidade de um LED utilizando PWM, ligue o LED como na figura a seguir:

Figura 3. Sinal PWM em um LED

Conecte o Arduino ao computador e upload o seguinte código:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
uint8_t pinLed = 11; // LED no pino 11

void setup() 
{
}

void loop() 
{
  for(uint8_t i = 0; i <= 255; i++)   // For loop
  {
    analogWrite(pinLed, i);
    delay(10);
  }
}

Se você seguiu os passos corretamente, a luminosidade do LED aumentará gradualmente. Esse efeito ocorre, pois, usamos a função for (for(valor inicial; condição final; valor incremento){instruções;}), que gera um laço de repetição, para variar o valor do PWM. Iniciamos com um valor zero e incrementamos esse valor até ao seu valor máximo, que é 255 (duty cycle = 100%). No ATmega328P é utilizado um valor de 8 bits para o duty cycle do sinal PWM.

Velocidade de motor com potenciômetro 


Agora que você já conhece o conversor AD e o PWM, utilizaremos esses dois assuntos para controlar a velocidade de um motor DC com um potenciômetro. Faça as ligações como na imagem a seguir:

Figura 4. Sinal PWM em um motor DC

As novidades nessa montagem são: um diodo, um transistor NPN e um motor DC. Pense no transistor como uma chave controlada por corrente, corrente essa fornecida pelo pino 11 do Arduino no terminal de Base do transistor, a partir, de um resistor de 1kΩ. O uso do transistor é necessário, pois o motor consome muita corrente, dessa forma, utilizamos uma fonte externa para alimenta-lo, no caso, uma bateria de 9 V. Para o teste foi utilizado o transistor BC548, mas qualquer transistor NPN de propósito geral funcionária da mesma forma, alguns transistores apresentam outra ordem na sequência de terminais, consulte o datasheet do transistor que será utilzado.

O motor DC é um motor que funciona com uma fonte DC, você pode encontra-lo em brinquedos, drive de DVD e etc. O Arduino não deve ser utilizado para ligar um motor diretamente, assim, utilizamos um transistor NPN para o chaveamento. Para a ligação, um terminal do motor é ligado ao terminal positivo da bateria e outro terminal ao terminal Coletor do transistor.

O diodo está ligado em paralelo com o motor, dessa forma, seu terminal cátodo (terminal com uma linha branca) está ligado ao terminal positivo da bateria e seu terminal Ânodo está ligado ao terminal Coletor do transistor. Seu uso é necessário, pois quando ocorrer o chaveamento do transistor o motor gerará um pico de tensão, isso ocorre, pois a corrente no motor se opõe a uma variação abrupta. Dessa forma, o diodo serve como um caminho para corrente do motor circular durante o chaveamento, essa topologia é conhecida como diodo de roda livre (flyback diode). Para o teste, foi utilizado o diodo 1N4001, que é um diodo retificador.

O terminal negativo da bateria deve ser ligado ao pino GND do Arduino.

Conecte o Arduino ao computador e upload o seguinte código:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
uint8_t pinMotor = 11; // Motor no pino 11
uint8_t pinPot = 0;    // Potenciometro no pino A0

uint16_t ADCpot = 0;   // Valor lido
uint8_t PWMmotor = 0;  // PWM do motor

void setup() 
{
}

void loop() 
{
  ADCpot = analogRead(pinPot); // Ler e salva em ADCpot

  PWMmotor = map(ADCpot, 0, 1023, 0, 255); // ADCpot = 0-1023 -> 0-255

  analogWrite(pinMotor, PWMmotor); // Envia sinal PWM ao pino do motor
  delay(100); // Delay de 100 ms, 0.1 s
}

A única novidade é na linha 13, onde utilizamos a função map (map(valor, de menor, de maior, para menor, para maior)), para mudar a escala dos valores lido de 0-1023 para 0-255. Essa função facilita essa mudança de escala, mas não é a única forma de fazê-la. Como os valores lidos estão em 10 bits e desejamos um número de 8 bits, basta deslocar o valor de ADCpot em dois bits para a direita (operador de deslocamento: >>) e salvar em PWMmotor, usando o seguinte comando:

PWMmotor = (ADCpot >> 2); 

Se você seguiu todos os passos correntemente, a velocidade do motor deve está mudando de acordo com a variação do potenciômetro. Agora você já pode impressionar seus amigos e familiares com suas habilidades incríveis.

Enfim, chegamos ao final dessa parte, parabéns por ter chegado até aqui. Na próxima parte serão abortados os assuntos Interrupções e Timer, até lá.

<< Arduino I/O                                                                                     Arduino Interrupções e Timer >>

Nenhum comentário:

Postar um comentário