Go Down

Topic: VFD Drive Program (Please criticise) (Read 2 times) previous topic - next topic

Resinator

So I have been double busy trying to write program to control a three phase inverter

the middle leg is driven at 16kHz square and the other two legs each use an Arduino each


I use a reference table and an interrupt to cycle through at the calculated time according to an input voltage from a pot on A0

I use 0-2.5V relating to 25Hz-50Hz and the slower the speed the less the amplitude of the current, I also need to synchronise with the other arduino so that the two cycle through the table in a locked manner!

Code: [Select]
    #include <TimerOne.h>
             volatile boolean enable_my_ints;
             volatile boolean READY;
             volatile int TEST_VIN;
             volatile int TEST_VIN2;
             float TEST_HERTZ;
             float TEST_HERTZ2;
             float FLOAT_NUM;
             float FLOAT_NUM2;
             volatile int NUM;
             volatile int NUM2;
             volatile int HERTZ;
             volatile int HERTZ2;
             volatile int STEP_TIME;
             volatile int STEP_TIME2;
             volatile int Vin;
             volatile int count;


int MainRef[] = {
 

  433, 435, 437, 439, 441, 443, 445, 447, 449, 451, 453, 455, 457,
  459, 461, 463, 465, 467, 469, 471, 473, 475, 477, 479, 481, 483,
  485, 487, 489, 491, 493, 495, 497, 499, 501, 503, 505, 507, 509,
  511, 
 
  513, 515, 517, 519, 521, 523, 525, 527, 529, 531, 533, 535, 537,
  539, 541, 543, 545, 547, 549, 551, 553, 555, 557, 559, 561, 563,
  565, 567, 569, 571, 573, 575, 577, 579, 581, 583, 585, 587, 589,
  591, 593


}; 
             volatile int index;
             volatile int increment ;
             long unsigned int REF = MainRef[index];
             int Iin;
             int ERR;
             int GATE = 12;
 
 
 
  void setup(){
 
             Serial.begin(9600);
             digitalWrite(6, HIGH);
             READY=false;
             pinMode(13, OUTPUT);
             pinMode(GATE, OUTPUT);
             pinMode(8, OUTPUT);
             pinMode(7, INPUT);
             pinMode(6, OUTPUT);
             bitClear(ADCSRA,ADPS0) ;
             bitClear(ADCSRA,ADPS1) ;
             bitSet(ADCSRA,ADPS2) ;
             
             
             float SETUP_VIN =(analogRead(A0)+ 494.0);
             float TEST_HERTZ = ((SETUP_VIN)/1020.0)*50.0;
             HERTZ =ceil(TEST_HERTZ);
             float FLOAT_NUM = HERTZ*1.6;
             NUM=ceil(FLOAT_NUM);
             
  TEST_VIN = SETUP_VIN;
 
 

  STEP_TIME = (1000000)/(HERTZ*2*NUM);
  index = 40;
  count = 0;
  increment=1;
  Timer1.initialize();
  Timer1.disablePwm(9);
  Timer1.disablePwm(10);
  digitalWrite(6, LOW);
 
  Serial.println(STEP_TIME);
  Serial.print("HERTZ  ");
  Serial.println(HERTZ);
  Serial.print("TEST_VIN  ");
  Serial.println(TEST_VIN);
  Serial.print("NUM  ");
  Serial.println(NUM);
  Serial.print("index  ");
  Serial.println(index);
  Serial.print("refindex  ");
  Serial.println(MainRef[index]);
  digitalWrite(6, LOW);
 
  while (digitalRead(7) == HIGH) {Serial.println("7 is HIGH...  ");
                                  if(digitalRead(7) == LOW){
                                  break;}
   
 
 
  }
 
  enable_my_ints= true;
  READY=true;
  Timer1.attachInterrupt(flash);
  Timer1.setPeriod(50000);

   
   
 
 
 






}
void flash ()
 
{   
   if( enable_my_ints == true){
                               digitalWrite(13, HIGH);
                               
                               
   if (index<=40 -(NUM/2)){
       (increment=1);}
     
  else{if (index>=(40 + (NUM/2))){
    increment=-1;}
             
}
   index = index+increment;
   
   count = count+1;
   
   if(count>= 20*NUM){
     noInterrupts();
     enable_my_ints =false;
     digitalWrite(6,HIGH);
     READY=false;
     digitalWrite(13, LOW);
     count=0;
     loop();}

   
   Iin=analogRead(A1);
   ERR = MainRef[index]-Iin;
   if (ERR>= 2){
     
   digitalWrite(GATE, HIGH);
}

   else{
     if (ERR <= -2){
       
     digitalWrite(GATE, LOW);}
   }
       
   
digitalWrite(13, LOW);




}

}




