sexta-feira, 27 de março de 2015

Controle remoto com PIC - Parte2

         Conforme demonstrado anterior o projeto é dividido em codificador e decodificador, agora vou mostrar como é o código do receptor de controle remoto.

O código fonte:

/*
 *                                               usando o modo CCP no MPlab XC8
 *
 * Compilador : MPlabXC8
 * Microcontrolador: 16F648A
 * Autor: aguivone
 * Versão: 1
 * Data :  01 de março de 2013
 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h> //para usar funçoes de string deve se adicionar este header
#define _XTAL_FREQ 4000000    // oscilador interno de 4 Mhz
#include <xc.h>
/////////////////////////////////////////////////////////configuraçôes//////////////////////////////////////////////////
#define LED_STATUS RB0
#define SINAL PORTAbits.RA0

#pragma config FOSC = INTOSCIO  // Oscillator Selection bits (INTOSC oscillator: I/O function on RA6/OSC2/CLKOUT pin, I/O function on RA7/OSC1/CLKIN)
#pragma config WDTE = OFF       // Watchdog Timer Enable bit (WDT disabled)
#pragma config PWRTE = OFF      // Power-up Timer Enable bit (PWRT disabled)
#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 = ON       // Brown-out Detect Enable bit (BOD enabled)
#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  anterior = 0, atual = 0,largura_pulso = 0;
int   primeiro_pacote = 0,valor_pulso=0;
long  timeout = 0;
long  bit_0=0,bit_1=0,start_stop=0,range_bit=150;

///////////////////////////////////////////////////interrupção//////////////////////////////////////////////////////////////
void interrupt CCP1(void)
{
 if(CCP1IF) //verifica se é interrupção de cpp
    {// cada incremtento do timer será a cada 1us ,pois estou usando o oscilador interno de 4mhz
        atual = CCPR1;
        CCP1IF = 0; //limpa interrupção de captura de sinal
                if (anterior > atual)
                {
                    largura_pulso = (0XFFFF - anterior) + atual;
                }
                else
                {
                    largura_pulso = atual - anterior;
                }
       anterior = atual;
   }
 }
/////////////////////////////////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 = 0;//não vou receber nenhum dado do pc
    //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 inicializa_CCP() {
    //habilita captura de pulso na borda de subida (prescaler sem divisão)
    CCP1CON = 0X05;//modo de captura sem divisão (borda de subida)
    CCP1IF = 0; //limpa flag de interrupção de captura
    CCP1IE = 1;//habilita modo de captura de pulsos*/
}

void inicializa_timer1() {
    TMR1IF = 0; //limpa flag de interrupção de timer
   // TMR1IE = 1; //habilita interrupção de estouro do timer
    TMR1IE = 0; //desabilita interrupção de estouro do timer
    T1CON = 0x81; //habilita leitura do timer 1 e o timer 1,sem prescaler
}


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

void main(void) {
    TRISA = 0XFF;//como entrada
    TRISB = 0X08;//configura portB  B3 (ccp1) como entrada
    PORTB = 0;  // limpar as portas que estão configuradas como saidas
    inicializa_CCP();
    inicializa_timer1();
    inicializa_RS232(9600,1);//modo de alta velocidade
    imprime("controle remoto");
    PEIE = 1;//habilita interrupção de perifericos do pic
    GIE = 1; //GIE: Global Interrupt Enable bit
    for(;;)
    {
          if(largura_pulso > 0)//leu pulsos
                     {
                      valor_pulso = largura_pulso;
                      if(primeiro_pacote == 0)
                          {
                           primeiro_pacote = 1;//descarta pois virá com lixo
                          }
                      else
                      {
                      if(primeiro_pacote == 1)
                        {//tenta localizar o protocolo
                          primeiro_pacote = 2;
                             escreve('\n');//pula para proxima linha
                             escreve('\r');//coloca no inicio da linha
                           if((valor_pulso > 2900)&&(valor_pulso < 3200))
                            {
                               escreve('N');
                               bit_0 = 1200;
                               bit_1 = 1800;
                               start_stop=3000;
                            }
                           if(valor_pulso < 2900)
                            {
                               escreve('P');
                               bit_0 = 1800;
                               bit_1 = 2700;
                               start_stop=0;
                               if(valor_pulso > (bit_0 + range_bit))
                              {//bit 1
                                escreve('1');
                              }
                              else
                              {//bit0
                                 escreve('0');
                              }
                            }
                            if((valor_pulso > 8000)&&(valor_pulso < 10000))
                            {
                               escreve('S');
                               bit_0 = 1100;
                               bit_1 = 2250;
                               start_stop=9000;
                            }
                            if(valor_pulso > 10000)
                            {
                               escreve('L');
                               bit_0 = 1100;
                               bit_1 = 2250;
                               start_stop=13500;
                            }

                        }
                      else
                      {
                         if((valor_pulso > (start_stop - range_bit))&&(valor_pulso < (start_stop + range_bit)))
                              {//start bit
                                escreve('S');//pra indicar que recebeu um bit de inicio ou fim de pacote
                              }
                      if(valor_pulso < (bit_1 + range_bit))
                      {
                          if(valor_pulso > (bit_0 + range_bit))
                              {//bit 1
                                escreve('1');
                              }
                              else
                              {//bit0
                                 escreve('0');
                              }

                      }
                      }
                      }
                    largura_pulso=0;
                        timeout = 3000;//prepara contagem
                     }//fim do leu pulsos
     if(timeout>0)
     {
     timeout--;
     }
     if(timeout==1)
     {// tempo usado para resetar ou descartar pacotes com defeito
      primeiro_pacote = 0;
     }
    }//loop infinito

}
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Depois de montado os códigos vamos a simulação,na simulação o primeiro pacote dá um erro, mas logo em seguida tudo funciona normalmente.Veja a imagem da simulação e do esquemático no proteus :


