Pages: [1]   Go Down
Author Topic: 3-phase sine wave generator(pwm)---need help with code  (Read 1662 times)
0 Members and 1 Guest are viewing this topic.
Offline Offline
Newbie
*
Karma: 0
Posts: 10
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I'm usually used to using the labview interface for arduino, but lately i've been trying to write my own code on the arduino compiler/uploader. I've already been able to use labview build a working 3-phase sine wave generator using the pwm outputs of my arduino uno, and the code i wrote works on relatively the same basis as the one on labview. here is how it's supposed to work:

upon pressing an external push-button, the code should enter a loop where 3 outputs are constantly updated at a rate proportional to a pot. the dead time of each of the 3 outputs is controlled by a sine function which outputs a value from 0-255, and each output has its separate equation for determining its dead-time. each sine function uses the variable x, which is supposed be the value of a counter, which  by increases by pi/120 each cycle, and resetting to 0 when x=2*pi. im using 3.14 for pi. when the button is released, the 3 outputs are all supposed to go to LOW, and x is supposed to reset to 0. unfortunately, writing code for a counter is a lot harder to make than on labview, and the counter is essential for x to increase.

anyway, here is the code(the outputs are labeled led1, led2, led3, since i'm first going to test the sine wave output on LED's):


int led1 = 11;
int led2 = 10;
int led3 = 9;
const double pi = 3.14;
int x = 0;
int enable = 8;
int freqpin = A0;
double p1 = 0;
double p2 = 0;
double p3 = 0;
const int y = 1;

void setup() {
  pinMode(led1, OUTPUT);
  pinMode(led2, OUTPUT);
  pinMode(led3, OUTPUT);
  pinMode(enable, INPUT);
  pinMode(freqpin, INPUT);
}

void loop()  {
 while(digitalRead(enable) == HIGH) {
  x = x + y;
  analogWrite(led1, p1);
  analogWrite(led2, p2);
  analogWrite(led3, p3);
  p1 = 127.5*sin(x+(2*pi/3))+127.5;
  p2 = 127.5*sin(x+(4*pi/3))+127.5;
  p3 = 127.5*sin(x+(2*pi))+127.5;
  if(x = 2*pi) x = 0;
  delay(freqpin/10);
}
analogWrite(led1, 0);
analogWrite(led2, 0);
analogWrite(led3, 0);
x = 0;
}


anyway, when i upload the code and press the button, the 3 led's light up, each one at a difference brightness, as expected, but they all stay that way. the brightness on each led doesn't change, which leads me to conclude that the counter isnt working.

what changes(if any) should i make to the code to make it work?
Logged

USA
Offline Offline
Sr. Member
****
Karma: 12
Posts: 322
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Woof - this is a target-rich environment.
Code:
const int y = 1;
This variable, y, is the increment that variable x, the phase counter, gets bumped by on each iteration.  With y=1, there will be about 6 iterations per cycle.  The argument to the sin() function is in radians, and a radian is about 57 degrees.  With y=1, you won't get much resolution.
Code:
const double pi = 3.14;
There's no benefit to using an abbreviated value for pi.  There's certainly no point in declaring it double - which is the same as float on the Arduino - and then rounding it to two decimals.  If you're going to use pi, get close.
Code:
double p1 = 0;
This value is only used in analogWrite(), which takes a value between 0 and 255.  It could be unsigned char.
Code:
p1 = 127.5*sin(x+(2*pi/3))+127.5;
Wow! Two multiplications, two additions, and a division, all floating point, and a trig function.  That's a lot for an 8-bit processor without a floating point unit.  I don't know how much optimization the compiler can do with this, but there's at least some that you can do:  define a const float = 2*pi/3, and another = 4*pi/3, and avoid doing that division each iteration; change the additive constant to 128 and do the addition after the storing the value in an unsigned char - your output would then range from 1 to 255, rather than from 0 to 255, but a lot of calculation delay would go away.
Code:
if(x = 2*pi) x = 0;
This won't work.  Instead of a test, it's an assignment; as a test, though, it's always true.  So, the program will set x to 0 on every iteration, and the analog outputs won't change.
Quote
... the brightness on each led doesn't change ...
That's why.  But, if it were a working test - if it said, "if(x == 2*pi)" - it would always fail, because x has type int, and 2*pi is 6.28 or thereabouts, and you'd never get equality.  If x were a float, the test would still always fail, because x starts at zero and increments by 1 - it'll pass right by 6.28, and x will eventually get so big that adding 1 to it won't have any effect - the additional 1 will get rounded off in the floating point calculation.  But, that would take a long time.
Code:
delay(freqpin/10);
This will technically work.  What you'll get is a delay that ranges from 0 to about 102 milliseconds.  With about six samples per cycle, that corresponds to about 600 milliseconds per cycle maximum, for a calculated minimum frequency of about 1.67Hz - actually, it'll be lower, because the loop calculations will take a long time.  You won't have much control when the analog input is close to zero, since the delay will increase by a proportionally large amount with one tick of the ADC output.  The maximum frequency will be determined by the speed of the loop calculations.  Or, it would be if x weren't set to zero each time through the loop.
Quote
What changes(if any) should i make to the code to make it work?
Many changes.  Read some tutorials about programming in C.  If you're intent on using floating point, then make x and y float.  Set y to pi/<some integer>, and use a counter to detect the end of a cycle and reset x.  Fix the test by changing = to ==.  When you get it running, see whether you like the performance.  Then, search "direct digital synthesis," since that's what you're trying to do here, and find a better method.  
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 10
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Thank you so much for your help! i've re-written the code according to your advice, and the led's seem to do exactly what i want them to. here is the revised code for the 3-phase sine wave generator:

int led1 = 11;
int led2 = 10;
int led3 = 9;
const float pi = 3.1415;
float x = 0;
int enable = 8;
int freqpin = A0;
unsigned char p1 = 0;
unsigned char pp1 = 0;
unsigned char pp2 = 0;
unsigned char pp3 = 0;
unsigned char p2 = 0;
unsigned char p3 = 0;
const float y = pi/30;
const float ph1 = 2*pi/3;
const float ph2 = 4*pi/3;
const float ph3 = 2*pi;

void setup() {
  pinMode(led1, OUTPUT);
  pinMode(led2, OUTPUT);
  pinMode(led3, OUTPUT);
  pinMode(enable, INPUT);
  pinMode(freqpin, INPUT);
}

void loop()  {
 while(digitalRead(enable) == HIGH) {
  x = x + y;
  analogWrite(led1, p1);
  analogWrite(led2, p2);
  analogWrite(led3, p3);
  pp1 = 126*sin(x+ph1);
  p1 = pp1+128;
  pp2 = 126*sin(x+ph2);
  p2 = pp2+128;
  pp3 = 126*sin(x+ph3);
  p3 = pp3+128;
  if(x >= 2*pi) x = 0;
  delay(freqpin);
}
analogWrite(led1, 0);
analogWrite(led2, 0);
analogWrite(led3, 0);
x = 0;
}


thanks again for your help! smiley-lol
« Last Edit: July 14, 2012, 10:41:17 am by ajrenzetti » Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 1
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Ajrenzetti,

Hello. I would like to output a sine wave from a arduino using labview as well. However I am new to programming arduino with labview and don't know where to start. Would you be willing to send me a sample of your labview sine wave generator code to get me started?

Thanks
 
Logged

Pages: [1]   Go Up
Jump to: