uControl
Abril 20, 2014, 12:25:59 *
Bienvenido(a), Visitante. Por favor, ingresa o regístrate.
¿Perdiste tu email de activación?

Ingresar con nombre de usuario, contraseña y duración de la sesión
 
   Inicio   Ayuda Buscar Ingresar Registrarse  
Páginas: [1]   Ir Abajo
  Imprimir  
Autor Tema: Esquema y librería para cargador de batería on-board  (Leído 2464 veces)
0 Usuarios y 1 Visitante están viendo este tema.
Suky
**----- ^^ ------**
Moderador
dsPIC
*****
Desconectado Desconectado

Sexo: Masculino
Mensajes: 5423


Con Qt...


WWW
« : Mayo 12, 2012, 02:08:00 »

En estos días he estado trabajando en la idea de implementar un circuito que me permita detectar cuando una batería necesita carga y que administre la carga. Mi necesidad es una batería SLA, pero puede que resulte de utilidad para otro tipo de baterías.

La parte eléctrica es casi idéntica a la que implementa Felixls en el proyecto UniversalBatteryCharger, esto en un principio. Puede que sea necesario implementar una llave bi-direccional con mosfet para desconectar totalmente la batería del sistema... Tongue


El proyecto lo que necesita es que el sistema esté alimentado la mayor parte del tiempo de la batería y cuando sea necesario cargarla. Para ello se testea la tensión de la batería, cuando cae sobre un nivel establecido comienza el proceso (2.0 V por celda). En este caso comienza con corriente constante de 0.1 C hasta llegar a 2.4 V por celda, luego pasa a tensión constante con 2.3 V por celda hasta que la corriente sea inferior a 0.05 C.

La librería dispone de 2 funciones principales, una que inicia todos los módulos encargados de trabajar con el testeo y carga (ADC, PWM, timer, etc) y otra que realiza las tareas de los distintos estados en el que se encuentre: testeando estado, cargando a corriente constante y cargando a tensión constante. Esta última función es importante que se llame con suficiente frecuencia, ya que entre más corto sea el periodo de llamado la respuesta sobre el control de corriente o tensión será más fino. En los ensayos la llamo cada ~5ms.

Los ensayos consistieron en observar el control de corriente frente a cambios de carga, en este caso conexión y desconexión de cargas, provocando un escalón (ascendente o descendente) en la corriente requerida por el sistema. En estos momento lo único que tengo es una batería SLA de 12 V/1.3 Ah.

Ensayo Nº1: Variación de la corriente del sistema en +-50 mA cada 5ms.
En este caso la corriente se mantiene entre 110 y 140 mA.

Ensayo Nº2: Variación de la corriente del sistema en +-200 mA
En este caso al aplicar la carga la corriente disminuye hasta ~10 mA y se estabiliza nuevamente en 100 ms. Luego al desconectar la carga hay un pico de sobre-corriente de ~200 mA que es estabilizado en ~25 ms.

En el caso de sobre-corriente el algoritmo dependiendo del nivel modifica en mayor o menor cantidad el ciclo de trabajo. En este punto me gustaría probar con una batería de mayor Ah para determinar si es correcto la forma de implementarlo o no  Grin

La librería sería la siguiente:

Código:
#include <p32xxxx.h>
#include <plib.h>
#include "HardwareProfileSkP32.h"
#include "TimeDelay.h"

#define CAPACIDAD_BATERIA       1.3
#define CORRIENTE_CARGA_MAX     0.1     // 0.1C

#define CELDAS_BATERIA          6
#define TENSION_MIN_CELDA       2.0
#define TENSION_CARGA_CTE       2.3
#define TENSION_MAX_CELDA       2.4


void vCargadorBateria_Init(void);
void vCargadorBateria_Tareas(void);

Código:
#include "CargadorBateriaSLA.h"

#define CICLO_TRABAJO_MAXIMO                            3200
#define SET_CICLO_TRABAJO_ALIMENTACION(a) OC1RS=a

#define CANAL_TENSION_BATERIA                   0
#define CANAL_CORRIENTE_BATERIA 1
#define CANAL_TEMPERATURA_BATERIA 2

#define MODO_TEST_BATERIA 0
#define MODO_CARGA_BATERIA 1

typedef struct{
    float Tension;
    float Corriente;
    float Temperatura;
}INF_BATERIA;

typedef enum{
    TEST,
    CARGA_CORRIENTE_CTE,
    CARGA_TENSION_CTE
}ESTADO_BATERIA;

struct{
    ESTADO_BATERIA Estado;
    UINT16 CicloTrabajoAlimentacion;
    float CorrienteCargaCte;
    float TensionCargaCte;
    float MaxTensionCarga;
    float MinTension;
    UINT16 Timeout;
    struct{
        volatile UINT8 Cont200ms;
        volatile UINT8 Segundos;
        volatile UINT16 Minutos;
        volatile unsigned kbhit_seg:1;
    }Time;
}CargadorBateriaData;

void vCargadorBateria_Estado(INF_BATERIA *Bateria, BOOL Modo);

#if defined(__PIC32MX__)
void __ISR(_TIMER_4_VECTOR, ipl2) Timer4Handler(void)
{

    CargadorBateriaData.Time.Cont200ms++;
    if(CargadorBateriaData.Time.Cont200ms==5){
        CargadorBateriaData.Time.Cont200ms=0;
        CargadorBateriaData.Time.Segundos++;
        CargadorBateriaData.Time.kbhit_seg=1;
        if(CargadorBateriaData.Time.Segundos==60){
            CargadorBateriaData.Time.Segundos=0;
            CargadorBateriaData.Time.Minutos++;
        }
    }
    mT4ClearIntFlag();

}
#endif

