Electrical Engineering advice - 36V auto range ohm meter

Board:
Mini Arduino Pro (3.3v/5v)

Scope:
Measure direct short; measure resistance of soft ground fault through water; measure resistance of hard ground fault on building structure.

Electrical engineering knowledge:
LOW; 30+ years of playing around and still low enough to let the smoke out and start over.

I found this as a great foundation for auto range:

My plan was to multiplex the common collectors: (see next post when 5min rule expires)

Concerns:
1.) I’m certain my design is incorrect; I can find a multitude of 5V voltage dividers which are arduino compatible but none specifically to my 36V multiplex project.

2.) standard NPN 2N222 can only handle 100mA (considering using this).

My google isn’t broken but my queries may be incorrect.
Any advice and direction appreciated.

You have drawn emitter followers. Voltage on the emitter of Q1 is always ~0.65volt lower than the base (Pin2).

I think you are looking for "high-side" switches (PNP). Not sure what the 36volt has to do with anything. Leo..

Thanks for the input.

I did see the common emmiter configuration but I was unsure how to configure the circuit in such a way to multiplex the pins and still keep the common leads for measuring.

Why 36V? The devices in the field communicate on range from 30 -40 volts and distances from the faulted device could reach 2000 feet or more; faults can also exist on the input side of the device.

I'm just of many lowly techs who work on finding these type faults and wanted to build a miniture wearable meter to keep hands free as opposed to carrying around an analog meter and other tools; the analog meter can detect faults in water while the digital cannot.

You’d be much better off using logic-level MOSFET’s for this job - eg the 2N7000

Allan

Thanks for the suggestion, Allen; I downloaded the spec.

It took me a couple of hours to arrange Leo's suggestion in my grey matter. Implementing the NPN version of his suggestion, I believe I'm on the correct path- if not, please warn me before I perform a disastrous field test.

Note: Resistor on base not shown

Thanks for the help!

You could blow the Arduino pin if "field resistance" is low enough. A 33k resistor between the A0 box you have drawn and the real analogue pin could prevent that. Leo..

Great catch, Leo; 97% of the time the field resistance will be considered a "dead short". I do have a question - I understand the 33k will drop the amperage but it's still 36v to the A0 pin since no transistors are turned on to provide a voltage divider; wouldn't this damage it also? Would it be better to add a resistor to Q1 and assume there is a short in the field before allowing the code to move forward with the multiplexing? In that scenario, I would consider changing Q1 to a PNP, as you suggested earlier.

There was an educated reason you chose 33k- I just want to learn why.

Just thinking out-loud.

Current will be limited to about 1mA. The internal pin protection will clamp this to VCC.

I still don't understand why the "gearbox" design. The A/D has a 10-bit resolution (1024 levels). A simple 33k:4k7 voltage divider could be enough. Leo..

Yes - you can extend the dynamic range of an a/d by use of a precision switched attenuator as you suggest.

But if you want accuracy to the 10 bit ( 0.1%) level provided by the arduino's a/d, you have to use resistors better than that. And the switching devices must not provide a significant part of that resistance. And no offset voltage - bipolars are out.

You'll have to use a precision reference voltage as well. Temperature compensated for good stuff.

The arduino's 5v supply volts is only +/- 5% if you're lucky. The internal 1.1v ref is more stable, but needs to be calibrated as it's absolute accuracy is poor.

You can buy such resistors and devices ....... not cheaply.

Or you could use a higher resolution a/d and a fixed precision attenuator to the accuracy and resolution required .

The above suggests why precision testgear isn't cheap.

How accurate do you need to be? How much do you want to spend?

Allan

JMeller: measure resistance of soft ground fault through water measure resistance of hard ground fault on building structure.

Seems accuracy is not in the picture. Leo..

Then buy a 5 quid DMM from ebay. Plenty good enough.

Allan

allanhurst: Then buy a 5 quid DMM from ebay. Plenty good enough.

Allan

No, that's not 36V, it will not be measuring resistance so much as ground voltage differences.

So a multimeter plus a 36V supply and current-limiting resistor for the hard-short case?

I'm not married to this design, so I am open to better suggestions; I've performed an extensive amount of reading and figured this option gave me some flexibility.

The crux of the design just has to have a small footprint (wearable on the wrist), capable of measuring between a conductor in water and the building structure, direct shorts, and measuring for five 'ball park" values of end-of-line resistors - 3.3k, 4.7k, 6.8k, 10k, and 15k. I figure total investment will be less than $50USD.

Thanks guys.

OK… now we know what you want!

to build it you need :

1/ a small power source - eg a couple of biggish coin cells or a LiPo - 3.7 volts or more . Arduinos will run on that.
2/ a psu capable of 30+ volts - look on eg ebay for boost convertors.
3/ a current limiting resistor - say 39k to give about 1mA maximum
4/ a load resistor - perhaps 1k to give a maximum voltage of about 1v.
5/ a voltage measuring device - an arduino analog input using the 1.1v reference
6/ a display,

current into the 1k load = Vsupply/(resistance of loop + 39k)
edit : that should be : current into the 1k load = Vsupply/(resistance of loop + 39k + 1k)

Hence you can infer the resistance of the loop…

It would be sensible to measure the voltage produced by the boost convertor with a separate fixed voltage divider to another analog input, and use this to scale the measured voltage at the sensing 1k load - then the actual high voltage generated cancels out. It’s all resistor ratios.

1% resistors would be a good idea.
.

Suggest a 16x2 LCD as the display.

Once built , measure a direct short and various known resistors, and use those as calibration points. Adjust constants in your code as appropriate,

Could all be built into a little project box.

< $20 USD?

regards

Allan

Just about to post almost exactly what your're suggesting.

An 8Mhz Arduino, powered with one LiPo cell. A micro-power ~36volt boost converter with the output via an 18k resistor to one probe. The other probe via another 18k resistor to the analogue input (=36k total). 1k from analogue input to Arduino ground. 100n cap across that resistor.

There are tiny Oled displays. Leo..

Awesome, gentlemen! Thanks for the tips. I've never used a boost converter; game changer.

Agree - the Oled and the arduino micro were central to the design.

I'm off to do my homework on the boost converter. I'll report back in a few weeks with a finished product.

Thanks again, guys!

allanhurst:
OK… now we know what you want!

to build it you need :

1/ a small power source - eg a couple of biggish coin cells or a LiPo - 3.7 volts or more . Arduinos will run on that.
2/ a psu capable of 30+ volts - look on eg ebay for boost convertors.
3/ a current limiting resistor - say 39k to give about 1mA maximum
4/ a load resistor - perhaps 1k to give a maximum voltage of about 1v.
5/ a voltage measuring device - an arduino analog input using the 1.1v reference
6/ a display,

current into the 1k load = Vsupply/(resistance of loop + 39k)
edit : that should be : current into the 1k load = Vsupply/(resistance of loop + 39k + 1k)

Hence you can infer the resistance of the loop…

It would be sensible to measure the voltage produced by the boost convertor with a separate fixed voltage divider to another analog input, and use this to scale the measured voltage at the sensing 1k load - then the actual high voltage generated cancels out. It’s all resistor ratios.

1% resistors would be a good idea.
.

Suggest a 16x2 LCD as the display.

Once built , measure a direct short and various known resistors, and use those as calibration points. Adjust constants in your code as appropriate,

Could all be built into a little project box.

< $20 USD?

regards

Allan

Hello, how is current into the 1k load = Vsupply/(resistance of loop + 39k + 1k)? Isn’t 39k is in between the divider and the A0 and not in series with the load?
Also how to measure the supply voltage with another voltage divider without affecting the supply?

I am also working on a simillar project where the current in low resistance Rx is already supplied with an external power source.

See the enclosed circuit.

Yes - the measuring part will probably alter the supply volts, but without it you don’t know what that voltage is.

I take it you can do the sums using ohm’s law?

Allan

loopmeas.pdf (19.6 KB)

I was able to return to this project this weekend - after holding onto parts for nearly 2 months; life happens.
Below is the code. Please advise of smarter programming techniques.

Fact: Arduino compiler - 1.8.1
Fact: mini Arduino pro
Fact: OLED amazon.com
Fact: OLED library (IIC_OLED.zip) - adafruit
Fact: 36v booster - not yet implemented.

Demonstration video: simple meter

/*********************************************************************
This is an example for our Monochrome OLEDs based on SSD1306 drivers

  Pick one up today in the adafruit shop!
  ------> http://www.adafruit.com/category/63_98

This example is for a 128x64 size display using I2C to communicate
3 pins are required to interface (2 I2C and one reset)

Adafruit invests time and resources providing this open source code, 
please support Adafruit and open-source hardware by purchasing 
products from Adafruit!

Written by Limor Fried/Ladyada  for Adafruit Industries.  
BSD license, check license.txt for more information
All text above, and the splash screen must be included in any redistribution
*********************************************************************/

#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

#define OLED_RESET 4
Adafruit_SSD1306 display(OLED_RESET);

//#define NUMFLAKES 10
//#define XPOS 0
//#define YPOS 1
#//define DELTAY 2


#define LOGO16_GLCD_HEIGHT 16 
#define LOGO16_GLCD_WIDTH  16 


#if (SSD1306_LCDHEIGHT != 64)
#error("Height incorrect, please fix Adafruit_SSD1306.h!");
#endif

int analogPin= 0;
int raw= 0;
int Vin= 5;
float Vout= 0;
float R1= 39000;
float R2= 0;
float old_R2=0;
float MYbuffer= 0;
float R2buff[10];
float sum= 0;
int slot;
char R2char[10];
char oldR2char[10];

bool shortckt;
bool openckt;

void setup()   {                
  Serial.begin(9600);
  delay(200);
  //for(int i=0; i<255; i++){Serial.print(i); Serial.print(':'); Serial.println(char(i));}
  
  display.begin(SSD1306_SWITCHCAPVCC, 0x3C);  // initialize with the I2C addr 0x3D (for the 128x64)
    display.display(); // show splashscreen per Ladyada's request; support her time/investment via purchasing power.
    delay(2000);
  display.clearDisplay();
 
  display.setTextSize(1);
  display.setTextColor(WHITE);
  display.setCursor(0,5); display.print("Resistance: "); 
}

unsigned long uptime = 0;
unsigned long old_uptime = 0;
void loop() {

  raw= analogRead(analogPin);
 
    MYbuffer= raw * Vin;
    Vout= (MYbuffer)/1024.0;
    MYbuffer= (Vin/Vout) -1;
    R2= R1 * MYbuffer;
    R2buff[slot] = R2;
    slot++; 
    if(slot == 10){
      GetAVGr2();
      }
}

void clearScreen(){
    display.clearDisplay();
    display.setTextSize(1);
    display.setTextColor(WHITE);
    display.setCursor(0,5); display.print("Resistance: "); 
}

void GetAVGr2(){
  sum =0;
  for(slot=0; slot<10; slot++){
    sum = sum + R2buff[slot];
  }
  sum = sum/10;
  slot = 0;
  int real = sum;
  if(real>0 && real <500)  {printSHORT();}else{if(shortckt == true){clearScreen();} shortckt = false;}
  if(real == 0){printOPEN() ;}else{if(openckt == true){clearScreen();} openckt = false;}
  if(shortckt == true){return;}
  if(openckt == true){return;}

  if(sum>=1000){sum = sum/1000; real = sum;}

  dtostrf(sum, 6, 2, R2char);
  printR2();
  dtostrf(sum, 6, 2, oldR2char);

}
  
void printR2(void){

  R2char[6] = 'K';
  for (int i=0; i<10; i++){
    Serial.print(R2char[i]);
    if(R2char[i] != oldR2char[i]) {selectValue(i, oldR2char[i], R2char[i]);}
  }
  delay(200);
}

void selectValue(int caseNUM, char oldCHAR, char newCHAR){
  display.setTextSize(2);
  int xval = 10;
  int sep = 15;
  switch (caseNUM){

    case 0:
        WriteValue(BLACK, xval + (sep*caseNUM), oldCHAR);
        WriteValue(WHITE, xval + (sep*caseNUM), newCHAR);
    break;
    
    case 1:
        WriteValue(BLACK, xval + (sep*caseNUM), oldCHAR);
        WriteValue(WHITE, xval + (sep*caseNUM), newCHAR);
    break;

    case 2:
        WriteValue(BLACK, xval + (sep*caseNUM), oldCHAR);
        WriteValue(WHITE, xval + (sep*caseNUM), newCHAR);
    break;

    case 3:
        WriteValue(BLACK, xval + (sep*caseNUM), oldCHAR);
        WriteValue(WHITE, xval + (sep*caseNUM), newCHAR);
    break;

    case 4:
        WriteValue(BLACK, xval + (sep*caseNUM), oldCHAR);
        WriteValue(WHITE, xval + (sep*caseNUM), newCHAR);    
    break;

    case 5:
        WriteValue(BLACK, xval + (sep*caseNUM), oldCHAR);
        WriteValue(WHITE, xval + (sep*caseNUM), newCHAR);
    break;

    case 6:
        WriteValue(BLACK, xval + (sep*caseNUM), oldCHAR);
        WriteValue(WHITE, xval + (sep*caseNUM), newCHAR);
    break;

    case 7:
        WriteValue(BLACK, xval + (sep*caseNUM), oldCHAR);
        WriteValue(WHITE, xval + (sep*caseNUM), newCHAR);
    break;

    case 8:
        WriteValue(BLACK, xval + (sep*caseNUM), oldCHAR);
        WriteValue(WHITE, xval + (sep*caseNUM), newCHAR);
    break;

    case 9:
        WriteValue(BLACK, xval + (sep*caseNUM), oldCHAR);
        WriteValue(WHITE, xval + (sep*caseNUM), newCHAR);
    break;
  }
  display.display();
}

void WriteValue(uint16_t color, int x, char CHAR){
  
    display.setTextColor(color);
    display.setCursor(x,20);
    display.print(CHAR);
}

void printSHORT(){
  Serial.println("SHORT");
    if(shortckt == true){return;}
    
    memset(R2char, '\0', sizeof(R2char));
    memset(oldR2char, '\0', sizeof(oldR2char));
    
    display.clearDisplay();
    display.setTextSize(1);
    display.setTextColor(WHITE);
    display.setCursor(0,5); display.print("Resistance: "); 
    
    display.setTextSize(3);
    display.setCursor(10,20); 
    display.print("SHORT");
    display.display();
    shortckt = true;
}
  
void printOPEN(){
  Serial.println("OPEN");
    if(openckt == true){return;}

    memset(R2char, '\0', sizeof(R2char));
    memset(oldR2char, '\0', sizeof(oldR2char));
    
    display.clearDisplay();
    display.setTextSize(1);
    display.setTextColor(WHITE);
    display.setCursor(0,5); display.print("Resistance: "); 
    
    display.setCursor(10,20); 
    display.setTextSize(3);
    display.print("OPEN");
    display.display();
    openckt = true;
}