O esquemático:
    
     Testando com um controle remoto e com o prototipo montado numa proto-o-board recebi os seguintes códigos do controle:

Padrão samsung, 33bits + start_stop_bit:
 
Power = 111000001110000001000000101111110
vol+  = 111000001110000011100000000111110
vol-  = 111000001110000011010000001011110
ch+   = 111000001110000001001000101101110
ch-   = 111000001110000000001000111101110

Padrão LG, 32bits + start_stop_bit:

Power = 01000001101111100010000111011110
vol+  = 01000001101111101000000101111110
vol-  = 01000001101111111000000001111110
ch+   = 01000001101111100000000111111110
ch-   = 01000001101111110000000011111110

padrão sony, repete 3 vezes um codigo de 11 bits + start_bit
com intervalos de 27ms 
         
Power = 10101001000
vol+  = 01001001000
vol-  = 11001001000
ch+   = 00001001000
ch-   = 10001001000

padrão philips envia 10 bits sem pulsos de inicio e fim

Power = 0100000101
vol+  = 0100001100
vol-  = 0000001101
ch+   = 0000011000
ch-   = 0100011001

Para pegar os dados eu montei na proto-o-board o esquema elétrico seguinte:



Em breve vou postar um artigo usado este projeto como base para acionar leds com diferentes controles, até a próxima!

Controle remoto com PIC - Parte 1

             Olá, hoje vou demonstrar como montar um controle remoto com o PIC e também como montar um receptor de controle remoto, a ideia inicial era montar apenas o decodificador(receptor do controle remoto) mas para isso eu precisava simular um controle remoto a medida que montava todo o firmware então acabei montando também o simulador de controle remoto(codificador), mas eu também queria que meu circuito reconhecesse pelo menos uns 4 tipos de marcas para que vocês pudessem testar em casa sem grandes dificuldades, então peguei 4 marcas mais vistas no mercado: LG, PHILIPS, SAMSUNG e SONY.Então comecei a ver a forma de ondas no osciloscópio e levantar informações(o que não é tão simples de encontrar), dai encontrei sobre a Sony e a Lg(protocolo NEC) embora o padrão da Samsung é o mesmo mas com diferença no tamanho do pulsos, o padrão Philips deu um pouco mais de trabalho pois não possuem um bit de "start".
               A característica do padrão NEC é a presença de um bit de inicio(start bit) e outro de fim(stop bit) e mais 1 ou 2 bits após o "stop bit", sendo que antes do "stop bit" existe um espaço de 46ms(padrão samsung) ou 44ms(LG), ao todo são 33bits, no padrão Sony existe um "start bit" e em seguida 12 bits(mas no circuito montado foi lido somente 11 mas deve ser devido ao fato de eu estar ignorando os espaços entre os bits mas isso não atrapalha o reconhecimento) que é enviado 3 vezes em intervalos de 27ms . Já o padrão Philips não tem "stop bit" e nem "start bit" ao todo dá 10bits. Veja como é a onda gerada pelo controle remoto do PIC:
               veja que não coloquei  a onda inteira do padrão NEC (LG e Samsung) para facilitar a visualização mas abaixo coloquei a onda completa do padrão samsung para dar uma idéia, a diferença entre Samsung e LG é o tamanho do "start bit":

           Os bits "0" e "1" se diferenciam pelo tempo em que dura o nível alto e o nível baixo, se tempo iguais vale 0 se os tempos forem diferentes nível alto,mas para facilitar a decodificação eu peguei o valor do período do sinal ou seja na borda de subida do sinal, o valor desses períodos não são padrões cada fabricante escolhe o seu, mas o da Samsung e LG são iguais os bits "0" e "1"(talvez por usar o mesmo protocolo e com diferença apenas no "start bit").
         Vamos agora ao código fonte do codificador de controle remoto, vale lembrar que colocando um led infravermelho ele deve acionar uma tv, bastando para isso fazer pequenas alterações neste código fonte(não testei na TV ainda pois gerei ele só pra testar o decodificador):

O código fonte:

