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!