top graphic
top graphicPicture of cloudstop graphic

HOME | ESR Meters | LCR Meters | Continuity-Low Ohm Meter |Geiger Counters | Tektronix | Metal Detectors | Contact

Projects | Other Lab Tools | Solar | Master-Slave Switch | Semiconductor

Schematics

Source Code

PCB

Box

Videos

Download Source Code
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
#include <avr/io.h>
#include <util/delay.h>
#include <EEPROM.h>
#include <SPI.h>
#include <Wire.h>
#include <MCP342x.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

// ---------------------------------------------------------------------------------------------
//    some macros definitions
// --------------------------------------------------------------------------------------------- 
#define setPin(b) ( (b)<8 ? PORTD |=(1<<(b)) : PORTB |=(1<<(b-8)) )
#define setPinAnalog(b) (  PORTC |=(1<<(b))  )
#define clrPin(b) ( (b)<8 ? PORTD &=~(1<<(b)) : PORTB &=~(1<<(b-8)) )
#define clrPinAnalog(b) ( PORTC &=~(1<<(b)) )
#define tstPin(b) ( (b)<8 ? (PORTD &(1<<(b)))!=0 : (PORTB &(1<<(b-8)))!=0 )
#define tstPinAnalog(b) ( (PORTC &(1<<(b)))!=0 )
#define FastDigitalWrite(b,How) if (How) setPin(b); else clrPin(b)

#ifndef F_CPU
#define F_CPU 16000000UL
#endif

// ---------------------------------------------------------------------------------------------
//    pins definition
// --------------------------------------------------------------------------------------------- 
#define  BUZZER       6
#define  BUTTON       3
#define  TRANSISTOR   3
#define  AOP          2

// ---------------------------------------------------------------------------------------------
//    display constants for a 128x32 oled module
// --------------------------------------------------------------------------------------------- 
#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 32 // OLED display height, in pixels
#define OLED_RESET     4 // Reset pin # (or -1 if sharing Arduino reset pin)
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

// ---------------------------------------------------------------------------------------------
//    analog to digital constants
// --------------------------------------------------------------------------------------------- 
// 0x68 is the default address for all MCP342x devices
uint8_t address = 0x68;
MCP342x adc = MCP342x(address);
unsigned long probes_compensation;   // 80mohms de sonde => 1V sortie aop, 5mV par count
unsigned long adc_val;   // 0-65535+

unsigned int button_delay;  // to detect long press of the button
float Vbat;
float Rx;

void setup( void)
{
  Serial.begin(9600);      // open the serial port at 9600 bps:

  pinMode( BUTTON, INPUT_PULLUP);		// input en D3 button
  pinMode( BUZZER, OUTPUT);		      // output on D6 buzzer
  
  PORTD |= (1 << PORTD3);
  DDRC |= (1 << DDC3);				      // analog output 3 for pnp seeding
  DDRB |= (1 << DDC2);				      // analog input 2 for adc sampling
  DDRB |= (1 << DDC0);				      // analog input 0 for adc vbat
  PORTC &= ~(1 << PORTC3);
  ADCSRA = (1 << ADEN) | (1 << ADPS2) | (1 << ADPS0); // sets adc prescaler to 16 for max speed

// ---------------------------------------------------------------------------------------------
//    reads the stored probe compensation from the arduino eeprom
// --------------------------------------------------------------------------------------------- 
  probes_compensation = EEPROM.read( 0); // read probes compensation value from eeprom at startup
  probes_compensation += EEPROM.read( 1) << 8;
  probes_compensation += EEPROM.read( 2) << 16;
  probes_compensation += EEPROM.read( 3) << 24;
  //Serial.print("Probes:");Serial.println(probes_compensation);
  
  noTone( BUZZER);
  
  Wire.begin();                                  // join I2C bus
  
// ---------------------------------------------------------------------------------------------
//    initialize mcp3421 ADC
// --------------------------------------------------------------------------------------------- 
  MCP342x::generalCallReset();
  delay(1); // MC342x needs 300us to settle, wait 1ms
  
// ---------------------------------------------------------------------------------------------
//    initialize OLED display
// --------------------------------------------------------------------------------------------- 
  display.begin(SSD1306_SWITCHCAPVCC, 0x3c, 0);  // initialize display @ address 0x3c, no reset
  display.clearDisplay();
  display.display();

// ---------------------------------------------------------------------------------------------
//    powers pnp transistor
// --------------------------------------------------------------------------------------------- 
    clrPinAnalog( TRANSISTOR);
    _delay_ms(1);
}

void loop (void)
{
// ---------------------------------------------------------------------------------------------
//    measures battery voltage
// --------------------------------------------------------------------------------------------- 
    Vbat = analogRead(A0)*10.0/1024.0;    // 2:1 divider (10V FS) on 9V battery

// ---------------------------------------------------------------------------------------------
//    read ADC mcp3421 from i2c bus
// --------------------------------------------------------------------------------------------- 
    long value = 0;
    MCP342x::Config status;
    // Initiate a conversion; convertAndRead() will wait until it can be read
    uint8_t err = adc.convertAndRead(MCP342x::channel1, MCP342x::oneShot,
           MCP342x::resolution16, MCP342x::gain1, 1000000, value, status);
    adc_val = value;
    
// ---------------------------------------------------------------------------------------------
//    reads button state to engage REL mode
// --------------------------------------------------------------------------------------------- 
    if (digitalRead( BUTTON) == 0) // check D3 button state
    {
      noTone( BUZZER);
      display.clearDisplay();
      DisplayStr("REL");
      display.display();
      delay(500);
      probes_compensation = adc_val;
      button_delay = 0;
      while ((digitalRead( BUTTON) == 0) && (button_delay<10))
      {
         button_delay++;
         delay(100);
      }
// ---------------------------------------------------------------------------------------------
//    stores probe compensation in eeprom if long press button
// --------------------------------------------------------------------------------------------- 
      if (button_delay>8)
      {
        display.clearDisplay();
        DisplayStr("STORE");
        display.display();
        delay(500);
        EEPROM.update( 0, (byte) adc_val);  // stores probes compensation value in eeprom if different
        EEPROM.update( 1, (byte) adc_val >> 8);
        EEPROM.update( 2, (byte) adc_val >> 16);
        EEPROM.update( 3, (byte) adc_val >> 24);
        noTone( BUZZER);
        tone( BUZZER, 2000, 200);    // warn users of the eeprom update
        noTone( BUZZER);
        tone( BUZZER, 1000, 200);
        noTone( BUZZER);
        display.clearDisplay();
        DisplayStr("OK");
        display.display();
        delay(500);
      }
    }
// ---------------------------------------------------------------------------------------------
//    substract probe compensation from adc read value
// --------------------------------------------------------------------------------------------- 
    long real_adc = adc_val - probes_compensation;
    if (real_adc<=0) real_adc = 0;
    
    float volts = 2.048 * ((float)(real_adc)/32768);    // converts adc reading to volts
// ---------------------------------------------------------------------------------------------
//    converts volts reading to resistance using inverse R approximation
// --------------------------------------------------------------------------------------------- 
   Rx = 0.4595*volts + 0.8165*pow(volts,2) + (-0.595)*pow(volts,3) + 0.2596*pow(volts,4);
    
// ---------------------------------------------------------------------------------------------
//    final adjustment after reading the real value from the probes
// --------------------------------------------------------------------------------------------- 
    float lcr_measured_res = 1.005;   // calibrated using a 1 ohm resistor
    float shorty_measured_res = 0.853;
    float calibration_factor = lcr_measured_res/shorty_measured_res;
    Rx = Rx * calibration_factor;          

// ---------------------------------------------------------------------------------------------
//    converts resistance to tone frequency 0 (open probes) to 4KHz (shorted probes)
// --------------------------------------------------------------------------------------------- 
    if (adc_val>32500) {
      Rx = 9999;
      noTone( BUZZER);
    } else {
      long adc2 = adc_val/32; // maps 16 bits into 10
      // maps adc value to tone frequency from 0 to 4KHz exponential way for better difference in low ohms
      float ftone = -386.2467 + (4000 - -386.2467)/(1 + pow(adc2/26.40582,0.6354983));
      tone( BUZZER, ftone);
    }
     
// ---------------------------------------------------------------------------------------------
//    display resistance value on oled
// --------------------------------------------------------------------------------------------- 
    display.clearDisplay();                // ... and display result
    BatteryIcon((Vbat-6.5)/(9.0-6.5));     // 6.5V = 0%, 9V = 100%
    display.setTextSize(3);
    display.setTextColor(WHITE);
    display.setCursor(0,10);
    if (Rx>1000) {
      display.print("-----");
      noTone( BUZZER);
    } else {
      display.print(Rx,4);      
    }
    DisplayOmega();
    display.display();

}

void BatteryIcon(float charge)
// ---------------------------------------------------------------------------------------------
//   Draw a battery charge icon into the display buffer without refreshing the display
//     - charge ranges from 0.0 (empty) to 1.0 (full)
// ---------------------------------------------------------------------------------------------
  {
    int w = constrain(charge, 0.0, 1.0)*16;  // 0 to 16 pixels wide depending on charge
    if (charge<0) {
      w = 0;
    }
    display.drawRect(100, 0, 16, 7, WHITE);  // outline
    display.drawRect(116, 2,  3, 3, WHITE);  // nib
    display.fillRect(100, 0,  w, 7, WHITE);  // charge indication
  }

void DisplayOmega( void)
{
    static const unsigned char PROGMEM omega_bmp[] =     // omega (ohm) symbol
    { B00000011, B11000000,
      B00001111, B11110000,
      B00111000, B00011100,
      B01100000, B00000110,
      B01100000, B00000110,
      B11000000, B00000011,
      B11000000, B00000011,
      B11000000, B00000011,
      B11000000, B00000011,
      B11000000, B00000011,
      B01100000, B00000110,
      B01100000, B00000110,
      B01100000, B00000110,
      B00110000, B00001100,
      B11111000, B00011111,
      B11111100, B00111111 };
      
    // display omega (ohms) symbol
    display.drawBitmap(110, 14, omega_bmp, 16, 16, WHITE);

}

void DisplayStr(char *s)
// ---------------------------------------------------------------------------------------------
//    Adds a string, s, to the display buffer without refreshing the display @ (0,20)
// --------------------------------------------------------------------------------------------- 
  {
    display.setTextSize(3);              
    display.setTextColor(WHITE);
    display.setCursor(0,10);
    display.print(s);
  }

Shorty with Display Project

(original shorty here)

Shorty with Display Project

(original shorty here)

compteur