# Playing with the RadioShack 22-812 Meter



## Mr Happy (Feb 15, 2010)

For anyone unfamiliar with it, this is a moderately good digital multimeter you can find in RadioShack for about $70, maybe less on sale. What is really neat about it is that it has a RS232 serial interface for connecting to a computer. This means you can use it for unattended data logging!

(I have noticed the 22-812 seems to have disappeared from RadioShack’s web site, suggesting it might have been discontinued. If you want one, I would suggest grabbing one quick before the remaining stock runs out.)

The meter comes with some PC software that is functional but limited, but using standard software is no fun. It also doesn’t install nicely on Vista or Windows 7. What was more fun was to write my own program to capture data from the meter and record it the way I wanted. (The protocol can be found in the link at the bottom of this page).

Two meters is twice as much fun as one meter! I wrote my program to capture data from one, two or any number of meters at the same time and record all the results in a single file. If you have not got that many (or any) serial ports on your computer you will need a USB to serial port adapter for each meter (this is a good one).

Today I got all the pieces assembled and ran a real life test. Here is the result of charging a UltraLast Hybrio (not a Hybriloop) on the GP PowerBank Smart 2 charger I picked up recently. The plot shows voltage and temperature. The temperature was captured using a Fluke thermocouple adapter that was actually more expensive than the meter , though I have to say I was seriously impressed with the quality of it. I can see why Fluke products are worth the money.

The GPPB14 charges at 2000 mA, hence the rapid charging time. It is interesting how high the voltage went. I’m going to have to charge the same cell at 2000 mA on the C9000 for comparison sometime. (Edit: The chart below shows the closed circuit voltage with the charge current present, while the C9000 displays the open circuit voltage with the charge current disconnected. The difference between the two values can be quite significant.)

Here’s the pretty plot produced in Excel:







Notice how the −∆V signal can be seen just prior to termination, and how flat most of the voltage curve is.

Note: The code for this example is included in post #12 by request.


----------



## SilverFox (Feb 15, 2010)

Hello Mr Happy,

Nice...  

Tom


----------



## TakeTheActive (Feb 15, 2010)

Mr Happy said:


> ...Here is the result of charging a UltraLast Hybrio (not a Hybriloop) on the GP PowerBank Smart 2 charger I picked up recently. The plot shows voltage and temperature...
> 
> ...*The GPPB14 charges at 2000 mA*, hence the rapid charging time. *It is interesting how high the voltage went.* I’m going to have to charge the same cell at 2000 mA on the C9000 for comparison sometime...


I don't understand the voltage curve - more precisely, I don't understand how it got over 1.47VDC so fast.

It's my understanding that when we ask a charger to charge a cell at xx mA, it varies the voltage to maintain the current. Thus, to supply 2000mA, the GP PowerBank Smart 2 had to ramp up the voltage to over 1.50VDC. Going by this graph, if you were to attempt to charge these same cells on the C9000 @ 2000mA, it appears that one would expect the C9000 to terminate on Max Voltage of 1.47VDC in about 3 minutes.

My first thought was high Internal Resistance, but since the temperature didn't begin to climb in earnest until ~45min, the cells appear healthy.

What am I missing? :thinking:

Thanks!


----------



## Mr Happy (Feb 15, 2010)

TakeTheActive said:


> I don't understand the voltage curve - more precisely, I don't understand how it got over 1.47VDC so fast.
> 
> It's my understanding that when we ask a charger to charge a cell at xx mA, it varies the voltage to maintain the current. Thus, to supply 2000mA, the GP PowerBank Smart 2 had to ramp up the voltage to over 1.50VDC. Going by this graph, if you were to attempt to charge these same cells on the C9000 @ 2000mA, it appears that one would expect the C9000 to terminate on Max Voltage of 1.47VDC in about 3 minutes.
> 
> ...


I thought exactly the same thing, and I did a test on the C9000 to find out.

It seems the voltage indicated by the C9000 when it is operating is not exactly the voltage you can see with an external voltmeter.

The voltage shown on my plot is the maximum voltage across the cell terminals when the charging current is present. However, the C9000 applies the charging current in pulses and it measures and displays the cell voltage in the intervals when the current is turned off. It is difficult for slow acting voltmeters to catch this, apparently. (The C9000 has an internal microprocessor that can coordinate the voltage measurements at exactly the right time.)

To get an idea of the difference, see how the voltage dropped from about 1.61 V to 1.53 V when the charger stopped at the end. If you subtract about 0.08 V from the whole voltage curve you will get an estimate of what voltage the C9000 is looking at.


----------



## Mr Happy (Feb 16, 2010)

For comparison with the previous chart, here is a similar cell charged on the C9000 at 2000 mA indicated (1800 mA actual).






Notable features:


The voltage goes through a slight minimum between 10 and 20 minutes;
Charging terminates before the −∆V point is reached due to the max voltage cut-off of the C9000, but this results in a lower peak cell temperature.
It is unfortunate I could not obtain a true 2000 mA charge rate for a direct comparison with the GPPB14. Due to the 90% duty cycle of the C9000, 90% of 2000 mA is the highest charging current that can be obtained.


----------



## Russel (Feb 19, 2010)

A while back I used my CBAII to monitor the charge voltage of an Eneloop charged at 1000ma on my BC-900 charger. Below are the results. I may have to try the same thing with my MH-C9000. (The voltage seems a little high here also.)


----------



## Mr Happy (Feb 19, 2010)

