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.