void vADC_Init(void){

    AD1CON1=0; // Off
    AD1CON1bits.SIDL=0; // Encendido en modo IDLE
    AD1CON1bits.FORM=0; // Data Output Format: Entero 16-bits
    AD1CON1bits.SSRC=0; // Conversion manual
    AD1CON1bits.CLRASAM=0; // Operacion Normal
    AD1CON1bits.ASAM=0; // Para comenzar setear SAMP

    AD1CON2bits.VCFG=0; // Vdd/Vss
    AD1CON2bits.OFFCAL=0; // Apagada calibracion de offset
    AD1CON2bits.CSCNA=0; // Scan off
    AD1CON2bits.SMPI=0b0000;            // Interrupcion por cada conversion
    AD1CON2bits.BUFM=0; // Buffer 16-bits
    AD1CON2bits.ALTS=0; // Usar siempre MUXA

    AD1CON3bits.ADRC=0; // ADC Clock desde PBCLK
    AD1CON3bits.SAMC=0; // Muestreo manual
    AD1CON3bits.ADCS=20;                // ADC Conversion Clock Tad = TPB ? 2 ? (ADCS<7:0> + 1) = 525ns
                                        // ADC Conversion Time for 10-bit Tc=13*Tad =  ~7us

    //AD1CHS0/AD1CHS123: A/D Input Select Register
    AD1CHSbits.CH0SA=0; // MUXA +ve -> CH0 (Seleccion del canal analogico)
    AD1CHSbits.CH0NA=0; // MUXA -ve -> Vr-

    //AD1PCFGH/AD1PCFGL: Port Configuration Register
    AD1PCFG=0xFFFF;
    AD1PCFGbits.PCFG0 = 0; // AN0 as Analog Input
    AD1PCFGbits.PCFG1 = 0; // AN0 as Analog Input
    AD1CON1bits.ON = 1; // Turn on the A/D converter
}
// *--------------------------------------------------------------------------------*
UINT16 ADC_Conversion(UINT8 Canal){
    UINT8 k;
    UINT16 Sum;

    Sum=0;
    AD1CHSbits.CH0SA=Canal; // Seleccionamos canal
    Delay10us(1);
    for(k=0;k<8;k++){
        AD1CON1bits.SAMP=1;
        Delay10us(5);
        AD1CON1bits.SAMP=0;
        Nop();
        while(AD1CON1bits.DONE==0);
        Sum+=ADC1BUF0;
    }
    Sum/=8;
    return(Sum);
}
// *--------------------------------------------------------------------------------*
void vCargadorBateria_Init(void){

    CargadorBateriaData.CicloTrabajoAlimentacion=0;
    PORTSetPinsDigitalOut(IOPORT_D, BIT_0);
    OpenTimer2(T2_ON | T2_PS_1_1 |  T2_SOURCE_INT, CICLO_TRABAJO_MAXIMO); // 25k
    OpenOC1(OC_ON | OC_TIMER2_SRC | OC_TIMER_MODE16 | OC_PWM_FAULT_PIN_DISABLE, 0, CICLO_TRABAJO_MAXIMO);                       // Alimentacion apagada

    vADC_Init();

    OpenTimer4(T4_ON | T4_IDLE_STOP | T4_GATE_OFF | T4_PS_1_256 | T4_SOURCE_INT, 32500); // 80 MIPS -> 3.2 us. (=> 62500=0.200seg)
    CargadorBateriaData.Time.Cont200ms=0;
    CargadorBateriaData.Time.Segundos=0;
    CargadorBateriaData.Time.Minutos=0;
    CargadorBateriaData.Time.kbhit_seg=0;
    ConfigIntTimer4(T4_INT_ON | T4_INT_PRIOR_2);
    INTConfigureSystem(INT_SYSTEM_CONFIG_MULT_VECTOR);
    INTEnableInterrupts();

    CargadorBateriaData.Estado=TEST;
    CargadorBateriaData.CorrienteCargaCte=CAPACIDAD_BATERIA*CORRIENTE_CARGA_MAX;
    CargadorBateriaData.MinTension=TENSION_MIN_CELDA*CELDAS_BATERIA;
    CargadorBateriaData.TensionCargaCte=TENSION_CARGA_CTE*CELDAS_BATERIA;
    CargadorBateriaData.MaxTensionCarga=TENSION_MAX_CELDA*CELDAS_BATERIA;
    CargadorBateriaData.Timeout=(CAPACIDAD_BATERIA/(CAPACIDAD_BATERIA*CORRIENTE_CARGA_MAX))*60;
}
// *--------------------------------------------------------------------------------*
void vCargadorBateria_Tareas(void){
    INF_BATERIA Bateria;
    static UINT8 Segundos=0;

    if(CargadorBateriaData.Time.Minutos>CargadorBateriaData.Timeout){
        CargadorBateriaData.Estado=TEST;
        CargadorBateriaData.CicloTrabajoAlimentacion=0;
        SET_CICLO_TRABAJO_ALIMENTACION(CargadorBateriaData.CicloTrabajoAlimentacion);
        Segundos=0;
    }

    switch(CargadorBateriaData.Estado){
        case TEST:
            vCargadorBateria_Estado(&Bateria,MODO_TEST_BATERIA);
            // Determina cuando comenzar a cargar...
            if(Bateria.Tension<CargadorBateriaData.MinTension){
                if(CargadorBateriaData.Time.kbhit_seg==1){ // Se restea si o si al final...
                    Segundos++;
                    if(Segundos==60){  // Solo si esta por debajo del valor durante 60 segundos
                        Segundos=0;
                        CargadorBateriaData.Estado++;
                    }
                }
            }else{
                Segundos=0;
            }
            break;
        case CARGA_CORRIENTE_CTE:
            vCargadorBateria_Estado(&Bateria,MODO_CARGA_BATERIA);
            if(Bateria.Corriente>(CargadorBateriaData.CorrienteCargaCte*1.05)){
                if(Bateria.Corriente>(CargadorBateriaData.CorrienteCargaCte+0.4)){
                    CargadorBateriaData.CicloTrabajoAlimentacion-=300;
                }else if(Bateria.Corriente>(CargadorBateriaData.CorrienteCargaCte+0.2)){
                    CargadorBateriaData.CicloTrabajoAlimentacion-=100;
                }else if(Bateria.Corriente>(CargadorBateriaData.CorrienteCargaCte+0.1)){
                    CargadorBateriaData.CicloTrabajoAlimentacion-=50;
                }else if(Bateria.Corriente>(CargadorBateriaData.CorrienteCargaCte+0.05)){
                    CargadorBateriaData.CicloTrabajoAlimentacion-=25;
                }else{
                    CargadorBateriaData.CicloTrabajoAlimentacion-=5;
                }
            }else if(Bateria.Corriente<(CargadorBateriaData.CorrienteCargaCte*0.95)){
                CargadorBateriaData.CicloTrabajoAlimentacion+=5;
            }
            SET_CICLO_TRABAJO_ALIMENTACION(CargadorBateriaData.CicloTrabajoAlimentacion);
            if(Bateria.Tension>=CargadorBateriaData.MaxTensionCarga){  // Solo si esta por encima del valor durante 60 segundos
                if(CargadorBateriaData.Time.kbhit_seg==1){
                    Segundos++;
                    if(Segundos==60){
                        Segundos=0;
                        CargadorBateriaData.Estado++;
                    }
                }
            }else{
                Segundos=0;
            }
            break;
        case CARGA_TENSION_CTE:
            vCargadorBateria_Estado(&Bateria,MODO_CARGA_BATERIA);
            if(Bateria.Tension>CargadorBateriaData.TensionCargaCte){
                CargadorBateriaData.CicloTrabajoAlimentacion-=5;
            }else{
                CargadorBateriaData.CicloTrabajoAlimentacion+=5;
            }
            SET_CICLO_TRABAJO_ALIMENTACION(CargadorBateriaData.CicloTrabajoAlimentacion);
            
            if(Bateria.Corriente<(CAPACIDAD_BATERIA*0.05)){ // Solo si esta por debajo del valor durante 60 segundos
                if(CargadorBateriaData.Time.kbhit_seg==1){
                    Segundos++;
                    if(Segundos==60){
                        Segundos=0;
                        CargadorBateriaData.Estado=TEST;
                        CargadorBateriaData.CicloTrabajoAlimentacion=0;
                        SET_CICLO_TRABAJO_ALIMENTACION(CargadorBateriaData.CicloTrabajoAlimentacion);
                    }
                }
            }else{
                Segundos=0;
            }
            break;
    }

    if(Bateria.Temperatura>40.0){
        CargadorBateriaData.Estado=TEST;
        CargadorBateriaData.CicloTrabajoAlimentacion=0;
        SET_CICLO_TRABAJO_ALIMENTACION(CargadorBateriaData.CicloTrabajoAlimentacion);
        Segundos=0;
    }

    CargadorBateriaData.Time.kbhit_seg=0;
}
// *--------------------------------------------------------------------------------*
void vCargadorBateria_Estado(INF_BATERIA *Bateria, BOOL Modo){
    UINT16 Temp;
    UINT8 Text[50];

    if(Modo==MODO_CARGA_BATERIA){
        Temp=ADC_Conversion(CANAL_CORRIENTE_BATERIA);
        Bateria->Corriente=Temp*0.00088704;                                     // 0.001152 = (3.3/1023)*(1/(0.1*(28k/1k+1))) // x0.77 correccion
        Temp=ADC_Conversion(CANAL_TENSION_BATERIA);
        Bateria->Tension=Temp*0.018387096;                                      // 0.01838= (3.3/1023)*((10k+47k)/10k)
        Bateria->Temperatura=0;
    }else{
        Temp=ADC_Conversion(CANAL_TENSION_BATERIA);
        Bateria->Tension=Temp*0.018387096;                                      // 0.01838= (3.3/1023)*((10k+47k)/10k)
        Bateria->Corriente=0;
        Bateria->Temperatura=0;
    }
}
// *--------------------------------------------------------------------------------*

