terça-feira, 12 de março de 2013

PWM no XC8


/*
 *                          usando PWM no MPlab XC8
 *
 * Compilador : MPlabXC8
 * Microcontrolador: 16F877A
 * Autor: aguivone
 * Versão: 1
 * Data :  12 de março de 2013
 */
#include <stdio.h>
#include <stdlib.h>
#define _XTAL_FREQ 4000000    // cristal de 4 Mhz
#include <xc.h>

/////////////////////////////////////////////////////////configuraçôes//////////////////////////////////////////////////

#pragma config FOSC = HS        // Oscillator Selection bits (HS oscillator)
#pragma config WDTE = OFF       // Watchdog Timer Enable bit (WDT disabled)
#pragma config PWRTE = OFF      // Power-up Timer Enable bit (PWRT disabled)
#pragma config BOREN = OFF      // Brown-out Reset Enable bit (BOR disabled)
#pragma config LVP = OFF        // Low-Voltage (Single-Supply) In-Circuit Serial Programming Enable bit (RB3 is digital I/O, HV on MCLR must be used for programming)
#pragma config CPD = OFF        // Data EEPROM Memory Code Protection bit (Data EEPROM code protection off)
#pragma config WRT = OFF        // Flash Program Memory Write Enable bits (Write protection off; all program memory may be written to by EECON control)
#pragma config CP = OFF         // Flash Program Memory Code Protection bit (Code protection off)



///////////////////////////////////////////////////interrupção//////////////////////////////////////////////////////////////
void interrupt interrupcao(void)//vetor de interrupção
 {
    if(TMR2IF)
    {//interrupção do timer2
      TMR2IF = 0;//não será usado
    }
    if(CCP1IF)
    {//interrupção do ccp1
      CCP1IF = 0;//não será usado
    }
 }

void inicializa_PWM1(char prescaler,char pr2,char postcaler)//prescaler / PR2 / postcaler
{
    switch(prescaler)
    {
        case 1:
        {
           prescaler = 0;
        }break;
        case 4:
        {
           prescaler = 1;
        }break;
        case 16:
        {
           prescaler = 3;
        }break;
    }
    T2CON = (postcaler - 1)<<3;
    T2CON = T2CON + 4 + prescaler;//o 4 é para habilitar o timer 2
    PR2 = pr2;
    CCP1CON = 0X0F;//habilita pwm
    CCP1IE = 1;//habilita modulo ccp1
    TMR2IE = 1; //habilita timer 2
}
void duty_cicle(int valor)
{
   int baixo = (valor << 4)|0X0C;//assim mantem os 4 bits mais baixo como 1100 - modo pwm
   CCPR1L = valor >> 2;
   CCP1CON = baixo;
}
//////////////////////////////////////////////////////Rotina principal///////////////////////////////////////////////////////////////

void main(void)
{
    TRISC = 0;   //configura como saida
    PORTC = 0;  // limpar as portas que estão configuradas como saidas
    inicializa_PWM1(4,250,1);//1khz veja no comentario abaixo "SUGESTÃO DE DEFINES :"
    PEIE = 1;//habilita interrupção de perifericos do pic
    GIE = 1; //GIE: Global Interrupt Enable bit
    // N = (Fosc/(Fpwm * 4 * prescaler))
    //N = (4.000.000/(1000*4*1)) = 1000 incrementos
    duty_cicle(500);//1000 passos ,supondo que se queira 50% basta por a metade deste valor = 500.
    for(;;)
    {
      //faz nada
    }//loop infinito

}



/*
 *
 */


/*calculos para pwm
    *
    * periodo do pwm
    *
    *  Tpwm = [PR2+1]*4*Tosc*prescaler(do timer2)
    *
    * duty cycle
    *             <bits 5e4>
    * D = (CCPR1L + CCP1CON) * Tosc * prescaler (do timer2)
    *
    * numero de passos do pwm
    *
    * N = (Fosc/(Fpwm * 4 * prescaler)) 
    */

/*
 SUGESTÃO DE DEFINES :
 * use estes valores como referencia
 *
//clock de 4mhz
#define PWM_250HZ_CLK4         inicializa_PWM1(16, 250, 1) //
#define PWM_500HZ_CLK4         inicializa_PWM1(16, 125, 1) //
#define PWM_1KHZ_CLK4          inicializa_PWM1(4, 250, 1)  //
#define PWM_1K25HZ_CLK4        inicializa_PWM1(16, 50, 1)  //
#define PWM_2KHZ_CLK4          inicializa_PWM1(4, 125, 1)  //
#define PWM_2K5HZ_CLK4         inicializa_PWM1(4, 100, 1)  //
#define PWM_4KHZ_CLK4          inicializa_PWM1(1, 250, 1)  //
#define PWM_5KHZ_CLK4          inicializa_PWM1(1, 200, 1)  //
#define PWM_8KHZ_CLK4          inicializa_PWM1(1, 125, 1)  //
#define PWM_10KHZ_CLK4         inicializa_PWM1(1, 100, 1)  //
#define PWM_20KHZ_CLK4         inicializa_PWM1(1,  50, 1)  //
#define PWM_25KHZ_CLK4         inicializa_PWM1(1,  40, 1)  //
#define PWM_100KHZ_CLK4        inicializa_PWM1(1, 10, 1)   //
//clock de 8mhz
#define PWM_500HZ_CLK8         inicializa_PWM1(16, 250, 1) //
#define PWM_1KHZ_CLK8          inicializa_PWM1(16, 125, 1) //
#define PWM_2KHZ_CLK8          inicializa_PWM1(4, 250, 1)  //
#define PWM_2K5HZ_CLK8         inicializa_PWM1(16, 50, 1)  //
#define PWM_4KHZ_CLK8          inicializa_PWM1(4, 125, 1)  //
#define PWM_5KHZ_CLK8          inicializa_PWM1(4, 100, 1)  //
#define PWM_8KHZ_CLK8          inicializa_PWM1(1, 250, 1)  //
#define PWM_10KHZ_CLK8         inicializa_PWM1(1, 200, 1)  //
#define PWM_16KHZ_CLK8         inicializa_PWM1(1, 125, 1)  //
#define PWM_20KHZ_CLK8         inicializa_PWM1(1, 100, 1)  //
#define PWM_40KHZ_CLK8         inicializa_PWM1(1,  50, 1)  //
#define PWM_50KHZ_CLK8         inicializa_PWM1(1,  40, 1)  //
#define PWM_200KHZ_CLK8        inicializa_PWM1(1, 10, 1)   //
//clock de 16mhz
#define PWM_1KHZ_CLK16         inicializa_PWM1(16, 250, 1) //
#define PWM_2KHZ_CLK16         inicializa_PWM1(16, 125, 1) //
#define PWM_4KHZ_CLK16         inicializa_PWM1(4, 250, 1)  //
#define PWM_5KHZ_CLK16         inicializa_PWM1(16, 50, 1)  //
#define PWM_8KHZ_CLK16         inicializa_PWM1(4, 125, 1)  //
#define PWM_10KHZ_CLK16        inicializa_PWM1(4, 100, 1)  //
#define PWM_16KHZ_CLK16        inicializa_PWM1(1, 250, 1)  //
#define PWM_20KHZ_CLK16        inicializa_PWM1(1, 200, 1)  //
#define PWM_32KHZ_CLK16        inicializa_PWM1(1, 125, 1)  //
#define PWM_40KHZ_CLK16        inicializa_PWM1(1, 100, 1)  //
#define PWM_80KHZ_CLK16        inicializa_PWM1(1,  50, 1)  //
#define PWM_100KHZ_CLK16       inicializa_PWM1(1,  40, 1)  //
#define PWM_400KHZ_CLK16       inicializa_PWM1(1, 10, 1)   //

*/
Faça uma visita na página do face, basta procurar por microcontroladores-C,e dê um "curtir" assim vc fica por dentro das novidades do blog!  

