Bremsflüssigkeitstester

Bremsfluessigkeitstester1Neulich hatte ich mal so einen Bremsflüssigkeitstester in Stiftform in der Hand. Als alter Auto-Selberschrauber und Werkzeug-Fetischist dachte ich mir gleich, sowas will ich auch haben. Aber weil das Teil so simpel ist, wollte ich es dann gleich mal selber bauen. Es besteht nur aus einem kleinen Mikrocontroller, der an zwei Elektroden den Widerstand und damit den Wasseranteil in der Bremsflüssigkeit bestimmt. Das sollte doch kein Problem sein.

Um die geeichten Warnschwellen für die Signalisierungen grün/orange/rot nicht neu zu erfinden, habe ich diese an dem Tester eines namhaften Herstellers ausgemessen. Dazu habe ich mit einem Drehpotenziometer an den Elektroden durch Erhöhung und Erniedrigung des Widerstandes und mehrfaches Rumprobieren die Werte ermittelt, bei denen die LEDs umschalten. Also knallhartes Reverse Engineering 😉

Wasseranteil Widerstand Spannung ADC-Wert
grün  < 1,5% > 220kΩ > 3,82V > 783
orange  1,5 – 3,0% 43 – 220kΩ 1,94 – 3,82V 398 – 783
rot  > 3,0% < 43kΩ < 1,94V < 398




Diese Widerstandswerte habe ich anschließend für eine 10Bit ADC Messung bei einer (zunächst angenommenen) VCC Referenz von 5V berechnet und daraus die ADC Werte für ein Programm abgeleitet. Die Formeln dazu stehen im Datenblatt des von mir verwendeten ATtiny13A. Der Widerstand wird über einen Spannungsteiler mit 68kOhm Referenzwiderstand gemessen.

Brems_SchaltplanAls Batterie habe ich einen Li-Po 14500 Akku genommen, den man wunderbar mit einer Batteriehalterung einer AA-Zelle verwenden kann. Danach hat sich dann auch maßgeblich das PCB Layout gerichtet. Auf der Rückseite der Leiterplatte dominiert die Batteriehalterung, auf der Vorderseite sind die Bauteile an der Oberfläche verlötet. Das ist zwar stellenweise z.B. am IC Sockel schwierig zu löten, aber so kollidiert es nicht mit dem Akku. Die Messspitze verjüngt sich, sodass man gut in alle Bremsflüssigkeitsbehälter kommen sollte. Wichtig für einen reproduzierbaren Widerstandswert der Flüssigkeit ist es auch, dass die Messspitzen in Fläche und Abstand denen des originalen Messgerätes entsprechen. Dies sind zwei Kreise mit einem Durchmesser von 2,5mm und einem Abstand von 2,5mm. Da ich meine Leiterplatten meistens selber ätze, habe ich die Zuleitungen zu diesen „Testpads“ anstelle von Lötstoplack mit ein bisschen Klarlack isoliert (siehe Foto). Um mit möglichst wenig Bauteilen auszukommen habe ich nicht drei einzelne LEDs verbaut wie beim Original, sonder habe auf eine RGB-LED zurück gegriffen. Dabei entspricht die Farbe Blau dem Orange.

Das Programm ist so gestaltet, dass der ATtiny ständig schläft und durch einen Tasten-Interrupt aufwacht, die Messung ausführt und dann das Ergebnis kurz anzeigt. Dann geht er augenblicklich wieder schlafen und verbraucht währenddessen nur 0,3µA Strom. Tatsächlich werden allerdings 5 Messungen in Folge zu einem Durchschnittsergebnis verrechnet, um einen genaueren Messwert zu erhalten.

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
#define F_CPU 1200000UL	//9,6/8 = 1,2 MHz
#include <stdio.h>
#include <stdlib.h>		//Miscellaneous routines
#include <avr/io.h>		//Includes other I/O-Headers
#include <util/delay.h>
#include <avr/interrupt.h>	//Interrupt handling routines
#include <inttypes.h>		//Defines for different int data types
#include <avr/sleep.h>
 
