亿迅智能制造网
工业4.0先进制造技术信息网站!
首页 | 制造技术 | 制造设备 | 工业物联网 | 工业材料 | 设备保养维修 | 工业编程 |
home  MfgRobots >> 亿迅智能制造网 >  >> Manufacturing Technology >> 制造工艺

一体化太阳能电源中心:充电控制器、逆变器、移动电源与 LED 灯

组件与供应

Microchip ATmega8×1
降压转换器×1
SparkFun 3W 铝基板 LED (5 只装, 暖白)×1
Nokia 5110 显示屏×1
SparkFun 散热器×1
SparkFun N 沟道 MOSFET×4
SparkFun P 沟道 MOSFET×1
40W 或以下 12V 系统太阳能板×1
SparkFun 18650 锂电池×1
DC-DC 0.9V-5V 转 USB 模块 5V 升压电源×1
通用 NPN 三极管×1
12-0-12/220 中心抽头变压器×1
1N4007 高压大电流二极管×1
公排针 36P 单排×1
滑动开关×1
SparkFun 12mm 轻触开关×1
Arduino Proto Shield×1
条板/实验板 8x11 cm×1
Arduino UNO×1
Arduino Nano R3×1
Arduino Mega 2560×1
低压降肖特基二极管 5822×1
电容 10 µF×1
电容 100 nF×1

必要工具与机器

电烙铁
电钻
热熔胶枪

应用与在线服务

Arduino IDE
AutoDesk 123D

关于项目

项目简介

我有闲置的太阳能板、12V 电池、变压器等,决定整合成一个单板完整的小型光伏解决方案。先看看各功能模块:

本装置集成以上所有功能,后两项由板载锂电池独立供电。配合太阳能板(高达 100W)、12V 铅酸电池和变压器,所有功能均可使用。

Uno 原型版

首个版本在 Uno 板上开发,硬件最少、功能最基础。Nokia 显示屏直插,开发 MOSFET 扩展板控制电池充放电。无菜单控制、无逆变器、无 PWM 充电等高级功能,仅开关充电并显示电池/面板电压。虽能工作但无亮点。

一体化太阳能电源中心:充电控制器、逆变器、移动电源与 LED 灯

实验板完整版

新版本功能:

两按钮/开关控制滚动选择菜单,在 Nokia 5110 显示选项和状态。背面热熔胶绝缘防短路!

便捷功能:显示背光开关、降压模块可从内部电池断开独立工作。

一体化太阳能电源中心:充电控制器、逆变器、移动电源与 LED 灯
一体化太阳能电源中心:充电控制器、逆变器、移动电源与 LED 灯
一体化太阳能电源中心:充电控制器、逆变器、移动电源与 LED 灯
一体化太阳能电源中心:充电控制器、逆变器、移动电源与 LED 灯

技术原理解析

充电控制器分开关型、PWM 型、MPPT 型。开关型最简单(我 v1 版本),不随电池电压升高而限制充电电流。PWM 随电池充满逐渐减小充电电流,优势:

但 PWM 无法从光伏板获取最大电力,因它将面板电压拉近电池电压。MPPT 解决此问题,本质是可调升降压变换器,能转换更多太阳能。

逆变器分方波、修正正弦波、纯正弦波。方波设计最简单,适合交流灯、CFL、台扇、电烙铁等小负载,不适合感性电机、精密设备/电源(谐波失真)。修正正弦波由方波合成,优于方波。纯正弦波适配所有负载但硬件复杂、软件算法难、成本高。

降压稳压器是降压 DC-DC 变换器,这里用降压模块给 4.2V 锂电池充电,为控制器、移动电源、LED 灯供电。

一体化太阳能电源中心:充电控制器、逆变器、移动电源与 LED 灯

USB 移动电源本质是升压 DC-DC,将锂电池 3.3-4.2V 升至 5V USB 电压给移动设备充电,同时含充电降压电路。本项目中降压模块从面板取电给板载电池充电。

硬件工作原理

系统各硬件服务不同功能,核心是 AVR ATmega8A 单片机(可改 ATmega328P,微调后兼容),用 Arduino 编程。