I smoothed out the spikes in my plot by picking the maximum voltage seen in each sample period, which should correspond to the closed circuit voltage when the charging current is turned on.

A peak voltage of 1.6+ V for a modern cell under high rate charge is typical, actually. The C9000 can be misleading since the voltage it displays is the open circuit voltage sampled between charging pulses.


----------



## TakeTheActive (Feb 19, 2010)

*Mr Happy*,

Same request here as in the newer: *Charging NiMH at high and low rates -- what can go wrong*

Please consider revising your graph titles to include all of the relevant information:
Graph #1: UltraLast Hybrio AA @ 2000mA on GP GPPB14
.
Graph #2: UltraLast Hybrio AA @ 2000mA on Maha C9000
This way, when someone LINKs to just the graphs, they don't have to add any details.

BTW, what is the 'condition' of the cells before the 'Experiment'? (i.e. *DISCHARGED @ 0.2C on the Maha C9000 to 0.9VDC*)?

Thanks!


----------



## deb (Mar 23, 2010)

Mr. Happy,
Would you be willing to share your code for the RadioShack 22-812 communication?
Thanks,
Deb


----------



## petergunn (Mar 23, 2010)

deb said:


> Mr. Happy,
> Would you be willing to share your code for the RadioShack 22-812 communication?
> Thanks,
> Deb



FYI

Radioshack code: http://www.radioshack.com/search/softwareResults.jsp?kw=22-812

zmeter(linux): http://zmeter.sourceforge.net/
prsmeter(linux): http://prsmeter.sourceforge.net/

I haven't tried either 

Is the Mastech MAS345 any good? It seems readily available on Amazon and looks easy to read with custom Linux scripts: http://www.linux-magazine.com/w3/issue/83/Perl_Multimeter_to%20Measure_Power_Consumption.pdf

Actually I'm thinking any RS232 multimeter will likely be easy to read - any good cheap ones ~ $50?

-PG


----------



## Mr Happy (Mar 24, 2010)

deb said:


> Mr. Happy,
> Would you be willing to share your code for the RadioShack 22-812 communication?
> Thanks,
> Deb


Hi Deb,

My code is written in C++ and is strongly specific to Windows. It needs Visual Studio to compile it (Visual C++ Express 2008 will do).

The program is a simple command line app that logs the displayed values to a CSV file until you tell it to stop. It is neither elaborate nor richly functional. It doesn't have a graphical user interface since engineers don't need such frills 

However, I might be willing to make it publicly available after I tidy it up a bit. Watch this space over the next week or so and we'll see what happens.


----------



## Mr Happy (Mar 24, 2010)

Here is the code referenced in the first post of this thread to collect data from the RadioShack 22-812 meter.

There are four files. These should be added to a project in Visual Studio 2008 and built as a multi-threaded command line application. I called the application *rsdmm*.*MeterGather.h* declares a class that does the main work of opening and initializing a serial port and collecting meter data in a background thread.

*MeterGather.cpp* is the implementation of this class.

*LogData.cpp* is the driver function that launches the gathering threads in the background and then periodically logs the recorded data to a file.

*main.cpp* is the main program that starts everything off.​To run the program, use a command like this:

C:\Data>*rsdmm 10 COM4 COM5*

This will collect data from meters on COM4 and COM5 and log the results to file at 10 second intervals. To finish logging and close the file hit Ctrl-C.

The format of the log file is CSV as follows:

_Timestamp (HH:MM:SS.ss), Timestamp (SS.ss), First meter: Sample count, Mean value, Min value, Max value, Second meter: etc...
_ 
This file can be read into Excel for plotting and analysis.

*MeterGather.h*

```
// Copyright (C) 2010 Mr Happy, CandlePowerForums. All rights reserved.

#define _CRT_SECURE_NO_WARNINGS
#define WINDOWS_LEAN_AND_MEAN

#include <windows.h>
#include <string>

class MeterGather
{
public:
  MeterGather(const std::string &port);
  ~MeterGather();
  bool Init();
  void Start();
  void End();
  void GetReadings(int &count, double &meanval, double &minval, double &maxval);
private:
  static DWORD WINAPI startThread(LPVOID p);
  void readLoop();
  bool readMessage();
  bool checksumValid();
  double getValue();
  
  static const int MessageSize = 9;

  unsigned char mBuf[MessageSize];
  std::string   mPort;
  HANDLE        hPort;
  HANDLE        hThread;
  CRITICAL_SECTION mCS1;
  bool          mEndThread;
  int           mCount;
  double        mTotal;
  double        mMinVal;
  double        mMaxVal;
};
```
*MeterGather.cpp*

