In voorbereidingData Logger/ MiNH Tester

Het probleem: hoe goed is mijn batterij?

Ook een stapeltje oplaadbare batterijen liggen, en afgevraagd welke nog goed zijn (en vooral een lange levensduur hebben)? NiMH batterijen hebben een beperkte levensduur, maar hoe ver zijn ze 'op'? Ik had deze vragen, en vond dit een mooi projectje om de Butterfly voor in te zetten.

Hoe gedraagt een NiMH-batterij zich bij gebruik? Net na het laden komt er een spanning uit van 1.35 tot 1.4 Volt, die vrij snel wegzakt naar de normale werkspanning van ongeveer 1.2 Volt. Dit wordt een tijd volgehouden, waarna de spanning snel wegvalt: de batterij is leeg (zie het grafiekje hieronder). Hoe lang het duurt voor de spanning wegvalt is afhankelijk van de 'capaciteit' van de batterij, en deze neemt af met de leeftijd van de batterij. Op de batterij staat bijvoorbeeld 2500 mAh, dit is de capaciteit bij aankoop, en dit wordt dus minder over de jaren. Hoe snel? Hangt af van de temperatuur, het gebruik, het aantal keren laden, en zo voort.

Ontlading van NiMH batterijen

Wat betekent een capaciteit van 2500 mAh? Het is het product van de stroom en de tijd; de batterij kan dus bijvoorbeeld 1 mA leveren over 2500 uur, of 250 mA gedurende 10 uur, of elke andere combinatie van stroom maal tijd die 2500 oplevert.

Met deze opzet heb ik enkele batterijen (3 sets van 2) doorgemeten (apart, niet per set), allemaal van ongeveer 2500 mAh. In de praktijk bleken er grote verschillen te zijn tussen verschillende sets van batterijen, ook al zullen ze oorspronkelijk vergelijkbaar zijn geweest! Van een set (A1 en A2) zijn beide batterijen al na 10 uur uitgeput, bij de beste set (C1 en C2) duurde dit zo'n 24 uur...

