baso_syahrul:
hi ,
if anyone can help me. my experimet is about inverter 3 phase. i use arduino for generate 3-phase and i connect it with driver IR21362. i can't figure out how to generate pwm 3 phase from my arduino uno.
thanks for ur attention and any help.
3-phase what? sinusoidal or trapezoidal? Frequency range? Does the amplitude
need controlling?
Can you generate a single phase already? If so your code would be handy to see as
a guide to extending it.
To generate 1kHz sine wave you probably want to run your PWM at something like
50kHz.
If you are driving an inverter the output signals are not independent though, and for
sinusoidal is the most complex case. I think with a little care you can use the current
angle within the current 60-degree sector to determine the ratio of time spent in
two active drive states (and the zero drive state).
Think of the 8 inverter drive states as two zero-drives (all phases the same), and
six drive patterns arranged around a hexagon in phasor-space.
The problem this gives is that each PWM period needs to split into 3 parts,
2 different drive patterns and a zero-drive part. This requires at least two PWM
pins if you use the hardware, and you then need to read these pins and convert
the the right pattern (pin-change interrupts can handle that).
50kHz is ambitious, thinking about it, on a 328 based board at least.
There is another approach, hysteresis drive, where you examine the error
on a regular clock tick and change the output pattern based on the error - this
is simpler but needs to run even faster for good smooth sinusoid response.
This can work with actual current feedback from the inverter as well as with
a model of the average
I've been thinking about this some more and looking at what the Arduino
timers can do.
I've realised the Mega has some timers with 3 output pins, and this allows a
clever way to modulate 3 output signals for doing this.
It relies on having an inverter module that takes one input per phase (in
other words it generates its own high/low gate signals with appropriate
dead-time automatically generated - without this you'd need some
circuitry to do this).
Using phase-correct mode you can effectively get two control pulses per
cycle (where the pulses are differential between separate phase outputs).
So here's some test code - it drives pins 6/7/8 which are the pins for timer4.
// For the MEGA!
#define HALF 400
#define PERIOD 800
void setup ()
{
setup_cosines () ;
TCCR4A = 0xFE ; // phase correct (mode 1010)
TCCR4B = 0x11 ; // prescale by 1
TIMSK4 = 0x01 ; // overflow interrupt
ICR4 = PERIOD+1 ; // 100us cycle time, so effectively 50us.
OCR4A = HALF ;
OCR4B = HALF ;
OCR4C = HALF ;
pinMode (6, OUTPUT) ; // the OCR4A pin, our U phase
pinMode (7, OUTPUT) ; // the OCR4B pin, our V phase
pinMode (8, OUTPUT) ; // the OCR4C pin, our W phase
}
// control time values, in units of 62.5ns
volatile int u = HALF ;
volatile int v = HALF ;
volatile int w = HALF ;
// every complete cycle we update the registers.
ISR (TIMER4_OVF_vect)
{
OCR4A = u ;
OCR4B = v ;
OCR4C = w ;
}
// a cosine table, 1024 entries in range +/-127
char cosine [0x400] ;
void setup_cosines ()
{
for (int i = 0 ; i < 0x400 ; i++)
{
float a = PI * i / 0x200 ;
cosine [i] = round (127.0 * cos (a)) ;
}
}
int phase = 0 ; // taken modulo 1024
int amplitude = 200 ; // 201 is maximum value without overflow.
void loop ()
{
phase ++ ; // phase increment, normally this would be done by DDS loop
int newu = (cosine [phase & 0x3FF] * amplitude + 0x1F) >> 6 ;
int newv = (cosine [(phase + 0x155) & 0x3FF] * amplitude + 0x1F) >> 6 ;
int neww = - newu - newv ;
newu += HALF ;
newv += HALF ;
neww += HALF ;
noInterrupts () ; // interrupt-safe updating of u,v,w
u = newu ;
v = newv ;
w = neww ;
interrupts () ;
delay (2) ;
}
baso_syahrul:
can you recommend me a code agree with my problem?
Well you mentioned the IR21362 which looks like you can strap the HIN and LIN inputs
together per-phase as it has dead-time generation and shoot-through prevention. Then
the technique in my code above would be suitable. You might need to add stronger pull-down
resistors to park the bridge in all-low-side on configuration, needed to charge the bootstrap caps.
Well clearly you don't. I'm incrementing a phase variable and recomputing some
cosines. That's DDS and that's why its changing. Its test code to show it working.
MarkT:
Well clearly you don't. I'm incrementing a phase variable and recomputing some
cosines. That's DDS and that's why its changing. Its test code to show it working.