// ==== CONFIGURATION ==== // Frequency of sine wave output (can change to 60) const int freq = 50; // Number of steps in half sine wave const int steps = 21; // Dead time in microseconds const int deadTime = 50; // Output pins for SPWM (must be PWM capable) const int pwmPinA = 9; // OC1A on Arduino Uno const int pwmPinB = 10; // OC1B // Lookup table for one half sine wave (0 to 255) const byte sineTable[steps] = { 128, 147, 167, 185, 202, 218, 231, 241, 249, 253, 255, 253, 249, 241, 231, 218, 202, 185, 167, 147, 128 }; // Variables for ISR control volatile int index = 0; volatile bool halfCycle = false; // false = A active, true = B active void setup() { pinMode(pwmPinA, OUTPUT); pinMode(pwmPinB, OUTPUT); // Disable PWM on Timer1 temporarily TCCR1A = 0; TCCR1B = 0; // Set Timer1 compare interrupt for step timing // Total microseconds per step = 1 / (2 * freq * steps) unsigned long stepTimeMicros = 1000000UL / (2UL * freq * steps); // Convert to timer ticks (16 MHz / 8 prescaler = 2 MHz = 0.5 us per tick) unsigned int ocr1a = stepTimeMicros * 2; // Set Timer1 compare match value OCR1A = ocr1a; // Set Timer1 mode to CTC (Clear Timer on Compare Match) TCCR1B |= (1 << WGM12); // Set prescaler to 8 TCCR1B |= (1 << CS11); // Enable compare match interrupt TIMSK1 |= (1 << OCIE1A); } void loop() { // Main loop does nothing, all work is done by ISR } // ==== INTERRUPT SERVICE ROUTINE ==== // Runs every stepTimeMicros microseconds ISR(TIMER1_COMPA_vect) { // First add dead time analogWrite(pwmPinA, 0); analogWrite(pwmPinB, 0); delayMicroseconds(deadTime); // may cause slight jitter but works // Now output PWM value based on current half-cycle if (!halfCycle) { // A active analogWrite(pwmPinA, sineTable[index]); analogWrite(pwmPinB, 0); } else { // B active analogWrite(pwmPinA, 0); analogWrite(pwmPinB, sineTable[index]); } index++; // If we finish one half-cycle if (index >= steps) { index = 0; halfCycle = !halfCycle; // switch side } }