/*
 *                               Emulando um controle remoto de TV no MPlab XC8
 *
 * Compilador : MPlabXC8
 * Microcontrolador: 16F628A
 * Autor: aguivone
 * Versão: 1
 * Data :  16 de março de 2015
 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h> //para usar funçoes de string deve se adicionar este header
#define _XTAL_FREQ 4000000    // oscilador interno de 4 Mhz
#include <xc.h>
#include <delays.h>
/////////////////////////////////////////////////////////configuraçôes//////////////////////////////////////////////////
#define LED_STATUS RB0
#define LED_STATUS RB0


#pragma config FOSC = INTOSCIO  // Oscillator Selection bits (INTOSC oscillator: I/O function on RA6/OSC2/CLKOUT pin, I/O function on RA7/OSC1/CLKIN)
#pragma config WDTE = OFF       // Watchdog Timer Enable bit (WDT disabled)
#pragma config PWRTE = OFF      // Power-up Timer Enable bit (PWRT disabled)
#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 = ON       // Brown-out Detect Enable bit (BOD enabled)
#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)

long tempo_us1=0;

void interrupt interrupcao(void)//vetor de interrupção
 {
    if(T0IF)
    {//interrupção do timer0 - estoura quando atinge 255(0XFF)- estoura a cada 62.5us
        if(tempo_us1>0)
        {
            tempo_us1--;
        }
        TMR0 = 254;//reinicia timer com o valor calculado
        T0IF = 0;
        //62.5us + os delay da rotinas  = 75us
    }
 }

void inicializa_timer0()
{
    OPTION_REG = 0X03;//timer0 com prescaler dividido por 16
    T0IE = 1;//habilita interrupção do timer0
    TMR0 = 254;//zera registrador de contagem
}

void envia_bit(char protocolo,int val)
{
    switch(protocolo)
    {
        case 'G'://Samsung
        {
             if(val == 0)
            {//bit 0
             LED_STATUS = 1;
             __delay_us(560);
             LED_STATUS = 0;
             __delay_us(560);
            }
            else
            {//bit 1
             LED_STATUS = 1;
             __delay_us(560);
             LED_STATUS = 0;
             __delay_ms(1);
             __delay_us(680);
            }

        }break;
        case 'L'://LG 
        {
             if(val == 0)
            {//bit 0
             LED_STATUS = 1;
             __delay_us(560);
             LED_STATUS = 0;
             __delay_us(560);
            }
            else
            {//bit 1
             LED_STATUS = 1;
             __delay_us(560);
             LED_STATUS = 0;
             __delay_ms(1);
             __delay_us(680);
            }

        }break;
        case 'S'://sony
        {
                        if(val == 0)
            {//bit 0
             LED_STATUS = 1;
             __delay_us(600);
             LED_STATUS = 0;
             __delay_us(600);
            }
            else
            {//bit 1
             LED_STATUS = 1;
             __delay_ms(1);
             __delay_us(200);
             LED_STATUS = 0;
             __delay_us(600);
            }
        }break;
        case 'P'://
        {
           if(val == 0)
            {//bit 0
             LED_STATUS = 1;
             __delay_us(890);
             LED_STATUS = 0;
             __delay_us(890);
            }
            else
            {//bit 1
             LED_STATUS = 1;
             __delay_ms(1);
             __delay_us(800);
             LED_STATUS = 0;
             __delay_us(890);
            }

        }break;
    }
   
}

void envia_start_bit(char proto)
{
    switch(proto)
    {
    case 'L'://LG
    {
        LED_STATUS = 1;
        __delay_ms(9);
        LED_STATUS = 0;
        __delay_ms(4);
        __delay_us(500);
    }break;
   case 'G'://samsung
    {
        LED_STATUS = 1;
        __delay_ms(4);
        __delay_us(500);
        LED_STATUS = 0;
        __delay_ms(4);
        __delay_us(500);
    }break;
    case 'S'://sony
    {
        LED_STATUS = 1;
        __delay_ms(2);
        __delay_us(400);
        LED_STATUS = 0;
        __delay_us(600);
    }break;
    case 'P'://philips
    {
        LED_STATUS = 1;
        __delay_ms(1);
        __delay_us(800);
        LED_STATUS = 0;
        __delay_ms(1);
        __delay_us(800);
    }break;
}
}
void simula_pacote(char protocolo)
{
    switch(protocolo)
    {
        case 'L'://LG
        {
           envia_start_bit(protocolo);
           int temp = 0;
           while(temp<=10)//envia 10 bits 0
           {
              envia_bit(protocolo,0);
              temp++;
           }
           while(temp<=33)//envia 23 bit 1
           {
              envia_bit( protocolo,1);
              temp++;
           }
           __delay_ms(44);
           envia_start_bit(protocolo);
           envia_bit(protocolo,0);
           envia_bit(protocolo,1);
        }break;
       case 'G'://samsung
        {
           envia_start_bit(protocolo);
           int temp = 0;
           while(temp<=10)//envia 10 bits 0
           {
              envia_bit(protocolo,0);
              temp++;
           }
           while(temp<=33)//envia 23 bit 1
           {
              envia_bit( protocolo,1);
              temp++;
           }
           __delay_ms(46);
           envia_start_bit(protocolo);
           envia_bit(protocolo,0);
           envia_bit(protocolo,0);
        }break;
       case 'S'://sony
        {
           int envio = 0;
           while(envio<3)
           {
           envia_start_bit(protocolo);
           int temp = 0;
           while(temp<=6)//envia 6 bits 0
           {
              envia_bit(protocolo,0);
              temp++;
           }
           while(temp<=13)//envia 6 bit 1
           {
              envia_bit( protocolo,1);
              temp++;
           }
           __delay_ms(27);
           envio++;
           }
        }break;
        case 'P'://philips
        {
           int temp = 0;
           while(temp<3)//envia 2 bits 0
           {
              envia_bit(protocolo,0);
              temp++;
           }
           while(temp<7)//envia 4 bit 1
           {
              envia_bit( protocolo,1);
              temp++;
           }
           envia_start_bit(protocolo);
           while(temp<11)//envia 3 bit 1
           {
              envia_bit( protocolo,1);
              temp++;
           }
        }break;
    }
}
//////////////////////////////////////////////////////Rotina principal///////////////////////////////////////////////////////////////

void main(void) {
    TRISB = 0;//configura portB  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(;;)
    {
         simula_pacote('L');//simula um sinal de controle remoto LG
         __delay_ms(2000);//minimo de 100ms entre cada pacote mas para os teste vou colocar 5s
         simula_pacote('G');//simula um sinal de controle remoto Samsung
         __delay_ms(2000);//minimo de 100ms entre cada pacote mas para os teste vou colocar 5s
         simula_pacote('S');//simula um sinal de controle remoto Sony
         __delay_ms(2000);//minimo de 100ms entre cada pacote mas para os teste vou colocar 5s
         simula_pacote('P');//simula um sinal de controle remoto Philips
         __delay_ms(2000);//minimo de 100ms entre cada pacote mas para os teste vou colocar 5s

    }//loop infinito

}


Na segunda parte vou mostrar o código do receptor e mais algumas informações.


sábado, 14 de fevereiro de 2015

Usando display de 4X20 (4 linhas por 20 caracteres) com o 16F877A - XC8

Olá, neste exemplo vou demonstrar como usar um display de LCD 4X20 com o pic 16F877A no compilador XC8, vale lembra que os arquivos com a extensão ".c" e ".h" deve estar na mesma pasta em que é criado o arquivo main(), pois assim o compilador encontra esses arquivos,  veja que no meu código principal chamei apenas os arquivos ".h" pois os outros arquivos são chamados automaticamente pelo compilador, mas caso isso não aconteça vá na aba de projetos "source files"  e clicando no mouse como botão direito escolha a opção "add existing item...", e escolha o arquivo ".c", vamos ao Código fonte :

Código fonte do arquivo "main.c":
/*                         Usando display LCD 4X20
 * File:   main.c
 * Author: Aguivone
 *
 * Created on 14 de Fevereiro de 2015, 13:28
 */

