quarta-feira, 17 de abril de 2013

Comunicação SPI entre dois PIC com o 18F13K22:


               Quando fiz este código-fonte meu intuito era montar uma comunicação entre os dois chips mas devido a limitação do hardware do pic não foi possível(a menos que fizesse isso de modo manual sem usar o buffer do SPI) , então fiz somente um exemplo que demonstra como enviar os dados do mestre para o escravo sem que haja comunicação do escravo para o mestre,quem sabe futuramente posto aqui um modo de fazer isso manualmente(veja que no avr ATmega328 isso é perfeitamente possível), para quem quiser saber mais sobre o protocolo SPI e I2C veja este link:
http://dev.emcelettronica.com/i2c-or-spi-serial-communication-which-one-to-go
                 Neste código já está pronto o modo mestre e escravo bastando apenas mudar o nível logico do pino RA0(5V - modo mestre e GND - modo escravo), então o microcontrolador no modo mestre envia um carácter para o microcontrolador que está configurado como escravo, e se for o carácter esperado ele acende um led por um tempo e então deslia o led. Deixei até uma função para ler dados pela SPI no modo mestre("embora não foi utilizado") .

O código - fonte:

/*
 *                                              usando SPI no MPlab XC8(modo mestre e escravo)
 *
 * Compilador : MPlabXC8
 * Microcontrolador: 18F13K22
 * Autor: aguivone
 * Versão: 1
 * Data :  17 de abril de 2013
 */

#include <stdio.h>
#include <stdlib.h>
#define _XTAL_FREQ 12000000    // cristal de 20 Mhz
#include <xc.h>

#define SPI_SLAVE_WRITE 0x00
#define SPI_SLAVE_READ  0x01
/////////////////////////////////////////////////////configuraçôes do pic //////////////////////////////////////////////////

// CONFIG1H
#pragma config FOSC = HS        // Oscillator Selection bits (HS oscillator)
#pragma config PLLEN = OFF      // 4 X PLL Enable bit (PLL is under software control)
#pragma config PCLKEN = ON      // Primary Clock Enable bit (Primary clock enabled)
#pragma config FCMEN = OFF      // Fail-Safe Clock Monitor Enable (Fail-Safe Clock Monitor disabled)
#pragma config IESO = OFF       // Internal/External Oscillator Switchover bit (Oscillator Switchover mode disabled)

// CONFIG2L
#pragma config PWRTEN = OFF     // Power-up Timer Enable bit (PWRT disabled)
#pragma config BOREN = OFF      // Brown-out Reset Enable bits (Brown-out Reset disabled in hardware and software)
#pragma config BORV = 19        // Brown Out Reset Voltage bits (VBOR set to 1.9 V nominal)

// CONFIG2H
#pragma config WDTEN = OFF      // Watchdog Timer Enable bit (WDT is controlled by SWDTEN bit of the WDTCON register)
#pragma config WDTPS = 32768    // Watchdog Timer Postscale Select bits (1:32768)

// CONFIG3H
#pragma config HFOFST = ON      // HFINTOSC Fast Start-up bit (HFINTOSC starts clocking the CPU without waiting for the oscillator to stablize.)
#pragma config MCLRE = OFF      // MCLR Pin Enable bit (RA3 input pin enabled; MCLR disabled)

// CONFIG4L
#pragma config STVREN = ON      // Stack Full/Underflow Reset Enable bit (Stack full/underflow will cause Reset)
#pragma config LVP = ON         // Single-Supply ICSP Enable bit (Single-Supply ICSP enabled)
#pragma config BBSIZ = OFF      // Boot Block Size Select bit (512W boot block size)
#pragma config XINST = OFF      // Extended Instruction Set Enable bit (Instruction set extension and Indexed Addressing mode disabled (Legacy mode))

// CONFIG5L
#pragma config CP0 = OFF        // Code Protection bit (Block 0 not code-protected)
#pragma config CP1 = OFF        // Code Protection bit (Block 1 not code-protected)

// CONFIG5H
#pragma config CPB = OFF        // Boot Block Code Protection bit (Boot block not code-protected)
#pragma config CPD = OFF        // Data EEPROM Code Protection bit (Data EEPROM not code-protected)

// CONFIG6L
#pragma config WRT0 = OFF       // Write Protection bit (Block 0 not write-protected)
#pragma config WRT1 = OFF       // Write Protection bit (Block 1 not write-protected)

// CONFIG6H
#pragma config WRTC = OFF       // Configuration Register Write Protection bit (Configuration registers not write-protected)
#pragma config WRTB = OFF       // Boot Block Write Protection bit (Boot block not write-protected)
#pragma config WRTD = OFF       // Data EEPROM Write Protection bit (Data EEPROM not write-protected)

// CONFIG7L
#pragma config EBTR0 = OFF      // Table Read Protection bit (Block 0 not protected from table reads executed in other blocks)
#pragma config EBTR1 = OFF      // Table Read Protection bit (Block 1 not protected from table reads executed in other blocks)