Implementación:

Código:
#include "CargadorBateriaSLA.h"
// *--------------------------------------------------------------------------------*
int main(){

    vCargadorBateria_Init();
    while(1){
        vCargadorBateria_Tareas();
        DelayMs(5);
    }
}

Es un inicio, porque puede que el algoritmo para controlar sobre-corrientes no sea el más adecuado, se necesitan más ensayos  Grin


Saludos!

* IMAGE001.jpg (41.67 KB - descargado 1118 veces.)
* IMAGE002.jpg (44.5 KB - descargado 1082 veces.)
* IMAGE003.jpg (44.07 KB - descargado 1068 veces.)
* Esquema.png (41.05 KB - descargado 2163 veces.)
« Última modificación: Mayo 13, 2012, 12:31:40 por Suky » En línea

xesc0
PIC12F
**
Desconectado Desconectado

Sexo: Masculino
Mensajes: 302



« Respuesta #1 : Mayo 13, 2012, 08:47:01 »


Es como un SAI verdad? De dónde tomarás la alimentación externa? a mi las baterías de litio me dan respeto, pero tengo una SLA para hacer pruebas jijiji Una duda las 10 resistencias de un ohm qué función tienen? podrías poner directamente la masa, no? Tongue

Interesante Suky vamos a ver como se desarrolla el proyecto :)
En línea
el_vpi
Moderador
PIC18F
*****
Desconectado Desconectado

