Arduino-DC-12-24V-to-AC-230V-380V-3-phases-inverter

0 14002 Medium

This study is an example how to build a 3-phases 230V/380V from a 12-24V DC with an Arduino Uno

projectImage

Things used in this project

 

Hardware components

HARDWARE LIST
1 DFRobot I2C 16x2 Arduino LCD Display Module
1 Arduino UNO

Software apps and online services

 

Arduino IDE

Hand tools and fabrication machines

 

Digilent Mastech MS8217 Autorange Digital Multimeter

 

Soldering iron (generic)

Story

 

The story begins with an ugly device bought from China that was supposed to be an 230V inverter. But it was only a kind of high voltage generator, at the frequency of 20KHz. Absolutely nothing to regulate the output voltage, and no 50Hz to make supposing a AC use of this high voltage.

 

So I kept the high frequency transformer and I decided to build something with it.

Custom parts and enclosures

 

inverter manual

icon Arduino-DC-12-24V-to-AC-230V-380V-3-phases-inverter-master.zip 2.4MB Download(141)

Schematics

 

full inverter diagram

projectImage

Code

inverter code

Arduino

CODE
/*
Mini inverter for a 230Vac @ 50Hz from a 12V ro 24 DC, for a power up to 500W.
  _________________________________________________________________
  |                                                               |
  |       author : Philippe de Craene <[email protected]        |
  |       Free of use - Any feedback is welcome                   |
  _________________________________________________________________

The converter works in 2 parts:
- First the DC input is transformed to 220V/400VDC with a DC-DC converter based on 
  Timer2  31KHz. Timer2 works with Arduino pins 3 and 11.
- Then the high voltage is cut in a sequence 6x 3.33ms (300Hz x6 = 50Hz) from interrupts set by Timer1, 
  in order to make 3 phases AC sqare signal. Between 2 phases to result is a pseudo sinus signal, enough for a motor.

  PWM mode explanation: https://www.arduino.cc/en/Tutorial/SecretsOfArduinoPWM
  Timer 1 register access from: https://github.com/PaulStoffregen/TimerOne
  SPWM code from: https://github.com/Irev-Dev/Arduino-Atmel-sPWM

remarks:
--------

The _BV(XXX) function sets the XXX bit of whatever register you are working with to one.
It is defined by the following C macro buried somewhere in the libraries used by the compiler:
  #define _BV(bit) (1 << (bit)) 


Arduino Uno pinout
------------------

  A0  ==> AC output rectified voltage sensor
  A1  ==> DC input current sensor ACS712 20A
  A2  ==> heatsink temperature sensor LM35
  A3  ==> battery input voltage
  A4  ==> LCD 1602 SDA
  A5  ==> LCD 1602 SCL
   4  ==> disable: SD pin of IR2184 (AC output driver)
   8  ==> DC to AC phase 1 with IR2184
   9  ==> DC to AC phase 2 with IR2184
  10  ==> DC to AC phase 3 with IR2184
   3  ==> 12VDC to 400VDC with IR2011
  11  ==> 12VDC to 400VDC with IR2011 
  12  ==> synchro output (for oscilloscope external trigger)
  13  ==> activity / alarm LED output

Versions history
----------------
  version 0.5 - 20 july 2020 - first operational version
  version 0.6 -  2 aug  2020 - 50Hz starts once Vht is raised
  
*/

#include <LiquidCrystal_I2C.h>    // https://github.com/fdebrabander/Arduino-LiquidCrystal-I2C-library
#include <TimerOne.h>             // https://github.com/PaulStoffregen/TimerOne

// Parameters
//-----------

bool SETUP_MODE = false;        // read the Ioffset value needed for 0 current
bool VERBOSE_MODE = true;       // set the console display mode
const int Ioffset = 565;        // set to get 0 when no current (mid value 0-1023
const float coefVht = 1.26;     // calibrate the output 2 phases AC
const float coefVbat = 0.97;    // calibrate the input DC voltage

const int microseconds = 3333;  // AC period => 3.33ms for 300Hz = 6x 50Hz