#define SCHWELLE_1_5 783	//Schwelle für 1,5% Wasseranteil
#define SCHWELLE_3_0 398	//Schwelle für 3,0% Wasseranteil
#define ANZAHL_MESSUNGEN 5	//Anzahl der Messungen für Durchschnittswert
#define AD_KANAL 3		//Kanal für AD Wandlung
#define LEUCHTEN 2000	//Leuchtdauer für LED in ms
 
 
void led(unsigned char farbe, uint16_t zeit) 
{	
	if (farbe == 'R')
	{
		PORTB &= ~(1<<PB3);	// low
		for (zeit=zeit/10; zeit>0; zeit--) _delay_ms(10);
		PORTB |= (1<<PB3);	// high
	}
	else if (farbe == 'G')
	{
		PORTB &= ~(1<<PB2);	// low
		for (zeit=zeit/10; zeit>0; zeit--) _delay_ms(10);
		PORTB |= (1<<PB2);	// high
	}
	else if (farbe == 'B')
	{
		PORTB &= ~(1<<PB1);	// low
		for (zeit=zeit/10; zeit>0; zeit--) _delay_ms(10);
		PORTB |= (1<<PB1);	// high
	}
}
 
 
uint16_t adc(uint8_t pin)
{
	uint32_t ADC_Summe = 0;
	uint8_t i = 0;
 
	ADCSRA |= (1<<ADEN);	//ADC aktivieren
	ADMUX = (ADMUX & ~(0x1F)) | (pin & 0x1F);	//Pin wählen
 
	ADCSRA |= (1<<ADSC);	//Dummy-Messung starten
	while (ADCSRA & (1<<ADSC)) ;	//auf Abschluss der Messung warten
	(void)ADCW;		//Ergebnis verwerfen
 
	while(i < ANZAHL_MESSUNGEN+1) {
		ADCSRA |= (1<<ADSC);	//Messung starten
		while (ADCSRA & (1<<ADSC)) ;	//auf Abschluss der Messung warten
		ADC_Summe += ADCW;	//Ergebnis aufsummieren
		i++;
	}
 
	ADCSRA &= (0<<ADEN);	//ADC deaktivieren
	return (ADC_Summe/ANZAHL_MESSUNGEN);	//Ergebnis zurückgeben
}
 
 
int main(void)
{
	       //543210
	DDRB  = 0b001110;       //Ausgang=1, Eingang=0
	PORTB = 0b001111;       //preset Ausgänge / pullup Eingänge (unbenutzt: pullup ein!)
 
	//PCINT0 einstellen
	GIMSK |= (1<<PCIE);		//PCINT enable
	PCMSK |= (1<<PCINT0);	//PCINT Maske
 
	//ADC einstellen
	ADMUX &= ~(1<<REFS0);	//AVCC als Referenz (0=AVCC, 1=1.1V)
	ADCSRA |= (1<<ADPS1) | (1<<ADPS0);	//ADC prescaler auf 8 (ADclk mit 150khz)
 
	sei();		//enable global Interrupts
 
    while(1)
    {
		set_sleep_mode(SLEEP_MODE_PWR_DOWN);	// Schlafmodus wählen
		sleep_mode();			// schlafen schicken
 
		// <-- hier wird wieder aufgewacht
 
	}
 
    return 0;
}
 
 
ISR(PCINT0_vect)
{
	if (!(PINB & (1<<PB0)))	//wenn fallende Flanke
	{
		//Output Test
		led('R', 100);
		led('G', 100);
		led('B', 100);
		_delay_ms(100);
 
		//Messung starten
		uint16_t messung = adc(AD_KANAL);
 
		//Messung auswerten
		if (messung >= SCHWELLE_1_5)
		{
			led('G', LEUCHTEN);
		}
		else if ((messung < SCHWELLE_1_5) && (messung > SCHWELLE_3_0))
		{
			led('B', LEUCHTEN);
		} 
		else if (messung <= SCHWELLE_3_0)
		{
			led('R', LEUCHTEN);
		}
 
		//PCI Flag loeschen
		GIFR |= (1<<PCIF);
	}
}

Download Programmcode und PCB Layout



Haftungsausschluss: Ich übernehme keinerlei Verantwortung für auftretende Schäden oder Folgeschäden bei der Anwendung und Nutzung meiner Anleitungen. Alle Angaben sind ohne Gewähr. Außerdem obliegt jedem Leser die Prüfung der rechtlichen Zulassung in seinem Land, das gilt insbesondere für TÜV-Freigaben von baulichen Veränderungen an Fahrzeugen und Einbau von Zubehör. Meine Artikel sind nichts weiter als eine Art Machbarkeitsstudie zu verstehen. Jeder Leser hat vorher selbst die Durchführbarkeit zu überprüfen.



Noch keine Kommentare

Schreibe einen Kommentar