Conceitos Básico e recursos do PIC:
Muitos PICs, e outros microcontroladores em geral, possuem um módulo VREF que é um periférico bem versátil. É basicamente um conversor digital-analógico (CDA) e como tal, converte um valor binário em um nível tensão DC no pino de I/O do PIC. No caso do PIC, é possível escolher entre 26 valores distintos entre 0 e 5 Volts.
A arquitetura do módulo VREF é baseada em uma associação com 16 resistores multiplexados. Um divisor de tensão controlado pelo bit <VRR> permite o módulo trabalhar com duas escalas (ranges) de tensões. Cada divisão (high e low) pode assumir 16 valores diferentes.
figura 01 - Diagrama do Módulo de Tensão de Referência.
- retirado do datasheet do pic -
Como se pode ver na figura, escrevendo um valor binário entre 0000 e 1111 nos bits VR0 a VR3 do registrador VCON, você faz a multiplexação dos resistores que ficarão ativos e com isso, altera o valor da tensão de saída.
Quando programando em C no MPLAB e com o compilador CCS, o controle é feito utilizando a função SETUP_VREF(arg1| arg2 | arg3)que recebe 3 argumentos.
Argumento1: VREF_HIGH / VREF_LOW / FALSE- indica qual escala (range) deve ser usado. Alto ou baixo ou ainda se o módulo ficará desligado (false).
Argumento2: VREF_A2 - determina onde a tensão de saída do módulo será disponível interna ou externamente. Nesse exemplo, VREF estará disponível no pino A2.
Argumento3: Neste argumento deve ser passado um valor numérico de entre 0 e 15, que corresponde ao valor nos bits de controle <VR3:0>. O Efetivo valor da tensão DC é dado pelas equações mostradas abaixo.
Quando na escala alta (VREF_HIGH) o valor da tensão de saída é dado pela equação:
Quando na escala baixa (VREF_LOW), o valor da tensão é dado agora pela equação:
Note que o módulo também utiliza VDD e VSS como alimentação e portanto, variações ou flutuações em VDD/VSS irão refletir em VREF. Com base nas equações mostradas criei uma tabela onde calculei todos os valores que VREF pode assumir para um valor de VDD igual a 5 volts. Uma outra limitação é o fato que alguns pontos dos dois ranges são coincidentes, e portanto, não é possível ter 32 pontos de resolução mas apenas 26.
A tabela abaixo mostra todos as 32 tensões possíveis que podemos obter utilizando VDD = 5 Volts.
figura 02 - Valores possíveis de VREF para ambos os ranges
Lógica do Projeto: Uma vez que não estamos realmente gerando uma senoide pura, mas sim uma senoide modificada ou digitalizada. Configuramos VREF para fornecer a mínima tensão desejada na saída, fazemos um delay para que a tensão se estabilize, em seguida mudamos os argumentos da função SETUP_VREF() para aumentar a tensão de saída para o próximo valor, repetimos o processo até atingimos o valor máximo desejado e então fazemos o caminho inverso, diminuindo a tensão à cada delay. A figura abaixo ilustra um caso particular, onde foram usados 5 patamares distintos.
figura 03 - Senoide modificada, n=5 |
Software: Primeiro é feito a configuração dos registradores de controle do periférico em seguida, um laço garante a geração da senoide ad infinitum. O código abaixo foi escrito por meu colega Eng. Heitor M. Couto em 2014 na época, estudante de graduação e meu estagiário.
NOTA: Conforme o datasheet, quando configurado no modo de tensão de referência, o pino RA2 trabalha como uma saída de alta impedância. Antes de usa-lo é preciso configurá-lo como ENTRADA e conectar ao pino apenas cargas de alta impedância ligada ao pino.
void main()
{
SET_TRIS_A(0b00000100); //pino RA2 como ENTRADA!!!
setup_comparator(NC_NC_NC_NC);//desabilita o módulo comparador
for(;;)
{
senoide();
}
}
void senoide(void)
{
setup_vref(VREF_LOW | VREF_A2 | 9);//1,87
delay_us(245);
setup_vref(VREF_HIGH | VREF_A2 | 5);//2,03
delay_us(82);
setup_vref(VREF_LOW | VREF_A2 | 10);//2,08
delay_us(165);
setup_vref(VREF_HIGH | VREF_A2 | 6);//2,18
delay_us(167);
setup_vref(VREF_LOW | VREF_A2 | 11);//2,29
delay_us(84);
setup_vref(VREF_HIGH | VREF_A2 | 7);//2,34
delay_us(257);
setup_vref(VREF_LOW | VREF_A2 | 12);//2,5
delay_us(267);
setup_vref(VREF_HIGH | VREF_A2 | 9);//2,656
delay_us(92);
setup_vref(VREF_LOW | VREF_A2 | 13);//2,708
delay_us(190);
setup_vref(VREF_HIGH | VREF_A2 | 10);//2,81
delay_us(199);
setup_vref(VREF_LOW | VREF_A2 | 14);//2,916
delay_us(104);
setup_vref(VREF_HIGH | VREF_A2 | 11);//2,96
delay_us(333);
setup_vref(VREF_LOW | VREF_A2 | 15);//3,125
delay_us(385);
setup_vref(VREF_HIGH | VREF_A2 | 13);//3,28
delay_us(489);
setup_vref(VREF_HIGH | VREF_A2 | 14);//3,437
delay_us(1149);
setup_vref(VREF_HIGH | VREF_A2 | 15);//3,59
delay_us(1149);
//até aqui é 90°
setup_vref(VREF_HIGH | VREF_A2 | 14);//3,437
delay_us(489);
setup_vref(VREF_HIGH | VREF_A2 | 13);//3,28
delay_us(385);
setup_vref(VREF_low | VREF_A2 | 15);//3,125
delay_us(333);
setup_vref(VREF_HIGH | VREF_A2 | 11);//2,96
delay_us(104);
setup_vref(VREF_LOW | VREF_A2 | 14);//2,916
delay_us(199);
setup_vref(VREF_HIGH | VREF_A2 | 10);//2,81
delay_us(190);
setup_vref(VREF_LOW | VREF_A2 | 13);//2,708
delay_us(92);
setup_vref(VREF_HIGH | VREF_A2 | 9);//2,656
delay_us(267);
setup_vref(VREF_LOW | VREF_A2 | 12);//2,5
delay_us(257);
setup_vref(VREF_HIGH | VREF_A2 | 7);//2,34
delay_us(84);
setup_vref(VREF_LOW | VREF_A2 | 11);//2,29
delay_us(167);
setup_vref(VREF_HIGH | VREF_A2 |6);//2,18
delay_us(165);
setup_vref(VREF_LOW | VREF_A2 | 10);//2,08
delay_us(82);
setup_vref(VREF_HIGH | VREF_A2 |5);//2,03
delay_us(245);
//ATÉ AQUI 180°
setup_vref(VREF_LOW | VREF_A2 | 9);//1,87
delay_us(245);
setup_vref(VREF_HIGH | VREF_A2 | 3);//1,718
delay_us(82);
setup_vref(VREF_LOW | VREF_A2 | 8);//1,667
delay_us(166);
setup_vref(VREF_HIGH | VREF_A2 |2);//1,5625
delay_us(168);
setup_vref(VREF_LOW | VREF_A2 | 7);//1,4583
delay_us(85);
setup_vref(VREF_HIGH | VREF_A2 | 1);//1,4063
delay_us(260);
setup_vref(VREF_LOW | VREF_A2 | 6);//1,25
delay_us(365);
setup_vref(VREF_LOW | VREF_A2 | 5);//1,0417
delay_us(398);
setup_vref(VREF_LOW | VREF_A2 | 4);//0,8333
delay_us(455);
setup_vref(VREF_LOW | VREF_A2 | 3);//0,625
delay_us(572);
setup_vref(VREF_LOW | VREF_A2 | 2);//,04167
delay_us(1330);
setup_vref(VREF_LOW | VREF_A2 | 1);//0,2083
delay_us(1330);
//Até aqui 270°
setup_vref(VREF_LOW | VREF_A2 | 2);//,04167
delay_us(572);
setup_vref(VREF_LOW | VREF_A2 | 3);//0,625
delay_us(455);
setup_vref(VREF_LOW | VREF_A2 | 4);//0,8333
delay_us(398);
setup_vref(VREF_LOW | VREF_A2 | 5);//1,0417
delay_us(365);
setup_vref(VREF_LOW | VREF_A2 | 6);//1,25
delay_us(260);
setup_vref(VREF_HIGH | VREF_A2 | 1);//1,4063
delay_us(85);
setup_vref(VREF_LOW | VREF_A2 | 7);//1,4583
delay_us(168);
setup_vref(VREF_HIGH | VREF_A2 |2);//1,5625
delay_us(166);
setup_vref(VREF_LOW | VREF_A2 | 8);//1,667
delay_us(82);
setup_vref(VREF_HIGH | VREF_A2 | 3);//1,718
delay_us(245);
//Até aqui 360°
}
Hardware: A saída do módulo é feita no pino RA2/AN2, no caso do 16F628A corresponde ao pino 1 do CI. É preciso lembrar que o PIC não tem capacidade de corrente suficiente para a maioria das aplicações e portanto é preciso utilizar um driver ou buffer na saída para alimentar a sua carga. Se você não precisa de muita corrente, um simples transistor tipo BC ou BD com a base ligada através de um resistor de alto valor ao pino RA2 deve ser suficiente. Se o seu projeto necessita de mais corrente é mandatório o uso de mais estágios de amplificação filtros que podem melhorar a forma de onda, reduzindo as componentes harmônicas de alta frequência que sempre estão presentes quando se faz chaveamentos desse tipo.
A senoide gerada possui um nível DC incorporado, já que só podemos excursionar o sinal gerado pelo PIC entre 0V e 5V. Isso pode ser contornado utilizando fontes simétricas no circuito de amplificação.
Utilização: Para utilizar o circuito basta compilar o código, gravar no chip, uma vez alimentado, o circuito já começa a funcionar e fica gerando o sinal eternamente. Para melhorar esse projeto O primeiro refinamento é incluir uma interface com LCD e pelo menos dois botões para visualizar e fazer a seleção da frequência de forma mais simples e não ter que ficar recompilando toda vez que precisar fazer alguma mudança. Isso vai exigir uma abordagem diferente também no código. As constantes usadas na rotina delay_us()são transformadas em variáveis calculadas em uma rotina à parte que irá receber os argumentos via interface.
Quando chegar nesse ponto, já fica ridiculamente fácil incluir também outras formas de onda e construir um pequeno gerador de funções.
Na parte 2, vou mostrar as imagens obtidas com o código acima no osciloscópio e a análise no domínio da frequência da senoide gerada. Gostou, não gostou, achou um erro no projeto? deixe um comentário.