const int VhtRef = 200;         // 200V DC gives 192V AC
const int deltaVht = 4;         // tolerance/hysteresis on Vht
const int VbatMin = 11;         // inverter will stop below this input voltage
const int VbatMax = 29;         // inverter will stop after this input voltage
bool isThsSensor = false;       // is there or not a temperature sensor on IRFB4110 heatsink
const int ThsMax = 70;          // heater sink max temperature 
bool isIdcSensor = true;        // is there or not a current sensor in use
const int IdcMax = 10;          // absolute max current from DC input => 10 = 10A

// choose the right current sensor model for ACS712:
//float convI = 185.0;    // 5A ACS712 module => 185mV/A
float convI = 100.0;    // 20A ACS712 module => 100mV/A
//float convI = 66.0;     // 30A ACS712 module => 66mV/A

// Hardware connexion
//-------------------

const byte pp01Pin    = 3;     // push-pull output 1 for 12VDC / 400VDC converter
const byte pp02Pin    = 11;    // push-pull output 2 for 12VDC / 400VDC converter
const byte ac1Pin     = 8;     // DC to AC phase 1
const byte ac2Pin     = 9;     // DC to AC phase 2
const byte ac3Pin     = 10;    // DC to AC phase 3
const byte enablePin  = 4;     // disable/enable AC output, enable to LOW
const byte triggerPin = 12;    // ext trigger for oscilloscope
const byte ledPin     = 13;    // LED for activity and alarm
const byte VhtPin     = 0;     // analog 0 = output HT transformer sensor
const byte IdcPin     = 1;     // analog 1 = DC input current sensor ACS712 20A
const byte ThsPin     = 2;     // analog 2 = heatsink temperature sensor LM35
const byte VbatPin    = 3;     // analog 3 = input level voltage sensor

// Global variables
//-----------------

int HTduty = 1;                // duty cycle for HT converter
const int HTdutyMax = 127;     // must be below to 128 according to push-pull/bridge PWM
bool disable = true;           // flag for enabling/disabling AC 
unsigned int measures = 10;    // number of readings for each measure of Vht Idc and Ths
unsigned int displayUpdate = 50;  // number of measures cycles for LCD display update

// LCD declaration with I2C
//-------------------------
// set the I2C LCD address to 0x27 for a 16 chars and 2 line display
LiquidCrystal_I2C lcd(0x27, 16, 2);
// => pinup for I2C with Arduino Uno R3 : SDA = A4, SCL = A5

//
// setup
//____________________________________________________________________________________________

void setup() {

// define inputs & outputs
//------------------------
// do not set pinmode for analog entries, otherwise A3 causes a Timer2 error
  pinMode( enablePin, OUTPUT );  digitalWrite(enablePin, LOW);
  pinMode( ac1Pin, OUTPUT );     digitalWrite(ac1Pin, LOW);
  pinMode( ac2Pin, OUTPUT );     digitalWrite(ac2Pin, LOW);
  pinMode( ac3Pin, OUTPUT );     digitalWrite(ac3Pin, LOW);
  pinMode( pp01Pin, OUTPUT );    digitalWrite(pp01Pin, LOW);
  pinMode( pp02Pin, OUTPUT );    digitalWrite(pp02Pin, LOW);
  pinMode( triggerPin, OUTPUT );
  pinMode( ledPin, OUTPUT);

// LCD initialisation
  lcd.begin();                // initialize the lcd for 16 chars 2 lines
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("INVERTER");
  lcd.setCursor(0, 1);
  lcd.print("is starting !");

// console initialisation
  Serial.begin(250000);
  Serial.println("Starting....");

// prepare timers
//---------------
// set Timer2 clock divider at 1 for a PWM frequency fixed to 31372.55 Hz
// Arduino Uno pins 3 and 11
// https://etechnophiles.com/change-frequency-pwm-pins-arduino-uno/
  TCCR2B = _BV(CS10);     // set clock at 31KHz
  TCCR2A = _BV(COM2A1)    // set non-inverting pp01Pin output 3
         | _BV(COM2B1)    // set non-inverting pp02Pin output 11
         | _BV(COM2B0)    // set inverting mode on 
         | _BV(WGM20);    // fast PWM
  OCR2A = HTduty;         // set duty cycle <126 to prevent against both side continuity 
  OCR2B = 255 - HTduty;   // the inverting ratio

// set Timer1 for an interrupt every 3333us
  Timer1.initialize(microseconds);
  Timer1.attachInterrupt(ACgenerate);

}      // end of setup

