Páginas

sexta-feira, 9 de setembro de 2016

Projetos - Gerando Senoides com o PIC - Parte 1

Finalmente resolvi tirar essa postagem da gaveta de rascunhos e compartilhar um projeto de bancada que me foi útil na ocasião e pode também ser para outros. O Gerador de Onda Senoidal faz o que o nome diz, fornece um sinal tipo senoide modificada com resolução e frequência ajustáveis a nível de projeto. É possível também gerar outras formas de onda utilizando o mesmo conceito descrito e o Módulo de Tensão de Referência. Já falei sobre esse periférico do PIC aqui no blog quando utilizei ele em conjunto com o Comparador Analógico no projeto do Termômetro Bargraph. Agora vou mostrar como é possível gerar uma senoide ou outra forma de onda qualquer utilizando o VREF.

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
Aumentando o número de pontos, aumentamos a resolução e mais próximo vamos chegando da forma de uma senoide pura. Quanto a frequência da senoide, basta perceber que é preciso passar por todos os pontos, tanto de subida quanto de descida, no intervalo de tempo definido pelo período T=1/f.  Nesse projeto eu queria obter a máxima resolução bem como e a máxima excursão da amplitude do sinal de saída e portanto os intervalos foram calculados para se obter uma senoide com frequência de 1 kHz (que era o que eu precisava na hora pra testar um outro projeto). Formas de onda diferentes e frequências maiores podem ser alcançadas, porém é preciso ficar atento às limitações do componente e principalmente com o tempo de estabilização necessário do módulo VREF.

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.