// CONFIG7H
#pragma config EBTRB = OFF      // Boot Block Table Read Protection bit (Boot block not protected from table reads executed in other blocks)


/////////////////////////////

// Delay in 1 ms (approximately) for 12 MHz Internal Clock
void delay_ms(long mili)
{
   while(mili > 0)
   {
      _delay(2927);//aprox. 1ms com clock de 12mhz
      mili--;
   }
   // no caso do 18F o valor fica bem acima então é melhor montar essa funcão para que trabalhe bem
}


void MASTER_ESC_SPI(unsigned char dados)
{

    LATCbits.LC6 = 0;  // ativa CS(chip select do MCP23S17)
    SSPBUF = 0X01;//opcode que sinaliza que quer deixar um dado
    while(!SSPSTATbits.BF);//espera completar envio de dados
    delay_ms(1);//espera slave processar informação
    SSPBUF = dados;//envia os dados que será colocado no registrador
    while(!SSPSTATbits.BF);//espera completar envio de dados
    LATCbits.LC6 = 1;//desabilita chip
}

unsigned char MASTER_LER_SPI()
{
   LATCbits.LC6 = 0;  // ativa SS(slave select)
   SSPBUF = 0X00;//um valor qualquer para pegar os dados
  //desse registrador(assim gera o clock necessario para isto)
   while(!SSPSTATbits.BF);//espera completar envio de dados
   LATCbits.LC6 = 1;//desabilita chip
  return(SSPBUF);
}


unsigned char SLAVE_LER_SPI()
{
  while(!SSPSTATbits.BF);//espera completar recepção
  return(SSPBUF);
}

void SPI_MASTER()//modo mestre
{
  SSPCON1 = 0X20;//habilita modo SPI // FOSC/4 //
  SSPSTAT = 0XC0;//pega amostras no fim do bit e a trasmissão será na borda de descida
  TRISB = 0X10;//configura portB como saida exceto o pino b4(SDI)
  TRISC = 0X00;//configura portc como saida

  LATCbits.LC6 = 1;
}
void SPI_SLAVE()//modo slave
{
  SSPCON1 = 0X24;//habilita modo SPI // habilita pino SS(slave select) pois é mais usual assim
  SSPSTAT = 0X40;//trasmissão será na borda de descida
  TRISB = 0XFF;//configura portB como entrada
  TRISC = 0X40;//configura portc como saida exceto C6(SS)
  LATCbits.LC7 = 1;//sdo = 1

}


void main(void)
{
  TRISA = 0XFF;
  ANSEL = 0x00;//desabilita porta analogicas(para não atrapalhar recepção no pino)
  ANSELH = 0x00;//em alguns casos não funciona nem a interrupção de recepção.
  if(PORTAbits.RA0 == 1)
                   {//ligado ao vcc é master
                          SPI_MASTER();
                   }
                   else
                   {//se ligado ao gnd é slave
                          SPI_SLAVE();
                   }
  for(;;) {
              
              if(PORTAbits.RA0 == 1)
               {//ligado ao vcc é master
                 MASTER_ESC_SPI('F'); // ENVIA UM DADO
                 delay_ms(500);//tempo para nova solicitação
               }
               else
               {//se ligado ao gnd é slave
                  if(PORTCbits.RC6 == 0)//pino de ativação foi habilitado?
                    {
                        if(SLAVE_LER_SPI() == 'F')//verifica se recebeu um dado do mestre
                        {
                            LATCbits.LC0 = 1;
                            delay_ms(100);
                            LATCbits.LC0 = 0;
                        }
                        
                    }
               }

          }
}

A simulação:


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!  

terça-feira, 16 de abril de 2013

Expandindo as portas do PIC:

          Vou demonstrar aqui como aumentar o números de pinos do PIC simplesmente usando um CI fabricado pela própria microchip o MCP23S17, com ele você  pode ler e escrever no pinos do chip via comunicação SPI .O programa é bem simples o microcontrolador fica lendo o portB do chip o tempo todo dai se o botão for pressionado ele escreve no portA do chip o valor "0X0F" e quando o botão é liberado ele limpa o portA do chip.
           Esse chip é vendido no site da microchip por 1,50 dólar.Um detalhe que deve ser ressaltado as familias 18F  é que para ler um pino se usar  PORTXbits.RXY e para escrever se usa LATXbits.LXY onde o 'X' é o port e o 'Y' o numero do pino(0 a 7).

O código - fonte:


/*
 *                           usando a SPI(mestre) para comunicar com modulo expansor MCP23S17
 *
 * Compilador : MPlabXC8
 * Microcontrolador: 18F13K22
 * Autor: aguivone
 * Versão: 1
 * Data :  16 de abril de 2013
 */