void loop(){
   Serial.println(MainRef[index]);
   
   
       while(READY==false){
                           
                           noInterrupts();
                           digitalWrite(13, HIGH);
                           enable_my_ints =false;
                   
                                         
if(digitalRead(7)==LOW){
                        digitalWrite(13,LOW);
                        digitalWrite(6,LOW);
                        enable_my_ints =true;
                        READY=true;
                        interrupts();
                        break;}
                       
     
}   
     
     
     
   
             Vin=(analogRead(A0)+494);
             volatile int x = abs(TEST_VIN - Vin);
     
if (x>15){ 
            delay(10);
            Vin=(analogRead(A0)+494);
            x = abs(TEST_VIN - Vin);
           
       
if(x>50){
           
            digitalWrite(6,HIGH);
            noInterrupts();
            enable_my_ints = false;
       
     
            volatile int SETUP_VIN2 =(analogRead(A0)+494);
            TEST_VIN2 = Vin;
            TEST_VIN = TEST_VIN2;
            Vin=analogRead(A0+520);

            float TEST_HERTZ2 = ((SETUP_VIN2)/1020.0)*50.0;
            float FLOAT_NUM2 = TEST_HERTZ2*1.6;
            NUM2=ceil(FLOAT_NUM2);
            HERTZ2 =ceil(TEST_HERTZ2);
            STEP_TIME2 = (1000000)/(HERTZ2*2*NUM2);
            index = 40;
            increment=1;
            count =0;
           
  Serial.print("x  ");
  Serial.println(x);
  Serial.print("NEWSTEP_TIME  ");
  Serial.println(STEP_TIME2);
  Serial.print("TEST_VIN  ");
  Serial.println(TEST_VIN);
    Serial.print("HERTZ2  ");
  Serial.println(HERTZ2);
  Serial.print("NUM2  ");
  Serial.println(NUM2);

 
 
 
 
  while (   digitalRead(7) == HIGH) {
           
  if(digitalRead(7) == LOW){
                            break;}
 

 
  }
 
  enable_my_ints= true;
  Timer1.setPeriod(STEP_TIME2);
  interrupts();
     
}
}   
     
   
 

}

       

The other program is virtually identical apart from array size and starting index etc


I am just looking for tips and ways I could improve the code thats all as tbh I have struggled with some parts of the program


Thanks in advance

Grumpy_Mike

Why use three Arduinos? One could have done the job at only 16KHz. Then you would not have to worry about synchronising them.

Resinator

I am pretty new to programming and when I set out to do the easy part of generating a perfect square wave at 16 kHz I hit the problem of digitalwrite taking 4us which simply wasn't good enough the waveforms need to be pretty precise as if both transistors fire at the same time thenthe DC Bus will short out

So I use direct port addressing and the results is pretty good

For the other two legs I have a different lookup table and different step times which must be exact andI need to do analogue reads with a step time down to about 125us is quite a lot to ask from one arduino I reckon it could be done with two but my programming skills wouldnt allow for me to have two separate timed interrupts even if I knew how to set that up the problems must be much more complex

I am really keen to learn I would absolutely love to know if it would be possible to put this on one Arduino (not that it matters) if I had a faster board and more resources then of course one board is best but this is just a prototype with the idea of learning a few things


I want people to slate my program I am a complete novice and I really need the advice

WizenedEE

The maximum number of spaces between any two lines should be two or three, like


this.

Every time you use a brace (this { or this } ) put it on it's own line, and tab like this:
Code: [Select]

void loop()
{
  //See the single tab? ooh, pretty
  //I'm still tabbed in, let's do something
  digitalWrite(4, HIGH);
  dostuff();
  //Okay, that's enough looping
}

bool i;
void dostuff()
{
  if (i)
  {
    //Now we're double tabbed!
    int q = digitalRead(5);
    Serial.println(q);
  }
  else
  {
    Serial.println("failed");
  }
}


You can do all of that by going up to tools-> autoformat in the IDE.


Whenever you're testing something (in a while loop or if statement), it's false if the test is 0 and true otherwise. Thus, the line
Code: [Select]
while (digitalRead(7) == HIGH)  can be changed to simply
Code: [Select]
while(digitalRead(7))

PaulS

Quote
can be changed

But shouldn't be. The original meaning is MUCH clearer. What would happen in your code is the Arduino team decided that HIGH should be 0 and LOW 1?

Before you say that that will never happen, take a look at all the things changed between 22 and 1.0.

Resinator

Thanks for the tips

I have used the auto format thingy-ma-jig

I will leave the digitalRead(7)==HIGH as I can easily recognise it

Is there anything else people can criticise?, I was expecting a telling off for assigning certain variables globally, this is one of my biggest problems in deciding what needs to be global and what doesnt, it really baffles me when one part of the program doesnt see a variable elsewhere


Now my main challenge with my program is to sort out the speed change part


Code: [Select]

Vin=(analogRead(A0)+494);
             volatile int x = abs(TEST_VIN - Vin);
     
