In meiner Bastelkiste liegen viele Dioden herum. Neue unbenutzte, schon einmal in einem Projekt benutzt, ausgelötet, … Aber funktionieren die noch? Mit einem Allround-Bauteile-Tester wie diesem
kann man die wunderbar durchchecken. Bei einzelnen Dioden ist das auch recht praktisch. Wenn man jedoch viele hintereinander testen will, ist das eine sehr aufwändige Beschäftigung. Diode einspannen, Knopf drücken, Selbsttest und Splash-Screen abwarten, Test abwarten, Diode wieder ausspannen ...
Wenn man weiß, dass es sich um eine Diode handelt, geht es mit einem Arduino, einem Widerstand deutlich einfacher.
Inhaltsverzeichnis
Schritt 1: Kurschluss erkennen
Schritt 2: Diode in Durchlassrichtung erkennen
Schritt 3: Keine oder durchgebrannte Diode erkennen
Was soll der Tester können? Er muss erkennen, ob das Bauteil in der einer Polungsrichtung sperrt und in der anderen leitet. Das muss angezeigt werden. Am häufigsten werden Silizium-Dioden vorkommen. Die haben eine Durchlassspannung UF von etwa 0,7 V. Hat das Bauteil einen anderen Wert, soll das signalisiert werden. Dann kann man das Bauteil mit dem Allround-Tester noch einmal nachprüfen. Nach Möglichkeit soll auch eine Schottky-Diode erkannt werden. Die haben ein UF von 0,4 V oder darunter.
Ganz wichtig: Man muss nicht auf die Polung der Diode achten müssen. Einfach das Bauteil an zwei Messkontakte halten, soll genügen.
Zwei Pins schalten die Diode in Serie mit einem Widerstand abwechselnd in Sperr- und Durchlassrichtung. Die Spannung werden über drei ADC-Kanäle ausgewertet. Folgende Möglichkeiten müssen berücksichtigt werden:
Die letzten beide Möglichkeiten lassen sich nicht unterscheiden.
Damit ergibt sich folgende Situation für die Polung der Pins:
Da auch Standard-Si-Dioden (UF = 0,7 V) von anderen Dioden unterschieden werden sollen, reicht leider nicht, nur U2 zu messen. Die Ausgangsstufen der Pins besitzen Innenwiderstände, an denen Spannungen von mehreren 100 mV abfallen können.
Die Schaltung ist extrem einfach. Beim AVR können auch die Spannungen, die an den Pins anliegen, gemessen werden, wenn die Pins im Output-Modus geschaltet sind. Man benötigt also keine weiteren Pins. Die obige Abbildung zeigt damit die vollständige Schaltung. Ein Widerstand zwischen Pin A0 (= ADC1 in der Grafik) und A1 (= ADC2) und zwei Kontakte an A1 und A2 (= ADC3). Über die Software können auch andere ADC-Pins eingestellt werden.
Zur Anzeige dienen zwei LEDs, die eingebaute LED (LED_BUILTIN an Pin 13) und die LED an TX der seriellen Schnittstelle.
Insgesamt wird also nur ein zusätzliches Bauteil, ein Widerstand als Vorwiderstand benötigt. Es wurde ein Widerstand von 470Ω gewählt. Damit fließen durch die Diode etwa 10 mA.
Situation | Anzeige |
---|---|
Keine Diode angeschlossen oder defekt (durchgebrannt) | Beide LEDs aus |
Diode defekt, Kurzschluss | Beide LEDs an |
Si-Diode (UF = 0,7 V) | Beide LEDs blinken synchron |
Andere Diode (UF ≠ 0,7 V) | Beide LEDs blinken abwechselnd |
So sieht es auf dem Steckbrett aus:
Gleichgültig welche Situation vorliegt, ist bei einem Kurzschluss U2 immer gleich U3.
Der blaue markierte Bereich ist erledigt und damit bereits ausgeschlossen. |
Wenn U2 kleiner als U1 ist, liegt eine in Durchlassrichtung geschaltete Diode vor: UF = U2 - U3.
Es bleibt noch zu unterscheiden zwischen keine Diode angeschlossen und Diode in Sperrrichtung.
Dazu müssen die Pins umgeschaltet werden. Wenn eine intakte Diode vorliegt, ist diese nun in Durchlassrichtung geschaltet.
Wenn U2 gleich U1 ist, ist keine oder eine durchgebrannte Diode angeschlossen.
Übrig bleibt nur noch der Fall, dass eine Diode -jetzt in Durchlassrichtung- vorliegt: UF = U3 - U2.
Die Software sollte möglichst übersichtlich werden. Deshalb bietet es sich an möglichst viel in Klassen zu verstecken und im Hauptprogramm nur den Test zu steuern.
Es wird mit Messwerten gearbeitet. Messwerte unterliegen immer einer Streuung. Das macht den Vergleich schwierig. Man löst das Problem, indem man Werte, die sich nicht mehr als um einen Wert ε (Epsilon) unterscheiden, als gleich ansieht. Die Klasse Voltage dient dazu diese Vergleiche durch Operator-Überladung zu kapseln.
// Repräsentiert eine Spannung in der Einheit mV
class Voltage {
public:
uint16_t value;
static const uint16_t epsilon = 50;
Voltage() : value(0) {}
Voltage(const uint16_t value) : value(value) {}
bool operator== (Voltage& rhs) {
if (rhs.value > value + epsilon) return false;
if (value > rhs.value + epsilon) return false;
return true;
}
bool operator<(const Voltage& l) { return value + epsilon < l.value; } // mindestens um epsilon kleiner
bool operator>(const Voltage& l) { return value > l.value + epsilon; } // mindesten um epsilon größer
operator int() const { return value; }
Voltage& operator+=(const Voltage& rhs) { this->value += rhs.value; return *this; }
Voltage& operator-=(const Voltage& rhs) { this->value -= rhs.value; return *this; }
};
inline Voltage operator+(Voltage lhs, const Voltage& rhs) { lhs += rhs; return lhs; }
inline Voltage operator-(Voltage lhs, const Voltage& rhs) { lhs -= rhs; return lhs; }
Somit werden Ausdrücke wie (U2 == U1 + U3) möglich. Der Ausdruck liefert true, wenn U2 sich nicht mehr als ε von der Summe U1+U3 unterscheidet.
Diese Klasse übernimmt die Spannungsmessung per ADC. Die Parameter zur Ansteuerung der Wandler sind als enum class definiert (AdcChannel, AdcReference). Dadurch erreicht man Typsicherheit auch für Enumerationen. Man erkennt also schon zur Kompilierungszeit, wenn man falsche Parameter angegeben hat und muss sich nicht zur Laufzeit wundern, warum es nicht funktioniert.
Die im Programm benutzen Funktionen sind readVcc zur Messung der Versorgungsspannung über die intern bereit gestellte Bandgap-Spannung von 1,1 V. Für die Messung an den Testpunkte ist Vcc die Referenzspannung. Es wird der Mittelwert aus mehreren Messungen gebildet.
uint16_t AdcClass::readVcc() const {
uint8_t i;
uint16_t result = 0;
ADMUX = 0x0E // Bandgap als Input wählen
| (1 << REFS0); // Referenz: AVCC
if (!(ADCSRA = (1 << ADEN))) { // falls ausgeschaltet
ADCSRA = (1 << ADEN) | ADC_PRESCALER_MASK; // ADC einschalten
delay(10);
}
ADCSRA |= ADC_PRESCALER_MASK;
// Dummy-Readout zur Stabilisierung der Bandgap-Spannungsquelle
for (i = 0; i < VccDummyReads; i++)
{
ADCSRA |= (1 << ADSC); // eine ADC-Wandlung
while (ADCSRA & (1 << ADSC)); // auf Abschluss der Konvertierung warten
}
// Eigentliche Messung - Mittelwert aus VccReadCount aufeinanderfolgenden Wandlungen
// Der Messwert liegt zwischen etwa 220 bei 5V und 380 bei 3 V
for (i = 0; i < VccReadCount; i++)
{
ADCSRA |= (1 << ADSC); // eine Wandlung "single conversion"
while (ADCSRA & (1 << ADSC)); // auf Abschluss der Konvertierung warten
result += ADCW; // Ergebnisse aufaddieren
}
uint32_t r = (uint32_t)VccVbg * 1023 * VccReadCount / result;
return r;
}
VccDummyReads (=10), VccReadCount (=4) und VccVbg (=1100) sind als Konstanten hinterlegt (weitere Details im Code).
Bei dem Testgerät lag Vcc bei etwa 4,8 V. Das entspricht der USB-Spannung von 5,0 V abzüglich der Durchlassspannung einer Schottky-Polungsschutz-Diode.
readAvgmv dient zum Auslesen von Spannungswerten. Auch hier wird eine Mittelwertbildung vorgenommen.
Voltage AdcClass::readAvgmv(const AdcChannel channel, uint8_t count) const {
// vcc entspricht einem ADC-Wert von 1023;
uint32_t avg = readAvg(channel, count);
return avg * refVoltage / 1023;
}
uint16_t AdcClass::readAvg(const AdcChannel channel, uint8_t count) const {
uint8_t i;
uint16_t result = 0;
if (count > 63) count = 63;
if (count == 0) count = 1;
if (!(ADCSRA = (1 << ADEN))) { // falls ausgeschaltet
ADCSRA = (1 << ADEN) | ADC_PRESCALER_MASK; // ADC einschalten
delay(10);
}
ADCSRA |= ADC_PRESCALER_MASK;
// Kanal des Multiplexers wählen
ADMUX = ((uint8_t)analogReference << REFS0) | (uint8_t)channel;
// Den ADC initialisieren und eine Blind-Messung machen
ADCSRA |= (1 << ADSC);
while (ADCSRA & (1 << ADSC));
// Jetzt 'AdcAvgCount' mal die analoge Spannung and Kanal 'channel' auslesen
// und dann Durchschnittswert ausrechnen.
for (i = 0; i < count; i++)
{ // Eine Wandlung
ADCSRA |= (1 << ADSC);
// Auf Ergebnis warten...
while (ADCSRA & (1 << ADSC));
result += ADCW;
}
// Mittelwert zurückliefern
return result / count;
}
Alle relevanten Parameter sind als Konstanten hinterlegt:
const uint8_t pin1 = A0;
const AdcChannel channel1 = AdcChannel::ADC0; // Pin A0
const AdcChannel channel2 = AdcChannel::ADC1; // Pin A1
const uint8_t pin3 = A2;
const AdcChannel channel3 = AdcChannel::ADC2; // Pin A2
const uint8_t ledTx = 1; // TX-Pin
const uint8_t ledBi = LED_BUILTIN; // eingebaute LED
bool toggle = false; // zum Blinken
Voltage USi(700); // Durchlassspannung Si-Diode
In setup müssen nur die Pins konfiguriert werden:
void setup() {
pinMode(pin1, OUTPUT);
pinMode(pin3, OUTPUT);
pinMode(ledBi, OUTPUT);
pinMode(ledTx, OUTPUT);
}
In test werden die Spannungswerte ermittelt und ausgewertet.
// Führt den Test durch. Liefert:
// -1: Keine Diode
// -2: Kurzschluss
// >0: UF
int test() {
uint16_t vcc = Adc.readVcc();
Adc.setReference(AdcReference::Vcc, vcc);
// Schritt 1:
digitalWrite(pin1, HIGH);
digitalWrite(pin3, LOW);
auto U2 = Adc.readAvgmv(channel2, 16);
auto U3 = Adc.readAvgmv(channel3, 16);
if (U2 == U3) { // Kurzschluss
return -2;
}
// Schritt 2:
auto U1 = Adc.readAvgmv(channel1, 16);
if (U2 < U1) { // leitende Diode
return U2 - U3;
}
// Schritt 3:
// Jetzt kann noch sperrende oder keine Diode angeschlossen sein
// Polung umkehren
digitalWrite(pin1, LOW);
digitalWrite(pin3, HIGH);
U1 = Adc.readAvgmv(channel1, 16);
U2 = Adc.readAvgmv(channel2, 16);
U3 = Adc.readAvgmv(channel3, 16);
if (U2 == U1) {
return -1;
}
// Schritt 4:
return U3 - U2;
}
Es bleibt nur noch übrig, die LEDs zur Anzeige des Ergebnisses zu schalten:
void loop() {
delay(200); // Bestimmt die Blink-Frequenz
toggle = !toggle;
int result = test();
if (result == -2) { // Kurzschluss, beide LEDs an
digitalWrite(ledBi, HIGH);
digitalWrite(ledTx, LOW);
return;
}
if (result == -1) { // Keine Diode, beide LEDs aus
digitalWrite(ledBi, LOW);
digitalWrite(ledTx, HIGH);
return;
}
auto UF = Voltage(result); // Umwandeln in Spannung zum Vergleichen
if (UF == USi) { // Si-Diode, LEDs blinken synchron
digitalWrite(ledBi, toggle); // LED gegen Masse
digitalWrite(ledTx, !toggle); // LED gegen Vcc
}
else { // andere Diode, LEDs blinken abwechselnd
digitalWrite(ledBi, toggle); // LED gegen Masse
digitalWrite(ledTx, toggle); // LED gegen Vcc
}
}
Das Visual-Micro-Projekt zum Download. Arduino-IDE-Nutzer benutzen einfach nur die Dateien im Verzeichnis DiodenTester.