#include <stdio.h>
#include <stdlib.h>
#define _XTAL_FREQ 12000000    // cristal de 20 Mhz
#include <xc.h>

/////////////////////////////////////////////////////configuraçôes do pic //////////////////////////////////////////////////

// CONFIG1H
#pragma config FOSC = HS        // Oscillator Selection bits (HS oscillator)
#pragma config PLLEN = OFF      // 4 X PLL Enable bit (PLL is under software control)
#pragma config PCLKEN = ON      // Primary Clock Enable bit (Primary clock enabled)
#pragma config FCMEN = OFF      // Fail-Safe Clock Monitor Enable (Fail-Safe Clock Monitor disabled)
#pragma config IESO = OFF       // Internal/External Oscillator Switchover bit (Oscillator Switchover mode disabled)

// CONFIG2L
#pragma config PWRTEN = OFF     // Power-up Timer Enable bit (PWRT disabled)
#pragma config BOREN = OFF      // Brown-out Reset Enable bits (Brown-out Reset disabled in hardware and software)
#pragma config BORV = 19        // Brown Out Reset Voltage bits (VBOR set to 1.9 V nominal)

// CONFIG2H
#pragma config WDTEN = OFF      // Watchdog Timer Enable bit (WDT is controlled by SWDTEN bit of the WDTCON register)
#pragma config WDTPS = 32768    // Watchdog Timer Postscale Select bits (1:32768)

// CONFIG3H
#pragma config HFOFST = ON      // HFINTOSC Fast Start-up bit (HFINTOSC starts clocking the CPU without waiting for the oscillator to stablize.)
#pragma config MCLRE = OFF      // MCLR Pin Enable bit (RA3 input pin enabled; MCLR disabled)

// CONFIG4L
#pragma config STVREN = ON      // Stack Full/Underflow Reset Enable bit (Stack full/underflow will cause Reset)
#pragma config LVP = ON         // Single-Supply ICSP Enable bit (Single-Supply ICSP enabled)
#pragma config BBSIZ = OFF      // Boot Block Size Select bit (512W boot block size)
#pragma config XINST = OFF      // Extended Instruction Set Enable bit (Instruction set extension and Indexed Addressing mode disabled (Legacy mode))

// CONFIG5L
#pragma config CP0 = OFF        // Code Protection bit (Block 0 not code-protected)
#pragma config CP1 = OFF        // Code Protection bit (Block 1 not code-protected)

// CONFIG5H
#pragma config CPB = OFF        // Boot Block Code Protection bit (Boot block not code-protected)
#pragma config CPD = OFF        // Data EEPROM Code Protection bit (Data EEPROM not code-protected)

// CONFIG6L
#pragma config WRT0 = OFF       // Write Protection bit (Block 0 not write-protected)
#pragma config WRT1 = OFF       // Write Protection bit (Block 1 not write-protected)

// CONFIG6H
#pragma config WRTC = OFF       // Configuration Register Write Protection bit (Configuration registers not write-protected)
#pragma config WRTB = OFF       // Boot Block Write Protection bit (Boot block not write-protected)
#pragma config WRTD = OFF       // Data EEPROM Write Protection bit (Data EEPROM not write-protected)

// CONFIG7L
#pragma config EBTR0 = OFF      // Table Read Protection bit (Block 0 not protected from table reads executed in other blocks)
#pragma config EBTR1 = OFF      // Table Read Protection bit (Block 1 not protected from table reads executed in other blocks)

// CONFIG7H
#pragma config EBTRB = OFF      // Boot Block Table Read Protection bit (Boot block not protected from table reads executed in other blocks)



// defines para o MCP23S17 SPI Slave
#define SPI_SLAVE_ID    0x40
#define SPI_SLAVE_ADDR  0x00      // A2=0,A1=0,A0=0 pois os pinos estão aterrados
#define SPI_SLAVE_WRITE 0x00
#define SPI_SLAVE_READ  0x01

// MCP23S17 registradores padrão ( BANK=0)
#define IODIRA 0x00
#define IODIRB 0x01
#define IOCONA 0x0A
#define GPPUA  0x0C
#define GPPUB  0x0D
#define GPIOA  0x12
#define GPIOB  0x13
//variaveis usadas///////////
  unsigned char conta = 0 ,Botao = 0,porta =0;
/////////////////////////////

// Delay in 1 ms (approximately) for 12 MHz Internal Clock
void delay_ms(long mili)
{
   while(mili > 0)
   {
      _delay(2927);//aprox. 1ms com clock de 12mhz
      mili--;
   }
   // no caso do 18F o valor fica bem acima então é melhor montar essa funcão para que trabalhe bem
}


