Menu
JAQForum Ver 19.10.27

Forum Index : Solar : Looking for open source inverter code

Posted: 12:04pm
25 Aug 2026
Copy link to clipboard
Dev7
Newbie

Hi all, I am in the process of building a 1kW 24V Inverter for learning purposes. The design is similar to the typical EGS002/EG8010 low frequency design. However, instead of using the EG8010 I have used an Arduino Nano. I did this because I wanted to be able to adjust aspects such as switching frequency and PID gains for learning purposes.

Does anybody have open source inverter code that attempts to replicate the EG8010? I have uploaded my current schematic and code. The main thing I am struggling with at the moment is voltage feedback/regulation using PID.






// 20kHz Unipolar SPWM with PID control
// ZMPT101B module used for voltage feedback

#include <avr/io.h>
#include <avr/interrupt.h>
#include <ZMPT101B.h>

#define SENSITIVITY 450.0f        // Sensitivity of the ZMPT101B voltage sensor module
ZMPT101B voltageSensor(A0, 50.0);

// D10/D9 20kHz SPWM, D4/D5 50Hz square wave
// HIN1-D10, LIN1-D9, HIN2-D4, LIN2-D5
// Total samples per cycle: 20kHz/50Hz = 400
// ICR1 = (Micro clock (16Mhz)/ Carrier frequency)/2 = (16Mhz/20kHz)/2 = 400
// Look up table is for a half cycle (200 table entries) with a max value of 400 (100% duty cycle)

volatile float percentMod = 0.0;
float Kp = 0.001;  
float Ki = 0.0000;  
float P = 0.0;
float I = 0.0;
float voltageSetpoint = 230.0;
unsigned long lastControlTime = 0;
int            phs;

//---------------------------------Look Up Table for 20kHz carrier-----------------------------------
int lookUp1[] = {
 0, 6, 13, 19, 25, 31, 38, 44, 50, 56, 63, 69, 75, 81, 87, 93, 99, 106, 112, 118, 124, 130, 135, 141, 147, 153, 159, 165, 170, 176, 182, 187, 193,
 198, 204, 209, 214, 220, 225, 230, 235, 240, 245, 250, 255, 260, 265, 269, 274, 278, 283, 287, 292, 296, 300, 304, 308, 312, 316, 320, 324, 327,
 331, 334, 338, 341, 344, 347, 351, 354, 356, 359, 362, 365, 367, 370, 372, 374, 376, 378, 380, 382, 384, 386, 387, 389, 390, 392, 393, 394, 395,
 396, 397, 398, 398, 399, 399, 400, 400, 400, 400, 400, 400, 400, 399, 399, 398, 398, 397, 396, 395, 394, 393, 392, 390, 389, 387, 386, 384, 382,
 380, 378, 376, 374, 372, 370, 367, 365, 362, 359, 356, 354, 351, 347, 344, 341, 338, 334, 331, 327, 324, 320, 316, 312, 308, 304, 300, 296, 292,
 287, 283, 278, 274, 269, 265, 260, 255, 250, 245, 240, 235, 230, 225, 220, 214, 209, 204, 198, 193, 187, 182, 176, 170, 165, 159, 153, 147, 141,
 135, 130, 124, 118, 112, 106, 99, 93, 87, 81, 75, 69, 63, 56, 50, 44, 38, 31, 25, 19, 13, 6,
};



void setup() {
 // Initialising timer registers
 // WGM mode 8 is used (Phase Correct PWM Mode)
 TCCR1A = 0b10110000;
 TCCR1B = 0b00010001;
 TIMSK1 = 0b00000001;

 ICR1   = 400;       // Counter TOP value for timer 1
 sei();              // Enable global interrupts
 DDRB |= (1 << PB1) | (1 << PB2);  // D9 and D10 as outputs
 DDRD |= (1 << PD4) | (1 << PD5);  // D4 and D5 as outputs
 PORTB &= ~((1 << PB1) | (1 << PB2)); // Initially set D9 and D10 LOW
 PORTD &= ~((1 << PD4) | (1 << PD5));   // Initially set D4 and D5 to LOW

 percentMod = 0;
 for (int i = 0; i < 70; i++) {         // Soft Start (~3 seconds)
   percentMod = percentMod + 0.01;
   delay(40);
 }

 Serial.begin(9600);
 voltageSensor.setSensitivity(SENSITIVITY);   // Sensitivity of ZMPT101B
}


void loop() {
 // Run voltage control approximately every 20 ms (50Hz)
 if (millis() - lastControlTime >= 20) {
   lastControlTime = millis();
   float voltageFeedback = voltageSensor.getRmsVoltage();
   float error = voltageSetpoint - voltageFeedback;

     // Proportional term
     P = Kp * error;
     // Integral term
     if (abs(error) < 20.0) {  //Only enable integral term after soft start
       I += Ki * error * 0.02;
     }

     // Limit I term to prevent windup
     if (I > 0.1)
       I = 0.1;
     if (I < -0.1)
       I = -0.1;

     // PI controller
     percentMod += P + I;

   // Clamp modulation index
   if (percentMod > 0.97)
     percentMod = 0.97;
   if (percentMod < 0.10)
     percentMod = 0.10;

   Serial.print("V = ");
   Serial.print(voltageFeedback);
   Serial.print("  Error = ");
   Serial.print(error);
   Serial.print("  Mod = ");
   Serial.println(percentMod);
 }
}


ISR(TIMER1_OVF_vect) {
 static int num;
 static int  ph;
 static int dtA = 0;
 static int dtB = 5;

 if (num >= 199) {
   if (ph == 0) {          // OC1A as SPWM out
     TCCR1A = 0b10110000;  // clear OC1A, set OC1B on compare match
     dtA = 0;              // no dead time
     dtB = 5;              // adding 300ns dead time to OC1B
   } else {                // OC1B as SPWM out
     TCCR1A = 0b11100000;  // clear OC1B, set OC1A on compare match
     dtA = 5;              // adding 300ns dead time to OC1A
     dtB = 0;              // no dead time
   }
   ph ^= 1;
 }
 
 // SPWM duty cycle
 OCR1A = int(lookUp1[num] * percentMod) + dtA; // Duty cycle is controlled by percentMod
 OCR1B = int(lookUp1[num] * percentMod) + dtB; // dtA and dtB introduce a deadtime of ~300ns

 num++;  // Next lookup table sample

   // Generating two 50Hz square waves that are 180 degrees out of phase
 if (num >= 200) {                    
   if (ph == 1) {
     digitalWrite(5, LOW);
     digitalWrite(4, HIGH);
     phs = 1;
   } else {
     digitalWrite(4, LOW);
     digitalWrite(5, HIGH);
     phs = 0;
   }
   num = 0;
 }
}
 
Posted: 08:48pm
25 Aug 2026
Copy link to clipboard
Godoh
Guru

Dev there is a thread about doing what you seem to want to do, using Wiseguys boards and a nano'
have a look at this link
wiseguy inverter boards

good luck
pete
 


To reply to this topic, you need to log in.

The Back Shed's forum code is written, and hosted, in Australia.
© JAQ Software 2026