一体化太阳能电源中心:充电控制器、逆变器、移动电源与 LED 灯
一体化太阳能电源中心:充电控制器、逆变器、移动电源与 LED 灯

全新 ATmega8A 烧录 Arduino Optiboot8 引导程序,也可买已烧录引导程序的 Arduino Mini/ATmega328 避免麻烦。

控制器、显示屏、LED 灯、移动电源由板载锂电池供电。两个瞬时触摸按钮经并联电容硬件去抖动,用于菜单操作。滑动开关控制整机供电开关。

一体化太阳能电源中心:充电控制器、逆变器、移动电源与 LED 灯

太阳能充电由 P-MOSFET 执行,驱动电路用 2N2222 三极管,单片机 PWM 控制。PWM 占空比随外部电池电压调整。面板电流经 P-MOSFET 充入铅酸电池。电池充满则单片机关断 MOSFET。充电停止后电压缓慢下降,降至 13.6V 以低占空比恢复浮充。

12V 直流负载由 N-MOSFET 控制,单片机驱动其栅极。

一体化太阳能电源中心:充电控制器、逆变器、移动电源与 LED 灯

板载 LED 灯也由 N-MOSFET 驱动,栅极 PWM 控制亮度。

一体化太阳能电源中心:充电控制器、逆变器、移动电源与 LED 灯

逆变器部分由两个 N-MOSFET 交替导通模拟交流。外接中心抽头升压变压器可得方波交流输出。

一体化太阳能电源中心:充电控制器、逆变器、移动电源与 LED 灯

逆变器动作原理:

一体化太阳能电源中心:充电控制器、逆变器、移动电源与 LED 灯

让电流交替方向流过升压变压器中心抽头初级线圈,次级感应出交流电压。上管导通下管关断时电流向上,反之向下。两 MOSFET 需在两倍工频下翻转。产生 50Hz 交流需在 12-0-12V/220V 变压器低压侧施加方波,周期 20ms,故每 10ms 翻转一次栅极信号(即 100 次/秒)。

一体化太阳能电源中心:充电控制器、逆变器、移动电源与 LED 灯
一体化太阳能电源中心:充电控制器、逆变器、移动电源与 LED 灯
一体化太阳能电源中心:充电控制器、逆变器、移动电源与 LED 灯
一体化太阳能电源中心:充电控制器、逆变器、移动电源与 LED 灯

警告!!!:交流高压致命,可导致死亡/受伤!严禁裸手触碰变压器高压侧!

不使用逆变器功能时,“2XDC Load”选项允许在逆变器端子接两路 12V 直流负载。

软件设计精髓

提供两套代码:单文件完整版和按功能分标签的模块化版。

将任务组归纳为单一函数。例如:

用户输入通过中断驱动的瞬时按键获取。按键按下触发 INT0/INT1 中断,修改易变量 dp 和 ds。第三变量 level 配合 dp(显示指针)和 ds(显示内容选择器)实现菜单/子菜单导航和动作执行。

16 位 Timer1 配置为每 10ms 产生溢出中断,逆变器开启时翻转 PIN_INVP 和 PIN_INVN。

所有 Lcd_...() 函数处理显示控制。

ATmega8A 与 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.2kΩ 电阻替换 22kΩ以将面板/电池电压分压进 ADC 测量范围。

演示视频

我通常先看视频再读文字。同好者请欣赏视频:

(此处原文嵌入视频,略)

改进空间

ATmega8A Flash 空间耗尽,未能加入关键功能:

