segunda-feira, 13 de fevereiro de 2017

Comunicando com o RTC DS3234 (com PIC16F887 )

        Olá, hoje vou demonstrar como usar o RTC(real time clock) DS3234, a maior
vantagem é possuir internamente no chip o cristal oscilador e um sensor de temperatura,
assim não precisa elementos externo para fazer funcionar o chip RTC. Funcionou tanto na
simulação quanto fisicamente.
   

O código fonte :
/*
 *                                   RTC DS3234 com pic - MPlab XC8
 *
 * Compilador : MPlabXC8
 * Microcontrolador: 16F887
 * Autor: Aguivone
 * Versão: 1
 * Data :  13/02/2017
 */
#include <stdio.h>
#include <string.h> //para usar funçoes de string deve se adicionar este header
#include <stdlib.h>
#define _XTAL_FREQ 20000000//usado para rotinas de  delays
#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)
unsigned char gucAlternaPino;
unsigned char gucSPI_lido;
//Defines
#define LED_STATUS                  RD0 
/*#define DS3234_SDO                 TRISCbits.TRISC7
#define DS3234_SDI                 TRISBbits.TRISB0
#define DS3234_SCK                 TRISBbits.TRISB1*/
#define DS3234_SS                  RC2 
//***********************************************************************************************************
// Registradores do chip DS3234 - endereço de leitura,para escrever basta somar 0X80 ao valor hexadecimal
//***********************************************************************************************************
#define DS3234_SEG               0X00 // registrador de segundos
#define DS3234_MIN               0X01 // registrador de minutos
#define DS3234_HORA              0X02 // registrador de horas
#define DS3234_DIA_SEMANA        0X03 // registrador de dia da semana
#define DS3234_DIA               0X04 // registrador de dia
#define DS3234_MES               0X05 // registrador de Mes
#define DS3234_ANO               0X06 // registrador de ano

#define DS3234_ALM1_SEG          0X07 // registrador Alarme 1 de segundos
#define DS3234_ALM1_MIN          0X08 // registrador Alarme 1 de minutos
#define DS3234_ALM1_HORA         0X09 // registrador Alarme 1 de horas
#define DS3234_ALM1_DIA_SEMANA   0X0A // registrador Alarme 1 de dia e dia da semana

#define DS3234_ALM2_MIN          0X0B // registrador Alarme 2 de minutos
#define DS3234_ALM2_HORA         0X0C // registrador Alarme 2 de horas
#define DS3234_ALM2_DIA_SEMANA   0X0D // registrador Alarme 2 de dia e dia da semana

#define DS3234_CONTROL           0X0E // registrador de controle
#define DS3234_STAT_CONTROL      0X0F // registrador de controle e status
#define DS3234_CONF_CRISTAL      0X10 // registrador do cristal interno

#define DS3234_TEMP_H            0X11 // registrador do sensor de temperatura parte alta(msb))
#define DS3234_TEMP_L            0X12 // registrador do sensor de temperatura parte baixa(lsb)

#define DS3234_S_RAM             0X18 // registrador da memoria S_RAM
#define DS3234_S_RAM_DADOS       0X18 // registrador da memoria S_RAM dados

//***********************************************************************************************************
// FUNÇÕES
//***********************************************************************************************************
//===========================================================================================================
// Função:     _configura_SPI
// Parâmetros: nenhum
// Retorno:    nenhum
// Descrição:  configura a parte de hardware que gerencia a SPI.
//===========================================================================================================
void inicializa_spi() //o timer 2 é usado para controlar a spi
{
    //RTC - DS3234
      SSPSTAT = 0B10000000;//modo metre / clock na borda de decida
      SSPCON = 0B00110010;//habilita os pinos da SPI/config clock como nivel altoe freq osc/64.   
}

