// Arduino SPWM Sine Inverter
// https://electronoobs.com/eng_arduino_tut88.php
#include <avr/io.h>
#include <avr/interrupt.h>
// Look up tables with 200 entries each, normalised to have max value of 1600 which is the period of the PWM loaded into register ICR1.
uint16_t sine_table[] = {
0, 50, 100, 150, 200, 250, 300, 349, 398, 446,
494, 542, 589, 635, 681, 726, 770, 814, 857, 899,
940, 980, 1019, 1057, 1095, 1131, 1166, 1199, 1232, 1263,
1294, 1323, 1350, 1376, 1401, 1425, 1447, 1467, 1487, 1504,
1521, 1536, 1549, 1560, 1571, 1579, 1586, 1592, 1596, 1598,
1599
};
#include <avr/io.h>
#include <avr/interrupt.h>
#include <math.h>
void setup() {
// pinMode(LED_BUILTIN, OUTPUT);
DDRB |= (1 << PB1) | (1 << PB2) | (1 << PB5); // Set D9 (PB1), D10 (PB2) and D13 (PB5) as outputs
// Configure Timer1
TCCR1A = (1 << COM1A1) | (1 << COM1B1) | (1 << WGM11); // Non-inverting mode for both channels
TCCR1B = (1 << WGM12) | (1 << WGM13) | (1 << CS10); // No prescaler
ICR1 = 1599; // TOP value for 10 kHz sample rate
TIMSK1 = (1 << TOIE1); // Enable overflow interrupt
sei(); // Enable global interrupts
}
ISR(TIMER1_OVF_vect) {
static uint8_t index = 0;
static uint16_t nextOCR1A = 0;
static uint16_t nextOCR1B = 0;
// Always output positive part on OCR1A (D9)
OCR1A = nextOCR1A;
// For OCR1B (D10), output inverted sine only if negative, else 0
OCR1B = nextOCR1B;
asm volatile ("sbi %0, %1" :: "I" (_SFR_IO_ADDR(PORTB)), "I" (PB5)); // Set LED_BUILTIN
index = (index == 199) ? 0 : index + 1; // Move to next sample
if (index < 100) {
nextOCR1B = 0;
if (index < 50) {
nextOCR1A = sine_table[index]; // index < 50
} else {
nextOCR1A = sine_table[100 - index]; // 50 <= index < 100 -> 0 < (100 - index) <= 50
}
} else {
nextOCR1A = 0;
if (index < 150) {
nextOCR1B = sine_table[index - 100]; // 100 <= index < 150 -> 0 <= (index - 100) < 50
} else {
nextOCR1B = sine_table[200 - index]; // 150 <= index < 200 -> 0 < (200 - index) <= 50
}
}
asm volatile ("cbi %0, %1" :: "I" (_SFR_IO_ADDR(PORTB)), "I" (PB5)); // Clear LED_BUILTIN
}
void loop() {
// Nothing here; everything is handled in the ISR
}