```
// Copyright (C) 2010 Mr Happy, CandlePowerForums. All rights reserved.

#include "MeterGather.h"
#include <iostream>

using namespace std;

// Construct object and initialize variables
MeterGather::
MeterGather(const string &port) 
: mPort(port), hPort(0), hThread(0), mEndThread(false),
  mCount(0), mTotal(0), mMinVal(1e20), mMaxVal(0)
{
  InitializeCriticalSection(&mCS1);
}

// Close comm port, clean up
MeterGather::
~MeterGather()
{
  if (hThread) End();
  DeleteCriticalSection(&mCS1);
}

// Open and initialize comm port for reading
// : write message to cerr and return false on failure
bool MeterGather::
Init()
{
  bool status = false;
  do
  {
    HANDLE port_handle = CreateFile( 
      mPort.c_str(),  
      GENERIC_READ | GENERIC_WRITE, 
      0, 
      0, 
      OPEN_EXISTING,
      0,
      0);
                        
    if (port_handle == INVALID_HANDLE_VALUE) {
      DWORD code = GetLastError();
      LPVOID msgbuf;
      FormatMessage(
        FORMAT_MESSAGE_ALLOCATE_BUFFER | 
          FORMAT_MESSAGE_FROM_SYSTEM |
          FORMAT_MESSAGE_IGNORE_INSERTS,
        NULL,
        code,
        MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
        (LPTSTR) &msgbuf,
        0, NULL );
      cerr << "Error opening port " << mPort << ": " << static_cast<LPTSTR>(msgbuf) << endl;
      break;
    }
    
    DCB dcb;
    dcb.DCBlength = sizeof(DCB);
    if (!GetCommState(port_handle, &dcb)) {
      cerr << "Error getting comm state on " << mPort << endl;
      break;
    }
    
    dcb.BaudRate = CBR_4800;
    dcb.Parity = NOPARITY;
    dcb.ByteSize = 8;
    dcb.StopBits = ONESTOPBIT;
    dcb.fDtrControl = DTR_CONTROL_DISABLE;

    if (!SetCommState(port_handle, &dcb)) {
      cerr << "Error setting comm state on " << mPort << endl;
      break;
    }

    // zero for all timeout entries means wait forever and do not time out
    COMMTIMEOUTS timeouts;
    timeouts.ReadIntervalTimeout = 0;
    timeouts.ReadTotalTimeoutMultiplier = 0;
    timeouts.ReadTotalTimeoutConstant = 0;
    timeouts.WriteTotalTimeoutMultiplier = 0;
    timeouts.WriteTotalTimeoutConstant = 0;

    if (!SetCommTimeouts(port_handle, &timeouts)) {
      cerr << "Error setting comm timeouts on " << mPort << endl;
      break;
    }

    EscapeCommFunction(port_handle, CLRDTR);
    EscapeCommFunction(port_handle, CLRRTS);
    PurgeComm(port_handle, PURGE_RXCLEAR);
    
    hPort = port_handle;
    status = true;

  } while (0);

  return status;
}

// Start the reading thread in the background and return immediately
void MeterGather::
Start()
{
  hThread = CreateThread(
    0, 0,
    startThread, static_cast<void*>(this),
    0, 0
  );
}

// End the reading thread and wait for it to exit
void MeterGather::
End()
{
  mEndThread = true;
  WaitForSingleObject(hThread, 1000);
}

// Get the current accumulated readings and reset the accumulators
void MeterGather::
GetReadings(int &count, double &meanval, double &minval, double &maxval)
{
  EnterCriticalSection(&mCS1);
  count = mCount;
  meanval = mTotal / mCount;
  minval = mMinVal;
  maxval = mMaxVal;
  mTotal = 0.0;
  mCount = 0;
  mMinVal = 1e20;
  mMaxVal = 0.0;
  LeaveCriticalSection(&mCS1);
}

// Start the background thread for gathering meter readings
DWORD WINAPI MeterGather::
startThread(LPVOID p)
{
  MeterGather *g = static_cast<MeterGather *>(p);
  g->readLoop();
  return 1;
}

// The main method of the background meter reading loop
void MeterGather::
readLoop()
{
  double v;
  while (!mEndThread)
  {
    if (readMessage())
    {
      v = getValue();
    }
    else
    {
      Sleep(100);
      continue;
    }
    
    EnterCriticalSection(&mCS1);
    mTotal += v;
    ++mCount;
    if (v < mMinVal) mMinVal = v;
    if (v > mMaxVal) mMaxVal = v;
    LeaveCriticalSection(&mCS1);
  }
}

// Read message from serial port into buffer
bool MeterGather::
readMessage()
{
  EscapeCommFunction(hPort, SETDTR);
  DWORD nread = 0;
  ReadFile(hPort, (LPVOID)mBuf, MessageSize, &nread, 0);
  EscapeCommFunction(hPort, CLRDTR);
  if (nread != MessageSize || !checksumValid())
  {
    PurgeComm(hPort, PURGE_RXCLEAR);
    return false;
  }
  return true;
}

// Validate checksum of message
bool MeterGather::
checksumValid()
{
  const int LastByte = MessageSize - 1;
  unsigned sum = 0;
  for (int i = 0; i < LastByte; i++)
        sum += mBuf[i];
  return mBuf[LastByte] == ((sum + 0x39) & 0xFF);
}

// Get value from buffer
double MeterGather::
getValue()
{
  double v = 0.0;
  char s[8];
  char *p = s;
  if (mBuf[7] & 8) *p++ = '-';
  mBuf[6] &= ~8;
  bool have_digits = false;
  for (int i = 6; i > 2; --i)
  {
    if (mBuf[i] & 8)
    {
      *p++ = '.';
      mBuf[i] &= ~8;
    }
    char *p1 = p;
    switch (mBuf[i])
    {
      case  80: *p++ = '1'; break;
      case 181: *p++ = '2'; break;
      case 241: *p++ = '3'; break;
      case 114: *p++ = '4'; break;
      case 227: *p++ = '5'; break;
      case 231: *p++ = '6'; break;
      case  81: *p++ = '7'; break;
      case 247: *p++ = '8'; break;
      case 243: *p++ = '9'; break;
      case 215: *p++ = '0'; break;
      default:              break;
    }
    if (p > p1) have_digits = true;
  }
  *p = 0;
  if (have_digits) v = atof(s);
  if (mBuf[1] & 0x01) v *= 1e-3;
  if (mBuf[1] & 0x10) v *= 1e6;
  if (mBuf[1] & 0x20) v *= 1e3;
  if (mBuf[2] & 0x40) v *= 1e-9;
  if (mBuf[2] & 0x80) v *= 1e-6;
  return v;
}
```
*LogData.cpp*

