Eine leistungsfähige Stromversorgung für den Bastelkeller ist so ziemlich das wichtigste neben einem Lötkolben.
Solche Netzteile bekommt man am Markt für 20-2000 Euro. Mit und ohne Strombegrenzer, einstellbarer Spannung, ein oder zwei Ausgängen usw usw. Man sollte sich allerdings einmal Gedanken machen was man wirklich davon benötigt. In meinem Fall sind es zumeist 3.3 Volt oder 5 Volt für die Mikrokontrollerschaltungen. In Ausnahmefällen mal mehr um einen Motor anzusteuern oder ähnliches. Aktuell behelfe ich mir da zumeist mit regelbaren Spannungswandlern und einem 12 Volt Steckernetzteil.
Beim stöbern im Netz fand ich einige Projekte welche ATX-Netzteile von Computern nutzten. Ganz besonders interessant war das von hackmeister.dk.
Da musste ein Nachbau her 🙂
Die Komponenten
Das fertige Netzteil bietet drei feste Spannungswerte von 3.3V, 5V und 12V welche über Schraubklemmen (oder wie die heissen) ausgeführt sind.
An jedem Ausgang befindet sich ein ACS711EX Stromsensor (Messbereich -15,5 bis +15,5 Ampere) welche die Belastungen der Ausgänge messen. Diese Messwerte werden von einem Arduino Pro Mini ausgelesene und auf dem LCD-Display ausgegeben.
Zusätzlich besitzt das ganze eine Status LED mit zwei Farben (Rot / Grün) und einen Kippschalter zum ein und ausschalten.
Das Gehäuse
Das Gehäuse wurde nach den Plänen von der o.G. Seite mit einem 40 Watt Lasercutter aus 4mm Sperrholz geschnitten. Es ist so ausgelegt, das es nur auf ein ATX Netzteil aufgesteckt wird.

