MarkT:
While loops block, you should not have any, let loop() be the only loop....
No diffrence. Commenting while loop did not help!
MarkT:
While loops block, you should not have any, let loop() be the only loop....
No diffrence. Commenting while loop did not help!
I don’t even know what code your talking about anymore.
Much less what the actual project is, or how it’s wired, or what platform it’s running on.
Your last update post, did it include the actual code your still having a problem with?
Yes, perhaps repost the code as it is now and a description of what it is doing and a description of what you
want it to be doing. This will be easier to figure out.
MarkT:
Yes, perhaps repost the code as it is now and a description of what it is doing and a description of what you
want it to be doing. This will be easier to figure out.
I did many many changes on several source codes but all of them was unsuccessful except YOUR code Mark. So I tried to mix your PWM code with my tachometer code and seems it is working now, so many thanks! The final code is as follows:
// For the UNO et al.
#define PERIOD 250 // 250 cycles = 15.625us for each half of waveform, 32kHz
#define HALF 125 // half the period is the default PWM threshold - gives square wave.
#define MAXAMP 31
void setup_timers ()
{
TCCR1A = 0xF2 ; // phase correct (mode 1010, ICR1 controls period)
TCCR1B = 0x11 ; // prescale by 1, change to 0x12 for prescale by 8
TIMSK1 = 0x01 ; // overflow interrupt
TCCR2A = 0x31 ; // phase correct (mode 101, OCR2A controls period)
TCCR2B = 0x09 ; // prescale by 1, change to 0x0A for prescale by 8
ICR1 = PERIOD ; // 31.25us cycle time, 32kHz PWM but 64kHz drive pulses (differential)
OCR2A = PERIOD ;
OCR1A = HALF-100 ; // example U drive
OCR1B = HALF ;
OCR2B = HALF+100 ; // example W drive
GTCCR = 0x83 ; // clear and halt prescalers
TCNT1 = 0xFFFF ; // synchronize counters exactly.
TCNT2 = 0 ;
GTCCR = 0x00 ; // allow prescalers to fly
}
void setup ()
{
Serial.begin(57600);
setup_cosines () ;
setup_timers () ;
pinMode (9, OUTPUT) ; // OC1A pin = U drive
pinMode (12, OUTPUT) ; // OC1B pin = V drive
pinMode (11, OUTPUT) ; // OC2B pin = W drive
pinMode (0, INPUT) ; // pot pin
pinMode(A7, OUTPUT); //LED out pin
pinMode(A5,OUTPUT); //Sensor VCC pin
pinMode(A3,INPUT); //Sensor Input pin
}
volatile byte u = HALF ;
volatile byte v = HALF ;
volatile byte w = HALF ;
ISR (TIMER1_OVF_vect) // overflow triggers at BOTTOM, update all the compare regs, which are sampled at TOP
{
OCR1A = u ;
OCR1B = v ;
OCR2B = w ;
}
#define DEG_360 0x200
#define DEG_120 0x0AB
char cosine_tab [DEG_360+1] ; // fails to work if less than 0x202.
void setup_cosines ()
{
for (int i = 0 ; i < 0x202 ; i++)
{
float a = i * 6.283185 / 0x200 ;
if (i <= DEG_360)
cosine_tab [i] = round (127.0 * cos (a)) ;
}
}
/////////////////////////////////////////////////
unsigned int phase = 0 ;
int freq ; ////0
int amplitude = MAXAMP ;
/////////////////////////////////////////////////
long startTime = 0;
int state, prevState = 0;
int sensor = 0;
long counter = 0;
double Ff = 0;
long sample_time;
int magnet_number;
int sensore_output_voltage = 1000;
int prim_rpm = 0;
long sec_rpm = 0;
float pot_co = 0;
/////////////////////////////////////////////////
int my_cosine (int ph)
{
ph &= DEG_360-1 ;
int res = cosine_tab [ph] ;
res *= amplitude ;
return (res + 0x0F) >> 5 ;
}
void loop ()
{
sensor = 0;
Ff = 0;
state = 0;
prevState = 0;
counter = 0;
startTime = millis();
sample_time = 5000; //5000 for 5 sec Loop for sample duration of sec
magnet_number = 1; //is number of magnets per revulotion
// rpm = 0;
// samp=0;
//enable sensor and turn on LED when touched.
digitalWrite(A5, HIGH);
//Loop for sample duration of 10 sec
while((millis() - startTime) < sample_time)
{
sensor = analogRead(A3);
if (sensor > sensore_output_voltage) //sensore output voltage
{
state = 1;
}
else
state = 0;
digitalWrite(A7,state); // Blinking LED when sensor Activated
//On change of state increment counter.
//A change in state twice represents one revolution
if(state != prevState)
{
counter++;
prevState = state;
}
// freq = map(analogRead(A0),0,1023,0,100);
pot_co = map(analogRead(A0),0,1023,2500,50);
pot_co = pot_co / 50.0;
sec_rpm = prim_rpm / pot_co;
freq = map(sec_rpm, 10, 1500, 0, 100);
phase += freq ;
int newu = my_cosine (phase) ;
int newv = my_cosine (phase - DEG_120) ;
int neww = - newu - newv ;
newu += HALF ;
newv += HALF ;
neww += HALF ;
u = newu ; // no masking of interrupts needed as u,v,w variables are single byte each.
v = newv ;
w = neww ;
delayMicroseconds (2600) ;
}
digitalWrite(A7,LOW);
digitalWrite(A5, LOW);
counter = counter / 2;
prim_rpm = counter / magnet_number * 50;
}
The idea of this code is that tachometer will read speed of a shaft (not coupled to the motor) and force the motor to rotate with the speed of 0 to 100% (using pot on pin A0) of the shaft speed using PWM.
So, now I have 3 question:
1- For such speed control using above code, do I need PI control to add to the above code or not? (there is not any speed feedback from motor, we only have speed of a shaft which is not mechanically coupled with motor).
2- Mark set the Microseconds delay to 1000, I set it to 2600 to get approximately 50 Hz, how to accurately calculate the delay for 50Hz?
3- To drive 6-pulse IGBT, I want to use three IR2110 drivers, but as I found in its datasheet I need a H and L input for each phase to fire H and L output from the driver for each IGBT pairs. But on the code output I only have three output for 3 phase. So how to produce H and L signal for each phase?
Many thanks for your helps.
Any idea?
Maslord:
I did many many changes on several source codes but all of them was unsuccessful except YOUR code Mark. So I tried to mix your PWM code with my tachometer code and seems it is working now, so many thanks!....
The idea of this code is that tachometer will read speed of a shaft (not coupled to the motor) and force the motor to rotate with the speed of 0 to 100% (using pot on pin A0) of the shaft speed using PWM.
So, now I have 3 question:
1- For such speed control using above code, do I need PI control to add to the above code or not? (there is not any speed feedback from motor, we only have speed of a shaft which is not mechanically coupled with motor).
Without feedback you cannot close a control loop, the best you can do is feed-forwards to compensate for known factors.
2- Mark set the Microseconds delay to 1000, I set it to 2600 to get approximately 50 Hz, how to accurately calculate the delay for 50Hz?
delayMicroseconds() isn't the thing to use for accuracy, code waiting for micros() to reach a target time and increment the target time each time round,
then you compensate for time spent running code. Timing can only be as accurate as the system clock,
if thats not a quartz crystal or oscillator you have to expect a percent or so variation.
3- To drive 6-pulse IGBT, I want to use three IR2110 drivers, but as I found in its datasheet I need a H and L input for each phase to fire H and L output from the driver for each IGBT pairs. But on the code output I only have three output for 3 phase. So how to produce H and L signal for each phase?
Many thanks for your helps.
You'll need a high-low MOSFET driver with single input and automatic dead-time to drive from 3 signals.
Most let you determine the deadtime in software as this is the most flexible way.
Regardless of the feedback, I tried do use a not gate (2n3904) to generate Linput for driver IC in addition to isolation using 4n35 optocoupler. The schematic digaram of the circuit is attached for one phase. Note that pin5 4n35 is connected to 5vdc through a 1k resistor. Is it ok or has problem?
Regards.
I built the circuit and it is working fine when I apply a square wave and its inverted signal using simple low-high command with 500us dead-time on pin 11 and 12 for one phase circuit. But the problem is the generated sine wave and its inverted signal using following modified code. When I apply it to the circuit through 2 optocouplers, they burn IR2110. The reason is that the sine wave has cross its invert in some points at each period which cause short on high and low mosfets. So how to solve the problem? Should I convert sine waves to square wave or what and how?
// For the UNO et al.
#define PERIOD 250 // 250 cycles = 15.625us for each half of waveform, 32kHz
#define HALF 125 // half the period is the default PWM threshold - gives square wave.
#define MAXAMP 31
static unsigned int ocr3a, ocr3b, ocr1a; // auxiliary variables to store obl. fillings
static unsigned int ocr1b, ocr2a, ocr2b; // ^
void setup_timers ()
{
cli();
TCCR1A |= _BV(COM1A1) | _BV(COM1B0) | _BV(COM1B1) | _BV(WGM10);
TCCR1B |= _BV(CS11); // preskaler 8 | _BV(WGM02)
TIMSK1 |= _BV (TOIE1);
TCCR2A |= _BV(COM2A1) | _BV(COM2B0) | _BV(COM2B1) | _BV(WGM20);
TCCR2B |= _BV (CS21); // preskaler 8 // | _BV(WGM02)
TCCR3A |= _BV(COM3A1) | _BV(COM3B0) | _BV(COM3B1) | _BV(WGM30);
TCCR3B |= _BV(CS31); // preskaler 8 | _BV(WGM02)
TCNT1L = 0;
TCNT2 = 0;
TCNT3L = 0;
sei();
}
void setup ()
{
Serial.begin(57600);
setup_cosines () ;
setup_timers () ;
pinMode(2, OUTPUT); // OC0A Arduino Mega2560 pin 13
pinMode(5, OUTPUT); // OC0B Arduino Mega2560 pin 4
pinMode(11, OUTPUT); // OC1A Arduino Mega2560 pin 11 u
pinMode(12, OUTPUT); // OC1B Arduino Mega2560 pin 12 uu
pinMode(10, OUTPUT); // OC2A Arduino Mega2560 pin 10
pinMode(9, OUTPUT); // OC2B Arduino Mega2560 pin 9
pinMode (0, INPUT) ; // pot pin
pinMode(A7, OUTPUT); //LED out pin
pinMode(A5,OUTPUT); //Sensor VCC pin
pinMode(A3,INPUT); //Sensor Input pin
pinMode(A9,INPUT); //Sensor Input pin
pinMode(A10,INPUT); //Sensor Input pin
}
volatile byte u = HALF ;
volatile byte v = HALF ;
volatile byte w = HALF ;
volatile byte uu = 0 ;
volatile byte vv = 0 ;
volatile byte ww = 0 ;
ISR (TIMER1_OVF_vect) // overflow triggers at BOTTOM, update all the compare regs, which are sampled at TOP
{
OCR1AL = u; // pin 11
OCR1BL = uu ; // pin 12
OCR2A = v; // pin 10
OCR2B = vv ; // pin 9
OCR3AL = w; // pin 5
OCR3BL = ww ; // pin 2
}
#define DEG_360 0x200 //512
#define DEG_120 0x0AB //171
char cosine_tab [DEG_360+1] ; // fails to work if less than 0x202.
void setup_cosines ()
{
for (int i = 0 ; i < 0x202 ; i++) //514
{
float a = i * 6.283185 / 0x200 ;
if (i <= DEG_360)
cosine_tab [i] = round (127.0 * cos (a)) ;
}
}
/////////////////////////////////////////////////
unsigned int phase = 0 ;
int pp = 0;
int freq ; ////0
int amplitude = MAXAMP ;
float P = 0; //V/F constant corrector coefficient
/////////////////////////////////////////////////
long startTime = 0;
int state, prevState = 0;
int sensor = 0;
long counter = 0;
double Ff = 0;
long sample_time;
int magnet_number;
int sensore_output_voltage = 1000;
int prim_rpm = 0;
long sec_rpm = 0;
float pot_co = 0;
int u1;
int u2;
long samp = 0;
/////////////////////////////////////////////////
int my_cosine (int ph)
{
ph &= DEG_360-1 ;
int res = cosine_tab [ph] ;
// amplitude = P * amplitude; //8=V/F constant for V=400v and F=50Hz
res *= amplitude ;
return (res + 0x0F) >> 5 ;
}
void loop ()
{
sensor = 0;
Ff = 0;
state = 0;
prevState = 0;
counter = 0;
startTime = millis();
sample_time = 10; //5000 for 5 sec Loop for sample duration of sec
magnet_number = 1; //is number of magnets per revulotion
//enable sensor and turn on LED when touched.
digitalWrite(A5, HIGH);
// Serial.println("Measuring...");
//Loop for sample duration of 10 sec
while((millis() - startTime) < sample_time)
{
sensor = analogRead(A3);
samp=millis();
// Serial.print("sensor = "); Serial.println(sensor);
if (sensor > sensore_output_voltage) //sensore output voltage
{
state = 1;
}
else
state = 0;
digitalWrite(A7,state); // Blinking LED when sensor Activated
//
//On change of state increment counter.
//A change in state twice represents one revolution
if(state != prevState)
{
counter++;
prevState = state;
}
pot_co = map(analogRead(A0),0,1023,2500,50);
pot_co = pot_co / 50.0;
sec_rpm = prim_rpm / pot_co;
freq = map(sec_rpm, 10, 1500, 0, 100);
freq = 1 ;
phase += freq ;
int newu = my_cosine (phase) ;
int newv = my_cosine (phase - DEG_120) ;
int neww = - newu - newv ;
newu += HALF;
newv += HALF;
neww += HALF;
noInterrupts () ; // interrupt-safe updating of u,v,w
u = newu + 1 ; // no masking of interrupts needed as u,v,w variables are single byte each.
v = newv + 1 ;
w = neww + 1 ;
uu = newu - 1;
vv = newv - 1;
ww = neww - 1;
interrupts () ;
delayMicroseconds (2000) ;
}
digitalWrite(A7,LOW);
digitalWrite(A5, LOW);
counter = counter / 2; // 12*5sec=60sec
prim_rpm = counter / magnet_number ;
// prim_rpm = 1500;
//
}
Maslord:
Regardless of the feedback, I tried do use a not gate (2n3904) to generate Linput for driver IC in addition to isolation using 4n35 optocoupler. The schematic digaram of the circuit is attached for one phase. Note that pin5 4n35 is connected to 5vdc through a 1k resistor. Is it ok or has problem?Regards.
I can't read the component values, for instance the resistors around the inverting transistor could be R100,
100, 100k, really can't make it out. R100 means 0.1 ohm, for instance.
Since you are using a driver without shoot-through prevention, you have to provide deadtime when
switching, which necessitates using two Arduino pins per half-H-bridge with appropriate timing.
If one MOSFET is still turning off when you enable the other, bang they both pop... (or in marginal
cases rapidly get very hot), as you are shorting the supply directly to ground through both devices.
Using a high-low driver with shoot-through prevention is simpler to get right. Checkout IRS2004 for
instance.
Deadtime is between the high and low MOSFETs on a single arm of the bridge, and is typically of
the order of a few 100ns, not us.
Your optocoupler is too slow for switching MOSFETs, its has a switching time of 10µs,
you need a fast logic optocoupler for such purposes, on the <100ns timescale of operation,
not a phototransistor based one.
BTW I said use a high-low driver with automatic dead time generation in my post #27 already...
MarkT:
I can't read the component values, for instance the resistors around the inverting transistor could be R100,
100, 100k, really can't make it out. R100 means 0.1 ohm, for instance.Since you are using a driver without shoot-through prevention, you have to provide deadtime when
switching, which necessitates using two Arduino pins per half-H-bridge with appropriate timing.If one MOSFET is still turning off when you enable the other, bang they both pop... (or in marginal
cases rapidly get very hot), as you are shorting the supply directly to ground through both devices.Using a high-low driver with shoot-through prevention is simpler to get right. Checkout IRS2004 for
instance.Deadtime is between the high and low MOSFETs on a single arm of the bridge, and is typically of
the order of a few 100ns, not us.Your optocoupler is too slow for switching MOSFETs, its has a switching time of 10µs,
you need a fast logic optocoupler for such purposes, on the <100ns timescale of operation,
not a phototransistor based one.BTW I said use a high-low driver with automatic dead time generation in my post #27 already...
Thank you Mark for the reply. Regarding to resistors value, the gate source is 1kohm, gate resistor is 10 ohm, resistor before transistor, and pin 1 of optocoupler is 1kohm.
Regardless of those element's values and deadtime, the main problem is the the pwm generates a complete sine wave (0 to 255) for each phase and its inverted signal which means the signal and its invert cross each other somewhere around half of period (127). So my main question is, can I apply sine wave as gating signal to IR2110 and mosfets or I have to translate the sine wave to square one or what? Deadtime is the next step. It is appreciated if you can clarify my ambiguity on gating signal.