Промышленное производство
Промышленный Интернет вещей | Промышленные материалы | Техническое обслуживание и ремонт оборудования | Промышленное программирование |
home  MfgRobots >> Промышленное производство >  >> Manufacturing Technology >> Производственный процесс

Универсальный солнечный хаб: контроллер заряда, инвертер, пауэрбанк и LED-лампа в одном устройстве

Компоненты и материалы

Микроконтроллер Atmega8 (Microchip Technology) 1
Step-down (Buck) преобразователь 1
SparkFun LED 3W алюминиевая плата (5 шт., тёплый белый) 1
Дисплей Nokia 5110 1
Радиатор SparkFun 1
N-канальный MOSFET (SparkFun) 4
P-канальный MOSFET (SparkFun) 1
Солнечная панель 40 Вт или менее для 12V системы 1
Li-ion аккумулятор 18650 (SparkFun) 1
DC-DC 0.9V-5V → USB модуль 5V Boost Step-up 1
NPN транзистор общего назначения 1
Трансформатор с центральным отводом 12-0-12/220 1
Диод 1N4007 (высокое напряжение, большой ток) 1
Пин-хедер 36 позиций 1
Тумблер 1
Кнопка 12mm (SparkFun) 1
Arduino Proto Shield 1
Печатная/веро/макетная плата 8x11 см 1
Arduino UNO 1
Arduino Nano R3 1
Arduino Mega 2560 1
Шоттки диод 5822 (низкое прямое напряжение) 1
Конденсатор 10 мкФ 1
Конденсатор 100 нФ 1

Необходимые инструменты и оборудование

Паяльник
Дрель
Клеевой пистолет

Приложения и онлайн-сервисы

Arduino IDE
AutoDesk 123D

О проекте

О проекте

У меня было несколько солнечных панелей, 12-вольтовых батарей, трансформаторов и прочих деталей, лежавших без дела. Так родилось это устройство — компактное PV-решение на одной плате. Разберём, что за что отвечает:

В этом устройстве все эти функции. Последние две работают независимо от встроенного Li-ion аккумулятора. С солнечной панелью (до 100 Вт), 12V свинцово-кислотной батареей и трансформатором можно использовать все возможности.

Прототип на Arduino UNO

Первая версия на плате Uno с минимальным железом и функциями. Дисплей Nokia смонтирован прямо на плате, разработан щит с MOSFET для заряда/разряда. Нет меню, инвертера, ШИМ-заряда и прочих фишек! Только вкл/выкл зарядки и показ напряжений батареи и панели. Работает, но без изюминки.

Универсальный солнечный хаб: контроллер заряда, инвертер, пауэрбанк и LED-лампа в одном устройстве

Полнофункциональная версия на макетной плате

Затем разработана новая версия со следующими возможностями:

Управление двумя кнопками/переключателями: прокрутка и выбор в меню на дисплее Nokia 5110. Очень удобно! Обратная сторона изолирована термоклеем от коротких замыканий на металлических предметах.

Дополнительные удобства: выключатель подсветки дисплея, отделение buck для автономной работы от внутренней батареи.

Универсальный солнечный хаб: контроллер заряда, инвертер, пауэрбанк и LED-лампа в одном устройстве
Универсальный солнечный хаб: контроллер заряда, инвертер, пауэрбанк и LED-лампа в одном устройстве
Универсальный солнечный хаб: контроллер заряда, инвертер, пауэрбанк и LED-лампа в одном устройстве
Универсальный солнечный хаб: контроллер заряда, инвертер, пауэрбанк и LED-лампа в одном устройстве

Меню на Nokia 5110 с кнопками:

Технические детали

Контроллеры заряда бывают On/Off, PWM или MPPT. On/Off — простейшая форма (моя v1) — не дросселирует ток заряда при приближении к полному заряду.

PWM постепенно уменьшает ток заряда по мере наполнения батареи. Преимущества PWM:

Но PWM не извлекает максимум мощности из солнечных панелей, так как тянет панель к напряжению батареи. MPPT решает это — это регулируемый buck-boost преобразователь, извлекающий больше солнечной энергии.

Инвертеры: прямоугольный, модифицированный синус и чистый синус. Прямоугольный — простой, подходит для малых нагрузок (лампы, вентиляторы, паяльники), но не для индуктивных двигателей и чувствительной электроники из-за гармонических искажений.

Модифицированный синус — улучшенный прямоугольный. Чистый синус — лучший для всех нагрузок, но сложен в железе, алгоритмах и дорог.

