Improvements to 4 Phase Frequency Generator

I am working on a project and I am looking for a bit of help. I was wondering if anyone could help me improve it or add an ability to control duty cycles or at least display it in the serial monitor. My programing skill are pretty basic. I am using this as a pretty basic multi-phase frequency generator.

  • The frequency reading is displayed on Serial Monitor every 2 seconds.
  • The frequency range is 100Hz-125kHz.
    *It is phased at 90 degrees
  • A Push button to Start/Stop
  • A 10k pot

Below I have include a basic Fritzing schematic diagram

I have also added the 4 phase output as seen on Oscilloscope.

Here is the Code:


int button = 2;  // Start/Stop Button

int phase1 = 3;
int phase2 = 4;
int phase3 = 5;
int phase4 = 6;

int potPin = A0;
int potValue = 0;

float timePeriod = 500;       // In microseconds
unsigned long timePeriodMax = 10000;  // In microseconds
unsigned long timePeriodMin = 8;      // In microseconds
float frequency = 0;

unsigned long previousMillis = 0;
unsigned long interval = 2000;  // Every 5 seconds

bool startSig = false; //Stop by default

void setup() {
  Serial.begin(9600);
  pinMode(phase1, OUTPUT);
  pinMode(phase2, OUTPUT);
  pinMode(phase3, OUTPUT);
  pinMode(phase4, OUTPUT);
  pinMode(button, INPUT_PULLUP);
  pinMode(potPin, INPUT);
  attachInterrupt(digitalPinToInterrupt(button), start_stop, FALLING);
  Serial.println("Initialized");

}

void loop() {
  if (startSig == true) {

    if (millis() - previousMillis >= interval) {
      previousMillis = millis();

      potValue = analogRead(potPin);
      timePeriod = map(potValue, 0, 1023, timePeriodMin, timePeriodMax);
      frequency = 1 / (timePeriod / 1000000UL); // 1000000 microseconds = 1 second
      Serial.print("Frequency = ");
      Serial.print(frequency);
      Serial.println(" Hz");
    }

    digitalWrite(phase3, LOW);
    digitalWrite(phase1, HIGH);
    delayMicroseconds(timePeriod / 4);
    digitalWrite(phase4, LOW);
    digitalWrite(phase2, HIGH);
    delayMicroseconds(timePeriod / 4);

    digitalWrite(phase1, LOW);
    digitalWrite(phase3, HIGH);
    delayMicroseconds(timePeriod / 4);

    digitalWrite(phase2, LOW);
    digitalWrite(phase4, HIGH);
    delayMicroseconds(timePeriod / 4);

  }
  else {
    digitalWrite(phase1, LOW);
    digitalWrite(phase2, LOW);
    digitalWrite(phase3, LOW);
    digitalWrite(phase4, LOW);
  }
}

void start_stop()
{
  if (startSig == true) {
    startSig = false; //Stop
    Serial.println("Stopped.");
  }
  else {
    startSig = true; //Start
    Serial.println("Starteed.");
  }
}

That is not a 4 phase system, it's a 2 phase system with complimentary outputs. It's pointless to implement phases that are simply 180 degrees from each other, a simple logic inversion takes care of that.

Suggestions to Fix?

What are you using it for?

Multi-phase Frequency Generator

I read that. I mean, what are you using your Multi-phase Frequency Generator for? Actually, your code does the inversion as efficiently as you can using your chosen method (digitalWrite). The application or "specs" determine whether improvements are necessary.

Duty cycles can be implemented by using fractions other than f/4 for timing.

Hi,

I beg to differ.
2 phase the start of each waveform is 180Deg
3 phase the start of each waveform is 120Deg.
4 phase the start of each waveform is 90Deg.

Its just maths that the ODD phases are 180Deg out of phase., and the EVEN phases are 180Deg out of phase.

Tom... :smiley: :+1: :coffee: :australia:
PS. How would you describe a 4 phase system?

Oh, I see. Yes, strictly speaking that is right. My point, though, 180 degree phase difference is easier to achieve digitally, than in the analog domain.

It does introduce a question for the OP, will two of the phases always be complementary to two others, regardless of frequency and duty cycle?

Which might be more obvious, if the end use were known... which seems just as unlikely to be forthcoming as when the OP was asked about it 2 years ago.
https://forum.arduino.cc/t/stepper-motor-or-4-phase-power-suggestion/642758

Someone did their homework. I guess, I keep on making the mistake of asking for help. Exactly, why I left two years ago. I have been up front about my basic programming skills. Again, its end use is to be a novelty sometimes to experiment with an play around with that is it.

I would be interested in understanding about inversion and the use of (digitalWrite). Or how I would implement the Duty cycle by using fractions other than f/4 for timing.

Anyone who would like to help me I would greatly appreciate your thoughts on any improvements.

For me I would describe it similarly to a three phase inverter or like a PWM. Where the Arduino generates 3 seprate waveform with 120 degree out of phase between each individual waveform.

The Arduino generates two voltage levels: HIGH and LOW. I understand with just two voltage levels we are generating wide range of voltage levels like a PWM. That is why I am trying to implement or atleast monitor the duty Cycles.

Here the arduino is generating a full 5 Volts, so that would be 100% duty cycle. If we set duty cycle to 50% we will get average of lets say voltage half of the source voltage, here it is 2.5V at output.

So generate 4 seprate waveforms with a 90 degree, as opposed to 120 degrees.

The code can't run at desired higher frequency i suppose.
First, get rid of the following:
if (millis() - previousMillis >= interval)
and replace it by some global counter value which increases in the loop and if it's bigger than certain value, then execute analogRead and serial communication tasks.

Then replace everywhere:
timePeriod / 4
I'm not sure if Arduino IDE compiler can handle such optimization itself, so worth to do manually. By the once computed temporary variable instead of 4 times, like:
timetowait = timePeriod >> 2;

Replace delayMicroseconds by cycle which read time elapsed and when the time is equal or bigger, then exit the cycle. This will raise precision.

Finally, bit more complicated for beginner, replace digitalWrite function by direct writing and performance increase significantly. But still don't expect good results at high frequencies, it's not precise enough way to do your task and i think need to work with timers, which is much more complicated thing.

Did you want one duty-cycle value for all four phases or a separate duty-cycle setting for each? The pot is used for frequency. Did you want to use one or four more pots for duty-cycle(s)?

My thought was to have one duty-cycle value for all four phases outputs and add an additional pot to control the duty-cycle value. I accidentally deleted this comment this forum layout is werid for my phone.

So, one step will be to add another pot. Then you have to map that pot to a duty-cycle value.

I would switch from using delayMicroseconds() to scheduling transitions with micros().

It was an attempt to find an answer to a question you didn't answer. That's all, except for the observation that you didn't answer...