```
// Copyright (C) 2010 Mr Happy, CandlePowerForums. All rights reserved.

#include "MeterGather.h"
#include <string>
#include <vector>
#include <iostream>
#include <fstream>
#include <sstream>
using namespace std;

namespace
{

HANDLE hExit = CreateEvent(0, FALSE, FALSE, 0);

char *
timeString()
{
  static DWORD tzero = GetTickCount();
  static char timestr[64]; // HH:MM:SS.ss, SS.ss
  DWORD delta;
  
  DWORD time = GetTickCount();
  if (time >= tzero)
    delta = time - tzero;
  else
    delta = (0xFFFFFFFFu - tzero) + time;
  int cs = ((delta % 1000u) + 5u) / 10u;
  delta /= 1000u;
  int totsec = delta;
  int sec = delta % 60u;
  delta /= 60u;
  int min = delta % 60u;
  int hr = delta / 60u;
  sprintf(timestr, "%2.2d:%2.2d:%2.2d.%2.2d, %d.%2.2d", 
            hr, min, sec, cs, totsec, cs);
  return timestr;
}

BOOL WINAPI ctrlcHandler(DWORD ctrl_type)
{
  if (ctrl_type == CTRL_C_EVENT)
  {
    SetEvent(hExit);
    return TRUE;
  }
  
  return FALSE;
}

}

int
LogData(int interval, vector<string> &ports)
{
  vector<MeterGather *> meters;
  
  for (size_t i = 0; i < ports.size(); i++)
  {
    MeterGather *m = new MeterGather(ports[i]);
    meters.push_back(m);
  }
  
  bool initialized = true;
  for (size_t i = 0; i < meters.size(); i++)
  {
    if ( !meters[i]->Init() ) initialized = false;
  }
  
  if (initialized)
  {
    SYSTEMTIME lt;
    GetLocalTime(&lt);
    char filename[64];
    sprintf(filename, "DMM%4.4d%2.2d%2.2d_%2.2d%2.2d%2.2d.csv",
                       lt.wYear, lt.wMonth, lt.wDay, lt.wHour, lt.wMinute, lt.wSecond);
    cout << "Log file is " << filename << endl;
    ofstream logfile(filename);
    if (logfile.fail())
    {
      cerr << "Error opening log file" << endl;
      return 1;
    }

    for (size_t i = 0; i < meters.size(); i++)
    {
      meters[i]->Start();
    }
  
    // infinite timed loop
    HANDLE hTimer = CreateWaitableTimer(0, FALSE, 0);
    LARGE_INTEGER cycle_time;
    LONG period = interval * 1000; // ms
    cycle_time.QuadPart = period * -10000LL; // 100ns
    SetWaitableTimer(hTimer, &cycle_time, period, 0, 0, 0);
    SetConsoleCtrlHandler(ctrlcHandler, TRUE);
    HANDLE handles[] = {hExit, hTimer};
    
    char localtime[80];
    GetTimeFormat(LOCALE_USER_DEFAULT, 0, NULL, NULL, (LPSTR)localtime, 79);
    cout << "Logging begins at " << localtime << endl;
    int count;
    double meanval, minval, maxval;
    char *time;
    for (;;)
    {
      DWORD status = WaitForMultipleObjects(2, handles, FALSE, INFINITE);
      if (status == WAIT_OBJECT_0)
      {
        break;
      }
      stringstream ss;
      time = timeString();
      ss << time;
      for (size_t i = 0; i < meters.size(); i++)
      {
        meters[i]->GetReadings(count, meanval, minval, maxval);
        ss << ", " << count << ", " << meanval << ", " << minval << ", " << maxval;
      }
      cout << ss.str() << endl;
      logfile << ss.str() << endl;
    }

    cout << "Logging concluded." << endl;
    logfile.close();
  }
  
  for (size_t i = 0; i < meters.size(); i++)
  {
    delete meters[i];
  }
  
  return 0;
}
```
*
main.cpp*

```
// Copyright (C) 2010 Mr Happy, CandlePowerForums. All rights reserved.
//
// RadioShack 22-812 Meter logging program

#define _CRT_SECURE_NO_WARNINGS
#include <cstring>
#include <cstdlib>
#include <string>
#include <vector>
#include <iostream>
using namespace std;

int LogData(int interval, vector<string> &ports);

int
main(int argc, char *argv[])
{
  int status = 0;
  vector<string> ports;

  if (argc < 3) goto usage;
  
  int interval = atoi(argv[1]);
  if (interval <= 0) goto usage;
  
  for (int i = 2; i < argc; i++)
  {
    ports.push_back(argv[i]);
  }

  status = LogData(interval, ports);
  
  return status;
  
usage:
  cout << "usage: RSDMM <interval> <port1> [<port2> ...]" << endl;
  return 1;
}
```


----------



## petergunn (Mar 24, 2010)

Couldn't justify the price of an RS232 or USB capable multimeter (more $$$ == less flashlights ) so I just ordered a cheapo [FONT=Arial, Helvetica, sans-serif]Sear's Digital Mini Multimeter with autorange that works of AAAs.

Now I'm playing with the idea of simply reading the LCD display into the computer via webcam. Looks pretty easy given the limited display capabilities of multimeters and I guess its safer as well as there is no physical connection to the PC.

Anyone else tried this approach with multimeters? :thinking:

-PG
[/FONT]


----------



## Mr Happy (Mar 24, 2010)

Sounds like hard work to me as you now have to do image recognition, but it's a creative solution and kudos to you if you can make it work.

Although it might seem the RS meter is tethered to a computer, the RS232 output is optically isolated so it is not as connected as it seems.


----------



## petergunn (Mar 26, 2010)

Mr Happy said:


> Sounds like hard work to me as you now have to do image recognition...



Been a while since I wrote any Windows software (more of a Linux guy ) but after a little research it doesn't look super impossible, especially after google turned up the awesome OpenCV: http://sourceforge.net/projects/opencvlibrary/ :thumbsup::thumbsup::thumbsup:

My multimeter still hasn't arrived yet, but my cheapo lightmeter was waiting when I got back from work. A quick install of freeware Dev C++ and 90mins later we have...





Yes, so not quite the full thing yet but webcam is streaming fine, hacked up a bit of code to mark the LCD surface and project the pixels to a flat 2D window - now I need to identify the digits and output them to a file 

... but out of time for tonight  - maybe have a bit more of a hack on Sunday :thinking:

-PG


----------



## krisirk (Apr 7, 2010)

Mr Happy,

I too have a Radioshack 22-812 that I've used for data logging. I previously used QtDMM on Ubuntu 8.10, but one day it mysteriously stopped working and I couldn't get it to work.

I wanted something exactly like the program you made, simple and effective. I downloaded the Visual Studio Express C++ and it compiled nicely. One thing to note, it needed to be compiled on the machine it will be run on. I compiled it on my laptop running Windows 7 32 bit and the executable wouldn't run on an older desktop running Windows XP 32 bit.

I've used your program for doing a few runtime tests using a homemade light box, if anyone is interested I can share a few photos and details.

Thanks again for the software.

Kris


----------



## Mr Happy (Apr 8, 2010)

krisirk said:


> I wanted something exactly like the program you made, simple and effective. I downloaded the Visual Studio Express C++ and it compiled nicely. One thing to note, it needed to be compiled on the machine it will be run on. I compiled it on my laptop running Windows 7 32 bit and the executable wouldn't run on an older desktop running Windows XP 32 bit.


Thanks for the feedback, I'm glad the code was useful.

You should be able to overcome the portability problem by going into the project properties and changing the Runtime Library in C/C++ Code Generation from Multi-threaded DLL (/MD) to Multi-threaded (/MT). This will create a slightly bigger executable but it should then run on other computers without needing to be rebuilt. Alternatively you could copy the required run-time DLLs along with the executable (keep them all in the same directory), or you could experiment with creating a setup project for the program...


----------



## turboBB (Oct 23, 2011)

Mr. Happy,

I'm reviving this old thread since thanks to you, I've found what is likely the most economical data logging DMM. The only thing is the readout is off by more than .5V as compared to my Fluke 289. Do you know if there is a way this meter can be calibrated?

I just used it to graph the V portion of the V60C charging base review. It's my first go at it so I'd appreciate if anyone can point out any mistakes I made (kudos to HKJ for his awesome write up re: his charger testing methodology).

Cheers,
Tim


----------



## HKJ (Oct 23, 2011)

turboBB said:


> The only thing is the readout is off by more than .5V as compared to my Fluke 289. Do you know if there is a way this meter can be calibrated?



DMM are usual not that wrong. The first thing to do is check the battery in the RadioShack meter.
When comparing voltage readout, did you wire the meters in parallel to secure exactly same voltage to them?

In your charging setup you might easily have a 0.2 volt difference between charger base and battery, due to the wires and ammeter.


----------



## turboBB (Oct 23, 2011)

Thx HKJ, I goofed and shifted the decimal spot over. I meant to say there was up to a .05V difference. It seems it depends on the V range as below 4V, it is nearly spot on w/the Fluke. Measuring a sinlge LiIon cell, it's about .02-.03 off and w/2 cells around .04 and w/3 cells there can be greater than .05 difference. I suppose it's negligible and for the price I paid, I can't really complain.

These readings were unloaded (meaning not connected to the charger) so should be an apples:apples comparo.

As for the wiring set up during monitoring, it's as follows:



So basically:
- Positive lead from Fluke 289 & RS 22-812 are connected to anode of charger
- Negative lead from 289 connected to jumper on anode of battery carrier
- Negative lead from 22-812 and cathode from battery carrier are connected to jumper of cathode of V60C charging base

So it's not exactly parallel. Does that look right? I could've saved one connection/wire between the meters but I don't have a stacking patch cord yet (coming next week).

Thx!,
Tim


----------



## Mr Happy (Oct 23, 2011)

I have two of the 22-812 meters and they do read slightly low on volt scales (about 0.03 V typically), which is disappointing but not disastrous. I think there is some systematic error when they calibrate them.

[Edit: Redacted old comments in light of more recent post by turboBB that appeared while I was composing this one.]


----------



## turboBB (Oct 24, 2011)

Well, curiosity got the better of me (which has been happening a lot lately... ) and I took the meter's back panel off and discovered there are a few adjustable potentiometers of which one is marked DCV:




I made a little mark so I know where I started with and adjusted it a hair CCW and took some readings, it got closer to the Fluke, AWESOME! So I adjusted again just a very minute amount CCW and now I get these readings for 2x18650:

*Fluke 289*
Cell 1 - 3.645
Cell 2 - 4.194
Combined - 7.84

*22-812*
Cell 1 - 3.643
Cell 2 - 4.2
Combined - 7.84

I can TOTALLY live with that! Thanks again for this post Mr. Happy!! Thanks :twothumbs

Now just a matter of finding good quality 9V rechargeable bats and some decently priced but reasonable quality silicone test leads. 

Cheers,
Tim


----------



## Mr Happy (Oct 24, 2011)

turboBB said:


> I made a little mark so I know where I started with and adjusted it a hair CCW and took some readings, it got closer to the Fluke, AWESOME! So I adjusted again just a very minute amount CCW and now I get these readings for 2x18650:
> 
> *Fluke 289*
> Cell 1 - 3.645
> ...


Ah, I might have to try that myself. After you made the adjustment was the zero volts reading still OK (with shorted probes)?


----------



## turboBB (Oct 24, 2011)

Yup, shorts to zero (btw, what exactly does that do?).

Cheers,
Tim


----------



## Mr Happy (Oct 24, 2011)

turboBB said:


> Yup, shorts to zero (btw, what exactly does that do?).


I don't follow? Shorting the probes ensures there is close to zero potential difference across them, so the meter will see 0 V on its input.


----------



## turboBB (Oct 24, 2011)

Ah ok, I didn't know that. Yes, confirmed that it shorts to zero when I crossed the probes.

Cheers,
Tim


----------



## S Rooker (Feb 7, 2012)

Hello, 

Thanks for the cal info. As I remember my 22-812 is slightly out of cal as well but I didn't realize these inexpensive meters had cal pots and if so whether they would be offset or gain correction. Soon as I get a chance I'll take it apart and calibrate. Re: calibration there are usually older 6.5 digit DMM's that can be picked up pretty cheap that can be used to cal your other test equipment with. I prefer this option to the newer name brand meters that cost quite a bit more. 

I was surprised / disappointed to find that the included software didn't have a feature to export data to a spreadsheet. :hairpull: My guess is that most people who want to record data via PC also want to use it in a more sophisticated manner than just looking at the numbers. The scope type graph with it's features and the data log are handy but I really need to perform some math functions on the data. If you have or know anyone who has an app that will make the data available to a spread sheet that would be appreciated. I noticed that Uni-T now has an economical RS232 meter that has 4.5 digits. Haven't checked into it but perhaps their software is more functional. 

Thanks again, Steve


----------



## Bryan_W (Sep 1, 2012)

Mr. Happy,
I have two 22-812 meters and I'm wondering if you wouldn't mind helping me with regards to the MeterView (Radiio Shack software) and/or rsdmm problems I'm having.
I'll try to be brief (but it's going to be hard)....

Without knowing if it's even possible, I've been trying to run two instances of MeterView simultaneously with each meter connected thru a usb adapter and set to different com ports.
My results have been very sporadic, with most attempts ending with either total program crashes or partial logfile data corruption where portions of one log file gets overwritten by the other.

First, I'm wondering if (prior to writting rsdmm) you tried anything like this and/or if you know for certain that this should work.

In addition.....

Needless to say, after having the above mentioned experiences I was greatful to find your rsdmm and BELIEVE I was able to compile it correctly with Visual C++ 2008 Express.

Unfortunately, along with being a non-programmer I'm also an idiot, I need someone to look at samples of rsdmm data that I've generated from two different computers (both XP SP3)and try to help me wrap my head aound what I'm seeing.


On the original laptop that had the MeterView problems I get results like:


```
00:00:00.00, 0.00, 230, 10.5401, 10.54, 10.55, 230, 2.48998, 2.489, 2.49
00:01:00.01, 60.01, 229, 10.54, 10.54, 10.54, 230, 2.4899, 2.489, 2.49
00:02:00.01, 120.01, 231, 10.5368, 10.53, 10.54, 230, 2.48973, 2.489, 2.49
00:03:00.02, 180.02, 230, 10.531, 10.53, 10.54, 230, 2.4895, 2.489, 2.49
00:04:00.03, 240.03, 230, 10.53, 10.53, 10.53, 229, 2.4891, 2.489, 2.49
00:05:00.03, 300.03, 231, 10.53, 10.53, 10.53, 230, 2.48903, 2.489, 2.49
00:06:00.04, 360.04, 229, 10.5297, 10.52, 10.53, 229, 2.489, 2.489, 2.489
00:07:00.04, 420.04, 230, 10.5275, 10.52, 10.53, 230, 2.48899, 2.488, 2.489
00:08:00.05, 480.05, 230, 10.5217, 10.52, 10.53, 229, 2.48897, 2.488, 2.489
00:09:00.06, 540.06, 230, 10.5206, 10.52, 10.53, 230, 2.48895, 2.488, 2.489
00:10:00.06, 600.06, 230, 10.52, 10.52, 10.52, 229, 2.48897, 2.488, 2.489
00:11:00.07, 660.07, 230, 10.52, 10.52, 10.52, 230, 2.4887, 2.488, 2.489
00:12:00.08, 720.08, 230, 10.52, 10.52, 10.52, 230, 2.4883, 2.488, 2.489
00:13:00.08, 780.08, 230, 10.52, 10.52, 10.52, 230, 2.48804, 2.488, 2.489
00:14:00.09, 840.09, 231, 10.52, 10.52, 10.52, 230, 2.48803, 2.488, 2.489
00:15:00.09, 900.09, 230, 10.5193, 10.51, 10.52, 230, 2.488, 2.488, 2.488
00:16:00.10, 960.10, 231, 10.5169, 10.51, 10.52, 229, 2.488, 2.488, 2.488
00:17:00.11, 1020.11, 231, 10.5132, 10.51, 10.52, 230, 2.488, 2.488, 2.488
00:18:00.11, 1080.11, 230, 10.5103, 10.51, 10.52, 230, 2.48796, 2.487, 2.488
00:19:00.12, 1140.12, 231, 10.51, 10.51, 10.51, 230, 2.48796, 2.487, 2.488
00:20:00.13, 1200.13, 230, 10.51, 10.51, 10.51, 229, 2.48786, 2.487, 2.488
00:21:00.13, 1260.13, 230, 10.51, 10.51, 10.51, 230, 2.48744, 2.487, 2.488
00:22:00.14, 1320.14, 230, 10.51, 10.5, 10.51, 229, 2.48706, 2.487, 2.488
```

