Three square waves

That is a very demanding and egoistic request:
almost zero work from you 99.9% work for others

If you don't want to pay money. You will have to "pay" some time.

2 Likes

Okay guys, I’m very interested to hear your opinions and thank you very much for some software calculations. My goal is to create a three-phase driver based on a simple Arduino module to control a powerful thyristor three-phase bridge. This is not for controlling motors but for emergency powering three-phase existing circuits commercial industrial and residential arias. Idea to create affordable reliable device

Decimal places are out. And micros() granularity is 4µs chunks.

using a ESP32 Timer0 interrupts to generate 666uSec pulses (period 1332uSec)

// ESP32 666uSec interrupt - generate pulse

// from original code
/****************************************************************************************************************************
  TimerInterruptTest.ino
  For ESP32, ESP32_S2, ESP32_S3, ESP32_C3 boards with ESP32 core v2.0.2+
  Written by Khoi Hoang

  Built by Khoi Hoang https://github.com/khoih-prog/ESP32TimerInterrupt
  Licensed under MIT license
 */

#include "ESP32TimerInterrupt.h"

#define PIN_D19 19  // Pin D19 mapped to pin GPIO19 of ESP32

// Timer0 interrupt handler - invert pin GPIO19 and increment counter
volatile int counter = 0;
bool IRAM_ATTR TimerHandler0(void* timerNo) {
  static bool toggle0 = false;
  digitalWrite(PIN_D19, toggle0);
  toggle0 = !toggle0;
  counter++;
  return true;
}

// Init ESP32 timer 0
ESP32Timer ITimer0(0);

void setup() {
  pinMode(PIN_D19, OUTPUT);
  Serial.begin(115200);
  while (!Serial && millis() < 5000)
    ;
  delay(500);
  Serial.print(F("\nStarting TimerInterruptTest on "));
  Serial.println(ARDUINO_BOARD);
  Serial.println(ESP32_TIMER_INTERRUPT_VERSION);
  Serial.print(F("CPU Frequency = "));
  Serial.print(F_CPU / 1000000);
  Serial.println(F(" MHz"));

  // Interval in microsecs
  if (ITimer0.attachInterruptInterval(666, TimerHandler0)) {
    Serial.print(F("Starting  ITimer0 OK "));
  } else
    Serial.println(F("Can't set ITimer0. Select another freq. or timer"));
  Serial.flush();
}

// display counter every second
void loop() {
  static long timer = millis();
  if (millis() - timer >= 1000) {
    timer = millis();
    Serial.println(counter);
    counter = 0;
  }
}

serial monitor output

Starting TimerInterruptTest on ESP32_DEV
ESP32TimerInterrupt v2.3.0
CPU Frequency = 240 MHz
Starting  ITimer0 OK 1516
1501
1502
1501
1502
1501
1502
1501
1502
1501
1502
1501

oscilloscope plot
image

a Tensey 4 may be able to get closer to 666.6uSec otherwise build some hardware

Well that's the wrong order of updates and the initial state needs defining, I think this might be closer to the OP's timing diagram:

const byte Pins[] = {9,10,11};

void setup()
{
  for (byte i = 0 ; i < 3 ; i++).    // set modes to OUTPUT
    pinMode(Pins[i], OUTPUT);
  digitalWrite(Pins[0], HIGH);  // initial state
  digitalWrite(Pins[1], LOW);
  digitalWrite(Pins[2], HIGH);
}

void loop()
{
  for (int i = 2; i >= 0; i--)  // order of update to match diagram
  {
    digitalWrite(Pin[i], ! digitalRead(Pin[i]));   // toggle pin
    delayMicroseconds(333);
  }
}
1 Like

possibly a state machine may work, e.g. ESP32

// ESP32 333.3uSec interrupt - generate 3 phase pulses