/////////////////////////////////funçoes usadas pela uart //////////////////////////////////////////////////////
void inicializa_RS232(void)
{//// por padrão é usado o modo 8 bits e sem paridade, mas se necessario ajuste aqui a configuração desejada.
    //modo alta velocidade
    RCSTA = 0X90;//habilita porta serial,recepção de 8 bit em modo continuo,assincrono.
    TXSTA = 0X24;//modo assincrono,trasmissao 8 bits.
    //somente para cristal de 20Mhz.           
    SPBRG = 129;//9600    
 //   RCIE = 1;//habilita interrupção de recepção
    RCIE = 0;//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 cValor)
{
     TXIF = 0;//limpa flag que sinaliza envio completo.
     TXREG = cValor;
     __delay_us(1);//1us para evitar problemas de perder caracteres
     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 hex_to_int_char(char quant)
{//converte para inteiro e imprime
     unsigned char ucDez='0', ucUn='0';
    if(quant>=100)
    {//imprime centenas
       while(quant>=100)
       {
          quant -= 100;  
           ucDez++;  
       }
       escreve(ucDez);
       ucDez='0';//zera variavel novamente
    }
    while(quant>=10)
    {
      quant -= 10;  
      ucDez++;  
    }
    while(quant>=1)
    {
       quant -= 1; 
       ucUn++;  
    }
     escreve(ucDez);
     escreve(ucUn);
}
void hex_to_char(char quant)
{//converte para char e imprime
   unsigned char ucDez, ucUn;
    
    ucDez = quant/16;
    ucUn = quant%16;
    if(ucDez >= 10)
        ucDez = (ucDez-10) + 'A';
    else
        ucDez += '0';
    if(ucUn >= 10)
        ucUn = (ucUn-10) + 'A';
    else
        ucUn += '0';
          escreve(ucDez);
          escreve(ucUn);

}

unsigned char DS3234_LER_SPI(unsigned char registrador)
{ 
   unsigned char dado  = SSPBUF;//para limpar buffer 
   DS3234_SS  = 0;  // ativa SS(slave select)
   SSPBUF = registrador;//envia endereço
   while(!SSPSTATbits.BF);//espera completar envio de dados
   dado  = SSPBUF;//para limpar buffer e SSPSTATbits.BF
 //  for(unsigned char Cont=0;Cont<10;Cont++);  // Este tempo é necessário para finalizar  primeira transmissão
   SSPBUF = 0X00;//envia um informação qualquer para que os dados do slave chegue(pois ainda precisa de mais 8 clock)
   while(!SSPSTATbits.BF);//espera completar envio de dados
   dado  = SSPBUF;//para limpar buffer e SSPSTATbits.BF
   DS3234_SS  = 1;//desabilita chip   
  return(dado);//retorna valor
}
void DS3234_ESCREVE_SPI(unsigned char endereco,unsigned char valor)
{
    unsigned char dado  = SSPBUF;//para limpar buffer 
    endereco = endereco|0X80;//pronto pra escrever
    DS3234_SS  = 0;  // ativa SS(slave select)
    SSPBUF = endereco;//opcode que sinaliza que quer deixar um dado
    while(!SSPSTATbits.BF);//espera completar envio de dados
    dado  = SSPBUF;//para limpar buffer e SSPSTATbits.BF
 //   for(unsigned char Cont=0;Cont<10;Cont++);  // Este tempo é necessário para finalizar  primeira transmissão
    SSPBUF = valor;//envia os dados que será colocado no registrador
    while(!SSPSTATbits.BF);//espera completar envio de dados
    dado  = SSPBUF;//para limpar buffer e SSPSTATbits.BF
    DS3234_SS  = 1;//desabilita chip
}

void inicializa_RTC()
{    
    DS3234_ESCREVE_SPI(DS3234_CONTROL,0X80);//80= desliga saida do oscilador , SQ wave @1hz, Alarme desabilitados
    DS3234_ESCREVE_SPI(DS3234_ANO,0X17);//25/08/2017 - 15:05
    DS3234_ESCREVE_SPI(DS3234_MES,0X08);//colocar os valores sempre em hexadecimal
    DS3234_ESCREVE_SPI(DS3234_DIA,0X25);
    DS3234_ESCREVE_SPI(DS3234_HORA,0X15);
    DS3234_ESCREVE_SPI(DS3234_MIN,0X05);
    
}
//////////////////////////////////////////////////////Rotina principal///////////////////////////////////////////////////////////////

void main(void)
{
    TRISA = 0XDF;   //somente pino 5 é saida
    TRISB = 0;   //configura como saida
    TRISC = 0X10;   //somete C4 é entrada(SDI))
    TRISD = 0;   //configura como saida
    TRISE = 0XFF;   //configura como entrada
    PORTA = 0;
    PORTB = 0;  // limpar as portas que estão configuradas como saidas
    PORTC = 0;
    PORTD = 0;
    PORTE = 0;
    inicializa_RS232();
    inicializa_spi();
    GIE = 0; //desliga interrupções 
    ADCON0 = 0X00;//desabilita modulo ADC
    ADCON1 = 0X07;//desliga modulo comparador
    ANSEL = 0x00;   // Disable todas as portas analogicas
    CM1CON0 = 0;
    CM2CON0 = 0;
    long Pisca = 200;//tempo qualquer 
    __delay_ms(50);
    imprime("Usando : RTC_DS3234 \r\n");
    inicializa_RTC();
    for(;;)    
    {        
        if(Pisca == 0)
            {
                 if(gucAlternaPino == '0')
                {
                  LED_STATUS=0;
                  gucAlternaPino = '1';
                  gucSPI_lido = DS3234_LER_SPI(DS3234_HORA);                  
                  hex_to_char( gucSPI_lido);
                  escreve(':');
                  gucSPI_lido = DS3234_LER_SPI(DS3234_MIN);
                  hex_to_char( gucSPI_lido);
                  escreve(':');
                  gucSPI_lido = DS3234_LER_SPI(DS3234_SEG);
                  hex_to_char( gucSPI_lido);
                  escreve('-');
                  escreve('>');
                  gucSPI_lido = DS3234_LER_SPI(DS3234_DIA);
                  hex_to_char( gucSPI_lido);
                  escreve('/');
                  gucSPI_lido = DS3234_LER_SPI(DS3234_MES);
                  hex_to_char( gucSPI_lido);
                  escreve('/');
                  gucSPI_lido = DS3234_LER_SPI(DS3234_ANO);
                  hex_to_char( gucSPI_lido);  
                 imprime("\r\n Temperatura :");//para temperatura negativas é preciso fazer 
                  gucSPI_lido = DS3234_LER_SPI(DS3234_TEMP_H);//alguns tratamentos aqui vamos demontrar apena para uma escala acima de 0
                  hex_to_int_char( gucSPI_lido); 
                  // praticamente não vai fazer diferença
                  // gucSPI_lido = DS3234_LER_SPI(DS3234_TEMP_L);
                  //hex_to_int_char( gucSPI_lido);
                  imprime("\r\n");
                }
                else
                {
                  LED_STATUS=1;
                  gucAlternaPino = '0';
                } 
                 Pisca = 200;
            }
        else
        {
           Pisca--;
           __delay_ms(1);
        }
            
    }//loop infinito

}

A simulação ficou assim:


sexta-feira, 10 de fevereiro de 2017

Usando o ESP8266 como cliente(acess point) - IP fixo via WIFI - Parte2

        Olá, as vezes não queremos configurar um dispositivo a ser conectado no modulo ESP8266, então a solução é colocar como um ponto de acesso("client server"), assim basta conectar a rede WIFI criada pelo modulo e digitar seu ip para ter acesso ao dispositivo.
        No código abaixo feito na IDE do Arduíno a conexão funcionou muito bem e o IP fixo também, porém ao colocar a senha e o nome do dispositivo "não funcionou",  apesar da documentação da lib do arduino dizer para usar estas funções, na pratica isso não foi verdade("ainda não sei o por que?mas quando eu tiver a resposta vou postar nos comentários", se alguém souber por favor dê um help ai), o nome do WIFI não mudou e nem pediu senha.Foi resolvido este problema do nome da wifi e da senha apenas colocando uma senha maior que 8 caracteres.

O código fonte:


#include <ESP8266WiFi.h>
#include <ESP8266WebServer.h>//caso use o modo servidor

WiFiServer server(80);//usa porta 80

void setup() 
{
  setupWiFi();  
}

void loop() 
{
  // checa se tem algum dispositivo conectado!
  WiFiClient client = server.available();
  if (!client) 
  {return;}

  // Lê a primeir linha dos dados recebidos pelo pacote ethernet
  String req = client.readStringUntil('\r');
  client.flush(); 

  // prepara pagina ehtenet
  String s = "HTTP/1.1 200 OK\r\n";
  s += "Content-Type: text/html\r\n\r\n";
  s += "<!DOCTYPE HTML>\r\n<html>\r\n";
  s += "<br> você está conectado 2 <br>";
  s += "</html>\n";
  // envia a pagina
  client.print(s);
  delay(1);
  //cliente desconectado
  // a cada requisição a pagina é enviada e o cliente é desconectado
}

void setupWiFi()
{
    //////////////////////
    // definições da WiFi  //
    //////////////////////
  const char*  WiFi_Senha = "123456789";//senha que você quer usar(deve ser em branco(aberta) ou maior que 8 caráteres,senão não funciona e não troca o nome da wifi)

  const char*  WiFi_Nome = "Microcontroladores-c";//nome que você quer dar a sua rede 
  IPAddress ip(192,168,50,4);//ok
  IPAddress gateway(192,168,50,1);//ok
  IPAddress subnet(255,255,255,0);//ok
  //////inicializa a wifi//////////////////////////////////////////////  
  uint8_t mac[WL_MAC_ADDR_LENGTH];
  WiFi.softAPmacAddress(mac);//mac qualquer pra testar
  WiFi.softAPConfig(ip, gateway, subnet);
 // WiFi.mode(WIFI_AP);//modo acess point(cliente)  
   WiFi.mode(WIFI_AP_STA);//modo acess point e servidor
  WiFi.softAP(WiFi_Nome, WiFi_Senha); 
  WiFi.begin(); 
  server.begin();
}

    Como estamos usando a porta 80 não precisa digitar a porta, apenas IP no dispositivo
que está sendo conectado a placa.veja na foto a imagem da tela de meu smartphone.




quinta-feira, 2 de fevereiro de 2017

Usando o modulo ESP8266 12+ via interface Arduíno - WIFI - Parte1

         Olá, hoje vou mostrar um exemplo simples de como criar um servidor web WIFI sem usar arduino,PIC,ATmega ou qualquer outro microcontrolador exceto o que já vem na placa do modulo.Vou dividir a experiencia desse modulo em 2 ou 3 artigos.
         Recentemente comprei uns módulos  ESP8266 12+ por incrível que pareça paguei 15 reais(ou seja o mesmo preço de um microcontrolador porem com a wifi já integrada), a "cara" da placa é esta:
         De cara o primeiro desafio é soldar essa placa num soquete para que se possa colocar na protoboard, para isto tive que fazer essa "aranha"! veja :


         Dentre as complicações estão:
->  Pinos com furos pequenos(não dá pra por barra de pinos nele).
->  Os pinos traseiros impede de se colocar na protoboard.
->  E por ultimo o nomes das portas não seguem um padrão sequencial.
-> necessidade de configurar 2 modos de operação, um pra gravação e outro para funcionamento.
         Mas esses destalhes não ofuscam em nada as vantagem deste "pequeno notável", com ele é possível fazer leituras analogicas de tensão , leitura digital, acionar os pinos para integrar com outros dispositivo, comunicação serial(rs232) e Spi (com essas comunicações pode se implementar seu próprio protocolo de comunicação com outros microcontroladores,se necessario, o que substituem os "pobres" e "massantes " comandos AT's).
        Para programar diretamente o chip pode-se usar o software LUA(com desenvolvimento inclusive no Brasil) , interface do Arduino e por ultimo os comandos AT's(já discutido aqui no blog em um exemplo).Eu particularmente optei pela IDE do arduino por ser mais divulgado e consolidado pela comunidade de hobbystas e iniciantes em programação embarcada.
        A configuração do hardware e explicação de como configurar o ambiente de programação pode ser visto clicando aqui! apesar de que a configuração do hardware lá é para uso com o bootloder deles é possível usar a configuração padrão alterando as ligações conforme esta figura que foi retirado do site "Laboratório de garagem" e ajustado por mim:

         Note que o resistor de 10k é para evitar curto circuito caso se deseje usar aquele pino como saída,claro que minha montagem não ficou bonitinha igual essa da imagem, vê ai o resultado:

        Lembrando que este módulo funciona com 3,3V e a maioria dos conversores usb/serial é de 5V, então devemos montar um divisor resitivo para não queimar o pino rx do modulo, e colocar um resitor de 1,2K(deve ficar parecido com este ).
        Depois de tudo montado o código foi algo simples e rápido uma vez que o arduino tem muitas bibliotecas prontas.A página Web ficou assim :
            Para acessar a página pelo celular primeiro você deve usar o dispositivo como roteador wifi, dai pela porta serial do pc vc pega o ip recebido pelo ESP8266 e digita no buscador de internet, então basta pressionar os botões e ver o resultado.

O Código fonte  :

/*
 * Nesta aplicação o hardware se conecta a uma rede wi fi e envia os staus a um pc pela porta serial(rs232)
 */

#include <ESP8266WiFi.h>
//para conectar a um roteador basta colocar o nome da rede e a senha da wifi do roteador(mas não testei isso!). 
const char* ssid = "AndroidAP"; // para conectar no celular  - nome da rede wifi do celular 
const char* password = "ocno33801";//senha gerada pelo android - senha da rede wifi do celular
//senha que você quer usar(deve ser em branco(aberta) ou maior que 8 caráteres,senão não funciona e não troca o nome da wifi) 
WiFiServer server(80);//escolhe a porta 80
//const int LED_STATUS = 14; // led de status
const int LED_CONEX = 16; // led de conexão
const int LED_1 = 5; 
const int LED_2 = 4; 
unsigned int gui_pisca=0;
 
void setup() {
  Serial.begin(115200);
  delay(10);
 
  // inicializa e configura oas pinos que serão utilizados
  
 // pinMode(LED_STATUS, OUTPUT);//configura como saida 
  //digitalWrite(LED_STATUS, 0);//desliga pino   
  pinMode(LED_CONEX, OUTPUT);
  digitalWrite(LED_CONEX, 0);
  pinMode(LED_1, OUTPUT);//configura como saida 
  digitalWrite(LED_1, 0);//desliga pino   
  pinMode(LED_2, OUTPUT);
  digitalWrite(LED_2, 0);
  
  // Escreve na porta serial
  Serial.println();
  Serial.print("Conectado a rede wifi : ");
  Serial.println(ssid);
  Serial.println();
    
  WiFi.begin(ssid, password);//inicia conexão
  
  while (WiFi.status() != WL_CONNECTED) //fica esperando uma conexão
  {
    delay(500);
    Serial.print(".");
  }
  
  Serial.println("");
  Serial.println("Conexão realizada com sucesso");
  digitalWrite(LED_CONEX, 1);
  // inicia o servidor
  server.begin();
  Serial.println("Servidor iniciado!");
  Serial.println(WiFi.localIP());//mostra qual o ip
}
 //rotina pricipal da aplicação
void loop() 
{
  WiFiClient client = server.available();
  if (!client) { 
      if(WiFi.status() != WL_CONNECTED) //se desconectado da wifi
        {
          digitalWrite(LED_CONEX, 0);
          digitalWrite(LED_1, 0);
          digitalWrite(LED_2, 0);
        }   
    return;
  }  
  //novo pacote chegou!
  while(!client.available()){
    delay(1);//fica esperando chegar dados
  }
  
  String req = client.readStringUntil('\r');//pegas tudo que estiver na string até o caracter de retorno('\r') 
  Serial.println(req); // mostra o conteudo na serial
  client.flush();//limpa buffer de recepção
 
  String buf = "";//cria uma string para colocar a pagina web
  //vai adicionando linhas a string criada
  buf += "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n<!DOCTYPE HTML>\r\n<html>\r\n";
  buf += "<h3> Servidor Web com ESP8266 </h3>";
  buf += "<h4> Usando wifi </h4>";
  buf += "<p>Led 1 <a href=\"?function=led1_on\"><button>ON</button></a> <a href=\"?function=led1_off\"><button>OFF</button></a></p>";
  buf += "<p>Led 2 <a href=\"?function=led2_on\"><button>ON</button></a> <a href=\"?function=led2_off\"><button>OFF</button></a></p>";  
  buf += "</html>\n";
  client.print(buf);//envia os dados pela wifi
  client.flush();  
  ///avalia o retorno da pagina HTTP
  if (req.indexOf("led1_on") != -1)
    digitalWrite(LED_1, 1);
  else if (req.indexOf("led1_off") != -1)
    digitalWrite(LED_1, 0);
  else if (req.indexOf("led2_on") != -1)
    digitalWrite(LED_2, 1);
  else if (req.indexOf("led2_off") != -1)
    digitalWrite(LED_2, 0);
  else {
     //fim de recpção de dados
     ///fecha socket e irá voltar ao inicio do loop,ou seja cria uma novo socket e reenvia a pagia web
    client.stop();    
  }  
 
    
}
         


     

quarta-feira, 25 de janeiro de 2017

Usando o Timer0 do 18F4550 no XC8

/*
 *                                              Usando o timer0 do  18F4550
 *
 * Compilador : MPlabXC8.
 * Microcontrolador: 18F4550. 
 * Autor: aguivone.
 * Versão: 1.
 * Data :  25 de janeiro de 2017.
 */ 
#include <xc.h>
#define _XTAL_FREQ 20000000    //  
/* COMPILER DIRECTIVES FOR CHIP CONFIGURATION BITS*/
#include "Wiznet.h"
// CONFIG1L
#pragma config PLLDIV = 4      // depois testar se não vai dar problemas com o ADC e wiznet
#pragma config CPUDIV = OSC1_PLL2// System Clock Postscaler Selection bits ([Primary Oscillator Src: /1][96 MHz PLL Src: /2])
#pragma config USBDIV = 1       // USB Clock Selection bit (used in Full-Speed USB mode only; UCFG:FSEN = 1) (USB clock source comes directly from the primary oscillator block with no postscale)

// CONFIG1H
#pragma config FOSC = HS //HSPLL_HS  //HS para cristal de 16 ou 20mhz(habilitei o pll interno mas para este exemplo nem precisava podia usar somete o HS)
#pragma config FCMEN = OFF      // Fail-Safe Clock Monitor Enable bit (Fail-Safe Clock Monitor disabled)
#pragma config IESO = OFF       // Internal/External Oscillator Switchover bit (Oscillator Switchover mode disabled)

// CONFIG2L
#pragma config PWRT = ON        // Power-up Timer Enable bit (PWRT enabled)
#pragma config BOR = ON        // Brown-out Reset Enable bits (Brown-out Reset disabled in hardware and software)
#pragma config BORV = 2         // Brown-out Reset Voltage bits (Setting 1 2.79V)
#pragma config VREGEN = OFF     // USB Voltage Regulator Enable bit (USB voltage regulator disabled)

// CONFIG2H
#pragma config WDT = OFF        // Watchdog Timer Enable bit (WDT disabled (control is placed on the SWDTEN bit))
#pragma config WDTPS = 32768    // Watchdog Timer Postscale Select bits (1:32768)

// CONFIG3H
#pragma config CCP2MX = OFF     // CCP2 MUX bit (CCP2 input/output is multiplexed with RB3)
#pragma config PBADEN = OFF     // PORTB A/D Enable bit (PORTB<4:0> pins are configured as digital I/O on Reset)
#pragma config LPT1OSC = OFF    // Low-Power Timer 1 Oscillator Enable bit (Timer1 configured for higher power operation)
#pragma config MCLRE = ON      // MCLR Pin Enable bit (RE3 input pin enabled; MCLR pin disabled)

// CONFIG4L
#pragma config STVREN = ON      // Stack Full/Underflow Reset Enable bit (Stack full/underflow will cause Reset)
#pragma config LVP = OFF        // Single-Supply ICSP Enable bit (Single-Supply ICSP disabled)
#pragma config ICPRT = OFF      // Dedicated In-Circuit Debug/Programming Port (ICPORT) Enable bit (ICPORT disabled)
#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 (000800-001FFFh) is not code-protected)
#pragma config CP1 = OFF        // Code Protection bit (Block 1 (002000-003FFFh) is not code-protected)
#pragma config CP2 = OFF        // Code Protection bit (Block 2 (004000-005FFFh) is not code-protected)
#pragma config CP3 = OFF        // Code Protection bit (Block 3 (006000-007FFFh) is not code-protected)

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

// CONFIG6L
#pragma config WRT0 = OFF       // Write Protection bit (Block 0 (000800-001FFFh) is not write-protected)
#pragma config WRT1 = OFF       // Write Protection bit (Block 1 (002000-003FFFh) is not write-protected)
#pragma config WRT2 = OFF       // Write Protection bit (Block 2 (004000-005FFFh) is not write-protected)
#pragma config WRT3 = OFF       // Write Protection bit (Block 3 (006000-007FFFh) is not write-protected)

// CONFIG6H
#pragma config WRTC = OFF       // Configuration Register Write Protection bit (Configuration registers (300000-3000FFh) are not write-protected)
#pragma config WRTB = OFF       // Boot Block Write Protection bit (Boot block (000000-0007FFh) is not write-protected)
#pragma config WRTD = OFF       // Data EEPROM Write Protection bit (Data EEPROM is not write-protected)

// CONFIG7L
#pragma config EBTR0 = OFF      // Table Read Protection bit (Block 0 (000800-001FFFh) is not protected from table reads executed in other blocks)
#pragma config EBTR1 = OFF      // Table Read Protection bit (Block 1 (002000-003FFFh) is not protected from table reads executed in other blocks)
#pragma config EBTR2 = OFF      // Table Read Protection bit (Block 2 (004000-005FFFh) is not protected from table reads executed in other blocks)
#pragma config EBTR3 = OFF      // Table Read Protection bit (Block 3 (006000-007FFFh) is not protected from table reads executed in other blocks)

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

// #pragma config statements should precede project file includes.
// Use project enums instead of #define for ON and OFF.

unsigned int guiPisca;
unsigned char gucAlternaPino;
//Defines
#define LED_STATUS                 LATDbits.LATD0

//***********************************************************************************************************
// FUNÇÕES
//***********************************************************************************************************

//===========================================================================================================
// Função:     _inicializa_timer0
// Parâmetros: nenhum
// Retorno:    nenhum
// Descrição:  configura o timer0.
//===========================================================================================================
void inicializa_timer0() //
{         
    TMR0IP  = 1;//configura timer0 como alta prioridade 
    //T0CON = 0X80;//habilita timer/modo 16bits/clock interno/prescaler dividido por 2
    T0CON = 0XC5;//habilita timer/modo 8bits/clock interno/prescaler dividido por 64
    TMR0IE  = 1; // habilita interrupção de estouro do timer.
    TMR0 = 250;//zera registrador de contagem
}


//===========================================================================================================
// Checagem de Interrupção 
//===========================================================================================================
void interrupt interrupcao(void)//vetor de interrupção
 {
    if(TMR0IF)//interrupçao de timer0
    {    //interrupção do timer0 - estoura quando atinge 255(0XFF) - 8bits
        //interrupção do timer0 - estoura quando atinge 65536(0XFF) - 16bits
        //updateWizTimer();
        TMR0 = 178;//reinicia timer com o valor calculado para 1ms 
        TMR0IF = 0;       
        if(guiPisca>0)
        {guiPisca--;}
    }
    
 }
void main(void) 
{
    TRISB = 0X00;   //Saida B1 e B0
    TRISA = 0XFF;   //
    TRISD = 0X00;   //saidas
    TRISE = 0X00;   //saidas
    TRISC = 0X10;   //todas são entradas//somente C4 é entrada (SDI)
    ADCON0 = 0x00;//configura os pinos para portas digitais(ADC OFF)
    ADCON1 = 0x0F;//configura os pinos para portas digitais(ADC OFF)    
    INTCON = 0XE0;//habilita interupção global , interrupção de periferico e
    inicializa_timer0();  
    
    for(;;)    
       {
        if(guiPisca == 0)
            {
                 if(gucAlternaPino == '0')
                {
                  LED_STATUS=0;
                  gucAlternaPino = '1';
                }
                else
                {
                  LED_STATUS=1;
                  gucAlternaPino = '0';
                }
                guiPisca = 250;//250ms               
            }
       }
}

Configurando fuses do oscilador do 18F4550 - avaliação de desempenho de clock

      Olá, minha motivação para este exemplo se deve ao fato de ter, perdido muito tempo tentando descobri por que meu código não rodava no microcontrolador apesar de estar tudo correto com os registradores configurados,tanto que no simulador "proteus" tudo funcionava,mas na protoboard nada funcionava(era como se estivesse resetado).
       Depois de vários testes descobri que meu erro foi habilitar o PLL(pois eu queria que ele rodasse mais rápido),O PLL é um recurso pra elevar a frequencia de trabalho do microcontrolador, mas se for configurado errado o microcontrolador nem funciona devido o clock exceder o potencial do hardware.
       Vamos a um exemplo, que foi o que aconteceu comigo, coloquei um clock de 20Mhz dai configurei o PLL para não divir o clock vindo do prescaler logo isso excede a capacidade de clock e então o microcontrolador não funciona,observe que o simulador não alerta para este tipo de erro o que leva a algumas pessoas a se descabelar com sua aplicação(pois mesmo o código estando correto o microcontrolador não funciona),uma vez me lembro de um seguidor do blog ter um problema parecido e na época eu não soube explicar o por que, mas agora diante deste problema resolvi investigar pra trazer a vcs um "estudo de caso".
        Para validar minhas suspeitas montei um código simples que apenas alterna um dos pinos do microcontrolador,pois segundo o datasheet essa operação gasta um ciclo de maquina(ou seja o sinal de saída terá a metade a frequência do clock interno),inicialmente eu mandei liga e desligar a porta do microcontrolador em C pra minha surpresa o sinal em nível alto era maior que o em nível baixo,então mandei que setasse apenas um pino e agora o sinal de saída foi simétrico(ou seja em C quando se seta a porta o compilador XC8 deve executar outras rotinas que o faz ter esse delay), Então para não ter essas influencia do compilador resolvi fazer o código em assembly(é então o sinal ficou fiel ao clock sem delay), mas como o laço for gasta alguns ciclo de maquina, resolvi executar o processo de alternar o led 3 vezes antes de retornar o laço "for".O resultado é visto nas figuras a seguir com um clock interno de 2,5Mhz.

Figura 1 - sinal completo.

Figura 2 - detalhe dos sinais.


        Veja que o postcaler esta para 1 ou seja não irá dividir o clock de saída(assim teremos qual o clock máximo que vamos ter j[a descontados a divisão por 4 do PIC), com esse procedimento podemos esta realizando algo conhecido como "overclock" ou seja forçar o hardware a trabalhar no limite, dentre os possíveis consequências podemos ter imprecisões nos conversores ADC,ou erros nas comunicações serial rs232,SPI, e outros,Então minha sugestão é testar para saber se realmente essas frequências de trabalho mais elevadas não se torne um problema para sua aplicação.

Os resultados encontrados para as configurações foram:

Usando um cristal de 20MHZ  sem o PLL ligado
   
#pragma config FOSC = HS // 2,5 MHZ

 Usando um cristal de 20MHZ  com o PLL ligado

#pragma config PLLDIV = 2  - para o valor 1 e 0 o microcontrolador atinge seu limete e não funciona mais    
#pragma config FOSC = HSPLL_HS // 0MHZ  - fica resetado.

#pragma config PLLDIV = 3    
#pragma config FOSC = HSPLL_HS // 20MHZ -- > 8X mais rapido

#pragma config PLLDIV = 4    
#pragma config FOSC = HSPLL_HS // 15MHZ -- > 6X mais rapido

#pragma config PLLDIV = 5    
#pragma config FOSC = HSPLL_HS // 12MHZ -- > 4,8X mais rapido


O código fonte :


/*
 *                                              Avaliação de desempenho 18F4550
 *
 * Compilador : MPlabXC8.
 * Microcontrolador: 18F4550. 
 * Autor: Aguivone.
 * Versão: 1.
 * Data :  24 de janeiro de 2017.
 *  
 * Neste exemplo vou demontrar como configurar o oscilador para usar o pll do pic(eleva seu clock e definir o quão mais rápido ele se tornara)
 */
#include <xc.h>
#define _XTAL_FREQ 20000000    // 
// CONFIG1L
#pragma config PLLDIV = 5     // 1X
#pragma config CPUDIV = OSC1_PLL2// System Clock Postscaler Selection bits ([Primary Oscillator Src: /1][96 MHz PLL Src: /2])
#pragma config USBDIV = 1       // USB Clock Selection bit (used in Full-Speed USB mode only; UCFG:FSEN = 1) (USB clock source comes directly from the primary oscillator block with no postscale)

// CONFIG1H
#pragma config FOSC = HSPLL_HS  //HS para cristal de 16 ou 20mhz(habilitei o pll interno mas para este exemplo nem precisava podia usar somete o HS)
#pragma config FCMEN = OFF      // Fail-Safe Clock Monitor Enable bit (Fail-Safe Clock Monitor disabled)
#pragma config IESO = OFF       // Internal/External Oscillator Switchover bit (Oscillator Switchover mode disabled)

// CONFIG2L
#pragma config PWRT = ON        // Power-up Timer Enable bit (PWRT enabled)
#pragma config BOR = ON        // Brown-out Reset Enable bits (Brown-out Reset disabled in hardware and software)
#pragma config BORV = 2         // Brown-out Reset Voltage bits (Setting 1 2.79V)
#pragma config VREGEN = OFF     // USB Voltage Regulator Enable bit (USB voltage regulator disabled)

// CONFIG2H
#pragma config WDT = OFF        // Watchdog Timer Enable bit (WDT disabled (control is placed on the SWDTEN bit))
#pragma config WDTPS = 32768    // Watchdog Timer Postscale Select bits (1:32768)

// CONFIG3H
#pragma config CCP2MX = OFF     // CCP2 MUX bit (CCP2 input/output is multiplexed with RB3)
#pragma config PBADEN = OFF     // PORTB A/D Enable bit (PORTB<4:0> pins are configured as digital I/O on Reset)
#pragma config LPT1OSC = OFF    // Low-Power Timer 1 Oscillator Enable bit (Timer1 configured for higher power operation)
#pragma config MCLRE = ON      // MCLR Pin Enable bit (RE3 input pin enabled; MCLR pin disabled)

// CONFIG4L
#pragma config STVREN = ON      // Stack Full/Underflow Reset Enable bit (Stack full/underflow will cause Reset)
#pragma config LVP = OFF        // Single-Supply ICSP Enable bit (Single-Supply ICSP disabled)
#pragma config ICPRT = OFF      // Dedicated In-Circuit Debug/Programming Port (ICPORT) Enable bit (ICPORT disabled)
#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 (000800-001FFFh) is not code-protected)
#pragma config CP1 = OFF        // Code Protection bit (Block 1 (002000-003FFFh) is not code-protected)
#pragma config CP2 = OFF        // Code Protection bit (Block 2 (004000-005FFFh) is not code-protected)
#pragma config CP3 = OFF        // Code Protection bit (Block 3 (006000-007FFFh) is not code-protected)

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

// CONFIG6L
#pragma config WRT0 = OFF       // Write Protection bit (Block 0 (000800-001FFFh) is not write-protected)
#pragma config WRT1 = OFF       // Write Protection bit (Block 1 (002000-003FFFh) is not write-protected)
#pragma config WRT2 = OFF       // Write Protection bit (Block 2 (004000-005FFFh) is not write-protected)
#pragma config WRT3 = OFF       // Write Protection bit (Block 3 (006000-007FFFh) is not write-protected)

// CONFIG6H
#pragma config WRTC = OFF       // Configuration Register Write Protection bit (Configuration registers (300000-3000FFh) are not write-protected)
#pragma config WRTB = OFF       // Boot Block Write Protection bit (Boot block (000000-0007FFh) is not write-protected)
#pragma config WRTD = OFF       // Data EEPROM Write Protection bit (Data EEPROM is not write-protected)

// CONFIG7L
#pragma config EBTR0 = OFF      // Table Read Protection bit (Block 0 (000800-001FFFh) is not protected from table reads executed in other blocks)
#pragma config EBTR1 = OFF      // Table Read Protection bit (Block 1 (002000-003FFFh) is not protected from table reads executed in other blocks)
#pragma config EBTR2 = OFF      // Table Read Protection bit (Block 2 (004000-005FFFh) is not protected from table reads executed in other blocks)
#pragma config EBTR3 = OFF      // Table Read Protection bit (Block 3 (006000-007FFFh) is not protected from table reads executed in other blocks)

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

void main(void) 
{
    TRISB = 0X00;   //saída B1 e B0
    TRISA = 0XFF;   //
    TRISD = 0X00;   //saídas
    TRISE = 0X00;   //saídas
    TRISC = 0X10;   //todas são entradas//somente C4 é entrada (SDI)
    ADCON0 = 0x00;//configura os pinos para portas digitais(ADC OFF)
    ADCON1 = 0x0F;//configura os pinos para portas digitais(ADC OFF)
    for(;;)    
       {
        asm("BSF  PORTD,0");
        asm("BCF  PORTD,0");//para garantir que cada instrução leve 1 ciclo de maquina
        asm("BSF  PORTD,0");// ou seja a frequência interna é igual a metade  da frequência do sinal 
        asm("BCF  PORTD,0");
        asm("BSF  PORTD,0");
        asm("BCF  PORTD,0");       
       }
}

     

terça-feira, 6 de dezembro de 2016

Conversor de 12V para 24V com microcontrolador pic18F13K22

         Olá, hoje o exemplo será de um conversor DC/DC (STEP UP) elevador de tensão, o projeto é dividido em 2 etapas;montagem do circuito de elevação DC e a implementação do firmware de controle.
          O "coração do circuito" é basicamente oc componentes L1,C1 e D1 além do componente de chaveamento que pode ser transistor(aquece mais) ou mosfet. Veja a figura a seguir para melhor compreensão:

         O circuito é bem simples de se implementar, provavelmente o mais trabalhoso será encontrar o indutor, dai se tem 3 escolhas : arrancar um indutor de uma fonte chaveada usada(sucata), este indutor pode ser feito com fios de cobre esmaltado, a bitola do fio vai depender da corrente a ser manuseada pelo circuito , e por ultimo ainda encontrar um indutor comercial que se aproxime do indutor desejado.Não vou entrar em muitos detalhes de dimensionamento do circuito pois isso foge da proposta do blog que é apenas montar o código-fonte.
          No microcontrolador PIC18F13K22 o pinos usado foram pino 5 (usado para pwm), pino 8(ref_tensão), pino 15 (para led que indica falha) e pino16 (indica o status, fica piscando).Este código pode ser transferido para qualquer outro modelo de microcontrolador  que tenha PWM.
          Vamos então agora para o código fonte :

Código-fonte principal :


/*
 *                 Conversor DC/DC
 *
 * Compilador :      MPlabXC8
 * Microcontrolador: 18F13K22
 * Autor:            Aguivone
 * Versão:           1
 * Data de criação:  19/05/2015.
 * Retomada do projeto:  30/11/2016
 * Primeira versão estavel:  06/11/2016
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h> //para usar funçoes de string deve se adicionar este header
#include <xc.h>
#include "config_cpu.h"
#include "conv_adc.h"

// configuração de frequencia de PWM  
#define PWM_20KHZ_CLK16        inicializa_PWM1(1, 200, 1)  
#define _XTAL_FREQ 16000000//usado para rotinas de  delays

#define VAL_MAX_PWM   70 //  valor max de pwm  pra não sobreaquecer demais a bobina
#define VAL_MIN_PWM   5  // valor minimo de pwm  

#define MAX_CORRENTE   1024//só pra ignorar por enquanto // em unidades do conversor
//para calcular a tensão faça : (tensão desejada)/0,05371 ;
// o valor deve ser inteiro(sem virgula) por exemplo;
//para 12V temos : 12/0,05371 = 223,4 então será 223 ou 224.
#define DDP_TRAB       450// para 24V (depende do divisor resistivo)

#define LED_STATUS                      LATCbits.LATC0
#define LED_FALHA                       LATCbits.LATC1

//************************************************************************************/
//VARIAVEIS GLOBAIS
//************************************************************************************/
//parametros de tensão/corrente
long   glTensao = 0;// em V
long   glCorrente = 0;// em A
int    uiStatus = 0; //indica o modo como está o estado das tensões


//pwm
long   uiMax_passos = 0;//frequencia em khz
int    uiDuty_cycle = 1;

//variaveis de uso geral
long glTempo_led=0;
int  uiAlterna_leds=0;


//===================================================================================
//Função:    _interrupcoes
//Parâmetro: não tem.
//Retorno:   não tem.
//Descrição: usada para tratar as interrupções geradas pelo microcontrolador.
//===================================================================================
void interrupt interrupcoes(void)//vetor de interrupção
 {
    if(ADIF)
    {//se interrupção do modulo analogico!
        ADIF = 0;//limpa flag
    }    
    if(TMR2IF)
    {//interrupção do timer2
      TMR2IF = 0;//não será usado
    }
    if(CCP1IF)
    {//interrupção do ccp1
      CCP1IF = 0;//não será usado
    }     
 }

//===================================================================================
//Função:    _delay_ms
//Parâmetros: long delay, essa função cobre uma falha nas rotinas de tempo para o pic da serie 18F
//Retorno:   não tem retorno.
//Descrição: faz microcontrolador perder tempo.
//===================================================================================
void delay_ms(long delay)
{
    while(delay > 0)
    {
     __delay_ms(1);
     delay--;
    }
}
//===================================================================================
//Função:    _liga_leitura_0
//Parâmetro: não tem.
//Retorno:   não tem.
//Descrição: liga entrada de sinal analogico na porta 0.
//===================================================================================
void  liga_leitura_0(void)
 {
      ADCON0 = 0X21;
 }
//===================================================================================
//Função:    _liga_leitura_1
//Parâmetro: não tem.
//Retorno:   não tem.
//Descrição: liga entrada de sinal analogico na porta 1.
//===================================================================================
void  liga_leitura_1(void)
 {
      ADCON0 = 0X25;
 }

void ler_ADC(int giMedia)//numero de amostras
{
      int iMedia=0;
      glTensao = 0;
      glCorrente = 0;
      while(iMedia < giMedia)
      {
        glTensao = glTensao +  ler_adc_un();
        __delay_us(2);//tempo minino para aquisições
        iMedia++;
      }
      liga_leitura_1();//agora lê a corrente
      __delay_us(2);//tempo minino para aquisições
      iMedia=0;
      while(iMedia < giMedia)
      {
        glCorrente = glCorrente + ler_adc_un();
        __delay_us(2);//tempo minino para aquisições
        iMedia++;
      }
      liga_leitura_0();//volta a ler tensão 
      glTensao = glTensao/giMedia;
      glCorrente = glCorrente/giMedia;
}
void inicializa_PWM1(char prescaler,char pr2,char postcaler)//prescaler / PR2 / postcaler
{
    uiMax_passos =(int) pr2;
    switch(prescaler)
    {
        case 1:
        {
           prescaler = 0;
        }break;
        case 4:
        {
           prescaler = 1;
        }break;
        case 16:
        {
           prescaler = 3;
        }break;
    }
    T2CON = (postcaler - 1)<<3;
    T2CON = T2CON + 4 + prescaler;//o 4 é para habilitar o timer 
    PR2 = pr2;
    CCP1CON = 0X0F;//habilita pwm
    CCP1IE = 1;//desabilita interrupção pois não vamos precisar dela, modulo ccp1
    TMR2IE = 0; //desabilita interrupção pois pode até travar processamento(não vamos usar tambem); timer 2
}

void duty_cicle(long valor)
{
    CCPR1 = valor;    
}

//===================================================================================
//Função:    _inicializa_cpu
//Parâmetros: não tem
//Retorno:   não tem retorno.
//Descrição: inicializa os registradores do microcontrolador.
//===================================================================================
void inicializa_cpu(void)
{
    TRISC = 0xC0;//habilita 6 e 7 com entrada analogica
    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
    ADCON0 = 0X21;//liga modulo analogico digital e configura   entrada de sinal para o pino RC6(AN8)
    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 = 0x00;//desabilita portas analogicas(para não atrapalhar recepção no pino)
    ANSELH = 0x03;//em alguns casos não funciona nem a interrupção de recepção. habilita somente os pinos que vão funcionar como AD
    PWM_20KHZ_CLK16;//100khz veja no comentario abaixo "SUGESTÃO DE DEFINES :"    
    duty_cicle(1);//inicia com valor minimo
    uiDuty_cycle = 1;
}
//


//*******************************Rotina principal*********************************************/
void main(void)
{
  inicializa_cpu();
  for(;;)
    {
        glTempo_led++; 
        if(glTempo_led > 100)
        {
            
            if(uiAlterna_leds == 0)
            {
               LED_STATUS = 1;
               uiAlterna_leds=1; ;//pisca led 
            }
            else
            {
                LED_STATUS = 0;
               uiAlterna_leds = 0; ;//pisca led 
            }
            if(uiStatus > 0)
            {
                LED_FALHA = 1;
            }
            else
            {
                LED_FALHA = 0;  
            }
            glTempo_led=0;
        }   
        ///processamento das tensões
        ler_ADC(4);//pega pelo menos 5 amostras para tirar media
         /// /verifica tensão
          if(glTensao > DDP_TRAB )//flutuação máxima 
          {//tensão superior a permitida
              if(uiDuty_cycle < VAL_MIN_PWM)
              {   //não consegue mais compensar chegou ao limite
                 uiStatus = 2;//sobretensão                
              }
              else
              { 
                  //tenta compensar valor
                  uiDuty_cycle--;//a
                  duty_cicle(uiDuty_cycle);
                  uiStatus = 0;//tudo ok
             }
          }
          else              
          {
                if(glTensao < DDP_TRAB )//flutuação máxima 
                {
                  //tensão inferior a permitida
                        if(uiDuty_cycle > VAL_MAX_PWM)
                        {
                             //não consegue mais compensar chegou ao limite
                             uiStatus = 3;//subtensão  
                        }
                        else
                        {
                            //tenta compensar valor
                            uiDuty_cycle++;//lembre que a saida é invertida
                            duty_cicle(uiDuty_cycle);
                            uiStatus = 0;//tudo ok
                        }

              }//fim de tensão fora do range
          }
      ////////////////       
           
    }//loop infinito
}



        

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


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

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

*/
Código-fonte "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 ****************************************************/

// 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 = OFF         // Single-Supply ICSP Enable bit (Single-Supply ICSP enabled) desliga programação em baixa voltage
#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)

#endif    /* CONFIG_CPU_H */
//////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////
Código-fonte "conv_adc.h" :

/*
 *                          FUNÇOES USADAS NA CONVERSAO ANALOGICO/DIGITAL
 *
 * Compilador :      MPlabXC8
 * Microcontrolador: 18F13K22
 * Autor:            Aguivone
 * Versão:           1
 * Data de criação:  21 de agosto de 2014.
 */

#include <xc.h>


// ===================================================================================
// Função:    _ler_adc_un
// Parâmetros: não tem.
// Retorno   : unsigned long ultensao.
// Descrição : retorna o valor lido em unidades de medidas.
// ===================================================================================

unsigned long ler_adc_un(void)
{
    unsigned long ultensao;
    ADCON0bits.GO = 1; //inicia conversão
    while (ADCON0bits.GO_DONE == 1); //espera finalizar leitura
    ultensao = (ADRESH << 8) | ADRESL;
    return(ultensao);
}

// ===================================================================================
// Função:    _ler_adc_mv
// Parâmetros: não tem.
// Retorno   : unsigned long ultensao.
// Descrição : retorna o valor lido em milivolts.
// ===================================================================================
unsigned long ler_adc_mv(void)
{
    unsigned long ultensao;
    ultensao =((ler_adc_un() * 5000)/1023); //Vref está em milliVolts
    return(ultensao);
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Exemplo do protótipo funcionando :


Conclusões do projeto: 

               O circuito funcionou de forma satisfatória, conseguiu compensar a queda de tensão para uma carga de 300mA(com uma queda de tensão de saída de 0,3V), além de regular a tensão na saída mesmo que a entrada de tensão do circuito variasse. Como todos os outros exemplos postados aqui no blog este projeto é apenas didático podendo ser melhorado para uso comercial.
              A tensão minima de trabalho ficou em 11V e a máxima é até 23V (geralmente até 1 ou 2 volta da tensão de saída), para mudar o valor da tensão de saída basta mudar o valor da variável "DDP_TRAB", não recomendo colocar um valor menor do que a entrada pois o circuito apenas eleva(conversor boost) a tensão.
             Uma ultima dica é usar um dissipador de calor no mosfet de chaveamento.
               Lembrando que para acompanhar as postagens basta entrar na página do facebook e curtir.
https://www.facebook.com/Microcontroladores-C-576463872371829  ou procurando por microcontroladores-c no face.