Ladungsmessgerät

#438957
Lesenswert?

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.
#438960
Lesenswert?

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
}
#440008
Lesenswert?

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.
Gast #440221
Lesenswert?

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.
#443498
Lesenswert?

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.
#468946
Lesenswert?

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
#469234
Lesenswert?

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
Gast #469627
Lesenswert?

>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.
#469655
Lesenswert?

>>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
#469949
Lesenswert?

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
Gast #1030967
Lesenswert?

...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.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren