terça-feira, 9 de agosto de 2016

Gerando sinais analógicos com o PIC(onda triangular e dente de serra).

Olá,
      As vezes precisamos converter dados digitais em sinais analógicos apesar de alguns microcontroladores terem esta opção já inclusa podemos também recorrer a chips dedicado para esta função como os chips da "analog devices" os AD5601/AD5611/AD5621 que são de 8,10 e 12 bits respectivamente.
      O circuito montado no proteus foi este a seguir:
     Observe que coloquei uma porta serial para saber o qual valor eu estava sendo enviado, o voltímetro 'lê'  a tensão que estava saindo a cada incremento no chip.O código fonte ficou dividido em duas partes; uma gera onda dente de serra e o outro gera uma onda triangular, veja na imagem abaixo os prints da tela:

As formas de ondas em azul são os pacotes SPI que foram enviados ,em verde o clock gerado a cada transmissão de pacotes e em vermelho o momento em que o pino de "slave select " é ativado. Na figura a seguir é visto como é feito o cálculo para o chip AD5601, para calcular para os outros chips segue o mesmo raciocínio ou seja pega o valor de 5V e divide pelo números de resolução(incrementos) do chip ou seja 255 incrementos para o AD5601,1024 para o AD5611 e 4096 incrementos para o AD5621.
O código fonte fica :


/*
 *                                Usando comunicação SPI  com ADS601/ADS611/ADS621     
 *
 * Compilador : MPlabXC8
 * Microcontrolador: 16F1947
 * Autor: aguivone
 * Versão: 1
 * Data :  09/08/2016
 */
#include <xc.h>
#include <stdio.h>
#include "serial16F1947.c"
#include "SPI.c"
#define _XTAL_FREQ 16000000  //usado para rotinas de  delays
#define LED               LATAbits.LATA0
#define LER_LED           PORTAbits.RA0


//
///////////configuração dos fuses bits/////////////////////////////////////////////
// CONFIG1
#pragma config FOSC = HS        // Oscillator Selection (HS Oscillator, High-speed crystal/resonator connected between OSC1 and OSC2 pins)
#pragma config WDTE = OFF       // Watchdog Timer Enable (WDT disabled)
#pragma config PWRTE = OFF      // Power-up Timer Enable (PWRT disabled)
#pragma config MCLRE = ON       // MCLR Pin Function Select (MCLR/VPP pin function is MCLR)
#pragma config CP = OFF         // Flash Program Memory Code Protection (Program memory code protection is disabled)
#pragma config CPD = OFF        // Data Memory Code Protection (Data memory code protection is disabled)
#pragma config BOREN = OFF      // Brown-out Reset Enable (Brown-out Reset disabled)
#pragma config CLKOUTEN = OFF   // Clock Out Enable (CLKOUT function is disabled. I/O or oscillator function on the CLKOUT pin)
#pragma config IESO = ON        // Internal/External Switchover (Internal/External Switchover mode is enabled)
#pragma config FCMEN = ON       // Fail-Safe Clock Monitor Enable (Fail-Safe Clock Monitor is enabled)

// CONFIG2
#pragma config WRT = OFF        // Flash Memory Self-Write Protection (Write protection off)
#pragma config VCAPEN = OFF     // Voltage Regulator Capacitor Enable (VCAP pin functionality is disabled)
#pragma config PLLEN = OFF      // PLL Enable (4x PLL disabled)
#pragma config STVREN = OFF     // Stack Overflow/Underflow Reset Enable (Stack Overflow or Underflow will not cause a Reset)
#pragma config BORV = LO        // Brown-out Reset Voltage Selection (Brown-out Reset Voltage (Vbor), low trip point selected.)
#pragma config LVP = OFF        // Low-Voltage Programming Enable (High-voltage on MCLR/VPP must be used for programming)
//////////////////////////////////////////////////////////////////////////////////

//************************************************************************************/
//VARIAVEIS GLOBAIS
//************************************************************************************/
bit flag_led=0;
////variaveis da porta serial
char   gcCaracter;
//*******************************************************************************/
//===================================================================================
//Função:    _interrupcoes
//Descrição: usada para tratar as interrupções geradas pelo microcontrolador.
//===================================================================================
void interrupt interrupcoes(void)//vetor de interrupção
 {
      if(RC1IF)//verifica interrupção da serial na COM1
    {//interrupção da serial
        gcCaracter = RC1REG;   
        escreve_RS232(gcCaracter,0);//finaliza string
        RC1IF = 0;//  limpa flag de interrupção de recepção
    }
    /*if(RC2IF)//verifica interrupção da serial na COM2
    {//interrupção da serial
        gcCaracter = RC2REG;
        escreve_RS232(gcCaracter,1);//finaliza string
        RC2IF = 0;//  limpa flag de interrupção de recepção
    }*/
}

//===================================================================================
//Função:    _config_CPU
//Parâmetros: não tem
//Retorno:   não tem retorno.
//Descrição: inicializa os registradores do microcontrolador.
//===================================================================================
void config_CPU()
{
    //configura portas logicas
    TRISA = 0X00;
    TRISB = 0X00;
    TRISC = 0x80;
    TRISD = 0x00;
    TRISE = 0x00;
    TRISF = 0x00;//todos entrada e ainda são as entrasas analogicas
    TRISG = 0x04;
    // inicializa portas logicas configuradas como saida para 0
    LATA = 0;
    LATB = 0;
    LATC = 0;
    LATD = 0;
    LATE = 0;
    LATF = 0;
    LATG = 0;
    inicializa_RS232(9600,1,0);//modo de alta velocidade inicializa COM1
    //inicializa_RS232(9600,1,1);//modo de alta velocidade inicializa COM2
    PEIE = 1;//habilita interrupção de perifericos do pic
    GIE = 1; //GIE: Global Interrupt Enable bit  
    __delay_ms(100);
    
}

void Envia_pacote(unsigned long valor,int modo,int tipo)//valor,modo de operação,tipo do sensor
{
    switch(tipo)
    {
        case 0:
        {
           valor = valor << 6; //8 bits - ADS601
        }break;
        case 1:
        {
            valor = valor << 4;//10 bits - ADS611
        }break;
        case 2:
        {
            valor = valor << 2;//12 bits - ADS621
        }break;
    }
     valor =  valor & 0B0011111111111111;//zera os 2 primeiros bits
     switch(modo)
    {//modos do power down
        case 1:
        {
           valor  = valor + 0X4000;//1K ligado ao gnd 
        }break;
        case 2:
        {
           valor  = valor + 0X8000;//100K ligado ao gnd 
        }break;
        case 3:
        {
           valor  = valor + 0XC000; //three state
        }break;
    }
    escreve_SPI(((unsigned char)(valor>>8)),(unsigned char)valor ,1,0);//byte1 , byte2,numero de bytes a ser enviado(0 = 1 e 1 = 2),tipo de ligação ao terra 
    
}

void main(void) 
{
    config_CPU(); 
    imprime_RS232("Imprimindo: COM 1!\r\n",0); 
    imprime_RS232("Digite um caracter:\r\n",0);
    inicializa_spi_mestre(0);
    long tensao,tempo=0;
    for(;;)
    { 
         ///////////////simulação do trecho 1(onda dente de serra)//////////////
            imprime_RS232("Valor enviado = ",0);
            long_to_char_RS232(tempo,5,0,0);
            Envia_pacote(tempo,0,0); //8 bits - ADS601  o valor a ser colocado deve ser de 0 a 255.
           // Envia_pacote(tensao,0,1); //10 bits - ADS611  o valor a ser colocado deve ser de 0 a 1024.
           // Envia_pacote(tensao,0,2); //12 bits - ADS601  o valor a ser colocado deve ser de 0 a 4096.
            __delay_ms(200);//tempo de cada degrau
            imprime_RS232("\r\n",0);
            if(tempo > 245)
            {
                tempo = 0;
            }
             tempo = tempo + 10;
            ////////////////fim do trecho 1//////////////////////
///////////////simulação do trecho 2(onda triangular)////////////// /* //descomente esta linha para gerar a onda senoidal mas o trecho 1 deve ser comentado if(tempo > 254) { tensao--; if(tensao == 0) { tempo =0; } } else { tensao++; } Envia_pacote(tensao,0,0); __delay_ms(1);//tempo de cada degrau *///descomente esta linha para gerar a onda senoidal mas o trecho 1 deve ser comentado ////////////////fim do trecho 2////////////////////// tempo++; } }

código dos includes externos
--------------------------------------------
"serial16F1947.c"
/*
 *                          FUNÇOES USADAS NA SERIAL
 *
 * Compilador :      MPlabXC8
 * Microcontrolador: 16F1947
 * Autor:            Aguivone
 * Versão:           1
 * Data de criação:  21 de agosto de 2014.
 */

#include <xc.h>
#include <stdio.h>
#include <string.h> //para usar funçoes de string deve se adicionar este header
#define _XTAL_FREQ 16000000//usado para rotinas de  delays

//===================================================================================
//Função:    _inicializa_RS232
//Parâmetros: unsigned long ulVelocidade
//          : unsigned int uiModo
//          : porta serial(1 ou 0) 
//Retorno:   não tem retorno.
//Descrição: usada para iniciar a porta serial.
//===================================================================================
void inicializa_RS232(unsigned long ulVelocidade,unsigned int uiModo,int porta)
{//// por padrão é usado o modo 8 bits e sem paridade, mas se necessario ajuste aqui a configuração desejada.
    // verifique datasheet para ver a porcentagem de erro e se a velocidade é possivel para o cristal utilizado.
    unsigned long valor;
    if(porta == 0)
    {
        RC1STA = 0X90;//habilita porta serial,recepção de 8 bit em modo continuo,assincrono.        
            if(uiModo == 1)
            {//modo = 1 ,modo alta velocidade
             TX1STA = 0X24;//modo assincrono,trasmissao 8 bits.
             valor =(((_XTAL_FREQ/ulVelocidade)-16)/16);//calculo do valor do gerador de baud rate
            }
            else
            {//modo = 0 ,modo baixa velocidade
             TX1STA = 0X20;//modo assincrono,trasmissao 8 bits.
             valor =(((_XTAL_FREQ/ulVelocidade)-64)/64);//calculo do valor do gerador de baud rate
            }
        SP1BRG = valor;
        RC1IE = 1;//habilita interrupção de recepção
        TX1IE = 0;//deixa interrupção de transmissão desligado(pois corre se o risco de ter uma interrupção escrita e leitura ao mesmo tempo)

    }
    else
    {
       RC2STA = 0X90;//habilita porta serial,recepção de 8 bit em modo continuo,assincrono.
        if(uiModo == 1)
        {//modo = 1 ,modo alta velocidade
         TX2STA = 0X24;//modo assincrono,trasmissao 8 bits.
         valor =(((_XTAL_FREQ/ulVelocidade)-16)/16);//calculo do valor do gerador de baud rate
        }
        else
        {//modo = 0 ,modo baixa velocidade
         TX2STA = 0X20;//modo assincrono,trasmissao 8 bits.
         valor =(((_XTAL_FREQ/ulVelocidade)-64)/64);//calculo do valor do gerador de baud rate
        }
    SP2BRGL = valor;
    SP2BRGH = valor<<8;
    RC2IE = 1;//habilita interrupção de recepção
    TX2IE = 0;//deixa interrupção de transmissão desligado(pois corre se o risco de ter uma interrupção escrita e leitura ao mesmo tempo)
    }
    
}
//===================================================================================
//Função:    _escreve1_RS232
//Parâmetros: char cValor, int porta
//Retorno:   não tem retorno.
//Descrição: usada para escrever 1 caracter.
//===================================================================================
 void escreve_RS232(char cValor,int porta)
{
     if(porta == 0)
    {
        TX1IF = 0;//limpa flag que sinaliza envio completo.
        TX1REG = cValor;
        while(TX1IF ==0);//espera enviar caracter
    }
    else
    {
        TX2IF = 0;//limpa flag que sinaliza envio completo.
        TX2REG = cValor;
        while(TX2IF ==0);//espera enviar caracter
    }
     __delay_us(50);
}
 
//===================================================================================
//Função:    _imprime_RS232
//Parâmetros: const char ccFrase[], int porta
//Retorno:   não tem retorno.
//Descrição: usada para escrever uma string(vetor de caracteres).
//===================================================================================
 void imprime_RS232(const char ccFrase[],int porta)
{
     unsigned char indice = 0;
     unsigned char tamanho = strlen(ccFrase);     
      while(indice < tamanho ) ///veja que o programa pode travar se aqui não tiver as duas aspas
       {
           escreve_RS232(ccFrase[indice],porta);
           indice++;
       }
}
//===================================================================================
//Função:    _long_to_char_RS232
//Parâmetros: unsigned long  ulQuant, -> valor a ser impresso na serial
//            int iTam,-> numero de caracter que deve ser impresso
//Retorno:   não tem retorno.
//Descrição: converte um long ou int em uma sequencia de caracteres.
//===================================================================================
void long_to_char_RS232(unsigned long  ulQuant,int iTam,int virgula,int porta)
{
        char cTexto[7];
        int  iValor = 0;
        if(virgula == 0)
        { virgula = 20;//dessa forma nunca será usado a virgula
        }
        while(iValor < 6 )
        {
             cTexto[iValor]='0';
             iValor++;
        }        
         while(ulQuant>=10000)
            {
             ulQuant=ulQuant-10000;
             cTexto[5]++;
             }
         while(ulQuant>=1000)
            {
             ulQuant=ulQuant-1000;
             cTexto[4]++;
             }
          while(ulQuant>=100)
            {
             ulQuant=ulQuant-100;
             cTexto[3]++;
             }
           while(ulQuant>=10)
            {
             ulQuant=ulQuant-10;
             cTexto[2]++;
             }
           while(ulQuant>=1)
            {
             ulQuant=ulQuant-1;
             cTexto[1]++;
             }
        iValor = iTam ;
          while(iValor != 0 )
           {
              escreve_RS232(cTexto[iValor],porta);
              iValor--;
              if(virgula == iValor){ escreve_RS232(',',porta);}
           }
}
------------------------------------------------------------------------------------
"SPI.c"

/*
 * File:   SPI.c
 * Author: aguivone
 *
 * Created on 14 de Julho de 2016, 14:54
 */
#include <xc.h>
#define _XTAL_FREQ 16000000  //usado para rotinas de  delays

#define SPI1_SS            LATCbits.LATC2 //configura pino de Slave selected
#define SPI2_SS            LATCbits.LATC0 //configura pino de Slave selected


unsigned char ler_SPI( unsigned char dado,int porta_spi)
{//le um byte
  unsigned char TempVar;
  unsigned char Retorno;
  if(porta_spi == 0)
  {
    SPI1_SS    = 1;
    __delay_us(5);
    TempVar = SSP1BUF;        // limpa BF
    SSP1BUF = dado;           // escreve no buffer o codigo da solicitação
    while (!SSP1STATbits.BF);//espera terminar o envio
    TempVar = SSP1BUF;        // limpa BF
    SSP1BUF = 0X00;           // envia um dado qualquer somente para fazer a leitura
    while (!SSP1STATbits.BF);
     SPI1_SS    = 0;
     Retorno = SSP1BUF;
  }
  else
  {
     SPI2_SS    = 1;
    __delay_us(5);
    TempVar = SSP2BUF;        // limpa BF
    SSP2BUF = dado;           //escreve no buffer o codigo da solicitação
    while (!SSP2STATbits.BF);//espera terminar o envio
    TempVar = SSP1BUF;        // limpa BF
    SSP2BUF = 0X00;           // envia um dado qualquer somente para fazer a leitura
    while (!SSP2STATbits.BF);
     SPI2_SS    = 0;
     Retorno = SSP2BUF;
  }
  return (Retorno);       // byte lido
}


void escreve_SPI( unsigned char byte0,unsigned char byte1 ,int num_byte,int porta_spi)
{//geralmente o primeiro byte tambem é chamado de opcode
   unsigned char TempVar;
   if(porta_spi == 0)
   {//usa a SPI 1
        SPI1_SS = 0;//verifique se o hardware funciona deste modo ou é invertido
        __delay_us(5);
        TempVar = SSP1BUF;        // limpa BF
        SSP1BUF = byte0;           // escreve no buffer
        while ( !SSP1STATbits.BF ); //espera terminar o envio
        if(num_byte == 1)
        {
            TempVar = SSP1BUF;        // limpa BF
            SSP1BUF = byte1;           // escreve no buffer o byte 2
            while (!SSP1STATbits.BF );//espera terminar o envio
        }
        SPI1_SS = 1;
   }
   else
   {//usa a SPI 2
       SPI2_SS    = 0;//verifique se o hardware funciona deste modo ou é invertido
        __delay_us(5);
        TempVar = SSP2BUF;        // limpa BF
        SSP2BUF = byte0;           // escreve no buffer
        while (!SSP2STATbits.BF); //espera terminar o envio
        if(num_byte == 1)
        {
            TempVar = SSP2BUF;        // limpa BF
            SSP2BUF = byte1;           // escreve no buffer
            while (!SSP2STATbits.BF);
        }
        __delay_us(5);
        SPI2_SS = 1;
   }
}
 void inicializa_spi_mestre(int tipo)//inicialica modo mestre - 0-habilita somente spi1 , 1- habilita spi2 e 2- habilita os 2 spi  
{  
     if((tipo == 0)||(tipo == 2))
     {
       // SSP1CON1 = 0X20; //habilita pinos de spi // FOSC/4 //clock em nivel 0
       // SSP1CON1 = 0X21; //habilita pinos de spi // FOSC/16 //clock em nivel 0
        SSP1CON1 = 0X22; //habilita pinos de spi // FOSC/64 //clock em nivel 0
       // SSP1STAT = 0X40; //pega amostras no meio do byte e a trasmissão será na borda de subida
        SSP1STAT = 0X40; //pega amostras no meio do byte e a trasmissão será na borda de descida
        SPI1_SS = 1;//inicia em nivel alto para AD5601/AD5611/AD5621
     }
     if((tipo == 1)||(tipo == 2))
     {
        SSP2CON1 = 0X21; //habilita pinos de spi // FOSC/16 //clock em nivel 0
        SSP2STAT = 0XC0; //pega amostras no fim do byte e a trasmissão será na borda de subida
        SPI2_SS = 0;
     }
}

Nenhum comentário :

Postar um comentário

olá,digite aqui seu comentário!