/* Sollte man so einen Leistungs-MOSFET zur Z-Diode machen können?
Erst mal mit ATtiny25 und seiner High-Speed-PLL
Eigentlich müsste auch ein ATtiny13 reichen
1 PB5 !RESET O frei — oder meldet Abschalten der Quelle nach Timeout
2 PB3 - O H zündet Überspannungsthyristor
3 PB4 ADC2 I Misst Hochspannung per Spannungsteiler 640:1
4 GND - - Masseanschluss
5 PB0 - O L meldet Begrenzungseinsatz an Optokoppler
6 PB1 OC1A O Gatespannung für Leistungs-MOSFETs (ATtiny13: OC0B)
7 PB2 ADC1 I Misst Strom per Shuntwiderstand 1 Ω (pro Transistor), also 1 V/A
8 Ucc - - Speisespannung, aus Hochspannung per Längsregler „verheizt“
*/
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/sleep.h>
#define UZ 500.0 // Simulierte Z-Spannung in Volt
#define PMAX 150.0 // Max. Dauerleistung am Transistor in Watt
#define SIGLEN 2.0 // Melde-Zeit in s (Monoflop-Verhalten)
// wenn der Thyristor zündet dann kürzer weil die Speisespannung zusammenbricht
#define STOPDLY 0.5 // Wartezeit bis zur Notabschaltung: „Alle Maschinen Stop“
FUSES={0b11000001,0b01010100,0b11111111};
// Unterspannungsdetektor auf = 4,3 V, EEPROM-Speicher behalten, RESET deaktivieren
// Taktfrequenz = 16 MHz mit 64-MHz-PLL, kürzeste Hochlaufzeit
volatile uint8_t vu,vi; // Messwert für Spannung bzw. Strom
// vu = U*256/Teiler/Uref
// vi = I*256*Rshunt/Uref
// vp = U*I * Rshunt/Teiler * (256/Uref)²
// GCC-Fehler: Register gehen nicht korrekt, da diese vor dem Sleep-Befehl geladen werden.
#define VU (uint8_t)(UZ*256/640/1.1) // Z-Schwelle als Messwert (181)
#define VP (uint16_t)(PMAX/640*65536/1.1/1.1) // Leistungsgrenze als Produkt von vu und vi (12694)
#define SL (uint16_t)(SIGLEN*F_CPU/128/13/2) // Startwert für Zykluszähler zur Signalisierung (Monoflop)
#define SD (uint16_t)(STOPDLY*F_CPU/128/13/2) // Startwert für Zykluszähler
ISR(ADC_vect) {
uint8_t v=ADCH;
if (v==0xFF) {
// Wenn die Spannung die Referenzspannung von 1,1 Volt erreicht (egal ob Spannungss- oder Strommessung)
PORTB|=0b00001000; // Thyristor durchzünden
sleep_cpu(); // Mikrocontroller stoppen (bei gesperrten Interrupts bleibt sleep hängen)
}
if (ADMUX&1) { // die LAUFENDE Messung misst ADC1?
ADMUX=0b10100010;
vu=v; // Das VORHERGEHENDE Ergebnis kommt von ADC2: Spannung
}else{
ADMUX=0b10100001;
vi=v; // Das VORHERGEHENDE Ergebnis kommt von ADC1: Strom
}
}
int main() {
MCUCR= 0b00100000; // Sleep aktivieren
PRR = 0b00000110; // Timer0 und USI wird nicht gebraucht
sei();
// Ports initialisieren
PORTB= 0b00100001;
DDRB = 0b00101011;
// D/A-Wandler (PWM-Generator) starten
PLLCSR=0b00000111; // PCKE setzen
OCR1C=255;
TCCR1= 0b01100001; // Schnelle PWM an OC1A mit f = 64MHz/256 = 250 kHz
// A/D-Wandler im Dauerlauf starten, misst Spannung und Strom im Wechsel mit 8 Bit Auflösung
ADMUX= 0b10100001; // Wert links ausgerichtet
ADCSRA=0b11111111; // Teiler 128 -> Wandlerfrequenz (2 Kanäle) = 16 MHz/128/13/2 = 4,8 kHz
ADMUX= 0b10100010; // nächste Wandlung vorbereiten
// Hauptschleife
uint16_t sl=0,sd=0;
for(;;) {
sleep_cpu();
sleep_cpu(); // 2 Wandlungsvorgänge abwarten: 4,8 kHz bzw. 208 µs
// Innerhalb von 208µs * 255 = 53 ms ist (theoretisch) die Gatespannung von 0 bis 5 V durchgelaufen.
// Der wirksame Stellbereich wird wohl eher ΔU = 2 V sein, somit ~ 20 ms oder 1 Netzperiode.
// Die Fage ist nur, ob die SOA-Kriterien im Fall von Überschwingen eingehalten werden.
// Die Pulsweite wird hier ständig moduliert.
uint8_t _vu=vu;
uint8_t _vi=vi;
char dir=0;
if (_vu<VU) { // Unterspannung
if (!_vi) dir=1; // ein bisschen Strom fließen lassen um an die Gate-Schwelle zu gehen
else dir=-1; // sonst Gatespannung reduzieren
if (sl && !--sl) PORTB|=0x01; // Melder verzögert abschalten
PORTB|=0x20; // Keine Notabschaltung (mehr)
sd=SD; // Notabschaltverzögerung neu starten
}else{ // Überspannung!
uint16_t vp=_vu*_vi; // einfache Multiplikation (ob der Compiler das merkt? Nein, er nimmt eine 16x16-Routine)
if (vp<VP) dir=1; // Gatespannung erhöhen
else dir=-1; // Gatespannung herabsetzen
PORTB&=~0x01; // melden
sl=SL;
if (sd && !--sd) PORTB&=~0x20; // nach StopDelay Notabschaltung aktivieren
}
int t=OCR1A; // D/A-Ausgabewert modifizieren ohne Überläufe zu riskieren
t+=dir;
if (t<0) t=0;
if (t>255) t=255;
OCR1A=t;
}
return 0;
}
Detected encoding: UTF-8 | 0
|