Hi noneyabussiness
I've been doing the same thing that you have, using the ATMega328 and I have got a running prototype working quite nicely.
The reasons why I built this is to explore how a pure sinewave inverter works and the influence of various factors on it's efficiency including
- 1/2 bridge dead time
- SPWM frequency
- SPWM modulation depth
- Mosfet bridge DC bus bulk capacitance
- DC bus supply voltage
- control loop design
and more
I highly recommend the use of a DSO when playing with this stuff.
The inverter uses IR21844 half bridge 2 Amp gate drivers which have variable dead time, taking 3 inputs. First is dead time (from 0.5 to 5 us, set by a trimpot), next is pwm, and the last is enable which is active HIGH.
The code has a soft start and hard stop that only occurs at zero AC voltage output thereby reducing stress on the mosfets.
See attached code and I will detail how it works.
Firstly, you will see two #defines, NPWM is the number of PWM cycles for 1/4 sinewave. I based it all on using a 1/4 wave. This saves memory and it's simple to use symmetry to obtain the other half of the 1/4 wave
PPWM is the PWM clock speed counter.
Next is a 14 bit lookup table of 1/4 sine wave values and a few globals. The table is stored in program memory so it does not chew up all the ram.
The setup() block does a few things, firstly it initialises the working pwm lookup table to zero power, programs timer2 to fire at 100Hz, programs timer1 to fire at
16Meg/NPWM Hz, in this case it will be 20kHz but this can be changed to anything you like. In testing I have run this code at 10, 20 and 40 kHz
but it could be anything (if NPWM = 123, then the SPWM freq would be 12.3kHz). Further setup code initialises a few output pins, counters and flags, disables the arduino clock interrupt (for smoother running of the 20K PWM)
and enables interrupts. These are running at all times. I control the inverter output via the enable signal sent to the mosfet drivers.
Then comes timer2 overflow interrupt code. This creates a 50hz signal by toggling the flag f50, and it outputs the enable/disable signal through pin5.
It resets the SPWM lookup table pointer to the start point and checks for a change in the enable/disable input switch.
timer1 overflow code will toggle the 50hz output pin as needed and update timer1 OCR1A counter appropriately with the first or second part of the 1/4 wave spwm lookup table.
pwm_mod(v) is something you might find interesting. This produces the working lookup table data for SPWM.
The input value is used to scale the sin wave from 0 to maximum. All calculations are performed in 32bit integer.
step 1 calculate the location of the needed value from the sine table
step 2, fetch it from program memory
step 3 scale it, with a result that is converted to 16 bits for storage into working table. And mirror it for the other 1/2 of the 1/4 wave.
The last line tidies up a bit of crap in the middle of the data due to poor programming.
Next comes loop() where two values are read from ADC inputs.
ch0 is the inverter output, scaled so that 220VAC = 3.5V DC roughly
ch2 is the setpoint where I control the output voltage. I like to run it at 220VAC but is can go to anything you want.
The toroid used in this prototype is a 1500VA unit from an aerosharp and I find it starts saturating at about 235VAC onwards.
The function of this code block is to update the working lookup table so that the desired AC voltage is maintained.
I choose to update the table at zero crossing times in the AC wave, so that means it gets updated 100 times a second.
the variable "uf" is used to flag when to run the update code, and this code only runs if the inverter is enabled.
update code first clears the update flag, then pulls pin6 high to show to the human that it's running this code.
I use a simple so called "bang-bang" control scheme with a small dead band. I could use PID or something else but first let's crawl before I walk.
If setpoint is larger than ACV then increase the power level by a small amount. If smaller, decrease by a tad.
It setpoint is close to ACV then just leave it alone. I found that not using a dead band creates annoying flicker in ACV output when hooked up to lights.
I then clamp the power level to something that will never cause problems in the integer scale code (and these issues will cause blown mosfets)
pwr is a float, I obtain my scale factor, call pwm_mod and print a few interesting numbers.
And pull pin6 low to show the human the job is done.
The last code is to give a nice debounced input from a very noisy push button switch.
This gets called 100 times a second. It toggles on and off the inverter.
When changing either on or off it zeros the pwr accumulator, ready for the next soft start.
the variable odis is mapped directly to the IR21844 enable pins and the arduino LED. This is useful and saves me from applying DC bus power
when the inverter is "on". Bad things happen when this occurs.
The control loop is clearly not great. While experimenting with an aliexpress EGS002 based inverter board I found that they take a low voltage sample
of the AC output voltage, rectify it and filter it so that is has very small AC ripple, then this is fed into the EGS002 board, where more low pass filtering occurs
and this nearly DC signal is fed into Vfb pin of the controller.
So it indicates to me the EGS002 based inverters use and expect a DC feedback signal.
The control loop will need to be designed with this slowly changing feedback signal in mind.
Future work on this project will look at filtering of AC feedback, the frequency response of the control loop
and what is really needed from an inverter from a transient response point of view.
The video of oscilloscope traces when operating.
soft start with no load -
soft start with test load of 114W -
SS with sudden application of load (can see SPWM in lower zoomed view) -
Yellow is 50Hz gate drive
Light Blue is output AC volts (100V/div)
other blue is DC bus current (0.041V/Amp)
Pink is 20kHz SPWM gate drive
The DSO screen capture shows the transient behavior when apply the test load. Notice how the voltage drops for one or two cycles then the control loop regains the upper hand.