Mensajes: 1201



« Respuesta #2 : Mayo 13, 2012, 10:32:01 »

xesc0, no podes eliminar esas resistencias. Sino no podrias medir la corriente de carga de bateria.
En línea
Suky
**----- ^^ ------**
Moderador
dsPIC
*****
Desconectado Desconectado

Sexo: Masculino
Mensajes: 5423


Con Qt...


WWW
« Respuesta #3 : Mayo 13, 2012, 12:35:28 »

Es como un SAI verdad?

No, todo lo contrario. Aquí la idea es solo utilizar la batería y cuando sea necesario re-cargarla. Para ese tipo de equipos la batería se mantiene conectada todo el tiempo a una tensión constante, modificando la librería se tendría un buen control de esa tensión.

De dónde tomarás la alimentación externa?

De la red eléctrica.

En línea

xesc0
PIC12F
**
Desconectado Desconectado

Sexo: Masculino
Mensajes: 302



« Respuesta #4 : Mayo 14, 2012, 08:56:43 »


Perdón es que no veo claro ese sistema de medida para mi es más sencillo si pones una o varias resistencias en serie a la carga de valor conocido y mides la tensión en ambos lados con un par de divisores, aunque al final vas a acabar necesitando operacionales para amplificar la diferencia de tensión Tongue

Entonces ese esquema es un "ejemplo" porque los condensadores C4 C3 de la entrada de red son a 25v Grin

Con tanta pregunta un día me matareis jajajaja  bang
En línea
el_vpi
Moderador
PIC18F
*****
Desconectado Desconectado

Mensajes: 1201



« Respuesta #5 : Mayo 14, 2012, 09:11:31 »

xesc, no es un "ejemplo" que tienen de malo esas tensiones ? podrian llegar a ser un poquito menores (16V) por ejm pero no cambia en nada.
Si pones una R en serie con la carga, solo podras medir el consumo de la misma, pero no la carga o descarga de la bateria que es lo que te interesa. Tendrias la medicion sobre el circuito de salida nada mas.
Por otro lado, si pones una R en serie con la salida y queres medir algo ahi, con que alimentas tu sistema de medicion ? deberia ser con una tension mayor y se te complicará, por ese siempre que se puede medis sobre el retorno.

saludos, Daniel.
En línea
Suky
**----- ^^ ------**
Moderador
dsPIC
*****
Desconectado Desconectado

Sexo: Masculino
Mensajes: 5423


Con Qt...


WWW
« Respuesta #6 : Mayo 14, 2012, 09:52:01 »

Perdón es que no veo claro ese sistema de medida para mi es más sencillo si pones una o varias resistencias en serie a la carga de valor conocido y mides la tensión en ambos lados con un par de divisores, aunque al final vas a acabar necesitando operacionales para amplificar la diferencia de tensión Tongue

 shocked Y aquí que se hace?

Entonces ese esquema es un "ejemplo" porque los condensadores C4 C3 de la entrada de red son a 25v Grin

 shocked Y el rectificador de la entrada?
En línea

lucho512
Amigo de uControl
PIC16F
******
Desconectado Desconectado