void ESCREVE_SPI(unsigned char endereco,unsigned char dados)
{
   LATCbits.LC6 = 0;  // ativa CS(chip select do MCP23S17)
  // inicia MCP23S17 OpCode
  SSPBUF = SPI_SLAVE_ID | ((SPI_SLAVE_ADDR << 1) & 0x0E)| SPI_SLAVE_WRITE;  
  while(!SSPSTATbits.BF);//espera completar envio de dados
  SSPBUF = endereco;//envia o endereço do regitrador que se quer acessar
  while(!SSPSTATbits.BF);//espera completar envio de dados
  SSPBUF = dados;//envia os dados que será colocado no registrador
  while(!SSPSTATbits.BF);//espera completar envio de dados
   LATCbits.LC6 = 1;//desabilita chip
}

unsigned char LER_SPI(unsigned char endereco)
{
     LATCbits.LC6 = 0;  // ativa CS(chip select do MCP23S17)
  // inicia MCP23S17 OpCode
  SSPBUF = SPI_SLAVE_ID | ((SPI_SLAVE_ADDR << 1) & 0x0E)| SPI_SLAVE_READ;
  while(!SSPSTATbits.BF);//espera completar envio de dados
  SSPBUF = endereco;//envia o endereço do regitrador que se quer acessar
  while(!SSPSTATbits.BF);//espera completar envio de dados
  SSPBUF = 0X00;//um valor qualquer para pegar os dados
  //desse registrador(assim gera o clock necessario para isto)
  while(!SSPSTATbits.BF);//espera completar envio de dados
   LATCbits.LC6 = 1;//desabilita chip
  return(SSPBUF);
}
void SPI_MASTER()//modo mestre
{
  SSPCON1 = 0X20;//habilita modo SPI // FOSC/4 //
  SSPSTAT = 0XC0;//pega amostras no fim do bit e a trasmissão será na borda de descida
  TRISB = 0X10;//configura portB como saida exceto o pino b4(SDI)
  TRISC = 0X00;//configura portc como saida
  ANSEL = 0x00;//desabilita porta analogicas(para não atrapalhar recepção no pino)
  ANSELH = 0x00;//em alguns casos não funciona nem a interrupção de recepção.
   LATCbits.LC6 = 1;
}
void INICIALIZA_MCP23S17()
{
  ESCREVE_SPI(IOCONA,0x28);   // I/O Registrador de controle: BANK=0, SEQOP=1, HAEN=1 (habilita endereçamento)
  ESCREVE_SPI(IODIRA,0x00);   // GPIOA será saida
  ESCREVE_SPI(IODIRB,0xFF);   // GPIOB será entrada
  ESCREVE_SPI(GPPUB,0xFF);    // habilita resistores de pull up no GPIOB
  ESCREVE_SPI(GPIOA,0x00);    // limpa saidas da GPIOA
}

void main(void)
{
  SPI_MASTER();//inicializa SPI no modo master
  INICIALIZA_MCP23S17();
  for(;;) {
             porta=LER_SPI(GPIOB);    // lê o valor do GPIOB
         if (porta == 0xFE)
               {      // se botão pressionado
                  delay_ms(100);//debounce(filtro de ruidos)
                  porta=LER_SPI(GPIOB);  // lê novamente
                  if (porta == 0xFE)
                  {//pressionado
                    ESCREVE_SPI(GPIOA,0X0F);//muda estado dos bits mais baixos
                  }                  
            }
             else
                  { //não pressionado
                    ESCREVE_SPI(GPIOA,0x00); // limpa o portA
                  }
        delay_ms(1000);//tempo para visualizar mudanças
        }
}

A simulação:

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, 12 de abril de 2013

Voltímetro com 18F13K22

Não esqueça de  curtir a página do facebook (procure por "microcontroladores-c")!
/*
 *                                              usando ADC no MPlab XC8(voltimetro)
 *
 * Compilador : MPlabXC8
 * Microcontrolador: 18F13K22
 * Autor: aguivone
 * Versão: 1
 * Data :  12 de abril de 2013
 */

#include <stdio.h>
#include <string.h> //para usar funçoes de string deve se adicionar este header
#include <stdlib.h>
#include <xc.h>
#define _XTAL_FREQ 12000000     /* required for __delay_ms, __delay_us macros */


/////////////////////////////////////////////////////configuraçôes do pic //////////////////////////////////////////////////

// CONFIG1H
#pragma config FOSC = HS        // Oscillator Selection bits (HS oscillator)
#pragma config PLLEN = OFF      // 4 X PLL Enable bit (PLL is under software control)
#pragma config PCLKEN = ON      // Primary Clock Enable bit (Primary clock enabled)
#pragma config FCMEN = OFF      // Fail-Safe Clock Monitor Enable (Fail-Safe Clock Monitor disabled)
#pragma config IESO = OFF       // Internal/External Oscillator Switchover bit (Oscillator Switchover mode disabled)

