#include <avr/io.h>
#include <avr/wdt.h>
#include <avr/eeprom.h>
#include <avr/interrupt.h>
#include <avr/pgmspace.h>
#include <util/delay.h>
#define INITIAL_FREQUENCY 107 // Ajustado para 50 Hz con tabla de 128
#define USE_INVERTED_OUTPUT 0
#define SINE_TABLE_LENGTH 128U
// Tabla de onda sinusoidal optimizada
const uint8_t sineTable[SINE_TABLE_LENGTH] PROGMEM = {
128, 134, 140, 146, 152, 158, 165, 170, 176, 182,
188, 193, 198, 203, 208, 213, 218, 222, 226, 230,
234, 237, 240, 243, 245, 248, 250, 251, 253, 254,
254, 255, 255, 255, 254, 254, 253, 251, 250, 248,
245, 243, 240, 237, 234, 230, 226, 222, 218, 213,
208, 203, 198, 193, 188, 182, 176, 170, 165, 158,
152, 146, 140, 134, 128, 121, 115, 109, 103, 97,
90, 85, 79, 73, 67, 62, 57, 52, 47, 42,
37, 33, 29, 25, 21, 18, 15, 12, 10, 7,
5, 4, 2, 1, 1, 0, 0, 0, 1, 1,
2, 4, 5, 7, 10, 12, 15, 18, 21, 25,
29, 33, 37, 42, 47, 52, 57, 62, 67, 73,
79, 85, 90, 97, 103, 109, 115, 121
};
// Definiciones mejoradas de pines
#define EXTERNAL_CONTROL_PIN PB2
#define ADC_FREQUENCY_PIN PB4
#define ADC_AMPLITUDE_PIN PB3
#define PWM_PINS ((1 << PB1) | (1 << PB0))
// Configuración del ADC
#define ADC_CHANNEL_FREQUENCY 2
#define ADC_CHANNEL_AMPLITUDE 3
#define ADC_REFERENCE_VOLTAGE (0 << REFS2) | (0 << REFS1) | (0 << REFS0)
#define ADMUX_FREQUENCY (ADC_REFERENCE_VOLTAGE | (1 << ADLAR) | ADC_CHANNEL_FREQUENCY)
#define ADMUX_AMPLITUDE (ADC_REFERENCE_VOLTAGE | (1 << ADLAR) | ADC_CHANNEL_AMPLITUDE)
// Variables críticas optimizadas
volatile uint8_t Inco;
volatile uint8_t amplitude = 255;
volatile uint8_t speedInput = 0;
volatile uint8_t amplitudeInput = 0;
volatile uint16_t sineTableIndex = 0;
// Estructura de flags usando bits
typedef struct {
uint8_t externalControl : 1;
uint8_t driveWaveform : 2;
} PMSMflags_t;
volatile PMSMflags_t controlFlags;
uint8_t ee_Inco __attribute__((section(".eeprom"))) = INITIAL_FREQUENCY;
// Prototipos de funciones
void PortsInit();
void EnablePWM();
void DisablePWM();
void UpdateWaveform();
void SetupPWM();
void ADC_Init();
ISR(TIMER0_OVF_vect) {
static uint8_t cycleCounter = 0;
if (Inco < 1) {
DisablePWM();
return;
}
// Actualización del índice de la tabla
sineTableIndex += Inco;
if ((sineTableIndex >> 8) >= SINE_TABLE_LENGTH) {
sineTableIndex -= (SINE_TABLE_LENGTH << 8);
}
// Lectura y escalado de la muestra
uint8_t sample = pgm_read_byte(&sineTable[sineTableIndex >> 8]);
int16_t scaled = ((int16_t)(sample - 128) * amplitude) >> 8;
uint8_t output = 128 + scaled;
// Modulación PWM
if (output > 127) {
OCR0A = (output - 128) << 1;
OCR0B = 1;
} else {
OCR0A = 1;
OCR0B = (127 - output) << 1;
}
// Actualización de parámetros
if (++cycleCounter >= 200) {
cycleCounter = 0;
if (controlFlags.externalControl) {
Inco = speedInput;
}
amplitude = amplitudeInput;
}
}
ISR(ADC_vect) {
static uint8_t currentChannel = 0;
if (controlFlags.externalControl) {
if (currentChannel == 0) {
speedInput = (ADCH + speedInput) >> 1;
ADMUX = ADMUX_FREQUENCY;
} else {
amplitudeInput = (ADCH + amplitudeInput) >> 1;
ADMUX = ADMUX_AMPLITUDE;
}
currentChannel ^= 1;
} else {
amplitudeInput = (ADCH + amplitudeInput) >> 1;
}
ADCSRA |= (1 << ADSC);
}
int main(void) {
cli();
// Inicialización de hardware
PortsInit();
ADC_Init();
Inco = eeprom_read_byte(&ee_Inco);
// Configuración inicial
controlFlags.externalControl = (PINB & (1 << EXTERNAL_CONTROL_PIN)) ? 0 : 1;
SetupPWM();
sei();
while (1) {
// Verificación continua del modo de control
if ((PINB & (1 << EXTERNAL_CONTROL_PIN)) && controlFlags.externalControl) {
controlFlags.externalControl = 0;
}
_delay_ms(100);
}
}
void PortsInit() {
DDRB = 0x00;
PORTB = (1 << EXTERNAL_CONTROL_PIN);
}
void EnablePWM() {
DDRB |= PWM_PINS;
}
void DisablePWM() {
DDRB &= ~PWM_PINS;
}
void SetupPWM() {
TCCR0A = (1 << WGM00);
TCCR0B = (1 << CS00);
TIMSK = (1 << TOIE0);
#if USE_INVERTED_OUTPUT
TCCR0A |= (1 << COM0A1) | (1 << COM0A0) | (1 << COM0B1) | (1 << COM0B0);
#else
TCCR0A |= (1 << COM0A1) | (1 << COM0B1);
#endif
EnablePWM();
}
void ADC_Init() {
ADCSRA = (1 << ADEN) | (1 << ADSC) | (1 << ADIE) | (1 << ADPS2) | (1 << ADPS1);
ADMUX = ADMUX_AMPLITUDE;
DIDR0 = (1 << ADC_FREQUENCY_PIN) | (1 << ADC_AMPLITUDE_PIN);
}