segunda-feira, 11 de março de 2013

Frequencimetro Atmega328(até 100khz) - Divisor de frequencia virtual

Olá postei anteriormente aqui um frequencimentro usando o ATmega328 porem ele media valores de até 10khz(quando passava disto ficava instavel,veja o post http://microcontroladores-c.blogspot.com.br/2013/03/frequencimetro-com-atmega328-usando-icp1.html ),para sanar o problema do range sem ter que recorrer a um divisor de frequência implementei no firmware o que eu chamo de "divisor de frequencia virtual",com isso consegui ler valores até 100Khz, alem de colocar um filtro contra ruidos e leitura erradas veja como ficou :




O código fonte:


//************************************************************************
//            usando o modo captura de pulsos para ler frequencia(range 1 a 100KHZ)
//  Version    : 1.2
//  microcontrolador : AVR ATMega328
//  Autor        : Aguivone
//  descrição  : captura de eventos externos  
//  data : 11/03/2013.
//
//************************************************************************
#define F_CPU 16000000UL  //  deve vir antes das interrupçoes
#include <avr/io.h>
#include <avr/interrupt.h>
#include <string.h>
#include <util/delay.h>
#include <string.h>

/////////////////////////declaração da variaveis ///////////////////////////////////
int flag_inte=0;
long estouro = 0,lido_estouro=0;
long lido;
long filtro;

long leitura[6];
int ler=0;

//////////////////////////interrupções do timer1 ///////////////////////////////////
#define liga_pino(x,y) x |= _BV(y)
#define desliga_pino(x,y) x &= ~(_BV(y))
#define alterna_pino(x,y) x ^= _BV(y)


ISR(TIMER1_OVF_vect )
  {                    //interrupção overflow
       estouro= estouro + 65535;
  }  
ISR(TIMER1_CAPT_vect)
{              //interrupção de captura de eventos externos.
          if(flag_inte< 2)
          {
          flag_inte++;
          TCNT1 = 0;//zera timer 
          TIFR1 = 0XF0; //limpa interrupcão pendente
          estouro = 0 ;
          lido = 0;
          filtro = 1;
          }
          else
          {
              lido = estouro + ICR1;
              if(lido >35000)// em testes de bancada vi que abaixo desse valor o avr fica impreciso
              {
              flag_inte++;
              if(ler < 6)
                   {//enquanto menor que 6 pega leitura
                             // em 1 segundo temos 15999693 ciclos ao inves de 16000000(segundo simulação do proteus)
                          //logo para calcular a frequencia basta:
                          lido = 15999693 / lido;
                          if(filtro > 1)
                          {
                           lido = lido * filtro ;  
                          }
                    leitura[ler] = lido;
                       flag_inte = 0;
                    ler++;
                  }
              }
              else
              {
               filtro++;
              }                             
          }           
          
}
///////////////////////////////////////////////funçoes usadas pela usart////////////////////////////////////////////////

void RS232_inicializa(unsigned int BAUD)
{
   unsigned int velocidade = F_CPU/16/BAUD-1;
   // veja que na simulação do proteus dá erros nas velocidade diferentes de 9600 mas na pratica funciona.
    UCSR0A = 0X20;
    UBRR0H = (unsigned char)(velocidade>>8);
    UBRR0L = (unsigned char)velocidade;
    UCSR0B = 0X18;//não vou habilitar nenhuma interrupção da porta serial
    /* 8 bits , 1 stop bit, assincrono , sem paridade,modo nornal */
    UCSR0C = (1<<USBS0)|(3<<UCSZ00);
}

void escreve_caracter(unsigned char carac)
{  
            _delay_loop_1(1);//tempo para estabilizar tensão            
            while ( !( UCSR0A & (1<<UDRE0)) ); //espera transmitir para enviar um novo
            UDR0 = carac;    
            while ( !( UCSR0A & (1<<UDRE0)) ); //espera transmitir desabilita a transmissão
            _delay_loop_1(1);//tempo para garantir o envio
}
void impri_serial(const char frase[20])
{
      unsigned int indice=0;
      unsigned int tamanho = strlen(frase);    
       while(indice<=tamanho)///veja que o programa pode travar se aqui não tiver as duas aspas
       {
            escreve_caracter(frase[indice]);
            indice++;
       }
}

void int_to_char(long quant)
{

       char convert_char5='0';
       char convert_char6='0';
       char convert_char7='0';
       char  convert_char8='0';
       char convert_char9='0';

      
       while(quant>=10000)
        {
           quant=quant-10000;
         convert_char5++;
         }

       while(quant>=1000)
        {
         quant=quant-1000;
         convert_char6++;
         }
       while(quant>=100)
        {
         quant=quant-100;
         convert_char7++;
         }
       while(quant>=10)
        {
         quant=quant-10;
        convert_char8++;
         }
       while(quant>=1)
        {
           quant=quant-1;
         convert_char9++;
         }
          escreve_caracter(convert_char5);
          escreve_caracter(convert_char6);
          escreve_caracter(convert_char7);
          escreve_caracter(convert_char8);
          escreve_caracter(convert_char9);

} 
  
/////////////////////////////////////////////////Funções usadas/////////////////////////////////////////////

void inicializa_modo_captura(void)
{
   TCCR1A = 0X00;//não tem uso para o modo captura de eventos externos
   TCCR1B = 0x01;//filtro desabilitado de ruido habilitado,captura na borda de descida do sinal, clock interno/1
   TCCR1C = 0X00;//não tem uso para o modo captura de eventos externos
   TIMSK1 = 0x21; //habilita interrupção de estouro de timer e de captura

}

//opcional vai depender da aplicação

long  filtro_de_ruido(int val)
{
 long valor;
//comparação de 3 valores pelo menos 2 leituras devem ser iguais 
                  if((leitura[val] == leitura[val+1])||(leitura[val] == leitura[val+2]))
                  {//ok
                      valor =  leitura[val]; 
                  }
                  else
                  {
                         if(leitura[val+1] == leitura[val+2])
                                  {//ok
                              
                                     valor =  leitura[val+1];                            
                                  }                      
                  }
                  return(valor);
}

//////////////////////////////////////////////função principal///////////////////////////////////////////
int main(void)
{
            DDRD = 0X1E;
            DDRB = 0x00;  //inicializa portb como  entrada
            PORTB = 0XFF;//desabilita pull-ups
            DDRC = 0xFF;  //inicializa portC como saida
            PORTC = 0;//limpa as portas logicas.
            inicializa_modo_captura();
            RS232_inicializa(9600);
            impri_serial("Inicializado...\n\r");
            sei(); // habilita interrupções
            desliga_pino(PORTC,0);
            desliga_pino(PORTC,1);
            ler = 0;
           for(;;)
            {
              if(ler >= 6 )
               {
                  cli();
                  long compara1,compara2;
                  compara1 = filtro_de_ruido(0);
                  compara2 = filtro_de_ruido(3);
                  //se de 6 amostras pelo menos 4 forem iguais
                      if((compara1 == compara2)&&(compara1 > 0))//filtra leitura errada
                      {
                          impri_serial("-> ");
                          int_to_char(compara1);//isso garante melhor performace
                          impri_serial("\n\r");
                      }
                  flag_inte = 0;
                  ler=0;
                  _delay_ms(100);                  
                  sei(); 
               }
          
            }//laço for
}//main

terça-feira, 5 de março de 2013

Timer 0 com 16F877A - Mplab XC8


*
 *                       usando timer no MPlab XC8
 *
 * Compilador : MPlabXC8
 * Microcontrolador: 16F877A
 * Autor: aguivone
 * Versão: 1
 * Data :  05 de março de 2013
 */
#include <stdio.h>
#include <string.h> //para usar funçoes de string deve se adicionar este header
#include <stdlib.h>
#define _XTAL_FREQ 4000000    // cristal de 4 Mhz
#include <xc.h>

/////////////////////////////////////////////////////////configuraçôes//////////////////////////////////////////////////

#pragma config FOSC = HS        // Oscillator Selection bits (HS oscillator)
#pragma config WDTE = OFF       // Watchdog Timer Enable bit (WDT disabled)
#pragma config PWRTE = OFF      // Power-up Timer Enable bit (PWRT disabled)
#pragma config BOREN = OFF      // Brown-out Reset Enable bit (BOR disabled)
#pragma config LVP = OFF        // Low-Voltage (Single-Supply) In-Circuit Serial Programming Enable bit (RB3 is digital I/O, HV on MCLR must be used for programming)
#pragma config CPD = OFF        // Data EEPROM Memory Code Protection bit (Data EEPROM code protection off)
#pragma config WRT = OFF        // Flash Program Memory Write Enable bits (Write protection off; all program memory may be written to by EECON control)
#pragma config CP = OFF         // Flash Program Memory Code Protection bit (Code protection off)



///////////////////////////////////////////////////interrupção//////////////////////////////////////////////////////////////
void interrupt interrupcao(void)//vetor de interrupção
 {
    if(T0IF)
    {//interrupção do timer0 - estoura quando atinge 255(0XFF)
        PORTB = ~PORTB;//alterna port B
        TMR0 = 61;//reinicia timer com o valor calculado
        T0IF = 0;
    }
 }

void inicializa_timer0()
{
    OPTION_REG = 0X07;//timer0 com prescaler dividido por 256
    T0IE = 1;//habilita interrupção do timer0
  /*
 para calcular faça F = (Fosc/4)/prescaler
 * logo F = (4.000.000/4)/256
 * então:F = 3906,25 hz  (aproximadamente) o que dá 256 us cada incremento
 * vamos fazer o portB inverter o estado logico a cada 50ms
 * então temos que :
 * numero de incrementos = 0,050/0,000256 = 195(aproximadamente)
 * para gerar uma interrupção a cada 50ms será preciso = 256(numero maximo de incrementos) - 195 = 61.
 */
    TMR0 = 61;//zera registrador de contagem
}
//////////////////////////////////////////////////////Rotina principal///////////////////////////////////////////////////////////////

void main(void)
{
    TRISB = 0;   //configura como saida
    PORTB = 0;  // limpar as portas que estão configuradas como saidas
     inicializa_timer0();
    PEIE = 1;//habilita interrupção de perifericos do pic
    GIE = 1; //GIE: Global Interrupt Enable bit
    for(;;)
    {
      //faz nada
    }//loop infinito

}
Faça uma visita na página do face, basta procurar por microcontroladores-C,e dê um "curtir" assim vc fica por dentro das novidades do blog!  

Acessando a eeprom - Mplab XC8

 
Neste exemplo é demonstardo como escrever e ler na eeprom do pic16F877A,depois de lido os dados e então enviado a porta serial do pic: 
        

O código fonte:
 
 
/*
 *                                              voltimetro usando RS-232 no MPlab XC8
 *
 * Compilador : MPlabXC8
 * Microcontrolador: 16F877A
 * Autor: aguivone
 * Versão: 1
 * Data :  04 de março de 2013
 */
#include <stdio.h>
#include <string.h> //para usar funçoes de string deve se adicionar este header
#include <stdlib.h>
#define _XTAL_FREQ 20000000    // cristal de 20 Mhz
#include <xc.h>

/////////////////////////////////////////////////////////configuraçôes//////////////////////////////////////////////////

#pragma config FOSC = HS        // Oscillator Selection bits (HS oscillator)
#pragma config WDTE = OFF       // Watchdog Timer Enable bit (WDT disabled)
#pragma config PWRTE = OFF      // Power-up Timer Enable bit (PWRT disabled)
#pragma config BOREN = OFF      // Brown-out Reset Enable bit (BOR disabled)
#pragma config LVP = OFF        // Low-Voltage (Single-Supply) In-Circuit Serial Programming Enable bit (RB3 is digital I/O, HV on MCLR must be used for programming)
#pragma config CPD = OFF        // Data EEPROM Memory Code Protection bit (Data EEPROM code protection off)
#pragma config WRT = OFF        // Flash Program Memory Write Enable bits (Write protection off; all program memory may be written to by EECON control)
#pragma config CP = OFF         // Flash Program Memory Code Protection bit (Code protection off)


////////////////////////////////////////////////variaveis globais///////////////////////////////////////////////////////////
char caracter,dados;
bit flag_interrupcao = 0;
///////////////////////////////////////////////////interrupção//////////////////////////////////////////////////////////////
void interrupt interrupcoes(void)//vetor de interrupção
 {
    if(RCIF)
    {//se interrupção de recepção da serial
        //aqui não será usado essa funcão
     caracter = RCREG;
     flag_interrupcao = 1;
     RCIF = 0;//  limpa flag de interrupção de recepção
    }
 }

/////////////////////////////////funçoes usadas pela uart //////////////////////////////////////////////////////
void inicializa_RS232(long velocidade,int modo)
{////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.
    RCSTA = 0X90;//habilita porta serial,recepção de 8 bit em modo continuo,assincrono.
    int valor;
        if(modo == 1)
        {//modo = 1 ,modo alta velocidade
         TXSTA = 0X24;//modo assincrono,trasmissao 8 bits.
         valor =(int)(((_XTAL_FREQ/velocidade)-16)/16);//calculo do valor do gerador de baud rate
        }
        else
        {//modo = 0 ,modo baixa velocidade
         TXSTA = 0X20;//modo assincrono,trasmissao 8 bits.
         valor =(int)(((_XTAL_FREQ/velocidade)-64)/64);//calculo do valor do gerador de baud rate
        }
    SPBRG = valor;
    RCIE = 1;//habilita interrupção de recepção
    TXIE = 0;//deixa interrupção de transmissão desligado(pois corre se o risco de ter uma interrupção escrita e leitura ao mesmo tempo)
}
void escreve_RS232(char valor)
{
    TXIF = 0;//limpa flag que sinaliza envio completo.
    TXREG = valor;
    while(TXIF ==0);//espera enviar caracter
}
void imprime_RS232(const char frase[])
{
     char indice = 0;
     char tamanho = strlen(frase);
      while(indice < tamanho ) ///veja que o programa pode travar se aqui não tiver as duas aspas
       {
           escreve_RS232(frase[indice]);
           indice++;
       }
}

char ler_memoria(char ende)
{
    RP0 = 1; RP1 = 0;//acessa banco de memoria 2,para acessar o registrador EEADR
    EEADR = ende;//endereço 1 , verifique qual o endereço maximo de seu microcontrolador
    RP0 = 1; RP1 = 1;//acessa banco de memoria 3,para acessar o registrador EECON1
    EEPGD = 0;//ponteiro da memoria de dados
    RD = 1;//inicia leitura
    RP0 = 1; RP1 = 0;//retorna ao banco para ler os dados
   return(EEDATA);
}
void escreve_memoria(char endereco,char dados)
{
     char interrupcao;
     if(GIE == 1)//pega o estado da interrupção
     { interrupcao = 1; }
     RP0 = 1; RP1 = 1;//acessa banco de memoria 3,para acessar o registrador EECON1
     while(WR == 1);//checa se está havendo escrita ,espera terminar algum processo de escrita se existir
     RP0 = 1; RP1 = 0;//acessa banco de memoria 2,para acessar o registrador EEADR
     EEDATA = dados; //escreve dados(é um bug do compilador mas os dados devem ser escritos antes do endereço)
     EEADR = endereco;//endereço 1 , verifique qual o endereço maximo de seu microcontrolador
     RP0 = 1; RP1 = 1;//acessa banco de memoria 3,para acessar o registrador EECON1
     EEPGD = 0;
     WREN = 1;//habilita escrita
     GIE = 0;//desabilita as interrupções
     EECON2 = 0X55;//ação requerida conforme datasheet
     EECON2 = 0XAA;//é um codigo de segurança
     WR = 1;//inicia escrita na memoria
     if(interrupcao == 1)
     { GIE = 1;}
     WREN = 0;//disabilita escrita
}
//////////////////////////////////////////////////////Rotina principal///////////////////////////////////////////////////////////////

void main(void)
{
    TRISB = 0X02;//configura portB  B1 (pino RX) como entrada
    PORTB = 0;  // limpar as portas que estão configuradas como saidas
    inicializa_RS232(9600,1);//modo de alta velocidade
    PEIE = 1;//habilita interrupção de perifericos do pic
    GIE = 1; //GIE: Global Interrupt Enable bit
    imprime_RS232("acessando a eeprom \n\r");
    escreve_memoria(0X01,'T');//escreve dados
    escreve_memoria(0X02,'E');
    escreve_memoria(0X03,'S');
    escreve_memoria(0X04,'T');
    escreve_memoria(0X05,'E');
     imprime_RS232("Dados da memoria : \n\r");
     escreve_RS232(ler_memoria(0X01)) ;//ler os dados do endereço
     escreve_RS232( ler_memoria(0X02)) ;//da eeprom
     escreve_RS232( ler_memoria(0X03)) ;
     escreve_RS232( ler_memoria(0X04)) ;
     escreve_RS232(ler_memoria(0X05)) ;
    for(;;)
    {
   
    }//loop infinito

}
 

Usando o conversor A/D - MPlab XC8

Neste exemplo é demonstrado como ler o conversor alógico/digital e mostrar o valor lido do registrador, este valor é variado pelo potênciometro :


O código fonte:

/*
 *                                              voltimetro usando RS-232 no MPlab XC8
 *
 * Compilador : MPlabXC8
 * Microcontrolador: 16F877A
 * Autor: aguivone
 * Versão: 1
 * Data :  04 de março de 2013
 */
#include <stdio.h>
#include <stdlib.h>
#define _XTAL_FREQ 20000000    // cristal de 20 Mhz
#include <xc.h>

#define delay_us(x) _delay((unsigned long)((x)*(_XTAL_FREQ/4000000.0)))
#define delay_ms(x) _delay((unsigned long)((x)*(_XTAL_FREQ/4000.0)))

/////////////////////////////////////////////////////////configuraçôes//////////////////////////////////////////////////

#pragma config FOSC = HS        // Oscillator Selection bits (HS oscillator)
#pragma config WDTE = OFF       // Watchdog Timer Enable bit (WDT disabled)
#pragma config PWRTE = OFF      // Power-up Timer Enable bit (PWRT disabled)
#pragma config BOREN = OFF      // Brown-out Reset Enable bit (BOR disabled)
#pragma config LVP = OFF        // Low-Voltage (Single-Supply) In-Circuit Serial Programming Enable bit (RB3 is digital I/O, HV on MCLR must be used for programming)
#pragma config CPD = OFF        // Data EEPROM Memory Code Protection bit (Data EEPROM code protection off)
#pragma config WRT = OFF        // Flash Program Memory Write Enable bits (Write protection off; all program memory may be written to by EECON control)
#pragma config CP = OFF         // Flash Program Memory Code Protection bit (Code protection off)



////////////////////////////////////////////////variaveis globais///////////////////////////////////////////////////////////
char caracter;
bit flag_interrupcao = 0;
///////////////////////////////////////////////////interrupção//////////////////////////////////////////////////////////////
void interrupt interrupcoes(void)//vetor de interrupção
 {
    if(RCIF)
    {//se interrupção de recepção da serial
        //aqui não será usado essa funcão
     caracter = RCREG;
     flag_interrupcao = 1;
     RCIF = 0;//  limpa flag de interrupção de recepção
    }
    if(ADIF)
    {//se interrupção do modulo analogico!
        ADIF = 0;//limpa flag
    }
 }

/////////////////////////////////funçoes usadas pela uart //////////////////////////////////////////////////////
void inicializa_RS232(long velocidade,int modo)
{////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.
    RCSTA = 0X90;//habilita porta serial,recepção de 8 bit em modo continuo,assincrono.
    int valor;
        if(modo == 1)
        {//modo = 1 ,modo alta velocidade
         TXSTA = 0X24;//modo assincrono,trasmissao 8 bits.
         valor =(int)(((_XTAL_FREQ/velocidade)-16)/16);//calculo do valor do gerador de baud rate
        }
        else
        {//modo = 0 ,modo baixa velocidade
         TXSTA = 0X20;//modo assincrono,trasmissao 8 bits.
         valor =(int)(((_XTAL_FREQ/velocidade)-64)/64);//calculo do valor do gerador de baud rate
        }
    SPBRG = valor;
    RCIE = 1;//habilita interrupção de recepção
    TXIE = 0;//deixa interrupção de transmissão desligado(pois corre se o risco de ter uma interrupção escrita e leitura ao mesmo tempo)
}
void escreve(char valor)
{
    TXIF = 0;//limpa flag que sinaliza envio completo.
    TXREG = valor;
    while(TXIF ==0);//espera enviar caracter
}
void imprime(const char frase[])
{
     char indice = 0;
     char tamanho = strlen(frase);
      while(indice < tamanho ) ///veja que o programa pode travar se aqui não tiver as duas aspas
       {
           escreve(frase[indice]);
           indice++;
       }
}
void int_to_char(int quant)
{

       char convert_char5='0';
       char convert_char6='0';
       char convert_char7='0';
       char  convert_char8='0';
       char convert_char9='0';


       while(quant>=10000)
        {
           quant=quant-10000;
         convert_char5++;
         }

       while(quant>=1000)
        {
         quant=quant-1000;
         convert_char6++;
         }
       while(quant>=100)
        {
         quant=quant-100;
         convert_char7++;
         }
       while(quant>=10)
        {
         quant=quant-10;
        convert_char8++;
         }
       while(quant>=1)
        {
           quant=quant-1;
         convert_char9++;
         }
                    escreve('\n');
                    escreve('\r');
          escreve(convert_char5);
          escreve(convert_char6);
          escreve(convert_char7);
          escreve(convert_char8);
          escreve(convert_char9);

}

///////////////////////////////////////funçoes usadas pelo conversor AD//////////////////////////////////////////
void inicializa_AD()
{
    ADCON0 = 0X10;//Tosc = 32 (20MHZ , veja datasheet) ;habilita modulo de conversão
    ADCON1 = 0X8E;//leitura do valor justificado a direita,apenas RA0 será de entrada de tensão()AN0.
    ADIE = 1;//não habilita interrupção de conversão analogica
}
int leitura()
{
          long valor;
          ADCON0 = 5;//solicita leitura
          while(ADCON0 == 5);//espera terminar leitura
          return((ADRESH<<8)+ ADRESL);
}
//////////////////////////////////////////////////////Rotina principal///////////////////////////////////////////////////////////////

void main(void)
{
    TRISC = 0X80;//configura portC  C7 (pino RX) como entrada
    PORTC = 0;  // limpar as portas que estão configuradas como saidas
    TRISA = 0XFF;//configura portA como entrada
    inicializa_RS232(9600,1);//modo de alta velocidade
    inicializa_AD();
    PEIE = 1;//habilita interrupção de perifericos do pic
    GIE = 1; //GIE: Global Interrupt Enable bit
    imprime("Voltimetro usando a serial! \n\r");
    for(;;)
    {
        int_to_char(leitura());
        delay_ms(1000);//espera 1 segundo
    }//loop infinito

}

segunda-feira, 4 de março de 2013

usando os comparadores internos do pic

Neste exemplo vou demontrar como configurar os comparadores internos para reconhecer 2 valores de tensão, veja que em uma das saidas(RB4) é preciso colocar um resitor de pull-up:



O código fonte:

/*
 *                               usando o modo comparador de tensão no MPlab XC8
 *
 * Compilador : MPlabXC8
 * Microcontrolador: 16F628A
 * Autor: aguivone
 * Versão: 1
 * Data :  01 de março de 2013
 * compara 2 valores de tensão.
 *
 */
#include <stdio.h>
#include <stdlib.h>
#define _XTAL_FREQ 20000000    // cristal de 20 Mhz
#include <xc.h>

#define delay_us(x) _delay((unsigned long)((x)*(_XTAL_FREQ/4000000.0)))
#define delay_ms(x) _delay((unsigned long)((x)*(_XTAL_FREQ/4000.0)))


/////////////////////////////////////////////////////////configuraçôes//////////////////////////////////////////////////


#define led RB0

#pragma config FOSC = HS        // Oscillator Selection bits (HS oscillator: High-speed crystal/resonator on RA6/OSC2/CLKOUT and RA7/OSC1/CLKIN)
#pragma config WDTE = OFF       // Watchdog Timer Enable bit (WDT disabled)
#pragma config PWRTE = ON       // Power-up Timer Enable bit (PWRT enabled)
#pragma config MCLRE = OFF      // RA5/MCLR/VPP Pin Function Select bit (RA5/MCLR/VPP pin function is digital input, MCLR internally tied to VDD)
#pragma config BOREN = OFF      // Brown-out Detect Enable bit (BOD disabled)
#pragma config LVP = OFF        // Low-Voltage Programming Enable bit (RB4/PGM pin has digital I/O function, HV on MCLR must be used for programming)
#pragma config CPD = OFF        // Data EE Memory Code Protection bit (Data memory code protection off)
#pragma config CP = OFF         // Flash Program Memory Code Protection bit (Code protection off)

//////////////////////////////////////////////funçoes auxiliares////////////////////////////////////////////////////////

void inicializa_comparador(int modo)
{
    /*
     * 0  ligado mas com saidas desligadas
     * 1  3 entradas,sendo uma selecionavel o pino(entrada não inversora comum )
     * 2  2 entradas,sendo duas entradas ligadas a referencia de tensão interna(entrada não inversora comum)
     * 3  3 entradas(entrada não inversora comum )
     * 4  2 comparadores independentes
     * 5  habilita apenas 1 comparador (C2)
     * 6  3 entradas(entrada não inversora comum ) e saidas independentes
     * 7  os dois comparadores desligados
     */
    CMCON  = modo;//saidas não invertidas
    VRCON = 0;//por garantia desliga-se o modulo de referencia de tensão
}

//////////////////////////////////////////////////////Rotina principal///////////////////////////////////////////////////////////////

void main(void) {
    TRISA = 0X07;
    PORTA = 0;  // limpar as portas que estão configuradas como saidas
    TRISB = 0X00;
    PORTB = 0;  // limpar as portas que estão configuradas como saidas
    inicializa_comparador(6);//lembre se que deve ser colocado um resistor de pull up no pino ra4,pois ele é dreno aberto 
    led = 0;//desliga led
    for(;;)
    {
                                led = 1;
                                delay_ms(100);
                                led = 0;
                                delay_ms(100);

    }//loop infinito

}

RS232 com o mplab XC8


Aqui é demonstrado como  implementar a comunicação serial com o Mplab xc8 no pic 16F628A, neste exemplo todo caracter que for digitado é mostrado no simulador de serial do proteus:


O código fonte:

/*
 *                                               usando RS-232 no MPlab XC8
 *
 * Compilador : MPlabXC8
 * Microcontrolador: 16F628A
 * Autor: aguivone
 * Versão: 1
 * Data :  04 de março de 2013
 */
#include <stdio.h>
#include <string.h> //para usar funçoes de string deve se adicionar este header
#include <stdlib.h>
#define _XTAL_FREQ 20000000    // cristal de 20 Mhz
#include <xc.h>

/////////////////////////////////////////////////////////configuraçôes//////////////////////////////////////////////////

#pragma config FOSC = HS        // Oscillator Selection bits (HS oscillator: High-speed crystal/resonator on RA6/OSC2/CLKOUT and RA7/OSC1/CLKIN)
#pragma config WDTE = OFF       // Watchdog Timer Enable bit (WDT disabled)
#pragma config PWRTE = ON       // Power-up Timer Enable bit (PWRT enabled)
#pragma config MCLRE = OFF      // RA5/MCLR/VPP Pin Function Select bit (RA5/MCLR/VPP pin function is digital input, MCLR internally tied to VDD)
#pragma config BOREN = OFF      // Brown-out Detect Enable bit (BOD disabled)
#pragma config LVP = OFF        // Low-Voltage Programming Enable bit (RB4/PGM pin has digital I/O function, HV on MCLR must be used for programming)
#pragma config CPD = OFF        // Data EE Memory Code Protection bit (Data memory code protection off)
#pragma config CP = OFF         // Flash Program Memory Code Protection bit (Code protection off)

////////////////////////////////////////////////variaveis globais///////////////////////////////////////////////////////////
char caracter;
bit flag_interrupcao = 0;
///////////////////////////////////////////////////interrupção//////////////////////////////////////////////////////////////
void interrupt RS232(void)//vetor de interrupção
 {
     caracter = RCREG;
     flag_interrupcao = 1;
     RCIF = 0;//  limpa flag de interrupção de recepção
 }

/////////////////////////////////funçoes usadas pela uart //////////////////////////////////////////////////////
void inicializa_RS232(long velocidade,int modo)
{////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.
    RCSTA = 0X90;//habilita porta serial,recepção de 8 bit em modo continuo,assincrono.
    int valor;
        if(modo == 1)
        {//modo = 1 ,modo alta velocidade
         TXSTA = 0X24;//modo assincrono,trasmissao 8 bits.
         valor =(int)(((_XTAL_FREQ/velocidade)-16)/16);//calculo do valor do gerador de baud rate
        }
        else
        {//modo = 0 ,modo baixa velocidade
         TXSTA = 0X20;//modo assincrono,trasmissao 8 bits.
         valor =(int)(((_XTAL_FREQ/velocidade)-64)/64);//calculo do valor do gerador de baud rate
        }
    SPBRG = valor;
    RCIE = 1;//habilita interrupção de recepção
    TXIE = 0;//deixa interrupção de transmissão desligado(pois corre se o risco de ter uma interrupção escrita e leitura ao mesmo tempo)
}
void escreve(char valor)
{
    TXIF = 0;//limpa flag que sinaliza envio completo.
    TXREG = valor;
    while(TXIF ==0);//espera enviar caracter
}
void imprime(const char frase[])
{
     char indice = 0;
     char tamanho = strlen(frase);
      while(indice < tamanho ) ///veja que o programa pode travar se aqui não tiver as duas aspas
       {
           escreve(frase[indice]);
           indice++;
       }
}
//////////////////////////////////////////////////////Rotina principal///////////////////////////////////////////////////////////////

void main(void)
{
    TRISB = 0X02;//configura portB  B1 (pino RX) como entrada
    PORTB = 0;  // limpar as portas que estão configuradas como saidas
    inicializa_RS232(9600,1);//modo de alta velocidade
    PEIE = 1;//habilita interrupção de perifericos do pic
    GIE = 1; //GIE: Global Interrupt Enable bit
    imprime("Usando a serial MPlab xc8 \n\r");
    imprime("digite algo? \n\r");
    for(;;)
    {
        if(flag_interrupcao ==  1)
        {//tem dados para ler
         imprime(" \n\r caracter digitado :");
         escreve(caracter);
         flag_interrupcao = 0;
        }

    }//loop infinito

}
Faça uma visita na página do face, basta procurar por microcontroladores-C,e dê um "curtir" assim vc fica por dentro das novidades do blog!  

sexta-feira, 1 de março de 2013

capturando eventos externos usando pic - Mplab XC8

     Um exemplo simples  pra demonstrar como usar a interrupção de ccp (muito útil pra calcular frequências), aqui basicamente quando se pressiona o botão o led acende ou apaga,basta pausa a simulação é verá que a variável ler já tem o valor do CCP.


O código fonte:

/*
 *                                usando o modo CCP no MPlab XC8
 *
 * Compilador : MPlabXC8
 * Microcontrolador: 16F628A
 * Autor: aguivone
 * Versão: 1
 * Data :  01 de março de 2013
 */
#include <stdio.h>
#include <stdlib.h>
#define _XTAL_FREQ 20000000    // cristal de 20 Mhz
#include <xc.h>
 
#define delay_us(x) _delay((unsigned long)((x)*(_XTAL_FREQ/4000000.0))) 
#define delay_ms(x) _delay((unsigned long)((x)*(_XTAL_FREQ/4000.0)))


/////////////////////////////////////////////////////////configuraçôes//////////////////////////////////////////////////



#define power_led RB0
#define led RB4

#pragma config FOSC = HS        // Oscillator Selection bits (HS oscillator: High-speed crystal/resonator on RA6/OSC2/CLKOUT and RA7/OSC1/CLKIN)
#pragma config WDTE = OFF       // Watchdog Timer Enable bit (WDT disabled)
#pragma config PWRTE = ON       // Power-up Timer Enable bit (PWRT enabled)
#pragma config MCLRE = OFF      // RA5/MCLR/VPP Pin Function Select bit (RA5/MCLR/VPP pin function is digital input, MCLR internally tied to VDD)
#pragma config BOREN = OFF      // Brown-out Detect Enable bit (BOD disabled)
#pragma config LVP = OFF        // Low-Voltage Programming Enable bit (RB4/PGM pin has digital I/O function, HV on MCLR must be used for programming)
#pragma config CPD = OFF        // Data EE Memory Code Protection bit (Data memory code protection off)
#pragma config CP = OFF         // Flash Program Memory Code Protection bit (Code protection off)

////////////////////////////////////////////////variaveis globais///////////////////////////////////////////////////////////
long ler = 0;
int  interru=0;
///////////////////////////////////////////////////interrupção//////////////////////////////////////////////////////////////
void interrupt CCP1(void)
{
                              led = ~led;
                             ler = CCPR1;//apesar de não ser usado aqui deixei esta variavel para demonstrar
                             CCP1IF = 0;//limpa flag de interrupção               
 }
//////////////////////////////////////////////////////Rotina principal///////////////////////////////////////////////////////////////

void main(void) {
    TRISB = 0X08;//configura portB  B3 (ccp1) como entrada
    PORTB = 0;  // limpar as portas que estão configuradas como saidas
    CCP1CON  = 0X05;//habilita captura de pulso na borda de subida (prescaler sem divisão)
    CCP1IE = 1;//habilita modo de captura de pulsos*/
    PEIE = 1;
    GIE = 1; //GIE: Global Interrupt Enable bit
    led = 0;//desliga led
    for(;;)
    {
                                power_led = 1;
                                delay_ms(1);
                                power_led = 0;
                                delay_ms(1);
                             
                                
    }//loop infinito

}

Frequêncimetro com atmega328 - usando ICP1

Veja na simulção como funcionou bem na faixa que vai de 1 hz a 10 Khz(acima deste valor até lê mas fica impreciso) , para conseguir ler sinal de frequencia mais alta é preciso usar um divisor de frequência ou implementar funçoes para isto.O compilador usado é o avr studio.



O Código fonte :

//************************************************************************
//            usando o modo captura de pulsos para ler frequencia(range 1 a 10KHZ)
//  Version    : 1.2
//  microcontrolador : AVR ATMega328
//  Autor        : Aguivone
//  descrição  : captura de eventos externos  
//  data : 01/03/2013.
//
//************************************************************************
#define F_CPU 16000000UL  //  deve vir antes das interrupçoes
#include <avr/io.h>
#include <avr/interrupt.h>
#include <string.h>
#include <util/delay.h>
#include <string.h>

/////////////////////////declaração da variaveis ///////////////////////////////////
int flag_inte=0;
long estouro = 0,lido_estouro=0;
long lido;

//////////////////////////interrupções do timer1 ///////////////////////////////////
#define liga_pino(x,y) x |= _BV(y)
#define desliga_pino(x,y) x &= ~(_BV(y))
#define alterna_pino(x,y) x ^= _BV(y)


ISR(TIMER1_OVF_vect )
  {                    //interrupção overflow
       estouro= estouro + 65535;
  }  
ISR(TIMER1_CAPT_vect)
{              //interrupção de captura de eventos externos.
          if(flag_inte < 2)
          {
          flag_inte++;
          TCNT1 = 0;//zera timer 
          TIFR1 = 0XF0; //limpa interrupcão pendente
          estouro = 0 ;
          lido = 0;
          }
          else
          {
              lido = estouro + ICR1;
              flag_inte++;                             
          }           
          
}
///////////////////////////////////////////////funçoes usadas pela usart////////////////////////////////////////////////

void RS232_inicializa(unsigned int BAUD)
{
   unsigned int velocidade = F_CPU/16/BAUD-1;
   // veja que na simulação do proteus dá erros nas velocidade diferentes de 9600 mas na pratica funciona.
    UCSR0A = 0X20;
    UBRR0H = (unsigned char)(velocidade>>8);
    UBRR0L = (unsigned char)velocidade;
    UCSR0B = 0X18;//não vou habilitar nenhuma interrupção da porta serial
    /* 8 bits , 1 stop bit, assincrono , sem paridade,modo nornal */
    UCSR0C = (1<<USBS0)|(3<<UCSZ00);
}

void escreve_caracter(unsigned char carac)
{  
            _delay_loop_1(1);//tempo para estabilizar tensão            
            while ( !( UCSR0A & (1<<UDRE0)) ); //espera transmitir para enviar um novo
            UDR0 = carac;    
            while ( !( UCSR0A & (1<<UDRE0)) ); //espera transmitir desabilita a transmissão
            _delay_loop_1(1);//tempo para garantir o envio
}
void impri_serial(const char frase[20])
{
      unsigned int indice=0;
      unsigned int tamanho = strlen(frase);    
       while(indice<=tamanho)///veja que o programa pode travar se aqui não tiver as duas aspas
       {
            escreve_caracter(frase[indice]);
            indice++;
       }
}

void int_to_char(long quant)
{

       char convert_char5='0';
       char convert_char6='0';
       char convert_char7='0';
       char  convert_char8='0';
       char convert_char9='0';

      
       while(quant>=10000)
        {
           quant=quant-10000;
         convert_char5++;
         }

       while(quant>=1000)
        {
         quant=quant-1000;
         convert_char6++;
         }
       while(quant>=100)
        {
         quant=quant-100;
         convert_char7++;
         }
       while(quant>=10)
        {
         quant=quant-10;
        convert_char8++;
         }
       while(quant>=1)
        {
           quant=quant-1;
         convert_char9++;
         }
          escreve_caracter(convert_char5);
          escreve_caracter(convert_char6);
          escreve_caracter(convert_char7);
          escreve_caracter(convert_char8);
          escreve_caracter(convert_char9);

} 

  
/////////////////////////////////////////////////Funções usadas/////////////////////////////////////////////

void inicializa_modo_captura(void)
{
   TCCR1A = 0X00;//não tem uso para o modo captura de eventos externos
   TCCR1B = 0x01;//filtro desabilitado de ruido habilitado,captura na borda de descida do sinal, clock interno/1
   TCCR1C = 0X00;//não tem uso para o modo captura de eventos externos
   TIMSK1 = 0x21; //habilita interrupção de estouro de timer e de captura

}

//opcional vai depender da aplicação



//////////////////////////////////////////////função principal///////////////////////////////////////////
int main(void)
{
            DDRD = 0X1E;
            DDRB = 0x00;  //inicializa portb como  entrada
            PORTB = 0XFF;//desabilita pull-ups
            DDRC = 0xFF;  //inicializa portC como saida
            PORTC = 0;//limpa as portas logicas.
            inicializa_modo_captura();
            RS232_inicializa(9600);
            impri_serial("Inicializado...\n\r");
            sei(); // habilita interrupções
            desliga_pino(PORTC,0);
            desliga_pino(PORTC,1);
           for(;;)
            {
              if(flag_inte == 3)
               {
                  cli();
                  impri_serial("-> ");
                 // em 1 segundo temos 15999693 ciclos ao inves de 16000000(segundo simulação do proteus)
                  //logo para calcular a frequencia basta:
                  lido = 15999693 / lido;
                  int_to_char(lido);//isso garante melhor performace
                  impri_serial("\n\r");
                  flag_inte = 0;
                  _delay_ms(1000);                  
                  sei(); 
               }
          
            }//laço for
}//main