// === Seno trifásico com PWM por software (STM32 Nucleo-C031C6, Wokwi) ===
// Baseado no guia de laboratório da UFPB - Profissional II
// Este exemplo usa PWM por software, pois os timers de hardware não estão
// disponíveis para esta placa no Wokwi na data do guia.
#include <Arduino.h>
#include <math.h>
// --- Pinos ---
// Pinos de saída para o PWM das fases A, B e C
const uint8_t PWM_PINS[3] = { D3, D5, D6 }; // [cite: 79]
// Pinos de entrada analógica para os potenciômetros
const uint8_t ADC_PINS[3] = { A0, A1, A2 }; // [cite: 81, 52]
// --- Parâmetros da Simulação ---
// Frequência fundamental do sinal senoidal
const float F_SINE_HZ = 60.0f; // [cite: 85, 13]
// A constante TWO_PI já é definida pelo Arduino.h
// --- Parâmetros do PWM por Software ---
// Período de atualização do cálculo do seno (1 ms -> 1 kHz)
const float DT_SINE_MS = 1.0f; // [cite: 92, 58]
// Resolução do contador do PWM. Período PWM = PWM_TOP * TICK_US
const uint16_t PWM_TOP = 200; // [cite: 93, 57]
// Passo de tempo do PWM (10 µs). F_pwm = 1 / (200 * 10µs) = 500 Hz
const uint32_t TICK_US = 10; // [cite: 95, 57]
// --- Defasagens de cada fase em radianos ---
const float PHASE_A = 0.0f; // [cite: 99]
const float PHASE_B = -2.0f * PI / 3.0f; // -120 graus [cite: 100, 59]
const float PHASE_C = 2.0f * PI / 3.0f; // +120 graus [cite: 103, 59]
// --- Variáveis Globais ---
volatile uint16_t pwmCount = 0; // [cite: 104] Contador atual do ciclo PWM por software
int dutyCount[3] = {0, 0, 0}; // [cite: 105] Valor de contagem (0 a PWM_TOP) para cada fase
unsigned long lastPwmTickUs = 0; // [cite: 106]
unsigned long lastSineTickUs = 0; // [cite: 108]
float theta = 0.0f; // [cite: 108] Ângulo atual da senóide em radianos
void setup() {
// Configura os pinos de PWM como saída e os inicializa em nível baixo
for (int i = 0; i < 3; i++) {
pinMode(PWM_PINS[i], OUTPUT); // [cite: 112]
digitalWrite(PWM_PINS[i], LOW); // [cite: 113]
}
// Os pinos analógicos (A0, A1, A2) são configurados automaticamente pela função analogRead()
}
void loop() {
const unsigned long nowUs = micros(); // [cite: 119]
// --- Bloco 1: Atualização da Senóide (executa a cada 1 ms) ---
if (nowUs - lastSineTickUs >= (unsigned long)(DT_SINE_MS * 1000.0f)) { // [cite: 123]
lastSineTickUs += (unsigned long)(DT_SINE_MS * 1000.0f); // [cite: 125]
// Lê os potenciômetros (ADC de 12 bits: 0-4095) e normaliza a amplitude para [0, 1] [cite: 60]
float A[3]; // [cite: 126]
for (int i = 0; i < 3; i++) {
int rawAdc = analogRead(ADC_PINS[i]); // [cite: 129]
A[i] = constrain(rawAdc / 4095.0f, 0.0f, 1.0f); // [cite: 131]
}
// Calcula o valor do seno para cada fase aplicando a devida defasagem [cite: 132]
float sA = sinf(theta + PHASE_A); // [cite: 133]
float sB = sinf(theta + PHASE_B); // [cite: 134]
float sC = sinf(theta + PHASE_C); // [cite: 136]
// Mapeia o seno bipolar [-1, 1] para o duty cycle unipolar [0, 1] [cite: 137]
// A fórmula é: duty = 0.5 (offset) + 0.5 * Amplitude * seno(theta) [cite: 31, 32, 33]
float duty[3] = {
0.5f + 0.5f * A[0] * sA, // [cite: 139]
0.5f + 0.5f * A[1] * sB, // [cite: 140]
0.5f + 0.5f * A[2] * sC
};
// Satura o duty cycle e converte para a contagem do PWM (0 a PWM_TOP) [cite: 141]
for (int i = 0; i < 3; i++) {
duty[i] = constrain(duty[i], 0.0f, 1.0f); // [cite: 143]
dutyCount[i] = (int)(duty[i] * PWM_TOP); // [cite: 144]
}
// Avança o ângulo para a próxima iteração (Δθ = 2π * f * Δt) [cite: 145]
theta += TWO_PI * F_SINE_HZ * (DT_SINE_MS / 1000.0f); // [cite: 146]
// Garante que o ângulo permaneça no intervalo [0, 2π) para evitar overflow
if (theta >= TWO_PI) {
theta -= TWO_PI; // [cite: 147]
}
}
// --- Bloco 2: Geração do PWM por Software (executa a cada 10 µs) ---
if (nowUs - lastPwmTickUs >= TICK_US) { // [cite: 149]
lastPwmTickUs += TICK_US; // [cite: 152]
// Incrementa o contador do PWM e o reinicia quando atinge o topo [cite: 67]
pwmCount++; // [cite: 153]
if (pwmCount >= PWM_TOP) {
pwmCount = 0; // [cite: 154]
}
// Atualiza os três pinos de saída [cite: 155]
// O pino fica em HIGH se o contador for menor que o valor de duty desejado
for (int i = 0; i < 3; i++) {
digitalWrite(PWM_PINS[i], (pwmCount < dutyCount[i]) ? HIGH : LOW); // [cite: 157]
}
}
}