//
// loop
//____________________________________________________________________________________________

void loop() {

  float Idc;                          // DC input current
  int Vbat, Vht, Ths;                 // Input voltage, HT output rectified voltage, heatsink temperature
  static long cumulIdc = 0;           // cumulative input DC current sensor
  static long cumulVbat = 0;          // cumulative input DC voltage sensor 
  static long cumulVht = 0;           // cumulative output AC voltage sensor
  static long cumulThs = 0;           // cumulative heatsink temperature sensor
  static int counter = 0;             // cycles counter
  static int counter2 = 0;            // measures counter

// Idc DC input current sensor reading with overcurrent security
  if( isIdcSensor ) {
    Idc = analogRead(IdcPin);         // 0 to 1023 in bytes for -20A to 20A, 512 in bytes =0A
    delayMicroseconds(100); 
    if( Idc < 2 || Idc > 1022 ) {     // reading in bytes
      ACenable(2);                    // stop AC
      return;                         // nothing else is done
    }
  }    // end of test isIdcSensor
  else Idc = Ioffset;                 // if no current sensor

// Vbat input volatge & Vht transformer output & Ths temperature reading
  Vbat = analogRead(VbatPin); delayMicroseconds(100);
  Vht  = analogRead(VhtPin);  delayMicroseconds(100);
  if( isThsSensor ) { Ths  = analogRead(ThsPin);  delayMicroseconds(100); }
  else Ths = 0;

// perform cumulative readings to improve accurancy against noises
  cumulIdc  += Idc;
  cumulVbat += Vbat;
  cumulVht  += Vht;
  cumulThs  += Ths;

  if( ++counter > measures ) {         // after 'measures' number we go in sensors reading cycles
    counter = 0;
    counter2 ++;
    if( !SETUP_MODE ) Idc = (((cumulIdc/measures) - Ioffset) *2500.0/convI/1023.0);
    else Idc = (cumulIdc/measures);
    if( Idc < 0 ) Idc = -Idc;          // input DC current positive whenever the sensor connection
    Vbat = (float)((cumulVbat/measures) *coefVbat*39.0/1023.0);  // input voltage 
    Vht = (float)((cumulVht/measures) *coefVht*500.0/1023.0);    // output HT voltage 
    Ths = (cumulThs/measures) *500/1023;                         // temperature in degrees Celsius
    cumulVbat = 0;
    cumulVht = 0;
    cumulIdc = 0;
    cumulThs = 0;
  }    // end of test counter

// what is done every time measures are completed
  if( counter != 0 ) return; // everything after is done when counter = 0

// manage HTduty to get the 'VhtRef' output voltage
  if( Vht < (VhtRef - deltaVht)) {
    if( ++HTduty > HTdutyMax ) HTduty = HTdutyMax;
  }
  else if( Vht > (VhtRef + deltaVht)) {
    if( --HTduty < 0 ) HTduty = 0;
  }
  
// verify normal working conditions
  if( Idc > IdcMax )           ACenable(3);
  else if( Vbat < VbatMin )    ACenable(4);
  else if( Vbat > VbatMax )    ACenable(5);
  else if( Ths > ThsMax )      ACenable(6);
  else if( Vht < (3*VhtRef/4)) ACenable(1); 
  else ACenable(0);       // allow inverter pseudo sinus output

// set the PWM
  OCR2A = HTduty;         // set duty cycle
  OCR2B = 255 - HTduty;   // the inverting ratio

// LCD 1602 display management
  if( counter2 > displayUpdate ) {
    counter2 = 0;
    lcd.setCursor(0, 0); 
    lcd.print("Vb: "); 
    if( Vbat < 10 ) lcd.print(" ");
    lcd.print(Vbat);
    lcd.setCursor(6, 0);
    lcd.print("V Ib: ");
    if( Idc < 10.0 ) lcd.print(Idc,1);
    else lcd.print(Idc,0);
    lcd.print("A");
    if( !disable ) {
      lcd.setCursor(0, 1);
      lcd.print("Vs: ");
      if( Vht < 100 ) lcd.print(" ");
      lcd.print(Vht);
      lcd.setCursor(7, 1);
      lcd.print("V d: ");
      int val = map( HTduty, 1, HTdutyMax, 0, 99 );
      if( val < 10 ) lcd.print(" ");
      lcd.print(val);
      lcd.print("%");
    }
  }

// console monitoring
  if( VERBOSE_MODE ) {
    Serial.print(" Vbat= ");  Serial.print(Vbat);
    Serial.print("\t Vht= "); Serial.print(Vht);
    Serial.print("\t Idc= "); Serial.print(Idc);
    Serial.print("\t Ths= "); Serial.print(Ths);
    Serial.print("\t HTduty= ");  Serial.print(HTduty);
    Serial.print("\t disable= "); Serial.print(disable);
    Serial.println();
  }
}      // end of loop