// from ESP32 Sine Wave Example https://deepbluembedded.com/esp32-dac-audio-arduino-examples/
/* original from
* LAB Name: ESP32 Sine Wave Generation Example
* Author: Khaled Magdy
* DeepBlueMbedded 2023
* For More Info Visit: www.DeepBlueMbedded.com
*/

#include <driver/dac.h>
#include <driver/adc.h>

#define PIN_D19 19  // phase 1, 2 and 3
#define PIN_D18 18
#define PIN_D5 5

// Timer0 Configuration Pointer (Handle)
hw_timer_t *Timer0_Cfg = NULL;

// Timer0 interrupt handler - output 3 phase pulses and increment counter
volatile int counter = 0;
void IRAM_ATTR Timer0_ISR() {
  static int state = 0;   // state machine
  switch (state) {
    case 0:
      digitalWrite(PIN_D19, 1);   // phase 1 HIGH
      break;
    case 1:
      digitalWrite(PIN_D5, 0);    // phase 3 LOW
      break;
    case 2:
      digitalWrite(PIN_D18, 1);   // phase 2 HIGH
      break;
    case 3:
      digitalWrite(PIN_D19, 0);   // phase 1 LOW
      break;
    case 4:
      digitalWrite(PIN_D5, 1);    // phase 3 HIGH
      break;
    case 5:
      digitalWrite(PIN_D18, 0);   // phase 2 LOW
      break;
  }
  if(++state > 5) state=0;    // increment state or reset to 0
  counter++;
}


void setup() {
  Serial.begin(115200);
  pinMode(PIN_D19, OUTPUT);
  pinMode(PIN_D18, OUTPUT);
  pinMode(PIN_D5, OUTPUT);
  Serial.println("\nESP32 3 phase pulses");
  // Configure Timer0 Interrupt 666.6uSec
  Timer0_Cfg = timerBegin(0, 8, true);
  timerAttachInterrupt(Timer0_Cfg, &Timer0_ISR, true);
  timerAlarmWrite(Timer0_Cfg, 3333, true);
  timerAlarmEnable(Timer0_Cfg);
}

// display counter every second
void loop() {
  static long timer = millis();
  if (millis() - timer >= 1000) {
    timer = millis();
    Serial.println(counter);
    counter = 0;
  }
}

gives (phase 1 yellow, phase 2 cyan phase 3 purple)
image

and
image

1 Like

Did you do a search for three phase square wave? It’s been solved lots of times:

https://forum.arduino.cc/search?q=three%20phase%20square%20wave

I know I tried it once:

And here's one with Bresenham-like timing. It does have some jitter due to the granularity micros() and the execution time in software, but the average frequency is phase-locked with the to the match the accuracy of the processor clock:

You're right. Getting the pin order and initial conditions with round-robin toggle scheme is a bit tricky.

Managing the transitions or swapping pins with a state machine per @horace could be more straightforward.

UNO generate 3 phase pulses using state machine

// UNO 333uSec interrupt - generate 3 phase pulses

#include <TimerOne.h>

const byte pinA = 7;
const byte pinB = 8;
const byte pinC = 9;

// 3 phase state sequence
enum states{P1_HIGH, P3_LOW, P2_HIGH, P1_LOW, P3_HIGH, P2_LOW};

// Timer0 interrupt handler - output 3 phase pulses and increment counter
volatile int counter = 0;
void Timer1_ISR() {
  static int state = P1_HIGH;   // state machine
  switch (state) {
    case P1_HIGH:
      digitalWrite(pinA, 1);   // phase 1 HIGH
      break;
    case P3_LOW:
      digitalWrite(pinC, 0);    // phase 3 LOW
      break;
    case P2_HIGH:
      digitalWrite(pinB, 1);   // phase 2 HIGH
      break;
    case P1_LOW:
      digitalWrite(pinA, 0);   // phase 1 LOW
      break;
    case P3_HIGH:
      digitalWrite(pinC, 1);    // phase 3 HIGH
      break;
    case P2_LOW:
      digitalWrite(pinB, 0);   // phase 2 LOW
      break;
  }
  if(++state > 5) state=P1_HIGH;    // increment state or reset to P1_HIGH
  counter++;
}