On the second computer I get:


```
00:00:00.00, 0.00, 4, 9.0025, 9, 9.01, 229, 3.98987, 3.98, 3.99
00:01:00.00, 60.00, 231, 9.00056, 9, 9.01, 230, 3.98913, 3.98, 3.99
00:02:00.00, 120.00, 230, 9.00009, 9, 9.01, 229, 3.98799, 3.98, 3.99
00:03:00.00, 180.00, 231, 9, 9, 9, 230, 3.98639, 3.98, 3.99
00:04:00.00, 240.00, 231, 9, 9, 9, 230, 3.98722, 3.98, 3.99
00:05:00.06, 300.06, 231, 9, 9, 9, 229, 3.98664, 3.98, 3.99
00:06:00.00, 360.00, 229, 9, 9, 9, 230, 3.98513, 3.98, 3.99
00:07:00.00, 420.00, 230, 9, 9, 9, 229, 3.98306, 3.98, 3.99
00:08:00.00, 480.00, 230, 9, 9, 9, 230, 3.98257, 3.98, 3.99
00:09:00.00, 540.00, 230, 8.99991, 8.99, 9, 230, 3.98157, 3.98, 3.99
00:10:00.00, 600.00, 230, 9, 9, 9, 231, 3.981, 3.98, 3.99
00:11:00.00, 660.00, 230, 8.99987, 8.99, 9, 230, 3.98057, 3.98, 3.99
00:12:00.00, 720.00, 230, 8.99883, 8.99, 9, 230, 3.98052, 3.98, 3.99
00:13:00.00, 780.00, 229, 8.9986, 8.99, 9, 231, 3.98074, 3.98, 3.99
00:14:00.00, 840.00, 230, 8.99478, 8.99, 9, 230, 3.98043, 3.98, 3.99
00:15:00.00, 900.00, 230, 8.99261, 8.99, 9, 229, 3.98079, 3.98, 3.99
00:16:00.00, 960.00, 230, 8.99117, 8.99, 9, 230, 3.98026, 3.98, 3.99
00:17:00.00, 1020.00, 231, 8.9903, 8.99, 9, 229, 3.98004, 3.98, 3.99
00:18:00.00, 1080.00, 230, 8.99, 8.99, 8.99, 230, 3.98, 3.98, 3.98
00:19:00.00, 1140.00, 230, 8.99, 8.99, 8.99, 230, 3.98, 3.98, 3.98
00:20:00.00, 1200.00, 231, 8.99, 8.99, 8.99, 230, 3.98, 3.98, 3.98
00:21:00.00, 1260.00, 229, 8.99, 8.99, 8.99, 229, 3.98, 3.98, 3.98
00:22:00.00, 1320.00, 231, 8.99, 8.99, 8.99, 230, 3.98, 3.98, 3.98
00:23:00.00, 1380.00, 231, 8.99, 8.99, 8.99, 229, 3.98, 3.98, 3.98
00:24:00.00, 1440.00, 231, 8.98974, 8.98, 8.99, 230, 3.98, 3.98, 3.98
00:25:00.00, 1500.00, 230, 8.98909, 8.98, 8.99, 230, 3.98, 3.98, 3.98
00:26:00.00, 1560.00, 230, 8.9883, 8.98, 8.99, 229, 3.98, 3.98, 3.98
00:27:00.00, 1620.00, 230, 8.9863, 8.98, 8.99, 230, 3.98, 3.98, 3.98
00:28:00.19, 1680.19, 232, 8.98362, 8.98, 8.99, 230, 3.98, 3.98, 3.98
00:29:00.00, 1740.00, 230, 8.98339, 8.98, 8.99, 229, 3.98, 3.98, 3.98
00:30:00.00, 1800.00, 230, 8.98174, 8.98, 8.99, 229, 3.98, 3.98, 3.98
00:31:00.00, 1860.00, 230, 8.98057, 8.98, 8.99, 230, 3.98, 3.98, 3.98
00:32:00.03, 1920.03, 230, 8.98009, 8.98, 8.99, 230, 3.98, 3.98, 3.98
00:33:00.00, 1980.00, 231, 8.98, 8.98, 8.98, 230, 3.98, 3.98, 3.98
00:34:00.00, 2040.00, 231, 8.98, 8.98, 8.98, 230, 3.98, 3.98, 3.98
00:35:00.00, 2100.00, 230, 8.98, 8.98, 8.98, 231, 3.98, 3.98, 3.98
```