if (x>15){ 
            delay(10);
            Vin=(analogRead(A0)+494);
            x = abs(TEST_VIN - Vin);
           
       
if(x>50){
           
            digitalWrite(6,HIGH);
            noInterrupts();
            enable_my_ints = false;
       
     
            volatile int SETUP_VIN2 =(analogRead(A0)+494);
            TEST_VIN2 = Vin;
            TEST_VIN = TEST_VIN2;
            Vin=analogRead(A0+520);

            float TEST_HERTZ2 = ((SETUP_VIN2)/1020.0)*50.0;
            float FLOAT_NUM2 = TEST_HERTZ2*1.6;
            NUM2=ceil(FLOAT_NUM2);
            HERTZ2 =ceil(TEST_HERTZ2);
            STEP_TIME2 = (1000000)/(HERTZ2*2*NUM2);
            index = 40;
            increment=1;
            count =0;
           
  Serial.print("x  ");
  Serial.println(x);
  Serial.print("NEWSTEP_TIME  ");
  Serial.println(STEP_TIME2);
  Serial.print("TEST_VIN  ");
  Serial.println(TEST_VIN);
    Serial.print("HERTZ2  ");
  Serial.println(HERTZ2);
  Serial.print("NUM2  ");
  Serial.println(NUM2);

 
 
 
 
  while (   digitalRead(7) == HIGH) {
           
  if(digitalRead(7) == LOW){
                            break;}
 

 
  }


 
  enable_my_ints= true;
  Timer1.setPeriod(STEP_TIME2);
  interrupts();
     
}


I read Vin on A0 and subtract this value from the old Vin at SETUP if the difference is greater than 15 then I redo the test now as I am getting strange readings then I have had to change the retest and see if its changed by more than 50 before stopping the interrupts calculating the new step time and then waiting for the other arduino to send a low pulse onto pin7 to allow the two to break out together i.e if the other Arduino isnt ready yet then it will wait until it receives the low pulse

Now what I want to do is to stop the strange readings I am getting, if I knock the potentiometer it can read some weird values (it is a rather cheap one atm) I dont know how to go about changing it

What I plan on doing is reading the value from the pot with one Arduino and instead of reading the same value from the pot with the other Arduino I will write the reading so that both work with the identical value but I get strange readings (the single reading at setup always seems to work just fine?)


So I need to change the above code to maybe work out an average with a for loop but I don't know if thats a good idea

lets say the program is in the middle of the for loop, and itinterrupts but the count hits the limit and this is exeuted


Code: [Select]
if(count>= 20*NUM){
     noInterrupts();
     enable_my_ints =false;
     digitalWrite(6,HIGH);
     READY=false;
     digitalWrite(13, LOW);
     count=0;
     loop();}



The program will restart the loop and I am unsure of the consequences of leaving the for loop in the middle never to return, maybe it will just restart with no problems


So in a nut shell how can I stop weird readings from the pot and allow my speed to change only when x is more than 20 codes (about 1 Hz) without an obscure reading spoiling it all for me


Thanks in advance

cyclegadget



Here is a old thread about averaging readings. http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1293893508

You could also consider throwing out the highest and lowest readings before you create an average.
Good links: Eagle tutorial= http://www.youtube.com/playlist?list=PLDE1858BD83D19C70
General Arduion tutorials = http://tronixstuff.wordpress.com
http://www.gammon.com.au/forum/bbshowpost.php?bbtopic_id=123

Resinator

Well I thought I would give a little update (I got a PM from an interested member)  I was successful in building a VFD, but due to uni health and safety I couldnt use 340VDC in the labs and I built a low voltage prototype which drove a dummy RL load at 30VDC

I actually won an award for my work as it was pretty impressive (to me at least!)

A pic of the proto type complete with electrical isolation, gate drive circuitry three phase inverter and current measurement stage

Speed select electronics which I had to implement a LP RC filter to filter the 16kHz transients from the common leg switching

One of the phase currents

and a shot of both outputs showing the 90 degree phase shift

Resinator

Upload limit oops

Speed selection with LP filter

Resinator

One of the currents

And both outputs check out the phase shift which is locked to the other through sync with two digi pins

Resinator

Output and pulse train check out the PWM!!!


Resinator


Resinator

PWM close up

Resinator

Closer close up!

Resinator

I had to overcome loads of problems so many that the program was totally revamped to change interrupt times and due to the arduino uno bein g so slow (i needed to do lots in 80us)  i had to write an array of times (long story)

I still have lots of work to do before its up to a decent standard though so I will defo improve it

using 3 uno's is taking the pee a bit I would like to do it all on a single board and I want/would like a 32bit DSP and I have waited too long for the due now I think I will look further afield a get a proper micro controller as I have learned a fair bit about C++

Can anyone recommend me a good board to start with that is 32 bit with a faster processor say 80MHz ish? theres lots I need one with a 5v output preferably with plenty on the net to learn from

Go Up