Centro de Energía Solar Todo en Uno: Controlador de Carga, Inversor, Power Bank y Lámpara LED
Componentes y materiales
|
Microchip Technology Atmega8
|
× | 1 | ||
|
Convertidor Buck
|
× | 1 | ||
|
SparkFun LED - 3W Aluminio PCB (Paquete de 5, Blanco Cálido)
|
× | 1 | ||
|
Pantalla Nokia 5110
|
× | 1 | ||
|
Disipador de calor SparkFun
|
× | 1 | ||
|
MOSFET Canal N SparkFun
|
× | 4 | ||
|
MOSFET Canal P SparkFun
|
× | 1 | ||
|
Panel Solar 40 Vatios o menos para sistema de 12V
|
× | 1 | ||
|
Batería de Ion-Litio SparkFun - Celda 18650
|
× | 1 | ||
|
Módulo DC-DC 0.9V-5V a USB 5V DC Boost Step-up Power Supply
|
× | 1 | ||
![]() |
Transistor NPN de Uso General
|
× | 1 | |
|
Transformador con Toma Central 12-0-12/220
|
× | 1 | ||
![]() |
1N4007 – Diodo de Alta Tensión y Corriente
|
× | 1 | |
![]() |
Header Macho 36 Posiciones 1 Fila - Largo (0.1")
|
× | 1 | |
![]() |
Interruptor Deslizante
|
× | 1 | |
![]() |
Pulsador SparkFun 12mm
|
× | 1 | |
![]() |
Arduino Proto Shield
|
× | 1 | |
|
Placa Strip/Vero/Proto 8x11 cm
|
× | 1 | ||
![]() |
Arduino UNO
|
× | 1 | |
![]() |
Arduino Nano R3
|
× | 1 | |
![]() |
Arduino Mega 2560
|
× | 1 | |
|
Diodo Schottky Baja Tensión 5822
|
× | 1 | ||
![]() |
Condensador 10 µF
|
× | 1 | |
![]() |
Condensador 100 nF
|
× | 1 |
Herramientas y máquinas necesarias
![]() |
Soldador (genérico)
|
|
|
Taladro
|
||
![]() |
Pistola de pegamento caliente (genérica)
|
Aplicaciones y servicios en línea
![]() |
Arduino IDE
|
|
|
AutoDesk 123D
|
Acerca de este proyecto
Sobre este proyecto
Tengo algunos paneles solares, baterías de 12 Voltios, transformadores y algunas cosas más por ahí desde hace un tiempo pidiendo a gritos que les diera un buen uso. Así nació este dispositivo: una solución fotovoltaica pequeña y completa en una sola placa. Revisemos primero qué hace cada cosa, ¿de acuerdo?
- Un controlador de carga es un dispositivo que regula la carga de almacenamiento DC/batería desde un panel solar fotovoltaico y la descarga de la batería por la carga para prolongar la vida útil de la batería.
- Un inversor es un dispositivo que convierte la electricidad de forma DC a forma AC para operar cargas AC.
- Un Power Bank proporciona alimentación de 5V DC a través de puerto USB a gadgets/dispositivos móviles para carga portátil o fuera de la red.
- Una lámpara de emergencia es una fuente de luz LED superbrillante que puede usarse durante cortes de energía, acampadas, actividades al aire libre después del anochecer.
Este dispositivo que hice tiene todas estas características, las dos últimas son soportadas independientemente por la batería de ion-litio a bordo. Con un panel solar (hasta 100 Vatios), una batería de plomo-ácido de 12 Voltios y un transformador, se pueden utilizar todas las opciones.
Versión Proto en Uno
La primera versión se desarrolló en una placa Uno con hardware mínimo y opciones mínimas. La pantalla Nokia se montó directamente y se desarrolló un shield de MOSFETs para soportar la carga/descarga de la batería. No hay control de menú, no hay inversor, no hay carga PWM y ¡funciones geniales! Solo carga on/off y mostrando niveles de voltaje de batería y panel. Hace el trabajo pero no tiene encanto.

Versión Completa en Protoboard
Luego desarrollé esta nueva con las siguientes características:
- Controlador de Carga Solar PWM hasta 100 Vatios de Panel
- Mini Inversor de Onda Cuadrada de 60 Vatios
- Control de hasta tres cargas DC de 12 Voltios
- Carga DC primaria soporta funciones auto on/off
- Power Bank USB independiente
- Módulo regulador Buck
- Lámpara LED de emergencia a bordo con control de parpadeo y brillo
Menú controlado por 2 botones/interruptores basado en desplazamiento y selección, mostrando opciones e información de estado en la pantalla Nokia 5110. ¡Muy guay! La parte trasera está aislada con pegamento caliente para protección contra cortocircuitos contra objetos metálicos.
Hay algunas características convenientes más como interruptor on/off para la retroiluminación de la pantalla, separar el buck para operación independiente desconectándolo de la batería interna.

Accediendo al menú en la pantalla Nokia 5110 con el botón de usuario se muestra aquí:
¡Aprendamos algo técnico!
El controlador de carga puede ser de tipos On/Off, PWM o MPPT. On/Off es la forma más simple (mi versión 1 - imagen arriba) de controlador que no limita la corriente de carga a medida que el voltaje de la batería se acerca a su voltaje de carga completa.
Mientras que PWM disminuye gradualmente la corriente de carga a medida que la batería se llena. El controlador PWM tiene los siguientes beneficios:
- Ayuda a recuperar la capacidad perdida de la batería y desulfatar una batería
- Aumenta la capacidad de la batería para aceptar más carga
- Mantiene altas capacidades promedio de batería hasta 95%
- Ecualiza celdas de batería a la deriva, para que las celdas internas puedan alcanzar el mismo potencial
- Reduce el calentamiento y gaseamiento de la batería, previniendo la pérdida de electrolito
- Ralentiza el envejecimiento y prolonga la vida del sistema
Pero el PWM no puede obtener la mayor parte de la energía eléctrica de los paneles solares fotovoltaicos, porque arrastra al panel a operar cerca del voltaje de la batería. MPPT es la solución a este problema, que básicamente es un convertidor buck-boost DC a DC ajustable, puede convertir la mayor parte de la energía solar comparado con el controlador PWM.
Los inversores pueden ser de tipos onda cuadrada, onda senoidal modificada y onda senoidal pura. El inversor de onda cuadrada es muy simple en diseño y suficiente para pequeñas cargas DC como lámparas AC, lámparas CFL, ventiladores de mesa, soldadores, pero no recomendado para motores inductivos, equipos delicados/fuentes de alimentación debido a la distorsión armónica.
La onda senoidal modificada es una especie de onda senoidal retardada creada a partir de ondas cuadradas, mejor que los inversores de onda cuadrada simples. Los inversores de onda senoidal son los mejores para todo tipo de cargas pero complejos de diseñar en hardware, algoritmo de software difícil de operar y caros de fabricar.
Un regulador buck es un convertidor DC-DC reductor, aquí he usado un módulo buck para cargar la batería de ion-litio de 4.2V que alimenta el controlador (Arduino + pantalla), power bank USB independiente, lámpara LED a bordo.

Ahora, el power bank USB básicamente es un boost DC-DC que puede convertir un rango de voltajes por debajo de 5 (como rango de 3.3 a 4.2 voltios) de una batería de ion-litio o LiPo a 5 voltios, que es el voltaje del bus USB que puede cargar dispositivos móviles.
También tiene un convertidor buck para cargar esa batería. En mi proyecto, el módulo buck toma algo de energía del panel para cargar la batería interna (a bordo).
Funcionamiento del hardware
Antes de entrar en detalles, revisa esta imagen de todo lo conectado alrededor del dispositivo:

El sistema tiene varios componentes de hardware para servir a diferentes propósitos. Por supuesto, el cerebro es el microcontrolador AVR Atmega8A (se puede usar Atmega328P con cambios menores, discutido abajo) que está programado en Arduino.

Un Atmega8A nuevo se graba con el bootloader Arduino Optiboot8, puedes comprar un Arduino Mini/Atmega328 con bootloader para evitar el lío.
El controlador, pantalla, lámpara LED y power bank se alimentan desde la batería de ion-litio a bordo. Dos botones momentáneos táctiles son para acceder al menú en la pantalla, lo que permite al usuario operar diferentes funciones del dispositivo. Los interruptores están desacoplados por hardware a través de condensadores de suavizado conectados en paralelo.
Un interruptor deslizante permite encender/apagar el dispositivo según sea necesario.

La función de carga solar se realiza mediante un MOSFET tipo P controlado por un circuito de control basado en transistor 2N2222 que es controlado mediante PWM desde el microcontrolador. El PWM se controla basado en el nivel de voltaje de la batería externa. La corriente de los paneles solares fluye a través del MOSFET tipo P a la batería de plomo-ácido. Cuando la batería está completamente cargada, el MOSFET se apaga desde el microcontrolador. Después de que la carga se apaga, el voltaje de la batería comienza a caer gradualmente, cuando alcanza 13.6 voltios la carga se reanuda de nuevo con bajo ciclo de trabajo para mantener la carga de flotación.
La carga DC de 12 Voltios se controla a través de un MOSFET tipo N controlando su pin Gate desde el microcontrolador.

La lámpara LED a bordo también es impulsada a través de un NMOS. El Gate de este MOSFET es controlado por PWM para ajuste de brillo del LED.

El bloque inversor consiste en 2 MOSFETs tipo N que se encienden/apagan alternativamente para simular CA. Al agregar un transformador con toma central externo, se puede realizar una alimentación CA de onda cuadrada.

La siguiente figura explica la acción del inversor:

Al permitir que la corriente fluya a través de la toma central de la bobina de un transformador elevador en dirección opuesta alternativamente usando MOSFETs, se puede crear voltaje CA en el secundario. Esto sucede porque cuando el MOSFET superior está encendido y el inferior apagado, la corriente fluye hacia arriba. Pero cuando el MOSFET superior está apagado y el inferior encendido, la corriente fluye hacia abajo.
Ambos MOSFETs deben conmutarse al doble de la frecuencia de CA. Revisa la siguiente imagen para entenderlo:

Para crear 50 Hz CA, se aplica una onda cuadrada alterna en el lado de baja tensión del transformador con toma central 12-0-12V/220V. 50 Hz significa 20 ms para cada onda.
Por eso 20ms/2 = 10 ms o 100 veces conmutar las señales de Gate aplicadas a los MOSFETs que impulsan el transformador (MOSFETs del inversor).

¡Advertencia! El voltaje CA es letal para los humanos, puede causar muerte/lesiones. ¡Nunca toques el lado de alta tensión del transformador con la mano desnuda!
Si no se usa la función inversor, la opción 2XDC Load permite usar dos cargas DC de 12 voltios más en la terminal del inversor.
Magia del software
Se proporcionan dos conjuntos de código, uno es el código completo en una sola pestaña de Arduino, otro es el código en pestañas según funciones separadas.
He generalizado grupos de tareas en una sola función.
Por ejemplo:
Get_ADCVal() medirá los voltajes de Panel, Batería Interna y Batería Externa, tomará 20 muestras, promediará esos valores y actualizará la variable que contiene la información de voltaje.
Context_Control() hará la Interacción de Usuario, Control de Acción, Actualización de Info en Pantalla, actividades relacionadas.
Charging_Control(), Discharging_Control(), Load_Control() son funciones de fondo que actúan como LAZO CERRADO para el sistema, monitorean el nivel de voltaje de la batería, controlan la función Auto Load, control de protección sobrecarga/descarga profunda, etc.
Las entradas de usuario se recogen a través de interruptores momentáneos impulsados por interrupciones. Cuando se presionan estos interruptores, se ejecutan las ISR relacionadas con INT0/INT1. Dos variables volátiles dp y ds cambian. Otra tercera variable level junto con dp (puntero de pantalla ->) y ds (selector de contenido de pantalla) permite al usuario navegar por menú/submenú y realizar acciones según sea necesario.
El Temporizador 1 de 16 bits de AVR está configurado para generar Interrupción por Desbordamiento de Temporizador cada 10 ms y voltea PIN_INVP y PIN_INVN cuando la función Inversor está Activa.
Todas las funciones Lcd_....() tienen que ver con el control de la pantalla.
Atmega8A vs Atmega328P (Uno)
El sistema se puede actualizar fácilmente para funcionar con Atmega328P/Uno haciendo los siguientes cambios en el código. Buscar y reemplazar:
TIMSK con TIMSK1
#define ADC_VREF 2.69 con #define ADC_VREF 1.11
#define ADCVDIV_R1 22 con #define ADCVDIV_R1 8.2
En la parte de hardware necesitas usar una resistencia de 8.2K en lugar de 22K para escalar los voltajes de panel y batería al rango de medición del ADC.
Videos de acción
Normalmente no leo solo palabras sobre algún proyecto, en su lugar voy por el video primero. Si eres como yo, disfruta los videos:
Alcance de mejora
Me quedé sin espacio Flash en Atmega8A. No pude añadir algunas características críticas como:
- Protección contra Sobrecarga/Cortocircuito Controlada por Software
- Algunos Iconos Gráficos y un Logo
- Medición de Energía y Registro
- Estimación y Alarma para Tiempo de Respaldo
- Opción de Carga de Portátil
- Soporte para Sistema de 6 Voltios
- Control de Carga Bluetooth
- Control de Carga Basado en Temporizador
- Un Reloj RTC para más características geniales
- Solución Conectada IoT
Si tienes planes para hacer algo como esto, ¡no olvides añadir algunas de estas características!
Atmega328P(Uno) o Arduino Mega podrían ser mejores candidatos para incluir todas estas opciones.
De todos modos, hace el trabajo, estoy contento con él.
Recursos adicionales
- Descargar Arduino 1.0.6 con soporte para placa Atmega8
- Abrir Arduino.exe, ir a Herramientas > Placa > Optiboot8
- Grabar bootloader usando este método
- Compilar y Subir Código
Código
- Código en Una Sola Pestaña
- Código Completo
- Bootloaders
Código en Una Sola Pestaña Arduino
#define PIN_SCE 12
#define PIN_RESET 13
#define PIN_DC 8
#define PIN_SDIN 7
#define PIN_SCLK 6
#define PIN_INVP 4
#define PIN_INVN 5
#define PIN_LOAD 9 // carga dc 12v
#define PIN_LAMP 10 // LUZ LED BLANCA
#define PIN_BATTPWM 11 // Controla PMOS para Carga Batería Ext
#define PIN_BATTint_Sense A2
#define PIN_SOLAR_Sense A0
#define PIN_BATText_Sense A3
#define ADC_VREF 2.695 // voltaje ref interno, alrededor de 1.11V para Arduino Uno aka Atmega328P, aquí mi Atmega8A da esto!
#define ADCVDIV_R1 22 // 22 K divisor de voltaje resistencia inferior
#define ADCVDIV_R2 175 // 175 K divisor de voltaje resistencia superior
//const uint8_t skulljoke[] PROGMEM ={2,} ; // PIN 2 & 3 USADOS COMO INTERRUPTOR
// PIN 0 & 1 COMO PROGRAMACIÓN
// PIN RESET COMO
#define LCD_C LOW
#define LCD_D HIGH
#define LCD_X 84
#define LCD_Y 48
uint8_t x=0;
uint8_t level=0;
uint8_t blinker=0;
boolean Load_Auto_Enable=0;
float maxADC_Voltage=0.0;
float BattInt_Voltage=0.0;
float BattExt_Voltage=0.0;
float PV_Voltage=0.0;
volatile int y=0;
volatile uint8_t dp =0;
volatile uint8_t ds =0;
volatile boolean cycle=0;
volatile uint8_t cdc_level =0;
//int i;
void setup(void) {
LcdInitialise();
LcdClear();
LcdString("*ARDUBOY PV*");
LcdString(" CONTROLADOR,");
LcdString("AC INVERSOR,");
LcdString("POWER BANK, ");
LcdString("LAMP THING!!");
delay(3000);
analogReference(INTERNAL);
maxADC_Voltage=(ADC_VREF/ADCVDIV_R1)*(ADCVDIV_R1+ADCVDIV_R2);
pinMode(PIN_LOAD,OUTPUT);
digitalWrite(PIN_LOAD,LOW);
pinMode(2, INPUT_PULLUP);
attachInterrupt(0, SW1, FALLING);// Interrupción para Interruptor 1
pinMode(3, INPUT_PULLUP);
attachInterrupt(1, SW2, FALLING);// Interrupción para Interruptor 2
}
void loop(void) {
Get_ADCVal();
Context_Control();
Charging_Control();
Discharging_Control();
Load_Control();
LcdClear();;
}
///////////// ADC ///////////////
void Get_ADCVal(void) {
int I=0;
int J=0;
int K=0;
for(x=0;x<20;x++) {
I=I+analogRead(PIN_BATTint_Sense);
J=J+analogRead(PIN_BATText_Sense);
K=K+analogRead(PIN_SOLAR_Sense);
}
// voltaje promedio
BattInt_Voltage=I/20.0;
BattExt_Voltage=J/20.0;
PV_Voltage=K/20.0;
BattInt_Voltage=maxADC_Voltage*BattInt_Voltage/1023.0;
BattExt_Voltage=maxADC_Voltage*BattExt_Voltage/1023.0;
PV_Voltage=maxADC_Voltage*PV_Voltage/1023.0;
}
//////////// Pantalla y Control //////////////
void Context_Control(void) {
if(ds==0) {show_menu();}
if(ds==1 && dp == 0) {show_info(); delay(100);} //LcdClear();Get_ADCVal();}
///////////////////////Entra al 1er Submenú////////////////////////////
if(ds==1 && dp == 1) {
level=1; dp=0;
while(level==1) {
int temp=ds;
LcdClear(); show_load_ctrl();delay(250);
if (dp==0){ if(ds!=temp){Load_Auto_Enable=0;digitalWrite(PIN_LOAD,LOW);}}
if (dp==1){if(ds!=temp){Load_Auto_Enable=0; digitalWrite(PIN_LOAD,HIGH);}}
if (dp==2){ if(ds!=temp){Load_Auto_Enable=1;}}
if (dp==3){show_load_ctrl();delay(250);level=0;dp=0;ds=0;}
}
}
//////////////////////Entra al 2do Submenú//////////////////////////////
if(ds==1 && dp == 2) {
level=2; dp=0;
while(level==2) {
int temp=ds;
show_inv_ctrl();delay(250);
LcdClear();
if (dp==0){ if(ds!=temp){Timer1_Init();}}
if (dp==1){ if(ds!=temp){Timer1_DeInit();}}
if (dp==2){ if(ds!=temp){Timer1_DeInit();digitalWrite(PIN_INVP,1);digitalWrite(PIN_INVN,1);}}
if (dp==3){show_inv_ctrl();delay(250);level=0;dp=0;ds=0;}
}
}
/////////////////////////////////////////////////////////
////////////////Entra al 3er Submenú/////////////////////////////
if(ds==1 && dp == 3) {
level=3; dp=0;
while(level==3) {
int temp=ds;
LcdClear(); show_led_ctrl();delay(250);
if (dp==0){blinker=0;if(ds!=temp) {if(y<=255){y=y+15;analogWrite(PIN_LAMP,y);}}}
if (dp==1){blinker=0;if(ds!=temp) {if(y>=0){y=y-15;analogWrite(PIN_LAMP,y);}}}
if (dp==2){if(ds!=temp) {blinker^=1;analogWrite(PIN_LAMP,127);delay(250);analogWrite(PIN_LAMP,0);}}
if (dp==3){show_led_ctrl();delay(250);level=0;dp=0;ds=0;}
}
}
/////////////////////////////////////////////////////////
// {show_inv_ctrl();}
// {show_led_ctrl();}
//}
if(blinker==1) {analogWrite(PIN_LAMP,0);}
delay(250);
if(blinker==1) {analogWrite(PIN_LAMP,127);}
}
/////////////////////////// Texto del Menú para mostrar en pantalla Nokia 5110 /////////////////
void show_menu(void) {
LcdXY(0,dp); LcdString("->");
LcdXY(15,0); LcdString("Sys Info");
LcdXY(15,1); LcdString("DC Load+");
LcdXY(15,2); LcdString("AC Load~");
LcdXY(15,3); LcdString("LED Lamp");
}
void show_info(void) {
LcdXY(0,0); LcdString("Bat_I="); LcdNumtoString(BattInt_Voltage); LcdString("v");
LcdXY(0,1); LcdString("Bat_E="); LcdNumtoString(BattExt_Voltage); LcdString("v");
LcdXY(0,2); LcdString("Sol_P="); LcdNumtoString(PV_Voltage); LcdString("v");
LcdXY(0,3);
if(BattExt_Voltage >8.0) {LcdString("Bat Conn OK");} else {LcdString("Conecta Bat");}
if (PV_Voltage > 10.5 && cdc_level!=3 && cdc_level!=0) {LcdString("Cargando:ON ");} else {LcdString("Cargando:OFF");}
if (TCNT1 >=45535 ) {LcdString("Inversor:ON");} else {LcdString("Inversor:OFF");}
}
void show_load_ctrl(void) {
LcdXY(0,dp); LcdString("->");
LcdXY(15,0); LcdString("Carga Off");
LcdXY(15,1); LcdString("Carga On");
LcdXY(15,2); LcdString("Carga Auto");
LcdXY(15,3); LcdString("Volver");
LcdXY(0,4); LcdString("Debe Conectar");
LcdString("Carga DC 12V");
}
void show_inv_ctrl(void) {
LcdXY(0,dp); LcdString("->");
LcdXY(15,0); LcdString("AC Inv On");
LcdXY(15,1); LcdString("AC Inv Off");
LcdXY(15,2); LcdString("2XDC Load");
LcdXY(15,3); LcdString("Volver");
LcdXY(0,4); LcdString("2XDC Load,NO");
LcdXY(0,5); LcdString("TRANSFORMADOR!");
}
void show_led_ctrl(void) {
LcdXY(0,dp); LcdString("->");
LcdXY(15,0); LcdString("LED ++");
LcdXY(15,1); LcdString("LED --");
LcdXY(15,2); LcdString("LED Parp");
LcdXY(15,3); LcdString("Volver");
LcdXY(0,4); LcdString("LED DESHABIL");
LcdXY(0,5); LcdString("Cuando INVR On");
}
///////////////// Interrupciones ISRs ////////////////
void SW1() {
dp++; if(dp>3){dp=0;}
}
void SW2() {
ds^=1;
}
ISR(TIMER1_OVF_vect) {
noInterrupts();
TCNT1 = 45535; // TCNT1 = 25535;
cycle^=1;
if(cycle==0); {
digitalWrite(PIN_INVP,HIGH);
delayMicroseconds(1); // banda muerta
digitalWrite(PIN_INVN,LOW);
delayMicroseconds(1);
}
if(cycle==1) {
digitalWrite(PIN_INVP,LOW);
delayMicroseconds(1); // banda muerta
digitalWrite(PIN_INVN,HIGH);
delayMicroseconds(1);
}
interrupts();
}
/////////////Funciones Nokia 5110 ////////////
static const byte ASCII[][5] = {
{0x00, 0x00, 0x00, 0x00, 0x00}, // 20
{0x00, 0x00, 0x5f, 0x00, 0x00}, // 21 !
{0x00, 0x07, 0x00, 0x07, 0x00}, // 22 "
{0x14, 0x7f, 0x14, 0x7f, 0x14}, // 23 #
{0x24, 0x2a, 0x7f, 0x2a, 0x12}, // 24 $
{0x23, 0x13, 0x08, 0x64, 0x62}, // 25 %
{0x36, 0x49, 0x55, 0x22, 0x50}, // 26 &
{0x00, 0x05, 0x03, 0x00, 0x00}, // 27 '
{0x00, 0x1c, 0x22, 0x41, 0x00}, // 28 (
{0x00, 0x41, 0x22, 0x1c, 0x00}, // 29 )
{0x14, 0x08, 0x3e, 0x08, 0x14}, // 2a *
{0x08, 0x08, 0x3e, 0x08, 0x08}, // 2b +
{0x00, 0x50, 0x30, 0x00, 0x00}, // 2c ,
{0x08, 0x08, 0x08, 0x08, 0x08}, // 2d -
{0x00, 0x60, 0x60, 0x00, 0x00}, // 2e .
{0x20, 0x10, 0x08, 0x04, 0x02}, // 2f /
{0x3e, 0x51, 0x49, 0x45, 0x3e}, // 30 0
{0x00, 0x42, 0x7f, 0x40, 0x00}, // 31 1
{0x42, 0x61, 0x51, 0x49, 0x46}, // 32 2
{0x21, 0x41, 0x45, 0x4b, 0x31}, // 33 3
{0x18, 0x14, 0x12, 0x7f, 0x10}, // 34 4
{0x27, 0x45, 0x45, 0x45, 0x39}, // 35 5
{0x3c, 0x4a, 0x49, 0x49, 0x30}, // 36 6
{0x01, 0x71, 0x09, 0x05, 0x03}, // 37 7
{0x36, 0x49, 0x49, 0x49, 0x36}, // 38 8
{0x06, 0x49, 0x49, 0x29, 0x1e}, // 39 9
{0x00, 0x36, 0x36, 0x00, 0x00}, // 3a :
{0x00, 0x56, 0x36, 0x00, 0x00}, // 3b ;
{0x08, 0x14, 0x22, 0x41, 0x00}, // 3c <
{0x14, 0x14, 0x14, 0x14, 0x14}, // 3d =
{0x00, 0x41, 0x22, 0x14, 0x08}, // 3e >
{0x02, 0x01, 0x51, 0x09, 0x06}, // 3f ?
{0x32, 0x49, 0x79, 0x41, 0x3e}, // 40 @
{0x7e, 0x11, 0x11, 0x11, 0x7e}, // 41 A
{0x7f, 0x49, 0x49, 0x49, 0x36}, // 42 B
{0x3e, 0x41, 0x41, 0x41, 0x22}, // 43 C
{0x7f, 0x41, 0x41, 0x22, 0x1c}, // 44 D
{0x7f, 0x49, 0x49, 0x49, 0x41}, // 45 E
{0x7f, 0x09, 0x09, 0x09, 0x01}, // 46 F
{0x3e, 0x41, 0x49, 0x49, 0x7a}, // 47 G
{0x7f, 0x08, 0x08, 0x08, 0x7f}, // 48 H
{0x00, 0x41, 0x7f, 0x41, 0x00}, // 49 I
{0x20, 0x40, 0x41, 0x3f, 0x01}, // 4a J
{0x7f, 0x08, 0x14, 0x22, 0x41}, // 4b K
{0x7f, 0x40, 0x40, 0x40, 0x40}, // 4c L
{0x7f, 0x02, 0x0c, 0x02, 0x7f}, // 4d M
{0x7f, 0x04, 0x08, 0x10, 0x7f}, // 4e N
{0x3e, 0x41, 0x41, 0x41, 0x3e}, // 4f O
{0x7f, 0x09, 0x09, 0x09, 0x06}, // 50 P
{0x3e, 0x41, 0x51, 0x21, 0x5e}, // 51 Q
{0x7f, 0x09, 0x19, 0x29, 0x46}, // 52 R
{0x46, 0x49, 0x49, 0x49, 0x31}, // 53 S
{0x01, 0x01, 0x7f, 0x01, 0x01}, // 54 T
{0x3f, 0x40, 0x40, 0x40, 0x3f}, // 55 U
{0x1f, 0x20, 0x40, 0x20, 0x1f}, // 56 V
{0x3f, 0x40, 0x38, 0x40, 0x3f}, // 57 W
{0x63, 0x14, 0x08, 0x14, 0x63}, // 58 X
{0x07, 0x08, 0x70, 0x08, 0x07}, // 59 Y
{0x61, 0x51, 0x49, 0x45, 0x43}, // 5a Z
{0x00, 0x7f, 0x41, 0x41, 0x00}, // 5b [
{0x02, 0x04, 0x08, 0x10, 0x20}, // 5c \
{0x00, 0x41, 0x41, 0x7f, 0x00}, // 5d ]
{0x04, 0x02, 0x01, 0x02, 0x04}, // 5e ^
{0x40, 0x40, 0x40, 0x40, 0x40}, // 5f _
{0x00, 0x01, 0x02, 0x04, 0x00}, // 60 `
{0x20, 0x54, 0x54, 0x54, 0x78}, // 61 a
{0x7f, 0x48, 0x44, 0x44, 0x38}, // 62 b
{0x38, 0x44, 0x44, 0x44, 0x20}, // 63 c
{0x38, 0x44, 0x44, 0x48, 0x7f}, // 64 d
{0x38, 0x54, 0x54, 0x54, 0x18}, // 65 e
{0x08, 0x7e, 0x09, 0x01, 0x02}, // 66 f
{0x0c, 0x52, 0x52, 0x52, 0x3e}, // 67 g
{0x7f, 0x08, 0x04, 0x04, 0x78}, // 68 h
{0x00, 0x44, 0x7d, 0x40, 0x00}, // 69 i
{0x20, 0x40, 0x44, 0x3d, 0x00}, // 6a j
{0x7f, 0x10, 0x28, 0x44, 0x00}, // 6b k
{0x00, 0x41, 0x7f, 0x40, 0x00}, // 6c l
{0x7c, 0x04, 0x18, 0x04, 0x78}, // 6d m
{0x7c, 0x08, 0x04, 0x04, 0x78}, // 6e n
{0x38, 0x44, 0x44, 0x44, 0x38}, // 6f o
{0x7c, 0x14, 0x14, 0x14, 0x08}, // 70 p
{0x08, 0x14, 0x14, 0x18, 0x7c}, // 71 q
{0x7c, 0x08, 0x04, 0x04, 0x08}, // 72 r
{0x48, 0x54, 0x54, 0x54, 0x20}, // 73 s
{0x04, 0x3f, 0x44, 0x40, 0x20}, // 74 t
{0x3c, 0x40, 0x40, 0x20, 0x7c}, // 75 u
{0x1c, 0x20, 0x40, 0x20, 0x1c}, // 76 v
{0x3c, 0x40, 0x30, 0x40, 0x3c}, // 77 w
{0x44, 0x28, 0x10, 0x28, 0x44}, // 78 x
{0x0c, 0x50, 0x50, 0x50, 0x3c}, // 79 y
{0x44, 0x64, 0x54, 0x4c, 0x44}, // 7a z
{0x00, 0x08, 0x36, 0x41, 0x00}, // 7b {
{0x00, 0x00, 0x7f, 0x00, 0x00}, // 7c |
{0x00, 0x41, 0x36, 0x08, 0x00}, // 7d }
{0x10, 0x08, 0x08, 0x10, 0x08}, // 7e ~
{0x78, 0x46, 0x41, 0x46, 0x78} // 7f
};
void LcdCharacter(char character) {
LcdWrite(LCD_D, 0x00);
for (int index = 0; index < 5; index++) {
LcdWrite(LCD_D, ASCII[character - 0x20][index]);
}
LcdWrite(LCD_D, 0x00);
}
void LcdClear(void) {
for (int index = 0; index < LCD_X * LCD_Y / 8; index++) {
LcdWrite(LCD_D, 0x00);
}
}
void LcdInitialise(void) {
pinMode(PIN_SCE, OUTPUT);
pinMode(PIN_RESET, OUTPUT);
pinMode(PIN_DC, OUTPUT);
pinMode(PIN_SDIN, OUTPUT);
pinMode(PIN_SCLK, OUTPUT);
digitalWrite(PIN_RESET, LOW);
digitalWrite(PIN_RESET, HIGH);
LcdWrite(LCD_C, 0x21); // Comandos Extendidos LCD.
LcdWrite(LCD_C, 0xA0); // Establecer Vop LCD (Contraste).
//0xB1
LcdWrite(LCD_C, 0x04); // Establecer coeficiente Temp.
//0x04
LcdWrite(LCD_C, 0x14); // Modo bias LCD 1:48.
//0x13
LcdWrite(LCD_C, 0x20); // Comandos Básicos LCD
LcdWrite(LCD_C, 0x0C); // LCD en modo normal.
}
void LcdString(char *characters) {
while (*characters) {
LcdCharacter(*characters++);
}
}
void LcdWrite(byte dc, byte data) {
// analogWrite(PIN_BL, 127);
digitalWrite(PIN_DC, dc);
digitalWrite(PIN_SCE, LOW);
shiftOut(PIN_SDIN, PIN_SCLK, MSBFIRST, data);
digitalWrite(PIN_SCE, HIGH);
}
void LcdXY(int x,int y) {
LcdWrite(LCD_C,0x80|x);
LcdWrite(LCD_C,0x40|y);
}
void LcdNumtoString(float number) {
char string[8];
LcdString(dtostrf(number,5,2, string));
}
///////////////// Funciones de Control de Bucle en Segundo Plano //////////////
// Este código habilitará automáticamente la carga externa cuando el sol se pone usando PV como Sensor de Luz
void Load_Control(void) {
if (Load_Auto_Enable == 1 && PV_Voltage < 4.5 && cdc_level > 0) {digitalWrite(PIN_LOAD,HIGH);}
if (Load_Auto_Enable == 1 && PV_Voltage >10.5 || cdc_level==0) {digitalWrite(PIN_LOAD,LOW);}
}
void Charging_Control (void) {
// Nivel BattExt_Voltage 14.3 Carga off, 13.5 o menos Carga on, 10.8 Carga off, 12.5 Carga on
// esta siguiente condición previene los intentos de carga durante la noche % noche PV es 0 volt!
if (PV_Voltage > 10.5 && BattExt_Voltage >8.0) {
if (BattExt_Voltage <= 12.5) { analogWrite(PIN_BATTPWM,255); cdc_level = 0; }
if (BattExt_Voltage > 12.5 && BattExt_Voltage <=12.9) { analogWrite(PIN_BATTPWM,200); cdc_level = 1; }
if (BattExt_Voltage > 12.9 && BattExt_Voltage <=13.3) { analogWrite(PIN_BATTPWM,160); cdc_level = 1; }
if (BattExt_Voltage > 13.3 && BattExt_Voltage <=13.6) { analogWrite(PIN_BATTPWM,120); cdc_level = 2; }
if (BattExt_Voltage > 13.6 && BattExt_Voltage <=13.9 && cdc_level == 2) { analogWrite(PIN_BATTPWM,80); cdc_level = 2; }
if (BattExt_Voltage > 13.9 && BattExt_Voltage <=14.3 && cdc_level == 2) { analogWrite(PIN_BATTPWM,40); cdc_level = 2; }
// Bloqueo por Sobrevoltaje, mientras cdc_level es 3, NO Carga! La carga reanuda cuando cdc es 2 que es debajo de 13.5v
if (BattExt_Voltage > 14.3) { analogWrite(PIN_BATTPWM,0); cdc_level = 3; }
} else {analogWrite(PIN_BATTPWM,0);cdc_level = 3;}
}
/// Bloqueo por Subvoltaje
void Discharging_Control (void) {
if (BattExt_Voltage <= 10.8) {
cdc_level = 0;
{digitalWrite(PIN_LOAD,LOW);}
Timer1_DeInit();
}
}
///////////////// Funciones del Temporizador 2 ////////////////
// Esta parte del código está escrita en estilo AVR
void Timer1_Init(void) {
noInterrupts(); // deshabilita todas las interrupciones
pinMode(PIN_INVP,OUTPUT);
pinMode(PIN_INVN,OUTPUT);
TCCR1A = 0;
TCCR1B = 0;
/* ========================================
50 Hz CA significa 20 ms Onda que se forma por 2, pulsos de 10 ms desde pines PIN_INVP y PIN_INVN
así que ambos pines deberían conmutar a 100 Hz!
Ahora 100 Hz = .01 seg
Reloj del Sistema Arduino 16 MHz = 16000000 ciclos en 0.01 seg tenemos 160000 ciclos
usando prescaler de 8 (CS11) hace que el temporizador cuente 160000/8 = 20000 ticks del temporizador
Como el temporizador 2 es Contador Ascendente de 16 bits y Desborda en valor 65635
necesitamos empezar a contar desde 65535-20000 = desde 45535 valor hasta 65535
así TCNT1 empieza en 45535 ..luego tick tick tick ... 46000 .... 50000 .............. 65536 !!!
Boom Interrupción por Desbordamiento de Temporizador y conmutar los pines de control del inversor en ISR
y empezar a contar desde 45535 Otra Vez !!! (Esto ocurre en Segundo Plano)
======================================== */
TCNT1 = 45535; //TCNT1 = 25535;
TCCR1B |= (1 << CS11); // prescaler 8
TIMSK |= (1 << TOIE1); // habilita interrupción por comparación de temporizador
interrupts();
}
void Timer1_DeInit(void) {
noInterrupts(); // deshabilita todas las interrupciones
TCCR1A = 0;
TCCR1B = 0;
TCNT1 = 0;
// TIMSK &= (0 << TOIE1); // deshabilita interrupción por comparación de temporizador
digitalWrite(PIN_INVP,LOW);
digitalWrite(PIN_INVN,LOW);
interrupts();
}
Código CompletoC/C++
Código Organizado y Legible
No hay vista previa (solo descarga).
BootloadersC/C++
No hay vista previa (solo descarga).
Esquemas

Proceso de manufactura
- Lámparas Halógenas: Tecnología, Historia y Futuro – Perspectiva Experta
- Lámpara de Lava: Historia, Diseño y Secretos de Fabricación
- Sistemas de calefacción solar: de soluciones pasivas a activas para calefacción sostenible del hogar
- Circuitos integrados (CI): chips compactos y potentes que impulsan la electrónica moderna
- Células solares: de los primeros experimentos a la fotovoltaica moderna – tecnología, producción y perspectivas
- Semáforo Inteligente: Iluminación Vial Adaptativa con IoT
- Mando USB para juegos DIY con Arduino – Construye tu propio gamepad de alto rendimiento
- Disfraz de nube DIY: Tira LED, Arduino Nano y componentes SparkFun
- Rastreador Solar V2.0 – Sistema Avanzado DIY de Seguimiento Solar
- Aprovechamiento de la energía solar: guía completa para una energía limpia y fiable
- Qué es un Inversor Solar: Cómo Convierte la Energía Solar en Electricidad Utilizable