若你打算制作类似装置,别忘了加这些功能!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 // 12V 直流负载
#define PIN_LAMP 10 // 白光 LED
#define PIN_BATTPWM 11 // 驱动 PMOS 给外部电池充电
#define PIN_BATTint_Sense A2
#define PIN_SOLAR_Sense A0
#define PIN_BATText_Sense A3
#define ADC_VREF 2.695 // 内部参考电压,Uno(ATmega328P)约 1.11V,我用的 ATmega8A 给出此值
#define ADCVDIV_R1 22 // 分压下电阻 22K
#define ADCVDIV_R2 175 // 分压上电阻 175K
// PIN 2 & 3 作中断按键
// PIN 0 & 1 作编程口
// PIN RESET 作...
#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;

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);
  pinMode(3, INPUT_PULLUP); attachInterrupt(1, SW2, FALLING);
}
void loop(void) {
  Get_ADCVal(); Context_Control(); Charging_Control(); Discharging_Control(); Load_Control(); LcdClear();;
}
void Get_ADCVal(void) {
  int I=0,J=0,K=0;
  for(x=0;x<20;x++) { I+=analogRead(PIN_BATTint_Sense); J+=analogRead(PIN_BATText_Sense); K+=analogRead(PIN_SOLAR_Sense); }
  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;
}
void Context_Control(void) {
  if(ds==0) {show_menu();}
  if(ds==1 && dp == 0) {show_info(); delay(100);}
  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;} } }
  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;} } }
  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;} } }
  if(blinker==1) {analogWrite(PIN_LAMP,0);} delay(250); if(blinker==1) {analogWrite(PIN_LAMP,127);}
}
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"); }
void SW1() { dp++; if(dp>3){dp=0;} }
void SW2() { ds^=1; }
ISR(TIMER1_OVF_vect) { noInterrupts(); TCNT1 = 45535; cycle^=1; if(cycle==0) { digitalWrite(PIN_INVP,HIGH); delayMicroseconds(1); digitalWrite(PIN_INVN,LOW); delayMicroseconds(1); } if(cycle==1) { digitalWrite(PIN_INVP,LOW); delayMicroseconds(1); digitalWrite(PIN_INVN,HIGH); delayMicroseconds(1); } interrupts(); }
static const byte ASCII[][5] = { {0x00,0x00,0x00,0x00,0x00}, {0x00,0x00,0x5f,0x00,0x00}, ... }; // 字体表省略
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); LcdWrite(LCD_C, 0xA0); LcdWrite(LCD_C, 0x04); LcdWrite(LCD_C, 0x14); LcdWrite(LCD_C, 0x20); LcdWrite(LCD_C, 0x0C); }
void LcdString(char *characters) { while (*characters) { LcdCharacter(*characters++); } }
void LcdWrite(byte dc, byte data) { 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)); }
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) { 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; } if (BattExt_Voltage > 14.3 ) { analogWrite(PIN_BATTPWM,0); cdc_level = 3; } } else {analogWrite(PIN_BATTPWM,0); cdc_level = 3;} }
void Discharging_Control (void) { if (BattExt_Voltage <= 10.8) { cdc_level = 0; digitalWrite(PIN_LOAD,LOW); Timer1_DeInit(); } }
void Timer1_Init(void) { noInterrupts(); pinMode(PIN_INVP,OUTPUT); pinMode(PIN_INVN,OUTPUT); TCCR1A = 0; TCCR1B = 0; TCNT1 = 45535; TCCR1B |= (1 << CS11); TIMSK |= (1 << TOIE1); interrupts(); }
void Timer1_DeInit(void) { noInterrupts(); TCCR1A = 0; TCCR1B = 0; TCNT1 = 0; digitalWrite(PIN_INVP,LOW); digitalWrite(PIN_INVN,LOW); interrupts(); }
完整代码 C/C++

代码已整理且可读,预览不可用(仅供下载)。

引导程序 C/C++

预览不可用(仅供下载)。

原理图

一体化太阳能电源中心:充电控制器、逆变器、移动电源与 LED 灯

制造工艺

  1. 卤素灯:技术原理、发展史与未来趋势深度解析
  2. 熔岩灯:历史、设计与制造奥秘
  3. 太阳能供暖系统:从被动式到主动式的可持续家居供暖方案
  4. 集成电路 (IC):微观世界里的算力引擎与制造极限
  5. 太阳能电池:从早期实验到现代光伏技术的演进与未来展望
  6. 智能路灯:物联网自适应照明系统
  7. DIY Arduino USB 游戏手柄 — 自制高性能游戏手柄
  8. DIY 云朵发光服装 — LED 灯带 + Arduino Nano + SparkFun 元件
  9. 智能 Arduino 水杯:实时监测饮水量与智能提醒
  10. 太阳能跟踪器 V2.0:进阶 DIY 光伏自动追日系统
  11. 太阳能利用全指南:清洁可靠电力的获取与应用
  12. 什么是太阳能逆变器?如何将太阳能转为可用电力