// CONFIG2L
#pragma config PWRTEN = OFF     // Power-up Timer Enable bit (PWRT disabled)
#pragma config BOREN = OFF      // Brown-out Reset Enable bits (Brown-out Reset disabled in hardware and software)
#pragma config BORV = 19        // Brown Out Reset Voltage bits (VBOR set to 1.9 V nominal)

// CONFIG2H
#pragma config WDTEN = OFF      // Watchdog Timer Enable bit (WDT is controlled by SWDTEN bit of the WDTCON register)
#pragma config WDTPS = 32768    // Watchdog Timer Postscale Select bits (1:32768)

// CONFIG3H
#pragma config HFOFST = ON      // HFINTOSC Fast Start-up bit (HFINTOSC starts clocking the CPU without waiting for the oscillator to stablize.)
#pragma config MCLRE = OFF      // MCLR Pin Enable bit (RA3 input pin enabled; MCLR disabled)

// CONFIG4L
#pragma config STVREN = ON      // Stack Full/Underflow Reset Enable bit (Stack full/underflow will cause Reset)
#pragma config LVP = ON         // Single-Supply ICSP Enable bit (Single-Supply ICSP enabled)
#pragma config BBSIZ = OFF      // Boot Block Size Select bit (512W boot block size)
#pragma config XINST = OFF      // Extended Instruction Set Enable bit (Instruction set extension and Indexed Addressing mode disabled (Legacy mode))

// CONFIG5L
#pragma config CP0 = OFF        // Code Protection bit (Block 0 not code-protected)
#pragma config CP1 = OFF        // Code Protection bit (Block 1 not code-protected)

// CONFIG5H
#pragma config CPB = OFF        // Boot Block Code Protection bit (Boot block not code-protected)
#pragma config CPD = OFF        // Data EEPROM Code Protection bit (Data EEPROM not code-protected)

// CONFIG6L
#pragma config WRT0 = OFF       // Write Protection bit (Block 0 not write-protected)
#pragma config WRT1 = OFF       // Write Protection bit (Block 1 not write-protected)

// CONFIG6H
#pragma config WRTC = OFF       // Configuration Register Write Protection bit (Configuration registers not write-protected)
#pragma config WRTB = OFF       // Boot Block Write Protection bit (Boot block not write-protected)
#pragma config WRTD = OFF       // Data EEPROM Write Protection bit (Data EEPROM not write-protected)

// CONFIG7L
#pragma config EBTR0 = OFF      // Table Read Protection bit (Block 0 not protected from table reads executed in other blocks)
#pragma config EBTR1 = OFF      // Table Read Protection bit (Block 1 not protected from table reads executed in other blocks)

// CONFIG7H
#pragma config EBTRB = OFF      // Boot Block Table Read Protection bit (Boot block not protected from table reads executed in other blocks)



unsigned long tensao;
void delay_ms(long mili)
{
   while(mili > 0)
   {
      _delay(12000);//1ms com clock de 12mhz
      mili--;
   }
   // no caso do 18F o valor fica bem acima então é melhor montar essa funcão para que trabalhe bem
}


void Read_ADC (void)
{
tensao = 0; //globally defined as unsigned long
ADCON0bits.GO = 1; //inicia conversão
while (ADCON0bits.DONE == 1); //espera finalizar leitura
tensao = (ADRESH << 8) | ADRESL; //carrega valor
tensao = (tensao * 5000)/1023; //Vref está em milliVolts
}