To me, the "meter data" both real and "calculated", seems to be as expected. My main areas of concern are with the :ss portions of the timestamps and the com port designations.
I understand that for each entry I have the required information (a given value for a given time)to generate a graph, it's just that the two computers are so different.
On the second computer the :ss (milliseconds???) seem to "adjust after an occassional change, but the first computer seems to "accumulate". 
Am I correct that the timestamp values have something to do with the line "Sleep(100);" in the MeterGather.cpp file?

Should the com ports be showing up more like the "4" in the first line of computer #2 or at least showing up as different numbers per entry?

Am I worrying over nothing? - If so please let me know.
Thanks in advance for your time.
Bryan


----------



## Bryan_W (Sep 2, 2012)

Just thought I'd post a follow-up to say that from the small amount of internet information I've been able to digest, it seems that the differences in the timestamp data I mentioned in my first post is a Windows thing having to do with timer resolution and/or the Windows timer not being the same on every computer ....or something like that, and I suspect that Mr. Happy intentionally wrote his code to handle this.

Now, I'm off to contimue my crash course in C++ and investgate the com port data.


----------



## tjb20171 (Feb 21, 2013)

Mr. Happy, 
I don't know if you are still around to look at this code or not. I just found it as part of a project. Anyway, I have created the files in Dev-C++, but I keep getting a compile error that shows an issue with the "usage" label in main.cpp. It seems to be tied to the "int interval = atoi(argv[1])" section. I have tried multiple ways around this but I keep getting the same compile error. Any ideas?


----------



## Mr Happy (Feb 21, 2013)

Oh, I didn't notice there were new comments on this thread. Sorry Bryan! I hope you got your problems sorted.

@tjb20171: The code posted above makes heavy use of the Windows API. It absolutely will _only_ compile and run on a Windows machine with the Windows SDK, probably only using Visual Studio. I have no idea if it could be made to work with Dev-C++. I recommend you obtain and use the free Visual C++ Express compiler from Microsoft.


----------



## Bryan_W (Mar 25, 2013)

Mr Happy said:


> Oh, I didn't notice there were new comments on this thread. Sorry Bryan! I hope you got your problems sorted.
> 
> @tjb20171: The code posted above makes heavy use of the Windows API. It absolutely will _only_ compile and run on a Windows machine with the Windows SDK, probably only using Visual Studio. I have no idea if it could be made to work with Dev-C++. I recommend you obtain and use the free Visual C++ Express compiler from Microsoft.




Hi Mr. Happy - glad you're not dead like I thought might have been the case.
Nope, never could get Meterview to be reliable - even when using two computers with one meter connected to each - seems like Meterview can only collect data for so long (if I remember correctly, something like 24 hours) before it screws up. - The friend I was working with on this required days of data.

As for rsdmm, I got the timestamp issue under control by running the following (free version) of an app called "Timer Resolution"
http://www.lucashale.com/timer-resolution/

Never could solve the com port mystery, but I didn't really care aas long as the ohms and amps data were correct.

As an aside, for anyone who likes the realtime graphing feature of Meterview (like my friend does) I ended up using the following "LiveGraph" program along with rsdmm and got pretty good results. However, I really wished I was more of a programmer so I could combine the two into one standalone program.
http://www.live-graph.org/


----------



## Mr Happy (Mar 25, 2013)

Bryan_W said:


> Never could solve the com port mystery, but I didn't really care as long as the ohms and amps data were correct.



There is no mystery about the com ports. The com port is not written to the output data.

The first number is a time stamp in the format HH:MM:SS.ss, where .ss is the fractional part of the seconds.

The second number is the same time stamp in seconds alone for ease of plotting.

The third, fourth, fifth and sixth entries are for the first meter. They are, in order:

- the number of samples collected in the current interval
- the average value of those samples
- the lowest sample value collected
- the highest sample value collected

It is a mystery to me why some of your data shows the number of samples as 4 when the expected number should be more like 230, and I have no idea why this should be. Sorry.


----------



## Mr Happy (Mar 25, 2013)

Bryan_W said:


> As an aside, for anyone who likes the realtime graphing feature of Meterview (like my friend does) I ended up using the following "LiveGraph" program along with rsdmm and got pretty good results. However, I really wished I was more of a programmer so I could combine the two into one standalone program.
> http://www.live-graph.org/



That LiveGraph app looks interesting. I'll check it out.

I was thinking about making RSDMM into an Excel plug-in so it could record data directly to a sheet and plot the graph live, but I have never got around to it. Maybe one day...


----------



## Bryan_W (Mar 26, 2013)

Thanks for both replies And thanks for clearing up my misunderstanding of those columns.

As for the livegraph:
1. I had better luck with the 2.0 beta version.
2. If I remember correctly, on both versions I sometimes had trouble getting Livegraph to "do it's thing". I think it had something to do with having to tell it what logfile to read before rsdmm writes the first (maybe second) row.


----------



## intdsys (Feb 8, 2014)

If anyone is still watching this thread, I was able to get a Tek Power TP4000ZC multimeter on ebay for under $40. It has basically the same kind of bit-to-LCD segment protocol as the Radio Shack 22-812 but uses different bits. You can figure out which bits control which LCD segments by decoding the decimal values it outputs for some fixed reading (i.e. 000.0 mV). In addition to voltage readings, you can figure out bits for other types of measurements to monitor current draw, resistance, etc.

Geoff


----------