#include <stdio.h>
#include <stdlib.h>
#include <xc.h>
#include "config_cpu.h"
#include "lcd_4X20_16F.h"
#include<delays.h>

/*
 * 
 */
void main()
{
///configuração das porta do microcontrolador///////////////////////
    TRISA = 0;//todas são saidas
    TRISB = 0;//configura portB   como saida
    TRISD = 0;//todas são saidas
    TRISC = 0;//todas são saidas
    TRISE = 0;//todas são saidas
    PORTA = 0;
    PORTB = 0;  // limpar as portas que estão configuradas como saidas
    PORTC = 0;
    PORTD = 0;
    PORTE = 0;
    ADCON0 = 0X00;//desabilita modulo ADC
    ADCON1 = 0X07;//desliga portas analogicas
    ////////////////////////////////////////////////////////////////////
    inicializar_LCD();
    GIE = 0; //desabilita GIE: Global Interrupt Enable bit
    escolhe_pos_do_cursor(1,0);//linha 1 posiçao 0
    imprime_LCD("escrevendo na linha1");
    escolhe_pos_do_cursor(2,0);//linha 2 posiçao 0
    imprime_LCD("escrevendo na linha2");
    escolhe_pos_do_cursor(3,0);//linha 3 posiçao 0
    imprime_LCD("escrevendo na linha3");
    escolhe_pos_do_cursor(4,0);//linha 4 posiçao 0
    imprime_LCD("escrevendo na linha4");
    for(;;)
    {
       // faz nada!
    }

}
Código fonte do arquivo "config_cpu.h":

/*
 * File:   config_cpu.h
 * Author: aguivone
 *
 * Created on 25 de Agosto de 2014, 16:24
 */

#ifndef CONFIG_CPU_H
#define    CONFIG_CPU_H

/*******************************configuraçôes do pic ****************************************************/
#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 = ON         //Codigo de proteção de firwmware




#define _XTAL_FREQ 20000000//usado para rotinas de  delays


#endif    /* CONFIG_CPU_H */

Código fonte do arquivo "lcd_4X20_16F.h":

The HTML source code is below.

/* 
 * File:   lcd_4X20_16F.h
 * Author: aguivone
 *
 * Created on 06 de fevereiro de 2015, 16:25
 */

#ifndef    LCD_4X20_16F_H
#define    LCD_4X20_16F_H

// ************************************************************************************
// Prototipos de funçoes
// ***********************************************************************************
extern void Saida_LCD(char a);
extern void comando_LCD(char a);
extern void limpar_LCD(void);
extern void escolhe_pos_do_cursor(char a, char b);
extern void inicializar_LCD(void);
extern void escreve_caracter(char a);
extern void imprime_LCD(char *a);
extern void rotaciona_LCD_direita();
extern void rotaciona_LCD_esquerda();
extern void long_to_char_LCD(unsigned long quant,int linha,int posicao);
extern void int_to_char_LCD(int quant,int linha,int posicao,int dig);

//#include "lcd_4X20_16F.c" //quando não reconhecer automaticamente usar este recurso


#endif    /*LCD_4X20_16F_H*/

Código fonte do arquivo "lcd_4X20_16F.c":

/*
 *                          FUNÇOES USADAS NO DISPLAY DE LCD
 *
 * Compilador :      MPlabXC8
 * Microcontrolador: 16F877A
 * Autor:            Aguivone
 * Versão:           1
 * Data de criação:  10/02/2015.
 */
//Biblioteca para fazer a comunicação com o display de LCD 16X2
//usando o modo 4 bits
//testada com a familia PIC16F mas pode facilmente ser usada para outras familias de pic
#include <xc.h>
#include "config_cpu.h"
#include<delays.h>

//configuracao dos pinos usado para comunicar com o display, onde os defines são os nomes dos pinos do display.

