Untitled
Anonymous
c_cpp
02/01/2026 4:09 PM
8.6 KB
16
Indexable
/**
* @file pico-spwm-headless.ino
* @brief Autonomous Grid-Tie SPWM (No Serial / Headless)
* @details Runs on 3.3V/5V power without USB.
* 5 Second Delay -> ZVS Start.
*/
#include <Arduino.h>
#include "hardware/pwm.h"
#include "hardware/irq.h"
#define AUTO_START_DELAY_MS 10000 // 5 Seconds Wait
#define PUSHPULL_DRIVE_1 2 // GP2
#define PUSHPULL_DRIVE_2 3 // GP3
#define SHUTDOWN_PIN 14 // GP14 (Master Switch)
#define ZC_INPUT_PIN 15 // GP15
#define STATUS_LED 25 // Onboard LED
#define MODULATING_FREQ 50000
#define PWM_RES 255
#define FULL_BRIDGE 1
#define MAX_STEPS 360.0
#define TRANSISTOR_SWITCH_STEP 179
// ==========================================
// GLOBALS
// ==========================================
volatile float sync_phase_shift = 6.2;
volatile int32_t amplitude = 240;
// System State
volatile bool systemEnabled = false;
volatile bool requestEnable = false;
bool autoStartTriggered = false;
// PLL Variables
volatile float phasor = 0.0;
const float BASE_INC = 0.36;
volatile float currentInc = 0.36;
// Debugging
volatile float lastPhaseError = 0.0;
volatile unsigned long last_sync_time = 0;
unsigned long lastLedToggle = 0;
bool ledState = false;
uint slice_num;
// Sine Lookup Table (0-255)
const int32_t sinetable[] = {
0, 4, 8, 13, 17, 22, 26, 31, 35, 39, 44, 48, 53, 57, 61, 65, 70, 74, 78, 83, 87, 91, 95, 99,
103, 107, 111, 115, 119, 123, 127, 131, 135, 138, 142, 146, 149, 153, 156, 160, 163, 167, 170,
173, 177, 180, 183, 186, 189, 192, 195, 198, 200, 203, 206, 208, 211, 213, 216, 218, 220, 223,
225, 227, 229, 231, 232, 234, 236, 238, 239, 241, 242, 243, 245, 246, 247, 248, 249, 250, 251,
251, 252, 253, 253, 254, 254, 254, 254, 254, 255, 254, 254, 254, 254, 254, 253, 253, 252, 251,
251, 250, 249, 248, 247, 246, 245, 243, 242, 241, 239, 238, 236, 234, 232, 231, 229, 227, 225,
223, 220, 218, 216, 213, 211, 208, 206, 203, 200, 198, 195, 192, 189, 186, 183, 180, 177, 173,
170, 167, 163, 160, 156, 153, 149, 146, 142, 138, 135, 131, 127, 123, 119, 115, 111, 107, 103,
99, 95, 91, 87, 83, 78, 74, 70, 65, 61, 57, 53, 48, 44, 39, 35, 31, 26, 22, 17, 13, 8, 4, 0,
5, 9, 14, 18, 23, 27, 32, 36, 40, 45, 49, 54, 58, 62, 66, 71, 75, 79, 84, 88, 92, 96, 100, 104,
108, 112, 116, 120, 124, 128, 132, 136, 139, 143, 147, 150, 154, 157, 161, 164, 168, 171, 174,
178, 181, 184, 187, 190, 193, 196, 199, 201, 204, 207, 209, 212, 214, 217, 219, 221, 224, 226,
228, 230, 232, 233, 235, 237, 239, 240, 242, 243, 244, 246, 247, 248, 249, 250, 251, 252, 252,
253, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 254, 254, 253, 252, 252,
251, 250, 249, 248, 247, 246, 244, 243, 242, 240, 239, 237, 235, 233, 232, 230, 228, 226, 224,
221, 219, 217, 214, 212, 209, 207, 204, 201, 199, 196, 193, 190, 187, 184, 181, 178, 174, 171,
168, 164, 161, 157, 154, 150, 147, 143, 139, 136, 132, 128, 124, 120, 116, 112, 108, 104, 100,
96, 92, 88, 84, 79, 75, 71, 66, 62, 58, 54, 49, 45, 40, 36, 32, 27, 23, 18, 14, 9, 5, 1
};
// ==========================================
// INTERRUPT 1: SPWM GENERATOR (50kHz)
// ==========================================
void isr_pwm() {
pwm_clear_irq(slice_num);
// Safety: If system disabled, force 0
if (!systemEnabled) {
analogWrite(PUSHPULL_DRIVE_1, 0);
analogWrite(PUSHPULL_DRIVE_2, 0);
// Keep phasor running for PLL
phasor += currentInc;
if (phasor >= MAX_STEPS) phasor -= MAX_STEPS;
return;
}
int current_step = (int)phasor;
int32_t val = (sinetable[current_step] * amplitude) >> 8;
if (current_step > TRANSISTOR_SWITCH_STEP) {
analogWrite(PUSHPULL_DRIVE_1, val);
analogWrite(PUSHPULL_DRIVE_2, 0);
} else {
analogWrite(PUSHPULL_DRIVE_1, 0);
analogWrite(PUSHPULL_DRIVE_2, val);
}
phasor += currentInc;
if (phasor >= MAX_STEPS) phasor -= MAX_STEPS;
}
// ==========================================
// INTERRUPT 2: GRID SYNC
// ==========================================
void isr_grid_sync() {
unsigned long now = millis();
if ((now - last_sync_time) < 15) return;
last_sync_time = now;
// --- ZVS STARTUP LOGIC ---
if (requestEnable) {
digitalWrite(SHUTDOWN_PIN, HIGH); // Enable Drivers
systemEnabled = true; // Update State
requestEnable = false; // Clear Request
}
// -------------------------
// PLL Logic
float targetPhase = (sync_phase_shift / 360.0) * MAX_STEPS;
float diff = targetPhase - phasor;
if (diff > (MAX_STEPS / 2)) diff -= MAX_STEPS;
else if (diff < -(MAX_STEPS / 2)) diff += MAX_STEPS;
float Kp = 0.0003;
float targetInc = BASE_INC + (diff * Kp);
currentInc = (currentInc * 0.90) + (targetInc * 0.10);
lastPhaseError = diff;
if (currentInc < 0.34) currentInc = 0.34;
if (currentInc > 0.38) currentInc = 0.38;
}
// ==========================================
// SETUP & LOOP
// ==========================================
void setup() {
// NO Serial.begin() here to prevent blocking!
// LED Setup
pinMode(STATUS_LED, OUTPUT);
// PWM Setup
analogWriteFreq(MODULATING_FREQ);
analogWriteRange(PWM_RES);
pinMode(PUSHPULL_DRIVE_1, OUTPUT);
pinMode(PUSHPULL_DRIVE_2, OUTPUT);
analogWrite(PUSHPULL_DRIVE_1, 0);
analogWrite(PUSHPULL_DRIVE_2, 0);
// Shutdown Pin (Start OFF)
pinMode(SHUTDOWN_PIN, OUTPUT);
digitalWrite(SHUTDOWN_PIN, LOW);
// Interrupts
slice_num = pwm_gpio_to_slice_num(PUSHPULL_DRIVE_1);
pwm_clear_irq(slice_num);
pwm_set_irq_enabled(slice_num, true);
irq_set_exclusive_handler(PWM_IRQ_WRAP, isr_pwm);
irq_set_enabled(PWM_IRQ_WRAP, true);
pinMode(ZC_INPUT_PIN, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(ZC_INPUT_PIN), isr_grid_sync, FALLING);
}
void loop() {
unsigned long now = millis();
// --- AUTO START LOGIC ---
if (!autoStartTriggered && !systemEnabled) {
if (now > AUTO_START_DELAY_MS) {
requestEnable = true; // Ask ISR to turn ON at next ZC
autoStartTriggered = true; // Don't ask again
}
}
// --- LED STATUS INDICATOR ---
if (systemEnabled) {
// SOLID ON = RUNNING
digitalWrite(STATUS_LED, HIGH);
} else {
// BLINK = WAITING / LOCKING
if (now - lastLedToggle > 500) {
lastLedToggle = now;
ledState = !ledState;
digitalWrite(STATUS_LED, ledState);
}
}
}Editor is loading...
Leave a Comment