Ontlading bij lege batterijenBij het uitschakelen van de belasting loopt de spanning weer op, en lijken ze weer in orde. Helaas, zodra je er weer iets op aan sluit zakt de spanning weer snel (na zo'n 5 tot 10 minuten, zie grafiekje links) in; ze zijn toch echt leeg. Dat de spanning daarna weer oploopt komt omdat mijn ontlader afschakelt zodra het denkt dat de batterij weer leeg is; de batterijspanning loopt dan alweer op.

Hoe werkt de tester?

Als gebruiker: Je stopt de batterijen er in (1 tot 4 stuks), kiest in het menu de NiMH test, en het programma gaat lopen. Op iedere batterij wordt een belasting aangesloten om hem leeg te trekken (met 100 mA). Elke seconde wordt er van een van de batterijen de spanning gemeten en weergegeven (en elke minuut worden de 4 waardes opgeslagen om later op de PC te kunnen bekijken). Dit gaat door tot een batterij tot op 1 Volt leeg is; op dat moment hoor je een piepje, wordt de belasting uitgeschakeld, en geeft vanaf dat moment op het display voor die batterij aan na hoe lang de ontlading was (uren:minuten).

Stroombron

Hoe krijg je een constante stroom, onafhankelijk van de spanning? Een transistor in een schakeling als schema 1 probeert een constant spanningsverschil VBE tussen basis en emitter te houden, typisch in de orde van 0.4..0.7 Volt (voor silicium-transistoren).

Door nu een constante spanning op de basis te zetten (van zeg 1.3V, de spanningsval over de dubbeldiode D1) zal de transistor de stroom door R1 dusdanig regelen dat de spanning hierover 1.2V - VBE is, hier 1.2V - 0.75V dus 0.45V, onafhankelijk van de voedingsspanning. Een vaste spanning over een weerstand resulteert in een vaste stroom door de transistor -> doel bereikt.

Bij een weerstand van 4.5 Ohm en een spanning van 0.45 Volt resulteert een stroom van 100 mA.

Op zich kan verdere ontlading dan 1 Volt bij een enkele NiMH-cel overigens niet zo veel kwaad. Het probleem van over-ontlading is pas een probleem met meerdere cellen: hier kan de spanning over de meest ontladen cel negatief kan worden, en dit kan de batterij wel echt beschadigen.

Als ontwerper: De basis is een 'data logger' functie in software. Deze meet regelmatig welke spanning uit de afzonderlijke batterijen komt, en slaat dit op om later te bekijken. De data logger bestaat in software uit verschillende delen:

  • een hoofdprogramma (met menu's) die de timing en het starten van metingen regelt; gebouwd op het framework van de Butterfly menu-structuur
  • De meetroutine, die de A/D convertor aanstuurt (kiezen van de te meten batterij en zo) en de waarde teruggeeft
  • de logroutine, die de data-waarden regelmatig wegschrijft naar de seriële flash-chip (en de routine om die gegevens vervolgens op verzoek naar een PC door te sturen, om bijvoorbeeld grafiekjes mee te maken)

Daarnaast is er wat hardware toegevoegd, die de batterijen koppelt aan de Butterfly, en die ook de 100 mA belasting per batterij maakt, met mogelijkheid die vanuit de Butterfly aan en uit te schakelen (zoals gezegd: als de batterij haast leeg is, wil je stoppen met verder ontladen).

De uitleg komt hier in de omgekeerde volgorde: eerst de hardware, dan de simpele routines, dan het hoofdprogramma, en uiteindelijk de resultaten.

De hardware

De extra hardware bestaat (naast de butterfly natuurlijk) uit twee delen; het batterij-meet-circuit en een spanningsreferentie.

Belasting en batterij-houder

Het batterij-meet-circuit

Batterij-belasting met 100 mAHet circuit om de batterijen op te meten bestaat uit:

  • De spanningsmeting: niet meer dan een weerstand R8 en condensator C5 (storingsonderdrukking en bescherming van de Butterfly) van de batterijen naar de A/D converter inputs (PF4-PF7)
  • De belasting met 100 mA: een constante stroombron, aan/uit te schakelen via vrije pinnen op de Butterfly (onderdelen: transistor, een dubbele diode, en twee weerstanden)

De ontlading van de batterij wordt gedaan met een constante stroom van 100 mA (zie kader 'Stroombron'). De spanning over de dubbele diode D1 is via R7 en de pinnen van de processor aan en uit te schakelen, daarmee is de belasting dus te schakelen: als de batterij tot 1 Volt ontladen is wordt door de software de belasting uitgeschakeld om te ver ontladen te voorkomen.

Het hele circuit is vier keer uitgevoerd, om vier batterijen onafhankelijk te meten (zie het plaatje links; een deel van de onderdelen zit als SMD-variant op de onderkant). De batterij-houder had de vier cellen oorspronkelijk in serie staan; ik heb ze losgeknipt om ze per stuk te kunnen ontladen/meten (met een gezamenlijke massa-aansluiting, de extra dik uitgevoerde zwarte draad.

Is dit de ideale schakeling? Niet echt; zie aan het einde van deze pagina voor verdere ideeën...

De referentiespanning

Voltage referenceDe on-board referentie is niet echt bruikbaar (zie de Butterfly pagina); dus ik besloot zelf een referentiespanningsblokje te maken, in een geschikt spanningsbereik (hoger dan de batterijspanning, zodat ik geen spanningsdelers bij de batterij hoef te hebben: de ADC kan geen spanningen meten hoger dan de referentiespanning). Dit heb ik gedaan met wat onderdelen die ik nog had liggen, een wat vreemde keuze hier en daar (zie schema hiernaast)...

Butterfly en spanningsreferentie

De basis is een LED (LED1): brandende LEDs hebben een vrij constante spanning (gedraagt zich ruwweg als een zenerdiode), zo'n 1.8 Volt bij het type rode LED dat ik nog had liggen, hoger bij bijvoorbeeld groen en blauw.

Door een LED met een constante stroom aan te sturen wordt deze spanning nog stabieler, ook bij verschillen in de voedingsspanning. Hiervoor gebruik ik weer een constante stroombron (zie eerder kader), al heb ik hem hier 'gespiegeld' en een PNP-transistor gebruikt, om de LED aan aarde te kunnen leggen. De spanning voor de stroombron komt uit LED2.

Op deze manier heb ik een referentie van 1.8 Volt, met behoorlijke onafhankelijkheid van de voedingsspanning (tussen de 2.7 en 10 Volt, al mag deze laatste waarde natuurlijk nooit voorkomen op een Butterfly), en ook een heel behoorlijke temperatuurstabiliteit. 1.8 Volt is ook een mooi meetbereik; minder dan 2x de maximum batterijspanning van 1.35 Volt, dus ik gebruik alle 10 bits van de ADC (al gebruikt de software er verder maar 8).

Software download

De software is hier als zip-archive te downloaden: NiMHtester.zip. Dit is de hele source, inclusief de (hier en daar aangepaste) standaard Butterfly-code.

De schema's zijn binnenkort als een PDF te downloaden.

En hier mijn simpele logfile naar spreadsheet (tab-separated ascii) converter geschreven in Perl.

De software

Het loggen van de data

Voor de datalogging gebruik ik de seriële flash chip AT45DB041B die op de Butterfly zit. Deze heeft een opslagruimte van ruim 512 kByte, bij een meting per seconde (4 kanalen, 8-bits opslag per kanaal) genoeg voor tientallen dagen opslag.

In de butterfly software zitten al routines om het flash aan te spreken (dataflash.c), maar daar komt nog al wat bij kijken. Opgebouwd in 2048 pages van 264 bytes is optimaal gebruik lastig, maar ik heb voor het gemak er nog een laagje overheen gelegd. De chip heeft een (eigenlijk zelfs twee) on-chip buffer, waar ik de waardes in weg schrijf; en pas als de buffer 256 bytes bevat, wordt de buffer naar de flash geschreven (duurt 20 ms voor wissen en programmeren). Dit bufferen beperkt het aantal schrijfacties naar de flash, en vergroot daarmee de levensduur.

De logging-routines heb ik in een aparte file 'datalog.c' gezet, zodat ze ook in andere projecten toegepast kunnen worden. Intern wordt er in een 32-bit teller bijgehouden hoeveel bytes naar de flash zijn geschreven, zodat de DataLogUpload() routine weet hoe veel gegevens er naar de PC gestuurd moet worden. De datalogging routines doen verder niets aan structuur, schrijven alleen maar bytes. De drie belangrijkste routines:

- void DataLogInit(void); initialiseert de zaak en reset de teller
- void DataLogWriteByte(uint8_t byte); schrijft een byte naar de buffer (en de buffer naar flash, indien nodig)
- void DataLogUpload(void); zend de bewaarde bytes via de seriële poort naar de PC via een simpel ASCII formaat

De spanningsmeting

Om de spanning te meten gebruik ik een aangepaste versie van de standaard Butterfly ADC.c. Ik maak gebruik van de analoge ingangen PF4..PF7, die ook dienst doen voor JTAG debugging (waar ik toch geen gebruik van maak). Dit houdt wel in dat bij initialisatie deze pinnen eerst als analoge ingangen moeten worden geconfigureerd, en dat JTAG debugging uitgeschakeld moet worden. Daarnaast moet bij elke conversie het goede kanaal gekozen worden, wordt er eerst een dummy-conversie gedaan, en dan worden 8 metingen gedaan waarvan het gemiddelde wordt teruggegeven. De routines (uit nimh_test.c):

- void NiMH_init(void); doet de initialisatie (JTAG uit, extra inputs configureren)
- uint16_t NiMH_read(uint8_t channel); leest het opgegeven kanaal

Piepjes

Nog even een hulproutine: het maken van piepjes. In de oorspronkelijke Butterfly zit een heel stuk software voor het afspelen van melodieën, maar dat neemt me te veel geheugen in gebruik, en de file sound.c heb ik dus verwijderd. In plaats daarvan een simpele routine die een piep kan afspelen (met selecteerbare frequentie, maar vaste amplitude) als een batterij leeg is. In de file 'beep.c' twee routines:

- void BeepStart(uint16_t pitch); start een toon; frequenties als in sound.c; 478 is een C (C2)
- void BeepStop(void); stopt de toon (moet je dus zelf doen!)

Overigens, tussen toetsaanslagen gaat de Butterfly zo veel mogelijk slapen. Dit is normaal geen probleem; behalve bij het afspelen van piepjes: deze klinken dan nogal stotterend. Vandaar dat ik gedurende een piepje de processor maar niet laat slapen.

Het hoofdprogramma

De Butterfly heeft een main loop die continue loopt en toetsaanslagen via de menu-structuur verwerkt. Er is dus geen gebruikersprogramma continue actief. In plaats daarvan hangt de NiMH tester de routine NiMH_periphery() in een timer-interrupt die elke 10 ms wordt geactiveerd (nou ja, ongeveer dan, de timing in de Butterfly is niet zo precies behalve voor de real-time clock). In deze routine wordt getest of er een nieuwe seconde begonnen is (via de real-time-clock variabelen), en alleen dan wordt er gemeten. Een aanpak die in real-time systemen overigens niet ongebruikelijk is. Wel oppassen: als de Butterfly in zijn main loop een tijd geen toetsaanslagen detecteert gaat hij in power-down; dit moet dus wel voorkomen worden (door de power-down timer te resetten).

Elke seconde wordt dus werk verzet. In de routine NiMH_periphery() wordt steeds één batterij doorgemeten, en de waarde op het display weergegeven (batterij-nummer gevolgd door een spatie en de gemeten spanning in drie cijfers, dus iets als '1 123 ' voor batterij 1 met 1.23 Volt).

Display bij lege batterijAls de waarde voor het eerst onder de 1 Volt komt wordt een piepje gegeven en de tijd gelogd. Bovendien wordt vanaf dat moment in het display niet meer de spanning weergegeven, maar de tijd (in uren en minuten) waarop de batterij leeg was, gevolgd door het batterijnummer (dus 12:02: 2). Op die manier worden spanning en tijd niet snel verwisseld.

Een keer per minuut worden de laatste 4 spanningen naar de flash geschreven, voor latere analyse in bijvoorbeeld een spreadsheet: via de seriële poort kan met DataLogUpload()de data naar een PC gezonden (vang ik op met GtkTerm), en een simpel Perl script vertaalt vervolgens de data naar een formaat dat in de meeste spread sheets wel gelezen kan worden. Zo heb ik ook de grafiekjes op deze pagina gemaakt.

Om deze routines aan te roepen zijn er in het Butterfly-menu twee entries toegevoegd, gebundeld in een NiMH-tester hoofdmenu:
- char NiMHStartFunc(char input); de functie die het meten start
- char NiMHUploadFunc(char input); de functie die de upload naar de PC start

En verder

Butterfly in doosjeOndertussen de Butterfly in een net kastje ingebouwd, zodat het geheel wat minder kwetsbaar is, en voorzien van een uitbreidingsconnector om bijvoorbeeld het meetcircuit van de batterijtester op aan te sluiten. Kan het dus ook voor andere toepassingen gebruiken.

Zoals al aangegeven; het batterij-ontladingscircuit is niet echt ideaal. De belangrijkste beperking is het gebruik van de BC549 als transistor: bij deze lage spanningen en (relatief) hoge stromen houd deze het maar net bij (en eigenlijk wil ik naar een hogere belastingsstroom,de meeste apparaten willen wel meer dan 100 mA). Beter is met een goede MOSFET te schakelen, zoals ik ook bij mijn RGB-controller doe (en dan de LEDS weg laten, en R3 weglaten of verlagen), maar die had ik op het moment niet liggen.

Belangrijk is hier een FET te kiezen met een lage schakelspanning (veel MOSFETS hebben 5 Volt of hoger nodig om goed te schakelen) en een lage aan-weerstand. De gebruikte IRL510 voldoet aardig; een meting geeft aan dat deze al schakelt vanaf 3 Volt, en dan een weerstand heeft van 0.5 Ohm (bij 1 Ampere). De BC549C uit het RGB-controllerschema wordt hier gebruikt om de stroomgrens aan te geven, waarbij die 350 mA een realistischer belasting is dan de door mij gebruikte 100 mA.

Wel denk ik een kleinere FET (IRLML2502PBF, 20 cent bij Dick Best, SMD-montage, schakelt al < 2.2 Volt?) te kiezen, zo veel vermogen hoeft er toch ook weer niet weg (stel dat ik de weerstanden zo kies dat er 0.5 Volt over de FET staat; met 350 mA is dat iets onder de 200 mW). Ach, toch ook niet niets, zal toch wat koeling nodig hebben...