#define RS RD2
#define EN RD3
//pinos de dados
#define D4 RD4
#define D5 RD5
#define D6 RD6
#define D7 RD7
//
//funçoes desta biblioteca
//
void Saida_LCD(char a)
{
    if(a & 1)
        {D4 = 1;}
    else
        {D4 = 0;}
        if(a & 2)
        {D5 = 1;}
    else
        {D5 = 0;}
        if(a & 4)
        {D6 = 1;}
    else
        {D6 = 0;}
        if(a & 8)
        {D7 = 1;}
    else
        {D7 = 0;}

}
void comando_LCD(char a)
{
    RS = 0;             // => RS = 0
    Saida_LCD(a);
    EN  = 1;             // => E = 1
        __delay_ms(4);       //tempo necessario para display reconhecer
        EN  = 0;             // => E = 0
}

void limpar_LCD(void)
{
    comando_LCD(0);
    comando_LCD(1);
}

void escolhe_pos_do_cursor(char a, char b)
{
    char temp,z,y;
    if(a == 1)
    {
      temp = 0x80 + b;
        z = temp>>4;
        y = temp & 0x0F;
        comando_LCD(z);
        comando_LCD(y);
    }
    else if(a == 2)
    {
        temp = 0xC0 + b;
        z = temp>>4;
        y = temp & 0x0F;
        comando_LCD(z);
        comando_LCD(y);
    }
        if(a == 3)
    {
      temp = 0x94 + b;
        z = temp>>4;
        y = temp & 0x0F;
        comando_LCD(z);
        comando_LCD(y);
    }
    else if(a == 4)
    {
        temp = 0xD4 + b;
        z = temp>>4;
        y = temp & 0x0F;
        comando_LCD(z);
        comando_LCD(y);
    }
}

void inicializar_LCD()
{
  Saida_LCD(0x00);
   __delay_ms(20);
  comando_LCD(0x03);
  __delay_ms(5);
  comando_LCD(0x03);
  __delay_ms(11);
  comando_LCD(0x03);
  /////////////////////////////////////////////////////
  comando_LCD(0x02);
  comando_LCD(0x02);
  comando_LCD(0x08);
  comando_LCD(0x00);
  comando_LCD(0x0C);
  comando_LCD(0x00);
  comando_LCD(0x06);
}

void escreve_caracter(char a)
{
   char temp,y;
   temp = a&0x0F;//pega a parte baixa do byte
   y = a&0xF0;//pega parte alta do byte
   RS = 1;             // => RS = 1
   Saida_LCD(y>>4);             //Envia a parte alta mas antes rotaciona 4 vezes
   EN = 1;
   __delay_us(40);
   EN = 0;
   Saida_LCD(temp);// envia a parte baixa
   EN = 1;
   __delay_us(40);
   EN = 0;
}

void imprime_LCD(char *a)
{
    int i;
    for(i=0;a[i]!='\0';i++)
       escreve_caracter(a[i]);
}

void rotaciona_LCD_direita()
{
    comando_LCD(0x01);
    comando_LCD(0x0C);
}

void rotaciona_LCD_esquerda()
{
    comando_LCD(0x01);
    comando_LCD(0x08);
}

void long_to_char_LCD(unsigned long quant,int linha,int posicao)//valor, posicão inicial,linha a ser usada
{
       char convert_char2='0';
       char convert_char3='0';
       char convert_char4='0';
       escolhe_pos_do_cursor(linha,posicao);//linha 1 posiçao 1
       if(quant <10)
       {
         convert_char2=' ';
         convert_char3=' ';
       }
       else
       {
           if(quant <100)
            {
              convert_char2=' ';
            }
       }

       while(quant>=100)
        {
         quant=quant-100;
         convert_char2++;
         }
       while(quant>=10)
        {
         quant=quant-10;
        convert_char3++;
         }
       while(quant>=1)
        {
           quant=quant-1;
         convert_char4++;
         }
          escolhe_pos_do_cursor(linha,posicao);//linha , posiçao
          escreve_caracter(convert_char2);
          escolhe_pos_do_cursor(linha,posicao+1);//linha , posiçao
          escreve_caracter(convert_char3);
          escolhe_pos_do_cursor(linha,posicao+2);//linha , posiçao
          escreve_caracter(convert_char4);
}
void int_to_char_LCD(int quant,int linha,int posicao,int dig)//valor, posicão inicial,linha a ser usada,numero de digitos
{
       char convert_char3='0';
       char convert_char4='0';
       escolhe_pos_do_cursor(linha,posicao);//linha 1 posiçao 1


       while(quant>=10)
        {
         quant=quant-10;
        convert_char3++;
         }
       while(quant>=1)
        {
           quant=quant-1;
           convert_char4++;
         }

          if(dig == 2)
          {
           escolhe_pos_do_cursor(linha,posicao);//linha , posiçao
           escreve_caracter(convert_char3);
           escolhe_pos_do_cursor(linha,posicao+1);//linha , posiçao
           escreve_caracter(convert_char4);
          }
          else
          {
            escolhe_pos_do_cursor(linha,posicao);//linha , posiçao
            escreve_caracter(convert_char4);
          }
}

A simulação:

segunda-feira, 29 de dezembro de 2014

Medindo temperatura com o sensor LM35(de baixíssimo custo).

            Olá hoje vou deixar um exemplo de como usar o CI LM35(TO92) com o PIC16F877A e um display de de LCD 16X2.Para isto montei uma biblioteca para o lcd funcionar em modo 4 bits, segue abaixo o exemplo,repare que no código tive que montar uma pequena correção de erro para compensar a (pequena)não linearidade do sensor:

O código fonte :