Funktion
Das Netzteil nutzt 3 Spannungen der ATX-PSU (3,3 V, 5 V und 12 V). Zusätzlich haben ATX Netzteile noch einen separaten 5 Volt Spannungsausgang der, im Gegensatz zu den anderen Ausgängen nicht geschaltet wird. Das bedeutet diese 5 Volt stehen auch bei ausgeschalteten Netzteil zur Verfügung. Dieser Ausgang befeuert sowohl den Arduino als auch das Display.
Damit ist es möglich, das der Arduino auch bei ausgeschalteten ATX-Netzteil weiterarbeitet. Der AN/AUS-Kippschalter z.B. schaltet nicht etwa den Arduino stromlos, sondern wird aktiv vom laufenden Programm abgefragt. Wird dieser in die richtige Posotion gebracht startet der Bootvorgang.
In dieser Bootvorgang wird aktuell nichts anderes gemacht als die Stromsensoren zu kalibrieren. Danach befindet sich das Netzteil im Normalmodus.
Die Stromsensoren messen alle paar Millisekunden den Strom aller drei Ausgänge. Diese Messungen werden auf dem LCD-Display angezeigt.
Da der Arduino und das Display also dauerhaft mit Strom versorgt sind, ist es nun möglich die primären Ausgänge zu schalten ohne das die ganze Regelung abgeschaltet wird. ATX Netzteile besitzen nämlich eine separate Schaltleitung um das ganze Netzteil an- und abzuschalten. Wird diese Leitung auf GND gelegt startet das Netzteil (Lüfter läuft an) und die Spannungen auf den „Nutzleitungen“ liegen an. Der Arduino ist also in der Lage das Netzteil zu schalten ohne sich selber den Saft abzudrehen.
Dieses Verhalten ist extrem nützlich um zusammen mit den Stromsensoren eine Sicherheitsprogrammierung vorzunehmen. Man kann nun für jeden der 3 Ausgänge eine maximale Stromlast vorgeben welche bei überschreiten das Netzteil abschaltet und auf dem Display (und mit der LED) einen Fehlerzustand anzeigt.
Der Code
Der aktuelle Arduino Code ist derzeit recht übersichtlich, alpha und ohne Gewähr für eventuelle Schäden die bei seiner Verwendung entstehen könnten 🙂
PSU.ino
Dieser Code beinhaltet die Hauptlogik des Ganzen.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 |
#include <Wire.h> #include <LiquidCrystal_I2C.h> LiquidCrystal_I2C lcd(0x27,16,2); // set the LCD address to 0x27 for a 16 chars and 2 line display #define PSU_OFF 0 #define PSU_BOOT 1 #define PSU_ONLINE 2 #define PSU_CUR_FAIL 10 #define PSU_CUR_FAIL_WAIT 11 int switch1pin = 2; int ledGreenPin = 5; int ledRedPin = 6; int psuPin = 8; int current3Pin = A0; int current5Pin = A1; int current12Pin = A2; int cur3Zero = 0; int cur5Zero = 0; int cur12Zero = 0; double cur3OldVal = 999; double cur5OldVal = 999; double cur12OldVal = 999; void setup() { lcd.init(); // initialize the lcd lcd.noBacklight(); lcd.clear(); Serial.begin(57600); Serial.println("PSU"); pinMode(ledGreenPin, OUTPUT); pinMode(ledRedPin, OUTPUT); pinMode(switch1pin, INPUT); digitalWrite(switch1pin, HIGH); // Pullup pinMode(psuPin, OUTPUT); digitalWrite(psuPin, HIGH); // PSU OFF ledsOff(); //digitalWrite(led1, HIGH); } int psuState = PSU_OFF; void loop() { int mainSwitchState = !digitalRead(switch1pin); // PSU in OFF state and Swich on if (mainSwitchState && psuState == PSU_OFF) { psuState = PSU_BOOT; ledRedOn(); lcd.backlight(); lcd.setCursor(0, 0); lcd.print(" ATX Bench PSU "); lcd.setCursor(0, 1); lcd.print(" Booting... "); cur3OldVal = 999; cur5OldVal = 999; cur12OldVal = 999; readCurrentZeroValues(); delay(1000); } else if (psuState == PSU_BOOT) { psuState = PSU_ONLINE; lcd.clear(); digitalWrite(psuPin, LOW); lcd.print(" 3.3 5.0 12.0 "); ledsOff(); ledGreenOn(); } else if (psuState == PSU_ONLINE) { Serial.println(currentSensor(analogRead(current5Pin))); double cur3Val = (readCurrentSensor(current3Pin) / 100); double cur5Val = (readCurrentSensor(current5Pin) / 100); double cur12Val = (readCurrentSensor(current12Pin) / 100); // Failsave if ( cur3Val > 5 || cur5Val > 5 || cur12Val > 5) { psuState = PSU_CUR_FAIL; } if (cur3OldVal != cur3Val) { cur3OldVal = cur3Val; lcd.setCursor(1,1); lcd.print(" "); lcd.setCursor(1,1); lcd.print(cur3Val); } if (cur5OldVal != cur5Val) { cur5OldVal = cur5Val; lcd.setCursor(6,1); lcd.print(" "); lcd.setCursor(6,1); lcd.print(cur5Val); } if (cur12OldVal != cur12Val) { cur12OldVal = cur12Val; lcd.setCursor(11,1); lcd.print(" "); lcd.setCursor(11,1); lcd.print(cur12Val); } } else if (psuState == PSU_CUR_FAIL) { psuState = PSU_CUR_FAIL_WAIT; digitalWrite(psuPin, HIGH); ledGreenOff(); ledRedOn(); lcd.clear(); lcd.print("FAIL!"); } else if(psuState == PSU_CUR_FAIL_WAIT) { int cur12Val = analogRead(current12Pin); lcd.setCursor(5,1); currentSensor(cur12Val); } if (!mainSwitchState) { psuState = PSU_OFF; digitalWrite(psuPin, HIGH); ledsOff(); lcd.noBacklight(); lcd.clear(); } } |
current.ino
Hier findet man Hilfsfunktionen zum auslesen der Stromsensoren.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 |
void readCurrentZeroValues() { cur3Zero = analogRead(current3Pin); cur5Zero = analogRead(current5Pin); cur12Zero = analogRead(current12Pin); } /* Stromsensor an Pin "pin" auslesen */ static int readCurrentSensor(int pin) { int value = analogRead(pin); double amp = currentSensor(value); if (amp < 0) { amp = 0.00; } int ampInt = amp/100; return ampInt; } static double currentSensor(int RawADC) { int Sensitivity = 90; // mV/A long InternalVcc = readVcc(); double ZeroCurrentVcc = InternalVcc / 2; double SensedVoltage = (RawADC * InternalVcc) / 1024; double Difference = SensedVoltage - ZeroCurrentVcc; double SensedCurrent = Difference / Sensitivity; return SensedCurrent; } // reads vcc in mV static long readVcc() { long result; // Read 1.1V reference against AVcc ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1); delay(2); // Wait for Vref to settle ADCSRA |= _BV(ADSC); // Convert while (bit_is_set(ADCSRA,ADSC)); result = ADCL; result |= ADCH<<8; result = 1126400L / result; // Back-calculate AVcc in mV return result; } |
leds.ino
Hier sind Hilfsfunktionen zum ansteuern der LEDs untergebracht.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
/* Dual-LED abschalten */ void ledsOff() { ledGreen(0); ledRed(0); } /* Grüne Dual-LED auf wert "value" setzen */ void ledGreen(int value) { analogWrite(ledGreenPin ,value); } /* Grüne Dual-LED anschalten */ void ledGreenOn() { ledGreen(255); } /* Grüne Dual-LED abschalten */ void ledGreenOff() { ledGreen(0); } /* Rote Dual-LED auf wert "value" setzen */ void ledRed(int value) { analogWrite(ledRedPin ,value); } /* Rote Dual-LED anschalten */ void ledRedOn() { ledRed(255); } /* Rote Dual-LED abschalten */ void ledRedOff() { ledRed(0); } |
Hallo,
schönes Projekt! Gibt es das Holzcover zufällig irgendwo zu kaufen?
Viele Grüße,
Manuel
Hi,
hm, wuesste ich nicht. Habe es in Hannover bei einem Makerspace per Lasercutter machen lassen. Ich glaube es gibt Firmen im Netz die sowas als Auftragsarbeit machen – dann auch aus Alu oder Kuststoff.