프로젝트 배경
최근에 온라인에서 50와트 태양 전지판을 구입했습니다. 이 전지판은 12볼트 DC 전원과 2암페어의 전류를 생성합니다. 또한 12볼트 7암페어 배터리도 구입하여 미니 태양계를 만들고자 합니다.
왜 MPPT 태양열 충전 컨트롤러가 필요한가요?
태양 전지판에서 직접 배터리를 충전하면 배터리가 손상될 수 있습니다. MPPT(Maximum Power Point Tracking) 충전 컨트롤러는 PV 모듈에서 생성되는 전압과 전류를 최적화하여 배터리에 적절한 전압과 전류를 공급합니다. 이로 인해 배터리의 수명이 연장되고, 에너지 효율이 극대화됩니다.
필요한 부품
- 아두이노 나노
- IR2104 MOSFET 구동기
- IRFZ44 MOSFET 트랜지스터
- 20x4 LCD 디스플레이
- ACS712 전류 센서
- LM2596 벅 컨버터
- 12V 릴레이
- 커넥터, 다이오드, 커패시터 등
회로도
각 부품을 연결하여 전체 회로를 구성합니다. 이때, IR2104와 IRFZ44를 이용해 MOSFET 구동 회로를 구성하고, LM2596 벅 컨버터를 사용해 전압을 조절합니다. 전류 센서(ACS712)를 통해 실시간으로 전류를 모니터링합니다.
소스 코드
아두이노를 사용하여 MPPT 알고리즘을 구현합니다. 다음은 기본적인 코드 예시입니다.
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <ACS712.h>
ACS712 sensor(ACS712_30A, A0);
LiquidCrystal_I2C lcd(0x27, 20, 4);
void setup() {
lcd.begin();
lcd.backlight();
sensor.calibrate();
pinMode(7, OUTPUT); // Relay control pin
digitalWrite(7, LOW); // Initially off
}
void loop() {
float current = sensor.getCurrentDC();
lcd.setCursor(0, 0);
lcd.print("Current: ");
lcd.print(current);
lcd.print(" A");
if (current > 2.0) { // Example condition
digitalWrite(7, HIGH); // Turn on relay
lcd.setCursor(0, 1);
lcd.print("Relay: ON ");
} else {
digitalWrite(7, LOW); // Turn off relay
lcd.setCursor(0, 1);
lcd.print("Relay: OFF");
}
delay(1000);
}
장점과 단점
장점:
- 배터리 수명 연장
- 에너지 효율 극대화
- 실시간 모니터링 가능
단점:
- 초기 비용 발생
- 복잡한 회로 구성
그래서 이 게시물에서 우리는 MPPT 태양광 충전을 만듭니다 다음과 같은 컨트롤러 : -
>>MPPT 태양광 충전 컨트롤러란 무엇이며 어떻게 잘돼요?
이 프로젝트에 대한 >> 부분 필요성
>>회로도
>>코딩
>>장점과 단점
MPPT란? 태양 광 충전 컨트롤러?
필요한 부품
아두이노 나노
IR2104 MOSFET 구동기
IRFZ44 MOSFET 트랜지스터
20x4 LCD 디스플레이
ACS712 전류 센서
LM2596 벅 컨버터
12V 릴레이
커넥터
다이오드
커패시터
그리고 더 많은 전자 부품은 회로도를 참조하십시오.
회로 다이어그램
먼저 이 회로도에서 태양 전지판을 볼 수 있습니다. 전원은 5Amps 퓨즈로 연결된 2 단자에서 나옵니다. 퓨즈는 이 회로에 대해 중요 : 태양 전지판 뒷면 라벨을 확인하십시오. 태양 전지판에 대한 정보는 다음과 같습니다.
ACS712 전류 센서가 있습니다. 배터리의 전류 제한을 확인하기 위한 홀 효과 방법. 센서는 다음과 같습니다. Arduino A1 아날로그 핀에 연결하고 여기에 볼륨이 있습니다.tage 태양열 볼륨용 센서 voltag전자 및 배터리 전압은 Arduino A0 핀 및 A2 핀에 연결됩니다.
여기서 나는 회로도에서 언급하지 않고 당신을 언급하고 있습니다. 5V 벅 컨버터가 필요합니다. 사용할 수 있는 LM2596 벅 컨버터 모듈을 사용하고 있습니다. 모든 벅 컨버터 최대 2-3Amps 모든 회로 및 마이크로 컨트롤러에 대해 또한 휴대전화 충전 시스템을 사용하는 경우.
MOSFET 드라이버 IR2104 핀 2, 3은 Arduino에 연결됩니다. 9K 저항이 있는 D8, D1 핀과 핀 7 및 5는 Mosfet IRFZ44에 연결됩니다. 10옴 저항을 사용하면 H 브리지 회로가 생성됩니다.
20x4 LCD 디스플레이는 A4, A5 핀에 연결됩니다. 이를 위한 I2C 모듈은 핀 수를 덜 사용하고 사용하기 쉽습니다. (이 게시물에서 "20x4 LCD 디스플레이 사용 방법 I2C 사용")
단순히 3개의 LED는 D13, D12, D11에 연결합니다 1k 저항기 첫 번째 LED는 배터리 부족용, 두 번째 LED는 오버 플로우용이고 세 번째 LED는 전체 배터리용입니다.
마지막은 연결된 릴레이 모듈입니다. 모듈은 Arduino D6 핀과 연결됩니다.
코딩
//This Code was made by Debasish Dutta
//Libraries
#include "TimerOne.h"
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
// A0 - Voltage divider (solar)
// A1 - ACS 712 Out
// A2 - Voltage divider (battery)
// A4 - LCD SDA
// A5 - LCD SCL
// D5 - LCD back control button
// D6 - Load Control
// D8 - 2104 MOSFET driver SD
// D9 - 2104 MOSFET driver IN
// D11- Green LED
// D12- Blue LED
// D13- Red LED
#define LOAD_ALGORITHM 0
#define SOL_VOLTS_CHAN A0
#define BAT_VOLTS_CHAN A1
#define SOL_AMPS_CHAN A2
#define AVG_NUM 8
#define SOL_VOLTS_SCALE 0.024900275
#define BAT_VOLTS_SCALE 0.024926075
#define SOL_AMPS_SCALE 0.024506081
#define PWM_PIN 9
#define PWM_ENABLE_PIN 8
#define PWM_FULL 1023
#define PWM_MAX 100
#define PWM_MIN 60
#define PWM_START 90
#define PWM_INC 1
#define TRUE 1
#define FALSE 0
#define ON TRUE
#define OFF FALSE
#define TURN_ON_MOSFETS digitalWrite(PWM_ENABLE_PIN, HIGH)
#define TURN_OFF_MOSFETS digitalWrite(PWM_ENABLE_PIN, LOW)
#define ONE_SECOND 50000
#define LOW_SOL_WATTS 5.00
#define MIN_SOL_WATTS 1.00
#define MIN_BAT_VOLTS 11.00
#define MAX_BAT_VOLTS 14.10
#define BATT_FLOAT 13.60
#define HIGH_BAT_VOLTS 13.00
#define LVD 11.5
#define OFF_NUM 9
#define LED_GREEN 11
#define LED_BLUE 12
#define LED_RED 13
#define LOAD_PIN 6
#define BACK_LIGHT_PIN 5
byte battery_icons[6][8] =
{{
0b01110,
0b11011,
0b10001,
0b10001,
0b10001,
0b10001,
0b11111,
0b00000,
},
{
0b01110,
0b11011,
0b10001,
0b10001,
0b10001,
0b11111,
0b11111,
0b00000,
},
{
0b01110,
0b11011,
0b10001,
0b10001,
0b11111,
0b11111,
0b11111,
0b00000,
},
{
0b01110,
0b11011,
0b11111,
0b11111,
0b11111,
0b11111,
0b11111,
0b00000,
},
{
0b01110,
0b11111,
0b11111,
0b11111,
0b11111,
0b11111,
0b11111,
0b00000,
},
{
0b01110,
0b11111,
0b11111,
0b11111,
0b11111,
0b11111,
0b11111,
0b00000,
}
};
#define SOLAR_ICON 6
byte solar_icon[8] =
{
0b11111,
0b10101,
0b11111,
0b10101,
0b11111,
0b10101,
0b11111,
0b00000
};
#define PWM_ICON 7
byte _PWM_icon[8] =
{
0b11101,
0b10101,
0b10101,
0b10101,
0b10101,
0b10101,
0b10111,
0b00000,
};
byte backslash_char[8] =
{
0b10000,
0b10000,
0b01000,
0b01000,
0b00100,
0b00100,
0b00010,
0b00000,
};
float sol_amps;
float sol_volts;
float bat_volts;
float sol_watts;
float old_sol_watts = 0;
unsigned int seconds = 0;
unsigned int prev_seconds = 0;
unsigned int interrupt_counter = 0;
unsigned long time = 0;
int delta = PWM_INC;
int pwm = 0;
int back_light_pin_State = 0;
boolean load_status = false;
enum charger_mode {off, on, bulk, bat_float} charger_state;
LiquidCrystal_I2C lcd(0x27, 2, 1, 0, 4, 5, 6, 7); // 0x27 is the default I2C bus address of the backpack-see article
void setup()
{
pinMode(PWM_ENABLE_PIN, OUTPUT);
TURN_OFF_MOSFETS;
charger_state = off;
lcd.begin(20, 4);
lcd.setBacklightPin(3, POSITIVE); // BL, BL_POL
lcd.setBacklight(HIGH);
for (int batchar = 0; batchar < 6; ++batchar)
{
lcd.createChar(batchar, battery_icons[batchar]);
}
lcd.createChar(PWM_ICON, _PWM_icon);
lcd.createChar(SOLAR_ICON, solar_icon);
lcd.createChar('\\', backslash_char);
pinMode(LED_RED, OUTPUT);
pinMode(LED_GREEN, OUTPUT);
pinMode(LED_BLUE, OUTPUT);
Timer1.initialize(20);
Timer1.pwm(PWM_PIN, 0);
Timer1.attachInterrupt(callback);
Serial.begin(9600);
pwm = PWM_START;
pinMode(BACK_LIGHT_PIN, INPUT);
pinMode(LOAD_PIN, OUTPUT);
digitalWrite(LOAD_PIN, LOW);
digitalWrite(BACK_LIGHT_PIN, LOW);
lcd.setCursor(0, 0);
lcd.print("SOL");
lcd.setCursor(4, 0);
lcd.write(SOLAR_ICON);
lcd.setCursor(8, 0);
lcd.print("BAT");
}
void loop()
{
read_data();
run_charger();
// print_data();
load_control();
led_output();
lcd_display();
}
int read_adc(int channel)
{
int sum = 0;
int temp;
int i;
for (i = 0; i < AVG_NUM; i++) {
temp = analogRead(channel);
sum += temp;
delayMicroseconds(50);
} return (sum / AVG_NUM);
} void read_data(void) {
sol_amps = (read_adc(SOL_AMPS_CHAN) * SOL_AMPS_SCALE - 13.51);
sol_volts = read_adc(SOL_VOLTS_CHAN) * SOL_VOLTS_SCALE;
bat_volts = read_adc(BAT_VOLTS_CHAN) * BAT_VOLTS_SCALE;
sol_watts = sol_amps * sol_volts ;
} void callback() {
if (interrupt_counter++ > ONE_SECOND)
{
interrupt_counter = 0;
seconds++;
}
}
void set_pwm_duty(void)
{
if (pwm > PWM_MAX)
{
pwm = PWM_MAX;
}
else if (pwm < PWM_MIN)
{
pwm = PWM_MIN;
}
if (pwm < PWM_MAX)
{
Timer1.pwm(PWM_PIN, (PWM_FULL * (long)pwm / 100), 20);
}
else if (pwm == PWM_MAX)
{
Timer1.pwm(PWM_PIN, (PWM_FULL - 1), 20);
}
}
void run_charger(void)
{
static int off_count = OFF_NUM;
switch (charger_state)
{
case on:
if (sol_watts < MIN_SOL_WATTS) {
charger_state = off;
off_count = OFF_NUM;
TURN_OFF_MOSFETS;
} else if (bat_volts > (BATT_FLOAT - 0.1))
{
charger_state = bat_float;
}
else if (sol_watts < LOW_SOL_WATTS)
{
pwm = PWM_MAX;
set_pwm_duty();
}
else
{
pwm = ((bat_volts * 10) / (sol_volts / 10)) + 5;
charger_state = bulk;
}
break;
case bulk:
if (sol_watts < MIN_SOL_WATTS) {
charger_state = off;
off_count = OFF_NUM;
TURN_OFF_MOSFETS;
} else if (bat_volts > BATT_FLOAT)
{
charger_state = bat_float;
}
else if (sol_watts < LOW_SOL_WATTS) {
charger_state = on;
TURN_ON_MOSFETS;
} else {
if (old_sol_watts >= sol_watts)
{
delta = -delta;
}
pwm += delta;
old_sol_watts = sol_watts;
set_pwm_duty();
}
break;
case bat_float:
if (sol_watts < MIN_SOL_WATTS) {
charger_state = off;
off_count = OFF_NUM;
TURN_OFF_MOSFETS;
set_pwm_duty();
} else if (bat_volts > BATT_FLOAT)
{
TURN_OFF_MOSFETS;
pwm = PWM_MAX;
set_pwm_duty();
}
else if (bat_volts < BATT_FLOAT)
{
pwm = PWM_MAX;
set_pwm_duty();
TURN_ON_MOSFETS;
if (bat_volts < (BATT_FLOAT - 0.1)) {
charger_state = bulk;
}
} break; case off: TURN_OFF_MOSFETS; if (off_count > 0)
{
off_count--;
}
else if ((bat_volts > BATT_FLOAT) && (sol_volts > bat_volts))
{
charger_state = bat_float;
TURN_ON_MOSFETS;
}
else if ((bat_volts > MIN_BAT_VOLTS) && (bat_volts < BATT_FLOAT) && (sol_volts > bat_volts))
{
charger_state = bulk;
TURN_ON_MOSFETS;
}
break;
default:
TURN_OFF_MOSFETS;
break;
}
}
void load_control()
{
#if LOAD_ALGORITHM == 0
load_on(sol_watts < MIN_SOL_WATTS && bat_volts > LVD);
#else
load_on(sol_watts > MIN_SOL_WATTS && bat_volts > BATT_FLOAT);
#endif
}
void load_on(boolean new_status)
{
if (load_status != new_status)
{
load_status = new_status;
digitalWrite(LOAD_PIN, new_status ? HIGH : LOW);
}
}
void print_data(void) // you can skip this part)
{
Serial.print(seconds, DEC);
Serial.print(" ");
Serial.print("Charging = ");
if (charger_state == on) Serial.print("on ");
else if (charger_state == off) Serial.print("off ");
else if (charger_state == bulk) Serial.print("bulk ");
else if (charger_state == bat_float) Serial.print("float");
Serial.print(" ");
Serial.print("pwm = ");
if (charger_state == off)
Serial.print(0, DEC);
else
Serial.print(pwm, DEC);
Serial.print(" ");
Serial.print("Current (panel) = ");
Serial.print(sol_amps);
Serial.print(" ");
Serial.print("Voltage (panel) = ");
Serial.print(sol_volts);
Serial.print(" ");
Serial.print("Power (panel) = ");
Serial.print(sol_volts);
Serial.print(" ");
Serial.print("Battery Voltage = ");
Serial.print(bat_volts);
Serial.print(" ");
Serial.print("\n\r");
//delay(1000);
}
void light_led(char pin)
{
static char last_lit;
if (last_lit == pin)
return;
if (last_lit != 0)
digitalWrite(last_lit, HIGH);
digitalWrite(pin, LOW);
last_lit = pin;
}
void led_output(void)
{
static char last_lit;
if (bat_volts > 14.1 )
light_led(LED_BLUE);
else if (bat_volts > 11.9)
light_led(LED_GREEN);
else
light_led(LED_RED);
}
void lcd_display()
{
static bool current_backlight_state = -1;
back_light_pin_State = digitalRead(BACK_LIGHT_PIN);
if (current_backlight_state != back_light_pin_State)
{
current_backlight_state = back_light_pin_State;
if (back_light_pin_State == HIGH)
lcd.backlight();
else
lcd.noBacklight();
}
if (back_light_pin_State == HIGH)
{
time = millis();
}
lcd.setCursor(0, 1);
lcd.print(sol_volts);
lcd.print("V ");
lcd.setCursor(0, 2);
lcd.print(sol_amps);
lcd.print("A");
lcd.setCursor(0, 3);
lcd.print(sol_watts);
lcd.print("W ");
lcd.setCursor(8, 1);
lcd.print(bat_volts);
lcd.setCursor(8, 2);
if (charger_state == on)
lcd.print("on ");
else if (charger_state == off)
lcd.print("off ");
else if (charger_state == bulk)
lcd.print("bulk ");
else if (charger_state == bat_float)
{
lcd.print(" ");
lcd.setCursor(8, 2);
lcd.print("float");
}
int pct = 100.0 * (bat_volts - 11.3) / (12.7 - 11.3);
if (pct < 0) pct = 0; else if (pct > 100)
pct = 100;
lcd.setCursor(12, 0);
lcd.print((char)(pct * 5 / 100));
lcd.setCursor(8, 3);
pct = pct - (pct % 10);
lcd.print(pct);
lcd.print("% ");
lcd.setCursor(15, 0);
lcd.print("PWM");
lcd.setCursor(19, 0);
lcd.write(PWM_ICON);
lcd.setCursor(15, 1);
lcd.print(" ");
lcd.setCursor(15, 1);
if ( charger_state == off)
lcd.print(0);
else
lcd.print(pwm);
lcd.print("% ");
lcd.setCursor(15, 2);
lcd.print("Load");
lcd.setCursor(15, 3);
if (load_status)
{
lcd.print("On ");
}
else
{
lcd.print("Off ");
}
spinner();
backLight_timer();
}
void backLight_timer()
{
if ((millis() - time) <= 15000)
lcd.backlight();
else
lcd.backlight();
}
void spinner(void)
{
static int cspinner;
static char spinner_chars[] = { '*', '*', '*', ' ', ' '};
cspinner++;
lcd.print(spinner_chars[cspinner % sizeof(spinner_chars)]);
}
프로
>>이 회로는 빌드 비용이 저렴합니다.
>> 분석 및 출력 결과를위한 더 크고 더 나은 디스플레이가 있습니다.
>>실제처럼 작동합니다.
>>최대 7-8Amps 배터리만 충전할 수 있습니다(더 적음) 10 Amps 태양열 충전 컨트롤러).
>> 빨리 가열됩니다 (12V 미니 PC 팬 필요).
'아두이노' 카테고리의 다른 글
Arduino 및 시리얼 시프트 레지스터를 이용한 피크 앤 홀드 기능이 있는 최고의 스테레오 VU 미터 (9) | 2024.10.17 |
---|---|
DIY 아두이노 OLED 스펙트럼 분석기 (1) | 2024.10.17 |
아두이노 러닝맨 만들기 (5) | 2024.10.07 |
컬러 실크스크린으로 맞춤형 Arduino Uno 만들기 (3) | 2024.10.04 |
제6회 파주 운정호수공원 불꽃축제 (1) | 2024.09.19 |