/*
 *                             Lendo temperatura com o CI LM35
 *
 * Compilador : MPlabXC8
 * Microcontrolador: 16F877A
 * Autor: aguivone
 * Versão: 1
 * Data :  29 de dezembro de 2014
 */

#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>
#include "16F_lcd.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;
bit flag_interrupcao = 0;
///////////////////////////////////////////////////interrupção//////////////////////////////////////////////////////////////

void interrupt interrupcoes(void)//vetor de interrupção
 {
    if(ADIF)
    {//se interrupção do modulo analogico!
        ADIF = 0;//limpa flag
    }
 }

///////////////////////////////////////funçoes usadas pelo conversor AD//////////////////////////////////////////
void inicializa_ADC()
{
    ADCON0 = 0X01;//Modulo ADC configurado para cristal de 20mhz(Fosc/2) e inicialmente lê a porta AN0/liga modulo de conversão
    ADCON1 = 0X82;//justificado a direita/habilita as portas de RA0 A RA4
}

unsigned long ler_adc(int iPorta_analogica)//aqui se coloca qual porta analogica se quer usar
{
        unsigned long ulTensao;  //familia 18F e 16F
        ADCON0 = ((iPorta_analogica<<3) | (ADCON0& 0XC7));
        ADCON0bits.GO = 1;//limpa conversão
        while(ADCON0bits.GO_DONE == 1); //espera finalizar leitura
        ulTensao = (ADRESH << 8) | ADRESL;
        if(ulTensao <= 1)
        {
        ulTensao = 0;   
        }
        else
        {
          ulTensao = ulTensao/2 ;
          //agora é só corrigir a não linearidade do sensor
          if(ulTensao>24)
          {
           ulTensao--;
          }
           if(ulTensao>64)
          {
            ulTensao--;
          }
          if(ulTensao>103)
          {
             ulTensao = 100;//valor maximo aceitavel
          }

        }
        return(ulTensao);
}


void tela_inicial()
{
    escolhe_pos_do_cursor(1,1);//linha 1 posiçao 1
    imprime_LCD("Usando sensor de");
    escolhe_pos_do_cursor(2,1);//linha 2 posiçao 1
    imprime_LCD("temperatura LM35");
}
void tela_principal()
{
    escolhe_pos_do_cursor(1,1);//linha 1 posiçao 1
    imprime_LCD("  Temperatura  ");
    escolhe_pos_do_cursor(2,1);//linha 2 posiçao 1
    imprime_LCD("       C       ");
}

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

void main(void)
{
    TRISA = 0XFF;//o portA será entrada
    TRISB = 0X00;//configura portB   como saida
    TRISD = 0X00;//todas são saidas
    TRISC = 0X80;//todas são saidas exceto C7(pino RX)
    TRISE = 0X00;//todas são saidas
    PORTB = 0;  // limpar as portas que estão configuradas como saidas
    PORTC = 0;
    PORTD = 0;
    PORTE = 0;
    inicializa_ADC();
    inicializar_LCD();//biblioteca lcd
    tela_inicial();
    __delay_ms(5000);
    limpar_LCD();
    tela_principal();
    PEIE = 1;//habilita interrupção de perifericos do pic
    GIE = 1; //GIE: Global Interrupt Enable bit

    for(;;)
    {
        long_to_char_LCD(ler_adc(0),2,5);//lê porta AN0, e escreve na linha2 e posição 5
        __delay_ms(1000);//espera 1 segundo para fazer nova atualização
    }//loop infinito
    

}

O código fonte da biblioteca 16F_lcd.h:

//Biblioteca para fazer a comunicação com o display de LCD 16X2
//usando o modo 4 bits
//testada com a familia PIC16F mas pode facilmente ser usada para outras familias de pic


//configuracao dos pinos usado para comunicar com o display, onde os defines são os nomes dos pinos do display.

#define RS RD2
#define EN RD3
//pinos de dados
#define D4 RD4
#define D5 RD5
#define D6 RD6
#define D7 RD7
//
//funçoes desta biblioteca
//
void Saida_LCD(char a)
{
    if(a & 1)
        {D4 = 1;}
    else
        {D4 = 0;}
        if(a & 2)
        {D5 = 1;}
    else
        {D5 = 0;}
        if(a & 4)
        {D6 = 1;}
    else
        {D6 = 0;}
        if(a & 8)
        {D7 = 1;}
    else
        {D7 = 0;}

}
void comando_LCD(char a)
{
    RS = 0;             // => RS = 0
    Saida_LCD(a);
    EN  = 1;             // => E = 1
        __delay_ms(4);       //tempo necessario para display reconhecer
        EN  = 0;             // => E = 0
}

limpar_LCD()
{
    comando_LCD(0);
    comando_LCD(1);
}

void escolhe_pos_do_cursor(char a, char b)
{
    char temp,z,y;
    if(a == 1)
    {
      temp = 0x80 + b - 1;
        z = temp>>4;
        y = temp & 0x0F;
        comando_LCD(z);
        comando_LCD(y);
    }
    else if(a == 2)
    {
        temp = 0xC0 + b - 1;
        z = temp>>4;
        y = temp & 0x0F;
        comando_LCD(z);
        comando_LCD(y);
    }
}

void inicializar_LCD()
{
  Saida_LCD(0x00);
   __delay_ms(20);
  comando_LCD(0x03);
  __delay_ms(5);
  comando_LCD(0x03);
  __delay_ms(11);
  comando_LCD(0x03);
  /////////////////////////////////////////////////////
  comando_LCD(0x02);
  comando_LCD(0x02);
  comando_LCD(0x08);
  comando_LCD(0x00);
  comando_LCD(0x0C);
  comando_LCD(0x00);
  comando_LCD(0x06);
}

