#include <avr/io.h>
#include <avr/interrupt.h>
#include <math.h>
#define TARGET_FREQ 60 // Frecuencia fundamental en Hz
#define DEAD_TIME_US 2 // Dead-time en microsegundos
#define OVERCURRENT_THRESHOLD 512 // Umbral de sobrecorriente (ajustar según sensor)
#define SPWM_SAMPLES 64 // Número de muestras por ciclo
volatile uint8_t amplitude = 255; // Amplitud máxima por defecto
volatile uint8_t overcurrent = 0;
volatile uint8_t spwm_table[SPWM_SAMPLES]; // Tabla SPWM de 64 muestras
// Genera tabla SPWM de 64 muestras
void generate_spwm_table() {
for (uint8_t i = 0; i < SPWM_SAMPLES; i++) {
double angle = 2 * M_PI * i / SPWM_SAMPLES;
double ref = 127.5 + 127.5 * sin(angle);
spwm_table[i] = (uint8_t)(ref / 2);
}
}
// Configuración de temporizadores
void setup_timers() {
// Timer1 para base de tiempo SPWM (modo CTC)
TCCR1 = (1 << CTC1) | (1 << CS10); // Prescaler 1, modo CTC
OCR1C = (F_CPU / (SPWM_SAMPLES * TARGET_FREQ)) - 1; // Valor automático para frecuencia objetivo
TIMSK |= (1 << OCIE1A); // Habilitar interrupción por comparación
// Timer0 para salida SPWM (modo Fast PWM)
TCCR0A = (1 << COM0A1) | (1 << COM0B1) | (1 << WGM01) | (1 << WGM00);
TCCR0B = (1 << CS00); // Prescaler 1
}
// Interrupción para actualizar valor SPWM
ISR(TIM1_COMPA_vect) {
static uint8_t index = 0;
OCR0A = spwm_table[index];
OCR0B = spwm_table[(index + SPWM_SAMPLES/2) % SPWM_SAMPLES]; // Desfase 180°
index = (index + 1) % SPWM_SAMPLES;
}
// Configuración de ADC para lectura de amplitud y sobrecorriente
void setup_adc() {
ADCSRA = (1 << ADEN) | (1 << ADPS2) | (1 << ADPS1); // Habilitar ADC, prescaler 64
ADMUX = (1 << MUX1) | (1 << MUX0); // Canal A3 (PB3) para amplitud
}
// Lectura de ADC con filtro
uint16_t read_adc_filtered(uint8_t channel) {
ADMUX = (ADMUX & 0xF0) | (channel & 0x0F);
uint32_t sum = 0;
for (uint8_t i = 0; i < 4; i++) {
ADCSRA |= (1 << ADSC);
while (ADCSRA & (1 << ADSC));
sum += ADC;
}
return sum / 4;
}
// Manejo de sobrecorriente
void check_overcurrent() {
static uint8_t counter = 0;
if (read_adc_filtered(1) > OVERCURRENT_THRESHOLD) { // Canal A1 (PB2)
counter++;
if (counter > 3) {
overcurrent = 1;
TCCR0A = 0; // Deshabilitar salidas
}
} else {
if (counter > 0) counter--;
if (overcurrent && counter == 0) {
overcurrent = 0;
TCCR0A = (1 << COM0A1) | (1 << COM0B1) | (1 << WGM01) | (1 << WGM00);
}
}
}
int main(void) {
// Configuración inicial
setup_timers();
setup_adc();
generate_spwm_table();
sei(); // Habilitar interrupciones
// Configuración de pines
DDRB = (1 << PB0) | (1 << PB1); // Salidas OC0A y OC0B
while (1) {
// Leer amplitud desde A3 (PB3)
amplitude = read_adc_filtered(3) >> 2;
// Verificar sobrecorriente
check_overcurrent();
}
}