본문 바로가기
아두이노

DIY Arduino MPPT 태양광 충전 컨트롤러

by 모빌리티키즈 2024. 10. 17.
728x90
반응형

프로젝트 배경

최근에 온라인에서 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 알고리즘을 구현합니다. 다음은 기본적인 코드 예시입니다.

cpp
#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);
}

장점과 단점

장점:

  • 배터리 수명 연장
  • 에너지 효율 극대화
  • 실시간 모니터링 가능

단점:

  • 초기 비용 발생
  • 복잡한 회로 구성

 

최근에 온라인에서 50와트 태양 전지판을 구입했습니다. 12볼트의 DC 전원과 2암페어의 전류를 생성하는 상점과 나는 또한 구입했습니다. 12볼트 7암페어 배터리. 나는 나를 위해 미니 태양계를 만들고 싶다. 내 충전을 위해 MPPT 태양열 충전 컨트롤러가 필요한 이유 작업용 책상 배터리에서 직접 배터리를 충전하면 나중에 배터리가 손상 될 수 있기 때문에 태양 전지판. Charge Controller에 대한 온라인 상점에는 다양한 옵션이 있습니다 10A, 20A, 30A, PWM, MPPT 등이 있지만 그 중 일부는 너무 비쌉니다. 그래서 배터리용으로 하나를 만들고 싶습니다.

그래서 이 게시물에서 우리는 MPPT 태양광 충전을 만듭니다 다음과 같은 컨트롤러 : -

>>MPPT 태양광 충전 컨트롤러란 무엇이며 어떻게 잘돼요?

이 프로젝트에 대한 >> 부분 필요성

>>회로도

>>코딩

>>장점과 단점

 

MPPT란? 태양 광 충전 컨트롤러?

Solar Voltage라고도 하는 태양광 충전 컨트롤러 전류 조정기 및 MPPT(Maximum Power Point Tracking)는 알고리즘입니다. 태양과 배터리에서 얼마나 많은 에너지 손실을 제어하고 최대를 추출하는지 어느 것이 적절한 시스템 제어를 통해 태양 전지판의 전력. 간단히 말해서 MPPT 충전 컨트롤러는 PV 모듈에서 얼마나 많은 전압과 전류가 생성되는지 확인합니다. 그리고 배터리에 얼마나 많은 전압과 전류가 필요한지. 또한 DC 전원을 공급할 수 있습니다. DC 부하(배터리에 직접 연결)의 경우 전원 모니터링을 확인하여 그리고 배터리 전압과 전류가 내려가면 자동으로 전원을 차단합니다. MPPT 요금 관제사는 일반적으로 그것의 일을 위해 PWM를 사용하고 산출은 조정될 수 있습니다 체계.

필요한 부품

아두이노 나노

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 팬 필요).

728x90
반응형