//============================================================================================
// list of functions
//============================================================================================

//
// ACenable() : allow AC or display error message
//____________________________________________________________________________________________

void ACenable( byte reason ) {
  if( reason == 0 ) {
    if( disable ) {
      for( byte i=0; i<3; i++ ) {
        digitalWrite(ledPin, HIGH); delay(10);
         digitalWrite(ledPin, LOW); delay(300);
      }
      digitalWrite(enablePin, HIGH);      // enable AC
      disable = false;                    // so that this is run once
    }  // end of test disable == true
  }    // end of test reason == 0
  else if( reason == 1 ) {
    digitalWrite(enablePin, LOW);         // disable AC
    disable = true;
    lcd.setCursor(0, 1); lcd.print("! waiting for HT!");
  }
  else {
    HTduty = 0;                           // stop the high volatge
    digitalWrite(ledPin, HIGH);           // alarm LED always on
    disable = true;
    switch( reason ) {
      case 2: lcd.setCursor(0, 1); lcd.print("! short circuit!"); break;
      case 3: lcd.setCursor(0, 1); lcd.print("! overcurrent  !"); break;
      case 4: lcd.setCursor(0, 1); lcd.print("! low battery  !"); break;
      case 5: lcd.setCursor(0, 1); lcd.print("! high battery !"); break;
      case 6: lcd.setCursor(0, 1); lcd.print("! over heating !"); break;
      default: lcd.setCursor(0, 1); lcd.print("! other error  !"); break;
    }  // end of switch
  }    // end of else
}      // end of EnableAC()

//
// ACgenerate() : function to create the 3 phase AC
//____________________________________________________________________________________________

void ACgenerate() {
  static byte cycle = 0;
  static bool trigger = false;
  switch( cycle ) {
    case 0: digitalWrite(ac1Pin, HIGH); digitalWrite(ac2Pin, LOW); digitalWrite(ac3Pin, HIGH); break;
    case 1: digitalWrite(ac1Pin, HIGH); digitalWrite(ac2Pin, LOW); digitalWrite(ac3Pin, LOW); break;
    case 2: digitalWrite(ac1Pin, HIGH); digitalWrite(ac2Pin, HIGH); digitalWrite(ac3Pin, LOW); break;
    case 3: digitalWrite(ac1Pin, LOW); digitalWrite(ac2Pin, HIGH); digitalWrite(ac3Pin, LOW); break;
    case 4: digitalWrite(ac1Pin, LOW); digitalWrite(ac2Pin, HIGH); digitalWrite(ac3Pin, HIGH); break;
    case 5: digitalWrite(ac1Pin, LOW); digitalWrite(ac2Pin, LOW); digitalWrite(ac3Pin, HIGH); break;
  }    // end of switch
  if( ++cycle >5 ) {
    cycle = 0;
    //digitalWrite(triggerPin, trigger);
    //trigger = !trigger;
  }
}      // end of ACgenerate()

The article was first published in hackster, August 2 2020

cr: https://www.hackster.io/philippedc/arduino-dc-12-24v-to-ac-230v-380v-3-phases-inverter-afe5e1

author: philippedc

License
All Rights
Reserved
licensBg
0