void setup() {
  Serial.begin(115200);
  pinMode(pinA, OUTPUT);
  pinMode(pinB, OUTPUT);
  pinMode(pinC, OUTPUT);
  Serial.println("\nUNO 3 phase pulses");
  Timer1.initialize(333); //Initialize timer with .1 mSec second period
  Timer1.attachInterrupt(Timer1_ISR);
}

// display counter every second
void loop() {
  static long timer = millis();
  if (millis() - timer >= 1000) {
    timer = millis();
    Serial.println(counter);
    counter = 0;
  }
}

serial monitor output

UNO 3 phase pulses
3012
3013
3010
3013
3010
3013
3010
3013
3012
3010
3013
3009
3013
3010

scope displays (phase 1 yellow, phase 2 cyan phase 3 purple)
image

2 Likes

If you tweak the Timer1.setPeriod() to also toggle between 333us and 334us, you can get the average right on target (as accurate as the processor clock)

#include <TimerOne.h>

const byte pinA = 7;
const byte pinB = 8;
const byte pinC = 9;

// 3 phase state sequence
enum states{P1_HIGH, P3_LOW, P2_HIGH, P1_LOW, P3_HIGH, P2_LOW};

// Timer0 interrupt handler - output 3 phase pulses and increment counter
volatile int counter = 0;
void Timer1_ISR() {
  static int state = P1_HIGH;   // state machine
  switch (state) {
    case P1_HIGH:
      digitalWrite(pinA, 1);   // phase 1 HIGH
      break;
    case P3_LOW:
      digitalWrite(pinC, 0);    // phase 3 LOW
      break;
    case P2_HIGH:
      digitalWrite(pinB, 1);   // phase 2 HIGH
      break;
    case P1_LOW:
      digitalWrite(pinA, 0);   // phase 1 LOW
      Timer1.setPeriod(334);
      break;
    case P3_HIGH:
      digitalWrite(pinC, 1);    // phase 3 HIGH
      break;
    case P2_LOW:
      digitalWrite(pinB, 0);   // phase 2 LOW
      Timer1.setPeriod(333);
      break;
  }
  if(++state > 5) state=P1_HIGH;    // increment state or reset to P1_HIGH
  counter++;
}

void setup() {
  Serial.begin(115200);
  pinMode(pinA, OUTPUT);
  pinMode(pinB, OUTPUT);
  pinMode(pinC, OUTPUT);
  Serial.println("\nUNO 3 phase pulses");
  Timer1.initialize(333); //Initialize timer with .1 mSec second period
  Timer1.attachInterrupt(Timer1_ISR);
}

// display counter every second
void loop() {
  static long timer = millis();
  if (millis() - timer >= 1000) {
    timer +=1000;
    Serial.println(counter);
    counter = 0;
  }
}

I also tweaked the printing so it won't lose synchronization in time or count:

// display counter every second
void loop() {
  static long timer = millis();
  if (millis() - timer >= 1000) {
    timer +=1000;
    Serial.println(counter);
    counter -= 3000;
  }
}

1 Like

Guys, in my opinion it’s a simple task, but I couldn't come up with anything. There are two outputs (pinMode, 13); and (pinMode, 12); if one is high then the other is low like a flip flop. ?? What code for those

Opinion doesn't code. Clarity is important. I can't reconcile post#1 with post#32. One has 3 outputs, the latter states two. I give up.

Okay/ When pin 13 ON then pin 7 OFF
pin 12 ON then pin 4 OFF
pin 8 ON then pin 2 OFF

So at least for you it is a difficult task
For others it is a difficult task you you do not specify the details on the functional level.

You are still collecting

ANTI-PATHY

by too short postings
how many users do you want to

That seems like 6 outputs.

possibly a 6-phase system?

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.