Buck-преобразователь — понижающий DC-DC. Здесь buck-модуль заряжает 4.2V Li-ion батарею, питание контроллера (Arduino + дисплей), независимый USB пауэрбанк, LED-лампу.

Универсальный солнечный хаб: контроллер заряда, инвертер, пауэрбанк и LED-лампа в одном устройстве

USB пауэрбанк — это DC-DC boost, преобразующий 3.3–4.2V от Li-ion/LiPo в 5V USB для зарядки мобильных устройств. Также имеет buck для заряда своей батареи. В проекте buck-модуль берёт энергию от панели для заряда внутренней батареи.

Принцип работы железа

Схема всех подключений:

Универсальный солнечный хаб: контроллер заряда, инвертер, пауэрбанк и LED-лампа в одном устройстве

Мозг — AVR Atmega8A (можно Atmega328P с небольшими правками), запрограммирован в Arduino.

Универсальный солнечный хаб: контроллер заряда, инвертер, пауэрбанк и LED-лампа в одном устройстве

Свежий Atmega8A прошит загрузчиком Arduino Optiboot8. Можно купить загруженный Arduino Mini/Atmega328, чтобы избежать сложностей.

Контроллер, дисплей, LED-лампа и пауэрбанк питаются от внутреннего Li-ion. Две тактовые кнопки — для меню на дисплее. Кнопки аппаратно антидребезжены конденсаторами параллельно. Тумблер — вкл/выкл устройства.

Универсальный солнечный хаб: контроллер заряда, инвертер, пауэрбанк и LED-лампа в одном устройстве

Солнечная зарядка: P-MOSFET, управляемый через 2N2222 транзисторную схему драйвера, управляемой ШИМ от микроконтроллера. ШИМ зависит от напряжения внешней батареи. Ток от панели через P-MOSFET к свинцово-кислотной батарее. При полном заряде MOSFET отключается микроконтроллером. После отключения напряжение батареи плавно падает, при 13.6V зарядка возобновляется с низким скважностью для поддержки плавающего заряда.

12V DC нагрузка управляется N-MOSFET через Gate от микроконтроллера.

Универсальный солнечный хаб: контроллер заряда, инвертер, пауэрбанк и LED-лампа в одном устройстве

LED-лампа тоже через NMOS. Gate ШИМ-управляется для регулировки яркости.

Универсальный солнечный хаб: контроллер заряда, инвертер, пауэрбанк и LED-лампа в одном устройстве

Инвертер: 2 N-MOSFET, чередующиеся вкл/выкл для симуляции AC. С внешним трансформатором с центральным отводом получаем прямоугольный AC.

Универсальный солнечный хаб: контроллер заряда, инвертер, пауэрбанк и LED-лампа в одном устройстве

Принцип инвертора:

Универсальный солнечный хаб: контроллер заряда, инвертер, пауэрбанк и LED-лампа в одном устройстве

Пропуская ток через центральный отвод катушки повышающего трансформатора в противоположные стороны поочерёдно через MOSFET, создаём AC на вторичке. Когда верхний MOSFET открыт, нижний закрыт — ток вверх. Наоборот — ток вниз.

Универсальный солнечный хаб: контроллер заряда, инвертер, пауэрбанк и LED-лампа в одном устройстве

Оба MOSFET должны переключаться на удвоенной частоте AC. Для 50 Гц (20 мс период) — 10 мс на полуволну, значит 100 переключений в секунду Gate-сигналов MOSFET инвертора.

Универсальный солнечный хаб: контроллер заряда, инвертер, пауэрбанк и LED-лампа в одном устройстве
Универсальный солнечный хаб: контроллер заряда, инвертер, пауэрбанк и LED-лампа в одном устройстве
Универсальный солнечный хаб: контроллер заряда, инвертер, пауэрбанк и LED-лампа в одном устройстве

Внимание! Высокое напряжение AC смертельно опасно! Никогда не касайтесь высоковольтной стороны трансформатора голыми руками!

Если инвертер не используется, опция 2XDC Load позволяет использовать две дополнительные 12V DC нагрузки на клеммах инвертера.

Магия программного обеспечения

Два варианта кода: монолитный в одной вкладке Arduino и модульный по вкладкам для отдельных функций.

Задачи обобщены в функции:

Ввод пользователя через прерывания от кнопок. При нажатии выполняются ISR для INT0/INT1. Меняются volatile переменные dp и ds. Третья переменная level вместе с dp (указатель меню) и ds (селектор контента) позволяет навигировать по меню/подменю и выполнять действия.