//////////////////////////////////////////////////interrupção//////////////////////////////////////////////////////////////
void interrupt RS232(void)//vetor de interrupção
 {
     //não faz nada
     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;
     unsigned 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(long quant)
{//converte long para char

       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('\n');
                    escreve('\r');
          escreve(convert_char1);
          escreve(convert_char2);
          escreve(convert_char3);
          escreve(convert_char4);

}

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

void main(void)
{

    TRISA = 0XFF;//configura portA como entrada
    TRISB = 0X20;//configura portB  B5 (pino RX) como entrada
    PORTB = 0;  // limpar as portas que estão configuradas como saidas
    inicializa_RS232(9600,1);//modo de alta velocidade
    ADCON0 = 0X01;//liga modulo analogico digital e configura entrada de sinal para o pino RA0(AN0)
    ADCON1 = 0X00;// Vref- seta ao Vss e  Vref+ ao Vdd
    ADCON2 = 0b10111110;// justificado a direita// tempo de aquisição 20TAD // clk Fosc/64
    PEIE = 1;//habilita interrupção de perifericos do pic
    GIE = 1; //GIE: Global Interrupt Enable bit
    ANSEL = 0x01;//desabilita porta analogicas(para não atrapalhar recepção no pino)
    ANSELH = 0x00;//em alguns casos não funciona nem a interrupção de recepção.
    imprime("Voltagem em milivolts : \n\r");

while (1)
{
   Nop();
   Read_ADC();
   long_to_char(tensao);
   delay_ms(500);
}

}
A simulação:

Usando rs-232 no pic 18F13K22



/*
 *                          exemplo usando RS232 no MPlab XC8 para os modelos 18F
 *
 * Compilador : MPlabXC8
 * Microcontrolador: 18F13K22
 * Autor: aguivone
 * Versão: 1
 * Data :  12 de abril de 2013
 */

#include <stdio.h>
#include <string.h> //para usar funçoes de string deve se adicionar este header
#include <stdlib.h>
#include <xc.h>
#define _XTAL_FREQ 12000000     /* required for __delay_ms, __delay_us macros */


/////////////////////////////////////////////////////configuraçôes do pic //////////////////////////////////////////////////

// CONFIG1H
#pragma config FOSC = HS        // Oscillator Selection bits (HS oscillator)
#pragma config PLLEN = OFF      // 4 X PLL Enable bit (PLL is under software control)
#pragma config PCLKEN = ON      // Primary Clock Enable bit (Primary clock enabled)
#pragma config FCMEN = OFF      // Fail-Safe Clock Monitor Enable (Fail-Safe Clock Monitor disabled)
#pragma config IESO = OFF       // Internal/External Oscillator Switchover bit (Oscillator Switchover mode disabled)

// CONFIG2L
#pragma config PWRTEN = OFF     // Power-up Timer Enable bit (PWRT disabled)
#pragma config BOREN = OFF      // Brown-out Reset Enable bits (Brown-out Reset disabled in hardware and software)
#pragma config BORV = 19        // Brown Out Reset Voltage bits (VBOR set to 1.9 V nominal)

// CONFIG2H
#pragma config WDTEN = OFF      // Watchdog Timer Enable bit (WDT is controlled by SWDTEN bit of the WDTCON register)
#pragma config WDTPS = 32768    // Watchdog Timer Postscale Select bits (1:32768)

// CONFIG3H
#pragma config HFOFST = ON      // HFINTOSC Fast Start-up bit (HFINTOSC starts clocking the CPU without waiting for the oscillator to stablize.)
#pragma config MCLRE = OFF      // MCLR Pin Enable bit (RA3 input pin enabled; MCLR disabled)

// CONFIG4L
#pragma config STVREN = ON      // Stack Full/Underflow Reset Enable bit (Stack full/underflow will cause Reset)
#pragma config LVP = ON         // Single-Supply ICSP Enable bit (Single-Supply ICSP enabled)
#pragma config BBSIZ = OFF      // Boot Block Size Select bit (512W boot block size)
#pragma config XINST = OFF      // Extended Instruction Set Enable bit (Instruction set extension and Indexed Addressing mode disabled (Legacy mode))

// CONFIG5L
#pragma config CP0 = OFF        // Code Protection bit (Block 0 not code-protected)
#pragma config CP1 = OFF        // Code Protection bit (Block 1 not code-protected)

// CONFIG5H
#pragma config CPB = OFF        // Boot Block Code Protection bit (Boot block not code-protected)
#pragma config CPD = OFF        // Data EEPROM Code Protection bit (Data EEPROM not code-protected)

// CONFIG6L
#pragma config WRT0 = OFF       // Write Protection bit (Block 0 not write-protected)
#pragma config WRT1 = OFF       // Write Protection bit (Block 1 not write-protected)

// CONFIG6H
#pragma config WRTC = OFF       // Configuration Register Write Protection bit (Configuration registers not write-protected)
#pragma config WRTB = OFF       // Boot Block Write Protection bit (Boot block not write-protected)
#pragma config WRTD = OFF       // Data EEPROM Write Protection bit (Data EEPROM not write-protected)

// CONFIG7L
#pragma config EBTR0 = OFF      // Table Read Protection bit (Block 0 not protected from table reads executed in other blocks)
#pragma config EBTR1 = OFF      // Table Read Protection bit (Block 1 not protected from table reads executed in other blocks)

// CONFIG7H
#pragma config EBTRB = OFF      // Boot Block Table Read Protection bit (Boot block not protected from table reads executed in other blocks)


////////////////////////////////////////////////variaveis globais///////////////////////////////////////////////////////////
char caracter;
bit flag_interrupcao = 0;

//////////////////////////delay/////////////////////////////
void delay_ms(long mili)
{
   while(mili > 0)
   {
      _delay(5000);//1ms com clock de 20mhz
      mili--;
   }
   // no caso do 18F o valor fica bem acima então é melhor montar essa funcão para que trabalhe bem
}


///////////////////////////////////////////////////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;
   // 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)
}
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;
     unsigned 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 = 0xFF;//configura portB  B5 (pino RX) como entrada
   // PORTB = 0;  // limpar as portas que estão configuradas como saidas
    inicializa_RS232(9600,1);//modo de alta velocidade
    INTCON = 0xC0;//interrrupção global e de periferico habilitadas
    ANSEL = 0x00;//desabilita porta analogicas(para não atrapalhar recepção no pino)
    ANSELH = 0x00;//em alguns casos não funciona nem a interrupção de recepção.
    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
}

