Analog

Introdução

Numa outra página foi possível ver como é que o PIC32 lidava com a leitura/escrita de sinais digitais. Mas como proceder se os sinais forem analógicos?

Entradas analógicas

Com efeito em certas situações é necessário medir determinados valores de tensão, já que eles se relacionam com uma grandeza física. Por exemplo o sensor LM35 gera uma tensão proporcional à temperatura a que está sujeito (10mV por cada ºC).

Para tal o PIC32 possui 16 pinos (designados de AN0 a AN15) onde podem ser aplicados sinais analógicos (com tensões entre 0 e 3,3V), que serão depois convertidos para valores digitais através dum conversor analógico/digital (ADC – Analog to Digital Converter) integrado no próprio microcontrolador. Alguns destes pinos estão disponíveis no conetor J7 da placa ChipKIT UNO:

No caso deste ADC a resolução, i.e. o número de bits usados nessa conversão, é igual a 10, sendo pois cada tensão convertida em valores entre 0 e 1023 (000h a 3FFh). Todos os detalhes sobre este assunto podem ser mais uma vez esclarecidos na datasheet do PIC32, mais concretamente na sua secção 17: 10-Bit A/D Converter.

Projeto analog

Neste exemplo, e para facilidade de teste, a tensão a medir será gerada por um divisor de tensão implementado por um simples potenciómetro de 10kΩ, sendo aplicada ao pino A0 da placa ChipKIT UNO32. Num divisor de tensão a tensão de saída Vout é igual a Vcc*R2/(R1+R2), sendo Vcc a tensão de alimentação (3,3V), e R1/R2 os valores das resistências entre Vout e o VCC/GND respetivamente.

pot

Vamos agora criar um novo projeto Arduino chamado analog que começará por apresentar periodicamente o valor da conversão analógico/digital. Para tal o conteúdo do ficheiro analog.cpp seria o seguinte:

#include <Arduino.h>

#define pinAnalog 0

void setup() {
    Serial.begin(115200);
}

void loop() {
    int n = analogRead(pinAnalog);
    Serial.print(n);
    Serial.print(" - ");
    Serial.print(n*3.3/1024);
    Serial.println(" V");

    delay(50);
}

Neste código é chamada ciclicamente a função analogRead() que lê o resultado da conversão analógico-digital do sinal ligado ao canal 0.

Saídas analógicas

Embora o microcontrolador PIC32 presente na placa ChipKIT UNO32 não possua um DAC (Digital to Analog Converter) é possível simular a geração de sinais analógicos recorrendo a sinais digitais PWM. Tratam-se de sinais digitais periódicos cujo valor médio pode ser alterado variando o seu duty-cycle.

Existe mesmo a função analogWrite(pin, v) que gera um sinal de 490Hz no pino pin cujo argumento v (de 0 a 255) permite controlar o seu duty-cycle de 0% (a que corresponde uma tensão média de 0V), até 100% correspondente a 3V3 de valor médio.

No seguinte exemplo a tensão medida no potenciómetro vai ser usada para controlar a intensidade luminosa dum LED a ligar ao pino 10. De notar que apenas é possível gerar sinais PWM em certos pinos da placa ChipKIT UNO32: os pinos cujos números estão sublinhados na figura do pinout da placa, ou seja o 3, 5, 6, 9 e 10, o que impossibilita o uso do LED presente na placa (pino 13).

chipkituno32_pinout

O seguinte código implementa a funcionalidade acima descrita:

#include <Arduino.h>

#define pinAnalog 0
#define pinPWM 10

void setup() {
    Serial.begin(115200);
}

void loop() {
    int n = analogRead(pinAnalog);
    Serial.print(n);
    Serial.print(" - ");
    Serial.print(n*100/1024);
    Serial.println(" %");

    analogWrite(pinPWM, n>>2);

    delay(50);
}

De notar que a gama de valores obtida pelo ADC (0..1023) pode ser facilmente convertida na gama 0..255 fazendo uma divisão por 4, ou como foi usado no código acima apresentado, um deslocamento de 2 bits para a direita (>>2).

Tal como se pode confirmar na datasheet do PIC32 onde esta funcionalidade PWM é abordada (secção 16: Output Compare), o pino do PIC32 onde é gerado o sinal PWM é o RD4. Isso mesmo é alertado no manual da placa ChipKIT UNO32, onde no final da página 5, é dito que o sinal PWM só surge no pino 10 da placa ChipKIT UNO32 caso o jumper JP4 esteja na posição da figura (de outra forma nesse pino surgirá antes o pino de entrada/saída digital RG9).

Observe no osciloscópio a forma de onda gerada no pino 10 e meça a sua frequência para além de comprovar as suas características PWM para diferentes posições do potenciómetro.

Servomotores

Por fim vamos também usar sinais PWM para controlar a posição do eixo dum servomotor como o SG90 ilustrado na seguinte figura:

servo

Essa posição está dependente da largura do impulso dum sinal de 50Hz (20ms de período) a aplicar a uma das suas entradas (linha laranja).

Existe mesmo uma biblioteca (Servo) que pode ser usada para este efeito. O seguinte código controla a posicão do veio do servomotor com base na posição do potenciómetro, gerando o sinal PWM adequado no pino 3:

#include <arduino.h>

#include "Servo.h"
Servo motor;

#define pinAnalog 0
#define pinPWM 10
#define pinMotor 3

void setup() {
    Serial.begin(115200);
    motor.attach(pinMotor);
}

void loop() {
    int n = analogRead(pinAnalog);
    Serial.print(n);
    Serial.print(" - ");

    analogWrite(pinPWM, n>>2);

    int a = map(n, 0, 1023, 0, 180);
    motor.write(a);
    Serial.print(a);
    Serial.println(" graus");

    delay(50);
}

Para além da função attach() que associa o pino onde pretendemos gerar o sinal de controlo, existe ainda a função write() que define o ângulo pretendido (de 0º a 180º), ambas funções do objeto Servo. Neste exemplo foi usada também usada a função map() que permite transformar valores compreendidos numa determinada gama, numa outra gama. Neste exemplo vamos transformar o resultado da conversão (0..1023) no ângulo (0º..180º) pretendido para o servomotor.

De notar que caso este sinal PWM fosse gerado no pino 9, a função analogWrite deixaria de funcionar. Isto é um alerta para o facto de certas funcionalidades por usarem os mesmos recursos poderem entrar em conflito. Este problema foi resolvido gerando o sinal PWM de controlo do servomotor num pino pertencente a outra porta (que não a usada pelo sinal PWM de controlo do LED).

Observe no osciloscópio a forma de onda gerada no pino 3 e comprove as suas características (período e largura do impulso) para diferentes posições do veio do motor.

Projeto analogserial

Neste projeto pretende-se criar um programa semelhante ao butledserial mas que agora explore as funcionalidades descritas nesta página. Concretamente, este programa deverá incluir os comandos analog, dim e motor:

  • ch<enter> – apresenta o valor da tensão presente no canal ch
  • pp ii<enter> – coloca o LED ligado ao pino pp* com ii% da sua intensidade
  • aa<enter> – posiciona o veio do motor ligado ao pino 3 com um ângulo aaº

* Note que o pino terá que pertencer ao conjunto {3, 5, 6, 9, 10}