16-битный Timer1 настроен на прерывание переполнения каждые 10 мс, переключая PIN_INVP и PIN_INVN при включённом инвертере.

Все функции Lcd_...() — работа с дисплеем.

Atmega8A vs Atmega328P (Uno)

Систему легко адаптировать под Atmega328P/Uno, заменив в коде:

TIMSK → TIMSK1
#define ADC_VREF 2.69 → #define ADC_VREF 1.11
#define ADCVDIV_R1 22 → #define ADCVDIV_R1 8.2

В железе: использовать резистор 8.2 кОм вместо 22 кОм для масштабирования напряжений панели/батареи в диапазон ADC.

Видео в действии

Обычно смотрю видео перед чтением. Если вы так же — наслаждайтесь роликами!

Перспективы улучшения

Место во Flash Atmega8A закончилось. Не удалось добавить критичные фичи:

Если планируете похожее — добавьте эти фичи! Atmega328P (Uno) или Arduino Mega подойдут лучше для всего этого. Но текущая версия работает, я доволен.

Дополнительные ресурсы

Код

Код во вкладке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 // 12 v dc load
#define PIN_LAMP 10 // WHITE LED LIGHT
#define PIN_BATTPWM 11 // Drives PMOS for Ext BAtt Charging
#define PIN_BATTint_Sense A2
#define PIN_SOLAR_Sense A0
#define PIN_BATText_Sense A3
#define ADC_VREF 2.695 // internal ref voltage, around 1.11V for Arduino Uno aka Atmega328P, here my Atmega8A gives this !
#define ADCVDIV_R1 22 // 22 K voltage divider lower Resistor
#define ADCVDIV_R2 175 // 175 K voltage divider upper Resistor
//const uint8_t skulljoke[] PROGMEM ={2,} ; // PIN 2 & 3 USED AS INTERRUPT SWITCH
// PIN 0 & 1 AS PROGRAMMING
// PIN RESET AS
#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(" CONTROLLER,");
  LcdString("AC INVERTER,");
  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);// Interrupt for Swithc 1
  pinMode(3, INPUT_PULLUP);
  attachInterrupt(1, SW2, FALLING);// Interrupt for Swithc 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);
  }
  // average voltage
  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;
}
//////////// Display and Control //////////////
void Context_Control(void) {
  if(ds==0) {show_menu();}
  if(ds==1 && dp == 0) {show_info(); delay(100);} //LcdClear();Get_ADCVal();}
  ///////////////////////Enters 1st Sub Menu////////////////////////////
  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;}
    }
  }
  //////////////////////Enters 2nd Sub Menu//////////////////////////////
  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;}
    }
  }
  /////////////////////////////////////////////////////////
  ////////////////Enters 3rd Sub Menu/////////////////////////////
  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);}
}
/////////////////////////// Menu Text to be shown on Nokia 5110 display ///////////////////
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("Batt Conn OK");} else {LcdString("Connect Batt");}
  if (PV_Voltage > 10.5 && cdc_level!=3 && cdc_level!=0) {LcdString("Charging:ON ");} else {LcdString("Charging:OFF");}
  if (TCNT1 >=45535 ) {LcdString("Inverter:ON");} else {LcdString("Inverter:OFF");}
}
void show_load_ctrl(void) {
  LcdXY(0,dp); LcdString("->");
  LcdXY(15,0); LcdString("Load Off");
  LcdXY(15,1); LcdString("Load On");
  LcdXY(15,2); LcdString("Load Auto");
  LcdXY(15,3); LcdString("Return");
  LcdXY(0,4); LcdString("Must Connect");
  LcdString("12V DC Load");
}
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("Return");
  LcdXY(0,4); LcdString("2XDC Load,NO");
  LcdXY(0,5); LcdString("TRANSFORMER!");
}
void show_led_ctrl(void) {
  LcdXY(0,dp); LcdString("->");
  LcdXY(15,0); LcdString("LED ++");
  LcdXY(15,1); LcdString("LED --");
  LcdXY(15,2); LcdString("LED Blk");
  LcdXY(15,3); LcdString("Return");
  LcdXY(0,4); LcdString("LED DISABLEs");
  LcdXY(0,5); LcdString("When INVR On");
}
////////////// Interrupt 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); // dead band
    digitalWrite(PIN_INVN,LOW);
    delayMicroseconds(1);
  }
  if(cycle==1) {
    digitalWrite(PIN_INVP,LOW);
    delayMicroseconds(1); // dead band
    digitalWrite(PIN_INVN,HIGH);
    delayMicroseconds(1);
  }
  interrupts();
}
/////////////Nokia 5110 Functions ////////////
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 ); // LCD Extended Commands.
  LcdWrite(LCD_C, 0xA0 ); // Set LCD Vop (Contrast). //0xB1
  LcdWrite(LCD_C, 0x04 ); // Set Temp coefficent. //0x04
  LcdWrite(LCD_C, 0x14 ); // LCD bias mode 1:48. //0x13
  LcdWrite(LCD_C, 0x20 ); // LCD Basic Commands
  LcdWrite(LCD_C, 0x0C ); // LCD in normal mode.
}
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));
}
///////////////// Background Loop Control Functions ////////////
// This codelet will automatically enable external load when Sun is Down using PV as Light Sensor
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) {
  // BattExt_Voltage Level 14.3 Charging off, 13.5 or below Charging on, 10.8 Load off, 12.5 Load on
  // this next condition prevenst the attemps of charging during night % night PV is 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; }
    // Over Voltage Lockout, while cdc_level is 3, NO Charging ! Charging Resumes when cdc is 2 which is below 13.5 v
    if (BattExt_Voltage > 14.3 ) { analogWrite(PIN_BATTPWM,0); cdc_level = 3; }
  } else {analogWrite(PIN_BATTPWM,0);cdc_level = 3;}
}
/// Under voltage Lockout
void Discharging_Control (void) {
  if (BattExt_Voltage <= 10.8) {
    cdc_level = 0;
    {digitalWrite(PIN_LOAD,LOW);}
    Timer1_DeInit();
  }
}
/////////////// Timer 2 Functions //////////////
// This portion of the code is written in AVR style
void Timer1_Init(void) {
  noInterrupts(); // disable all interrupts
  pinMode(PIN_INVP,OUTPUT);
  pinMode(PIN_INVN,OUTPUT);
  TCCR1A = 0;
  TCCR1B = 0;
  /* ========================================
     50 Hz AC means 20 ms Wave which is formed by 2, 10 ms Pulses from PIN_INVP and PIN_INVN pins
     so both this pin should toggle at 100 Hz !
     Now 100 Hz = .01 sec
     Arduino System Clock 16 MHz = 16000000 cycle in 0,01 sec we have 160000 cycles
     using prescaler of 8 (CS11) makes timer count 160000/8 = 20000 timer ticks
     Since the timer 2 is 16 bit Up Counter and it Overflows at 65635 value
     we need to start counting from 65535-20000 = from 45535 value upto 65535
     thus TCNT1 starts at 45535 ..then tick tick tick ... 46000 .... 50000 .............. 65536 !!!
     Boom Timer Over Flow Interrupt and toggle the Inverter driving pins in ISR
     and start counting from 45535 Again !!! (This happens in the Background)
     ======================================== */
  TCNT1 = 45535; //TCNT1 = 25535;
  TCCR1B |= (1 << CS11); // 8 prescaler
  TIMSK |= (1 << TOIE1); // enable timer compare interrupt
  interrupts();
}
void Timer1_DeInit(void) {
  noInterrupts(); // disable all interrupts
  TCCR1A = 0;
  TCCR1B = 0;
  TCNT1 = 0;
  // TIMSK &= (0 << TOIE1); // disable timer compare interrupt
  digitalWrite(PIN_INVP,LOW);
  digitalWrite(PIN_INVN,LOW);
  interrupts();
}
Полный кодC/C++

Код организован и читаем
Нет предпросмотра (только скачивание).

ЗагрузчикиC/C++

Нет предпросмотра (только скачивание).

Схемы

Универсальный солнечный хаб: контроллер заряда, инвертер, пауэрбанк и LED-лампа в одном устройстве

Производственный процесс

  1. Что такое солнечный инвертор? Как он преобразует солнечную энергию в пригодную электричество
  2. Галогенные лампы: технологии, история и будущее — экспертный обзор
  3. Лавовая лампа: история, дизайн и производственные секреты
  4. Солнечные отопительные системы: от пассивных к активным решениям для устойчивого отопления домов
  5. Интегральные схемы (ИС): компактные мощные чипы, питающие современную электронику
  6. Солнечные ячейки: от ранних экспериментов к современной фотовольтаике — технологии, производство и перспекти…
  7. Умный светофор: адаптивное уличное освещение на базе IoT
  8. DIY USB-геймпад на Arduino: собственный высокопроизводительный контроллер
  9. Солнечный трекер v2.0 — продвинутая DIY система слежения за солнцем
  10. Солнечная энергия: полное руководство по чистой и надежной энергии