void escreve_caracter(char a)
{
   char temp,y;
   temp = a&0x0F;//pega a parte baixa do byte
   y = a&0xF0;//pega parte alta do byte
   RS = 1;             // => RS = 1
   Saida_LCD(y>>4);             //Envia a parte alta mas antes rotaciona 4 vezes
   EN = 1;
   __delay_us(40);
   EN = 0;
   Saida_LCD(temp);// envia a parte baixa
   EN = 1;
   __delay_us(40);
   EN = 0;
}

void imprime_LCD(char *a)
{
    int i;
    for(i=0;a[i]!='\0';i++)
       escreve_caracter(a[i]);
}

void rotaciona_LCD_direita()
{
    comando_LCD(0x01);
    comando_LCD(0x0C);
}

void rotaciona_LCD_esquerda()
{
    comando_LCD(0x01);
    comando_LCD(0x08);
}

void long_to_char_LCD(unsigned long quant,int linha,int posicao)//valor, posicão inicial,linha a ser usada
{
       char convert_char2='0';
       char convert_char3='0';
       char convert_char4='0';
       escolhe_pos_do_cursor(linha,posicao);//linha 1 posiçao 1
       if(quant <10)
       {
         convert_char2=' ';
         convert_char3=' ';
       }
       else
       {
           if(quant <100)
            {
              convert_char2=' ';
            }
       }

       while(quant>=100)
        {
         quant=quant-100;
         convert_char2++;
         }
       while(quant>=10)
        {
         quant=quant-10;
        convert_char3++;
         }
       while(quant>=1)
        {
           quant=quant-1;
         convert_char4++;
         }
          escolhe_pos_do_cursor(linha,posicao);//linha , posiçao
          escreve_caracter(convert_char2);
          escolhe_pos_do_cursor(linha,posicao+1);//linha , posiçao
          escreve_caracter(convert_char3);
          escolhe_pos_do_cursor(linha,posicao+2);//linha , posiçao
          escreve_caracter(convert_char4);
}

A simulação do código:



quinta-feira, 11 de dezembro de 2014

Acessando a memoria eeprom no compilador XC8

         Olá, eu ja havia postado aqui uma forma de fazer o acesso da eeprom interna do microcontrolador PIC, mas recentemente vi que o compilador XC8 já contempla um modo de fazer isso de forma fácil e ágil e agora vou demonstrar como :

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++;
       }
}

//////////////////////////////////////////////////////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 com LIB XC8 \n\r");
     eeprom_write(0X01,'T');   //escreve na eeprom
     eeprom_write(0X02,'E');
     eeprom_write(0X03,'S');
     eeprom_write(0X04,'T');
     eeprom_write(0X05,'E');
     imprime_RS232("Dados da memoria : \n\r");
     escreve_RS232(EEPROM_READ(0X01)) ;//lê os dados do endereço
     escreve_RS232(EEPROM_READ(0X02)) ;//da eeprom
     escreve_RS232(EEPROM_READ(0X03)) ;
     escreve_RS232(EEPROM_READ(0X04)) ;
     escreve_RS232(EEPROM_READ(0X05)) ;
    for(;;)
    {
   
    }//loop infinito
}

A SIMULAÇÃO:




segunda-feira, 27 de outubro de 2014

Usando o watchdog do 16F877A no XC8

/*
 *                                        usando watchdog
 *
 * Compilador : MPlabXC8
 * Microcontrolador: 16F877A
 * Autor: aguivone
 * Versão: 1
 * Data :  27/10/2014
*/

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

// CONFIG
#pragma config FOSC = HS        // Oscillator Selection bits (HS oscillator)
#pragma config WDTE = ON       // Watchdog Timer Enable bit (WDT habilitado)
#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)


//===================================================================================
//Função:    _inicializa_RS232
//Parâmetros: unsigned long ulVelocidade
//          : unsigned int uiModo
//Retorno:   não tem retorno.
//Descrição: usada para iniciar a porta serial.
//===================================================================================
void inicializa_RS232(unsigned long ulVelocidade,unsigned int uiModo)
{//// 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(uiModo == 1)
        {//modo = 1 ,modo alta velocidade
         TXSTA = 0X24;//modo assincrono,trasmissao 8 bits.
         valor =(int)(((_XTAL_FREQ/ulVelocidade)-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/ulVelocidade)-64)/64);//calculo do valor do gerador de baud rate
        }
    SPBRG = valor;
   // PIE1 = 0X20;
    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)
}
//===================================================================================
//Função:    _escreve_RS232
//Parâmetros: char cValor
//Retorno:   não tem retorno.
//Descrição: usada para escrever 1 caracter.
//===================================================================================
 void escreve_RS232(char cValor)
{
    TXIF = 0;//limpa flag que sinaliza envio completo.
    TXREG = cValor;
    while(TXIF ==0);//espera enviar caracter
}
//===================================================================================
//Função:    _imprime_RS232
//Parâmetros: const char ccFrase[]
//Retorno:   não tem retorno.
//Descrição: usada para escrever uma string(vetor de caracteres).
//===================================================================================
 void imprime_RS232(const char ccFrase[])
{
     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]);
           indice++;
       }
}

 


