// Arduino SPWM Sine Inverter
// https://electronoobs.com/eng_arduino_tut88.php
// Does not work...
// 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.
int lookUp1[] = {
50, 100, 151, 201, 250, 300, 349, 398, 446, 494,
542, 589, 635, 681, 726, 771, 814, 857, 899, 940,
981, 1020, 1058, 1095, 1131, 1166, 1200, 1233, 1264, 1294,
1323, 1351, 1377, 1402, 1426, 1448, 1468, 1488, 1505, 1522,
1536, 1550, 1561, 1572, 1580, 1587, 1593, 1597, 1599, 1600,
1599, 1597, 1593, 1587, 1580, 1572, 1561, 1550, 1536, 1522,
1505, 1488, 1468, 1448, 1426, 1402, 1377, 1351, 1323, 1294,
1264, 1233, 1200, 1166, 1131, 1095, 1058, 1020, 981, 940,
899, 857, 814, 771, 726, 681, 635, 589, 542, 494,
446, 398, 349, 300, 250, 201, 151, 100, 50, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
int lookUp2[] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
50, 100, 151, 201, 250, 300, 349, 398, 446, 494,
542, 589, 635, 681, 726, 771, 814, 857, 899, 940,
981, 1020, 1058, 1095, 1131, 1166, 1200, 1233, 1264, 1294,
1323, 1351, 1377, 1402, 1426, 1448, 1468, 1488, 1505, 1522,
1536, 1550, 1561, 1572, 1580, 1587, 1593, 1597, 1599, 1600,
1599, 1597, 1593, 1587, 1580, 1572, 1561, 1550, 1536, 1522,
1505, 1488, 1468, 1448, 1426, 1402, 1377, 1351, 1323, 1294,
1264, 1233, 1200, 1166, 1131, 1095, 1058, 1020, 981, 940,
899, 857, 814, 771, 726, 681, 635, 589, 542, 494,
446, 398, 349, 300, 250, 201, 151, 100, 50, 0
};
void setup() {
DDRB = 0b00100110; // Set PB1, PB2 and PB5 (LED_BUILTIN) as outputs.
// Register initilisation, see datasheet for more detail.
TCCR1A = 0b10100010;
// 10 clear on match, set at BOTTOM for compA.
// 10 clear on match, set at BOTTOM for compB.
// 00 reserved
// 10 WGM1 1 : 0 for waveform 14 LSB.
TCCR1B = 0b00011001;
// 000 Input Capture & reserved
// 11 WGM1 3: 2 for waveform 14 MSB.
// 001 no prescale on the counter.
ICR1 = 1600; // Period for 16MHz crystal, for a switching frequency of 100KHz for 200 subdevisions per 50Hz sin wave cycle.
TIMSK1 = 0b00000001;
// 0000000
// 1 TOIE1 Flag interrupt enable.
sei(); // Enable global interrupts.
digitalWrite(LED_BUILTIN, HIGH);
}
ISR(TIMER1_OVF_vect) {
static int num;
asm volatile ("sbi %0, %1" :: "I" (_SFR_IO_ADDR(PORTB)), "I" (PB5)); // Set LED_BUILTIN
// change duty-cycle every period.
OCR1A = lookUp1[num];
OCR1B = lookUp2[num];
if (++num >= 200) { // Pre-increment num then check if it's below 200.
num = 0; // Reset num.
}
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
}