Zum Messen von Batterien und Akkus (laden oder entladen) Anlass war, dass Aldi plötzlich neue Mignonzellen hat. Ich wollte wissen ob die für das Geld die gleiche Kapazität bieten. Ein Messgerät in der Art konnte ich nicht finden. Da ich gerade angefangen habe AVR in C zu programmieren (nachdem die Leuchtdiode geblinkt hat), bot sich das Projekt geradezu an. Funktion: Bildet ein Integral über den gemessenen Strom. Zeigt das Ergebnis in mAh an. Ausserdem die Zeit und den aktuellen Strom. Anzeige über RS232 möglich Man kann z.B. einen Akku über eine Last entladen und den Strom mit diesem gerät messen. Hinterher weiss man wieviel drin war. Der Spannungsabfall ist so gering (z.B. 20mV bei 200mA), dass vermutlich auch Akkuladegeräte fast korrekt funktionieren und man somit auch Ladungen beim Aufladen messen kann Hardware: Das Gerät besitzt ledigleich 2 Anschlüssen. Zwischen beiden ist ein Widerstand von 0,1 Ohm. Der Spannungsabfall wird verstärkt und mit einem Mega8 gemessen. Software: Ich habe es mit dem AVR-Studio in GCC geschrieben (kein Makefile) Ich verwende einen Takt von 9,6MHz (ist Zufall den hatte ich gerade da). Achtung: Externer Takt -> Fuse Bits entsprechedn setzen Das Hauptprogramm macht eigentlich nichts. Timer 1 löst jede Sekunde einen Interrupt aus. Der Strom wird gemessen bis (1024 mA) Man könnte auch andere Faktoren einstellen ("strom = adWert * Faktor;") Den Strom gebe ich zudem als ASCII auf die serielle Schnittstelle. Dann wird der Wert je Sekunde aufaddiert und durch 3600 geteilt. Das Ergebnis sind die mAh. Der LCD Treiber stammt von Peter Fleury. Probleme: sehr kleine Ströme (unter 20mA) werden nicht korrekt gemessen, da der OP in diesem Bereich nicht linear arbeitet. Nachdem ich ihm eine negative Versorgungsspannung spendiert hatte, wurde es kaum besser. Ein CA3140 brauchte auch kein besseres Ergebnis. Ausserdem habe ich noch 2 Schaltungen getestet die im Forum empfohlen wurden. Aber keine hatte eine 100% ige Linearität. So dass ich beschlossen habe mit einer geringen Abweichung (bis zu 3mA) zu leben. Die Platine habe ich mit Eagle gezeichnet. Leider musste ich nachträglich am Layout einiges ändern, weil ich Fehler im Schaltplan hatte. Die Fehler habe ich Layout nicht mehr korrigiert. Deshalb nur der Schaltplan. ************************ Das Hauptprogramm habe ich mal angehängt Alle Files habe ich auch auf meine HP gestellt: http://www.stegem.de/Ladungsmesser/ Ich wäre dankbar für viele Verbesserungsvorschläge, weil ich an dem Projekt ja lernen will.
Hier das Hauptprogramm direkt als Text (lässt sicht nicht anhängen) ************
1 | #include <avr/io.h> |
2 | #include <avr/interrupt.h> |
3 | #include <stdlib.h> |
4 | #include <stdint.h> |
5 | #include <Stdio.h> |
6 | #include "BinaryNr.h" |
7 | |
8 | #define F_CPU 9600000 /* Quart 6,6 Mhz */ |
9 | #define UART_BAUD_RATE 9600 /* 9600 baud */ |
10 | #define UART_BAUD_SELECT (F_CPU/(UART_BAUD_RATE*16l)-1)
|
11 | #define Prescaler 1024;
|
12 | #define startwert 65537 - F_CPU/Prescaler; //Zähler Startwert, Überlauf bei 65536
|
13 | |
14 | #include "uart_routinen.c" |
15 | #include "lcd.h" |
16 | #include "lcd.c" |
17 | #include "sonst_routinen.c" |
18 | |
19 | #define u8 unsigned char
|
20 | #define u16 unsigned int
|
21 | |
22 | //Variablen
|
23 | u8 y; |
24 | u8 sekundenH=0; |
25 | u8 minutenH=0; |
26 | u8 stunden=0; |
27 | u8 sekundenL=0; |
28 | u8 minutenL=0; |
29 | |
30 | char s[4]; //hilfsvariablen |
31 | char z[4]; |
32 | |
33 | |
34 | u16 adWert; // AD-Wert |
35 | u16 strom; // Strom |
36 | u16 summe; // Strom aussummieren |
37 | u16 mah; // Umgerechnet |
38 | |
39 | |
40 | |
41 | /* Unterprogramme */
|
42 | /* INIT */
|
43 | |
44 | void port_init(void){ // initialize ports |
45 | DDRC = 0x20; // PORTA als Eingang BIT5 (LED) Ausgang |
46 | }
|
47 | |
48 | void timer_init(void){ // timer 0 overflow |
49 | TCCR1B = B00000101; // Prescaler auf 1024 stellen |
50 | TIMSK |= (1 << TOIE1); // Timer 1 Overflow Interrupt enable |
51 | TCNT1 = startwert; // vorbesetzen (zählt bis FFFF) |
52 | }
|
53 | |
54 | void ad_init(void){ // initialize ad-wandler |
55 | ADMUX = 0x00; // Kanal0 |
56 | ADMUX |= (1<<REFS1) | (1<<REFS0); //interne Referenzspannung 2,5V nutzen |
57 | ADCSR=B11000111; // enable ADC |
58 | }
|
59 | |
60 | //lese ad0 (Strom)
|
61 | int leseAD(void) |
62 | {
|
63 | uint16_t wert; |
64 | uint8_t highwert; |
65 | ADCSR |= (1<<ADSC); // eine Wandlung starten |
66 | while ( ADCSR & (1<<ADSC) ) {;} // auf Abschluss der Konvertierung warten |
67 | wert = ADCL; // Low auslesen |
68 | highwert = ADCH; // High auslesen |
69 | wert = wert + highwert*256;// |
70 | return wert; |
71 | }
|
72 | |
73 | |
74 | //Interrupt wenn Zeichen per uart empfangen (wird hier nicht gebraucht)
|
75 | ISR(SIG_UART_RECV) |
76 | {
|
77 | y = UDR; // lese byte aus UART |
78 | }
|
79 | |
80 | //Anzeige der Ladung auf LCD
|
81 | void zeige_Ladung(u16 mah){ |
82 | itoa(mah,s,10); // wert in ACSII |
83 | lcd_puts("Ladung: "); |
84 | lcd_puts(s); |
85 | lcd_puts(" mAh "); |
86 | }
|
87 | |
88 | //Anzeige der Zeit auf LCD
|
89 | void zeige_Zeit(void){ //hh,mm,ss berechnen |
90 | sekundenL++; // Sekunden zählen |
91 | if(sekundenL==10){ |
92 | sekundenH++;sekundenL=0;} |
93 | if(sekundenH==6){ |
94 | minutenL++;sekundenH=0;} |
95 | if(minutenL==10){ |
96 | minutenH++;minutenL=0;} |
97 | if(minutenH==6){ |
98 | stunden++;minutenH=0;} |
99 | // auf LCD ausgeben
|
100 | itoa(stunden,s,10);lcd_puts(s);lcd_puts(":"); |
101 | itoa(minutenH,s,10);lcd_puts(s); |
102 | itoa(minutenL,s,10);lcd_puts(s);lcd_puts(":"); |
103 | itoa(sekundenH,s,10);lcd_puts(s); |
104 | itoa(sekundenL,s,10);lcd_puts(s); |
105 | }
|
106 | |
107 | //Anzeige aktueller Strom auf LCD
|
108 | void zeige_Strom(u16 strom){ |
109 | itoa(strom,s,10); |
110 | lcd_puts(s); |
111 | lcd_puts(" mA"); |
112 | }
|
113 | |
114 | |
115 | //Timer Interrupt - genau jede Sekunde
|
116 | SIGNAL (TIMER1_OVF_vect) // Timer1 overflow |
117 | {
|
118 | cli(); |
119 | TCNT1 = startwert; // Vorbesetzen (1s) |
120 | |
121 | adWert=leseAD(); // lese Spannungswert |
122 | strom = adWert; // 1024 = 1024mA (1 zu 1) |
123 | |
124 | itoa(strom,s,10); // wert in ACSII |
125 | uart_puts(s); // auf uart ausgeben |
126 | uart_puts(" "); // auf uart ausgeben |
127 | |
128 | summe = summe + strom; // Strom aussummieren |
129 | |
130 | if (summe >= 3600){ // in mAh umrechnen |
131 | mah++; // wenn 1mAh voll +1 |
132 | summe = summe % 3600; // Rest weiterzählen |
133 | }
|
134 | |
135 | |
136 | lcd_clrscr(); // 1.Zeile |
137 | zeige_Ladung(mah); // Ladung anzeigen |
138 | |
139 | lcd_gotoxy(0,1); // 2. Zeile |
140 | zeige_Zeit(); // Zeit anzeigen |
141 | |
142 | lcd_gotoxy(10,1); // 2. Zeile Stelle 10 |
143 | zeige_Strom(strom); // aktuellen Strom anzeigen |
144 | |
145 | sei(); // enable interrupts |
146 | }
|
147 | |
148 | |
149 | |
150 | /*********************/
|
151 | int main() |
152 | {
|
153 | port_init(); // alles initialisieren |
154 | uart_init(); |
155 | ad_init(); |
156 | timer_init(); |
157 | sei(); // enable interrupts |
158 | lcd_init(LCD_DISP_ON);// initialisiere display, cursor off |
159 | for(;;){} // tut nix, Endlosschleife |
160 | }
|
Nachdem das Gerät nun 2 Tage gelaufen ist, erste Ergebnisse. Alle Alkaline Batterien haben ähnliche Werte (Mignon um die 2Ah), also kann man auch billige kaufen (Aldi und Lidl sind gleich) Die Anschaffung des Gerätes zu diesem Zweck ist uninteressant. Ich habe eine Mignonzelle mit meinem Reflexlader aufgeladen. Der hier: http://www.klaus-leidinger.de/mp/RC-Elektronik/Reflexlader/Reflexlader_m.html Durch den Messtakt von 1s ergaben sich anfangs große Abweichungen, da der Reflexlader wohl nur Ladeimpulse schickt und dann wieder misst. Bei längerer Laufzeit, hat man aber korrekte Werte, der Fehler gleicht sich aus. Am Ende ergab sich eine Abweichung der Kapazität von 10%. Ich vermute aber eher dass der Reflexlader nicht richtig abgeglichen ist. Muss mal reingucken. Gestört hat der Spannungsabfall den Reflexlader nicht.
Hallo, vielleicht kommt deine Abweichung hier her.
1 | //lese ad0 (Strom)
|
2 | int leseAD(void) |
3 | {
|
4 | uint16_t wert; |
5 | uint8_t highwert; |
6 | ADCSR |= (1<<ADSC); // eine Wandlung starten |
7 | while ( ADCSR & (1<<ADSC) ) {;} // auf Abschluss der Konvertierung warten |
8 | wert = ADCL; // Low auslesen |
9 | highwert = ADCH; // High auslesen |
10 | wert = wert + highwert*256;// |
11 | return wert; |
12 | }
|
Atmel schlaegt zwei Messungen beim ersten mal vor um ein richtigen Wert zuerhalten.
Danke für den Hinweis ich werde auf jeden Fall mal 2 Messungen machen und den Durchschnitt bilden. Inzwischen habe ich mal versucht den Reflexlader abzugleichen, was nicht ganz einfach ist, da er ja ständig kurz entlädt um zu messen. Ich denke meine Schaltung ist genau. Wenn ich 1Stunde genau 1A fliessen lasse stimmt die Anzeige.
moin moin, der LM358 ist für Messaufgaben wegen seines Offsets ( ca. 2mV )schlecht geeignet. Entweder es kommt noch ein Offsetabgleich hinzu oder gleich einen besseren OPV. Bei so etwas verwende ich den LTC1049, Offset <10µV. mfg Pieter
tolles Teil der LTC1049 :-) steht auf meiner Bestellliste drauf. Ich werde ihn aber für genauere Messungen aufheben. Beim Ladungsmessgerät kommt es mir nicht auf Genauigkeit an.
Hallo, ich habe da einen Fehler gefunden: summe = summe + strom; // Strom aussummieren if (summe >= 3600){ // in mAh umrechnen mah++; // wenn 1mAh voll +1 summe = summe % 3600; // Rest weiterzählen } Es muss doch "summe = summe - 3600" sein. Ansonsten egibt es für mich keinen Sinn. Es mag bei dir zwar so funktioniert haben, aber mit einem kleinen Fehler. Ich hoffe ich habe da kein Misst geschrieben. Bin gerade am Überlegen mir einen Akku Tester zu bauen. Da habe ich mir deinen Code angeschaut. MfG
% ist Modulo Division. Das heißt die 3600 fallen weg, der Rest bleibt. Ginge wohl auch mit minus.
Moin, schönes Projekt und als Einstieg gut gelungen! Modulo funktioniert natürlich, aber wenn man mit Resourcen (Flash, Zeit) geizen müsste, würde man Modulo (bzw. allgemein Division) möglichst durch Subtraktion oder Zuweisung "summe=0" ersetzen. Laut Schaltplan kriegt AVCC keine Spannung!?! Gruß Frank
> Laut Schaltplan kriegt AVCC keine Spannung!?!
scheint aber zu funktionieren
Ich habe REFS0 und REFS1 auf 1 gesetzt.
Im Datenblatt steht:
"Internal Voltage Reference (2.56V) with external Capacitor at AREF pin"
Frank N. wrote:
> Ich meine AVCC, nicht AREF ;-)
Sorry
Ich habe gerade nachgemessen AVCC liegt auf +5V. Ich frage mich nur
warum. Ich habe keine Verbindung. Muss irgendwie intern geschaltet sein?
>Atmel schlaegt zwei Messungen beim ersten mal vor um ein richtigen Wert >zuerhalten. Wo steht das? Das betrifft nur das Umschalten der Referenzen, nicht die AD-Wandlung eines einzelnen Kanals (der ja offensichtlich nicht gewechstelt wird). >Ich habe gerade nachgemessen AVCC liegt auf +5V. Ich frage mich nur >warum. Ich habe keine Verbindung. Muss irgendwie intern geschaltet sein? Interessant... Übrigens solltest du laut Datenblatt bei ADC-Benutzung ein LC-Glied an dem Pin haben.
>>Ich habe gerade nachgemessen AVCC liegt auf +5V. Ich frage mich nur >>warum. Ich habe keine Verbindung. Muss irgendwie intern geschaltet sein? > Interessant... > Übrigens solltest du laut Datenblatt bei ADC-Benutzung ein LC-Glied an > dem Pin haben. ja weiss ich. Aber wieso geht es? ich habe jetzt sogar auf der Platine nachmessen keine Verbindung zwischen + und AVCC
Hab hier grad nen ATMega8: VCC und AVCC sind niederohmig (~5ohm) miteinander verbunden und "Diodenprüfung" ergibt Spannungsdifferenz von 0,08V in beide Richtungen. Also nix (parasitäre) Diode oder so. Viel nutzen dürfte das LC-Glied also nicht...
ich habe mir jetzt mal die Werte anzeigen lassen. Ohne AVCC sind die Messungen falsch. Mit Referenz AVCC nimmt er 3,4V statt 5V Mit Int. Ref 2V statt 2,5V Bei meiner Schaltung ist das egal, weil ich sie entsprechend abgeglichen habe. Hab gerade gemerkt, dass in der Schaltung ein Mega8 drin ist. Obige Messung war mit Tiny26
...Hi, nun werd ich mein KapMessgerät auch mal fertig stellen, scheint ja gerade in Mode zu sein. Ist die ISR nicht etwas "voll"?! Sollte man doch für gewöhnlich in eine Unterfkt auslagern, oder? Wofür ist die Diode am Ausgangsspgsteiler des OP? Gruß, Klaus.
Hi Stefan, könntest Du die Ergebnisse Deiner Vergleichsmessung verschiedener Discounter-Batterien mal hier einstellen. cdg
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.