Sexo: Masculino
Mensajes: 797



WWW
« Respuesta #7 : Mayo 14, 2012, 10:02:05 »

Buen dia Gente, muy Bueno suky lo que vos esta haciendo en si es una (UPS On Line) aunque no lo quieras asumir jajaja  Grin

Yo ando tras algo parecido pero necesito para antener en cargar 2 Bat de 12V, en si cambiando los capacitores, Fuente y Codigo del Pic el circuito deberia funcionar? o me equivoco?

Luciano...
En línea
xesc0
PIC12F
**
Desconectado Desconectado

Sexo: Masculino
Mensajes: 302



« Respuesta #8 : Mayo 14, 2012, 10:05:48 »


Si se alimenta de la red eléctrica son 220V el rectificador no te baja la tensión, te pasa de media a doble onda, por eso digo lo de la tensión en los condensadores C3 y C4.
Si conozco el valor de la resistencia en serie y la corriente varia, su tensión también, el calculo de la corriente midiendo la tensión es directo y tal vez la carga y descarga se pueda sacar de las fluctuaciones de carga angel. Ahí las resistencias de 1ohm están en paralelo a la carga, no dudo que funcione en absoluto, tiene nombre este sistema de medida? Grin
Medir sobre el retorno?  me voy a pique aun me queda mucho que aprender Grin
En línea
Felixls
Moderador
PIC24F
*****
Desconectado Desconectado

Sexo: Masculino
Mensajes: 3032



WWW
« Respuesta #9 : Mayo 14, 2012, 01:24:50 »

Ahí las resistencias de 1ohm están en paralelo a la carga, no dudo que funcione en absoluto

La resistencia Shut está en serie con la carga, no en paralelo.

La carga, en este caso, es la resistencia interna de la batería.

P.D.: Por cierto, muy bueno el proyecto Suky, gracias por compartirlo.  Wink
En línea
Suky
**----- ^^ ------**
Moderador
dsPIC
*****
Desconectado Desconectado

Sexo: Masculino
Mensajes: 5423


Con Qt...


WWW
« Respuesta #10 : Mayo 14, 2012, 04:52:01 »

Buen dia Gente, muy Bueno suky lo que vos esta haciendo en si es una (UPS On Line) aunque no lo quieras asumir jajaja  Grin

 Grin Es que tenia como UPS el sistema que conecta la batería cuando no hay red eléctrica.

Yo ando tras algo parecido pero necesito para antener en cargar 2 Bat de 12V, en si cambiando los capacitores, Fuente y Codigo del Pic el circuito deberia funcionar? o me equivoco?

2 baterías en serie? El circuito y la lógica del programa sirve, como comentas solo hay que cambiar algunas cositas (V de los capacitores, constantes, divisores resistivos, etc.)

Si se alimenta de la red eléctrica son 220V el rectificador no te baja la tensión, te pasa de media a doble onda, por eso digo lo de la tensión en los condensadores C3 y C4.

Claro, pero es obvio que dados esos valores de tensión en los capacitores se va a utilizar un transformador  Wink

Si conozco el valor de la resistencia en serie y la corriente varia, su tensión también, el calculo de la corriente midiendo la tensión es directo y tal vez la carga y descarga se pueda sacar de las fluctuaciones de carga angel. Ahí las resistencias de 1ohm están en paralelo a la carga, no dudo que funcione en absoluto, tiene nombre este sistema de medida? Grin
Medir sobre el retorno?  me voy a pique aun me queda mucho que aprender Grin

Puede que no entiendas como funciona el sistema, lo que interesa medir es la corriente y tensión sobre la batería, y no sobre el sistema. Como bien comenta Felixls.


Saludos!
En línea

Páginas: [1]   Ir Arriba
  Imprimir  
 
Ir a:  

Impulsado por MySQL Impulsado por PHP Powered by SMF 1.1.19 | SMF © 2011, Simple Machines
SMFAds for Free Forums
XHTML 1.0 válido! CSS válido!
Página creada en 0.067 segundos con 28 consultas. (Pretty URLs adds 0.01s, 3q)
loggkey