//*******************************Rotina principal*********************************************/
void main(void)
{
    TRISA = 0XFE;
    TRISB = 0X00;//configura portB   como saida
    TRISD = 0X00;//todas são saidas
    TRISC = 0X80;//todas são saidas exceto C7(pino RX)
    TRISE = 0X00;//todas são saidas
    PORTA = 0X00;
    PORTB = 0;  // limpar as portas que estão configuradas como saidas
    PORTC = 0;
    PORTD = 0;
    PORTE = 0;
    inicializa_RS232(9600,1);//modo de alta velocidade
    PEIE = 1;//habilita interrupção de perifericos do pic
    GIE = 1; //GIE: Global Interrupt Enable bit
    ADCON0 = 0X00;//desabilita modulo ADC
    ADCON1 = 0X07;//desliga portas analogicas
    OPTION_REG = 0X0F;//habilita WDT e configura ele pra 1:128
    if((STATUS & 0X10) > 0)//verifica se watchdog já resetou alguma vez
    {
      imprime_RS232("Programa watchdog iniciado \n\r");//nunca resetou
    }
    else
    {
      imprime_RS232("houve um estouro de watchdog \n\r");//já resetou
    }
    for(;;)
    {
       //faz nada!
       //para não deixar o watchdog estourar é so colocar a linha abaixo
       //no local que se deseja monitorar 
       // CLRWDT();//limpa WDT
    }
}

A simulação:


segunda-feira, 6 de outubro de 2014

Medindo tensão de 4 canais analógicos (quase)ao mesmo tempo:

       Há momentos em que precisamos ler vários canais analógicos (quase)ao mesmo tempo dai uma maneira de se fazer isso é chaveando as entradas analógicas, veja que os valores são lidos em milivolts. 

O código fonte:

/*
 *                             lendo 4 valores de tensão usando RS-232 no MPlab XC8
 *
 * Compilador : MPlabXC8
 * Microcontrolador: 16F877A
 * Autor: aguivone
 * Versão: 1
 * Data :  06 de outubro de 2014
 */
#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;
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 long_to_char(unsigned long quant)
{
       char convert_char1='0';
       char convert_char2='0';
       char convert_char3='0';
       char convert_char4='0';
       while(quant>=1000)
        {
         quant=quant-1000;
         convert_char1++;
         }
       while(quant>=100)
        {
         quant=quant-100;
         convert_char2++;
         }
       while(quant>=10)
        {
         quant=quant-10;
        convert_char3++;
         }
       while(quant>=1)
        {
           quant=quant-1;
         convert_char4++;
         }
          escreve(convert_char1);
          escreve(convert_char2);
          escreve(convert_char3);
          escreve(convert_char4);

}

///////////////////////////////////////funçoes usadas pelo conversor AD//////////////////////////////////////////
void inicializa_ADC()
{
    ADCON0 = 0X01;//Modulo ADC configurado para cristal de 20mhz(Fosc/2) e inicialmente lê a porta AN0/liga modulo de conversão
    ADCON1 = 0X82;//justificado a direita/habilita as portas de RA0 A RA4
}

unsigned long ler_adc_mv(int iPorta_analogica)//aqui se coloca qual porta analogica se quer usar
{
    /*
     * se for usar a familia 12F e este
     *
        unsigned long ultensao;
        ADCON0 = (int iPorta_analogica<<2) | (ADCON0& 0XF3));
        PIR1bits.ADIF = 0;//limpa flag
        ADCON0bits.ADON = 1;//liga modulo de conversão
        ADCON0bits.GO = 1; //inicia conversão
        while (PIR1bits.ADIF == 0); //espera finalizar leitura
        ultensao = (ADRESH << 8) | ADRESL;
        ADCON0bits.ADON = 0;//desliga modulo de conversão
        return(ultensao);
    */
        unsigned long ulTensao;  //familia 18F e 16F
        ADCON0 = ((iPorta_analogica<<3) | (ADCON0& 0XC7));
        ADCON0bits.GO = 1;//limpa conversão
        while(ADCON0bits.GO_DONE == 1); //espera finalizar leitura
        ulTensao = (ADRESH << 8) | ADRESL;
        ulTensao =((ulTensao * 5000)/1023); //Vref está em milliVolts
        return(ulTensao);
}



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

void main(void)
{
    TRISA = 0XFF;//o portA será entrada
    TRISB = 0X00;//configura portB   como saida
    TRISD = 0X00;//todas são saidas
    TRISC = 0X80;//todas são saidas exceto C7(pino RX)
    TRISE = 0X00;//todas são saidas
    PORTB = 0;  // limpar as portas que estão configuradas como saidas
    PORTC = 0;
    PORTD = 0;
    PORTE = 0;
    inicializa_RS232(9600,1);//modo de alta velocidade
    inicializa_ADC();
    PEIE = 1;//habilita interrupção de perifericos do pic
    GIE = 1; //GIE: Global Interrupt Enable bit
    imprime("Voltimetro multiplo usando a serial! \n\r");
    imprime("AN0 - AN1 - AN2 - AN3  \n\r");
    for(;;)
    {
        long_to_char(ler_adc_mv(0));//lê porta AN0
        escreve('-');//separador de leituras
        long_to_char(ler_adc_mv(1));//lê porta AN1
        escreve('-');//separador de leituras
        long_to_char(ler_adc_mv(2));//lê porta AN2
        escreve('-');//separador de leituras
        long_to_char(ler_adc_mv(3));//lê porta AN3
        escreve('\r');//retorna pro inicio da linha
        escreve('\n');//pula linha
        __delay_ms(1000);//espera 1 segundo
    }//loop infinito

}

A simulação :


Curta a fan page do blog e tenha acesso as últimas postagem assim que publicadas!