terça-feira, 9 de abril de 2013

Discadora completa - Avr


          Como funciona?

               Olá, hoje vou trazer um projeto completo e funcional de uma discadora para alarmes
 usando a discagem por pulsos,o funcionamento é bem simples basta deixar o jumper (ou uma chave on/off) fechado para configurar os telefones a serem discados e com a chave aberta  ao energizar o circuito ele já inicia a discagem(após 5s). assim basta ligar a alimentação do circuito a saida da sirene(que geralmente é 12V).Para configurar os telefones basta deixar o jumper fechado e enviar pela serial do seu pc (lembre se de usar o ci max 232,para não queimar os pinos de comunicação do seu microcontrolador) um comando com a seguinte formatação "<" + "memoria" + "digitos do telefone" + ">",onde "memoria" é o numero do registro (no máximo 3 registros) e os digitos é o numero do telefone(maximo de 15 digitos ).Por exemplo vamos supor que vc queira liguar para três numeros '111','222' e '333'então basta enviar os comandos "<0111>","<1222>" e "<2333>", mas se vc quer apenas 2 telefones faça assim: "<0111>","<1222>" e "<2>",então o circuito só vai ligar para 111 e 222.
  
          O esquemático:

        

       O circuito de simulação:


        O código fonte:


/*
 *                                       Discadora simples configurada via porta serial
 *   Version    : 1.0
 *   microcontrolador : AVR ATMega328
 *   descrição  : discadora por pulso(apenas liga não toca som), liga para 3 numeros
 *   criado: 08/04/2013 
 *   autor: aguivone moretti fogia
 */


#define F_CPU 20000000  // 20 MHz
#include <avr/io.h>
#include <avr/interrupt.h>
#include <stdio.h>
#include <util/delay.h>
  #include <avr/eeprom.h>//usado para acessar memoria

//funçoes basicas dos pinos
#define alterna_pino(x,y) x ^= _BV(y)   
#define liga_pino(x,y) x |= _BV(y)
#define desliga_pino(x,y) x &= ~(_BV(y))
#define estado_pino(x,y) ((x & _BV(y)) == _BV(y)) //o pino deve estar como entrada ,testa se está em nivel logico 1

#define PULSO    PB0  //no rele de discagem deve ser colocado um resistor de 470R para não curto circuitar a linha telefonica 
#define LED     PB2  //led piscante

int tel_num[3][15];//matriz pra guardar os numeros dos telefones
int disparo = 0;
int tempo_led = 0;

//variaveis para RS-232
unsigned char caracter;            //usado para pegar o caracter que chega pela serial
int  tam_buffer;                   //usado para contar o tamanho do buffer de recepção
volatile char rec_buffer ='S';     //usado para notificar que chegou dados
char buffer_serial[17];            //buffer da serial,tamanho máximo de 17 caracter


///////////////////////////////////////////////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;
/* habilita receiver and transmitter buffers */
  UBRR0H = (unsigned char)(velocidade>>8);
  UBRR0L = (unsigned char)velocidade;
  UCSR0B = 0X98;//deve se habilitar somente a interrupção de recepção para não travar o microcontrolador
  /* 8 bits , 1 stop bit, assincrono , sem paridade,modo nornal */
  UCSR0C = (1<<USBS0)|(3<<UCSZ00);
}

void escreve_caracter(unsigned char carac)//adaptado para funcionar com RS485
{  
            _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 
}

//////////////////////////interrupções requerida para usar a recepção serial///////////////////////////////////
ISR(USART_RX_vect)//aqui pega os dados da serial
{
  caracter = (char)UDR0;
  if(caracter == '>')
   {
        if(tam_buffer<17)//max do buffer/maximo de digitos 17
          {
                          buffer_serial[tam_buffer]=caracter;
                          tam_buffer++;
                          rec_buffer ='F';
                          buffer_serial[tam_buffer]='\0';
           }
           else
           {
            rec_buffer ='E';//tamanhoa incompativel
           }
   }
   else
   {
      if(rec_buffer == 'I')
       {
        buffer_serial[tam_buffer]=caracter;
        tam_buffer++;
        }
    }
  if(caracter == '<')//inicia a captura dos numeros do telefone
   {
   rec_buffer ='I';
   buffer_serial[0]='<';
   tam_buffer=1;
   }
}

void numero(int valor)// função usada para fazer a discagem
{
    int xis=0;
     while(xis < valor)
     {
      desliga_pino(PORTB,PULSO);
      _delay_ms(35);
      liga_pino(PORTB,PULSO);
      _delay_ms(65); 
      xis++;
     }
     _delay_ms(400);//tempo necessario entre cada digito
}

int char_to_int(char valor,int seleciona)//seleciona entre numero e pulsos
 {//converte caracter para numero
      int retorno = 100;//se retornar 100 é porque deu erro
      switch(valor)
         {
           case '0':
               {
                 if(seleciona == 1)
                 {
                  retorno = 10;//nos pulsos 10 = 0    
                  }
                  else
                  {
                  retorno = 0;
                  }              
               }break;
           case '1':
               {
                 retorno = 1;
               }break;
           case '2':
               {
                 retorno = 2;
               }break;
           case '3':
               {
                 retorno = 3;
               }break;
           case '4':
               {
                 retorno = 4;
               }break;
           case '5':
               {
                 retorno = 5;
               }break;
           case '6':
               {
                 retorno = 6;
               }break;
           case '7':
               {
                 retorno = 7;
               }break;
           case '8':
               {
                 retorno = 8;
               }break;
           case '9':
               {
                 retorno = 9;
               }break;
           case '*':
               {
                 retorno = 11;
               }break;
           case '#':
               {
                 retorno = 12;
               }break;

         }

         return(retorno);
 }  

//////////////////////////////////////////////função principal///////////////////////////////////////////
int main(void)
{
           DDRB = 0XFF;  //inicializa portB como saida;
           DDRD = 0X02;  //inicializa portD como entrada e D1 como saida;
           desliga_pino(PORTB,PULSO);//rele de discagem
           RS232_inicializa(9600);//inicializa serial com a velocidae de 9600bps
           sei();//habilita interrupções
           char gravado = 'n';
           _delay_ms(500);//espera estabilizar a tensão
           _EEGET(gravado,50);//pega valor da posição de memoria 50

           if(gravado == 'G')//memoria já foi gravado alguma vez
           {     
                  int x = 0;  
                  while(x<3)
                   {
                    int posi = x*15;//pega posição inicial   
                    int y=0;      
                    while(y < 15 )
                        {
                         _EEGET(tel_num[x][y],posi); //pega valores da memoria eeprom
                         y++;
                           posi++;
                         }
                     x++;
                    }
            }
        
           for(;;)
           {
              if(estado_pino(PIND,2))//checa pra ver se modo discadora habilitado
                      {//se estiver no modo discadora nem chega a serial para evitar que ruidos apague os dados
                        if(disparo < 2)//aqui define quantas vezes o circuito vai repetir as chamadas
                         {
                          int nume=0;
                                 while(nume<3)
                             {
                               _delay_ms(5000);//espera 5s antes de discar pois pode ter sido só um bip do alarme ; comentar na simulação pois leva muito tempo
                               alterna_pino(PORTB,LED);
                               int digito = 0;
                               liga_pino(PORTB,PULSO);
                               _delay_ms(200); //espera para dar linha para discar
                               while((digito<15)&&(tel_num[nume][digito]!= 100)&&(tel_num[nume][digito] != 0))//se maior que 15 e se valor null ou '>' manda parar
                               {
                                 numero(tel_num[nume][digito]);//disca numero
                                 escreve_caracter(tel_num[nume][digito] + '0'); //escreve o digito na serial
                                 digito++;
                               }
                               alterna_pino(PORTB,LED);     
                               _delay_ms(20000);//tempo de chamada  //comentar na simulação pois leva muito tempo
                               desliga_pino(PORTB,PULSO);
                               escreve_caracter('\n'); //pula linha
                               escreve_caracter('\r'); //retorna a linha inicial
                               nume++;                         
                             }
                          disparo++;  
                         }
                      }
                      else
                      {
                        if(rec_buffer == 'F')//tem dados pra ler na serial.
                                  {
                                      int xis=255; 
                                      xis = char_to_int(buffer_serial[1],0);
                                      if(xis < 3)//vetor valido
                                              {   
                                                  xis = 2; 
                                                  while(xis<tam_buffer)
                                                    {//tem que converte para char
                                                     tel_num[char_to_int(buffer_serial[1],0)][xis-2] = char_to_int(buffer_serial[xis],1);//copia e já converte em numero e pulsos
                                                      _EEPUT(((xis-2) +(char_to_int(buffer_serial[1],0)*15) ),tel_num[char_to_int(buffer_serial[1],0)][xis-2] );//endereço/dado para memoria
                                                     xis++;            
                                                    }
                                                     _EEPUT(((xis-2) +(char_to_int(buffer_serial[1],0)*15) ),100);
                                                    escreve_caracter('O');//ok dados gravados
                                                    _EEPUT(50,'G');
                                              }
                                              else
                                              {
                                                escreve_caracter('F');//dados invalidos
                                              }
                                      rec_buffer ='S';//indica que foi lido 
                                  }
                      } 
            tempo_led++;
            if(tempo_led > 20000)//tempo do led piscar
                {                             
                alterna_pino(PORTB,LED);
                tempo_led = 0;    
                }  
           }//for infinito
}//main

até a próxima veja também a  pagina no face : busque pelo perfil "Microcontroladores-C"