Arduino-Ipamod_2022.php 19106 Bytes 04-06-2024 19:54:28
Arduino Automatic Capacitance Meter : Ipamod 2022
A final Thesis of my apprentice
This is a final work, an apprentice is doing in our lab. The task was assembly of one unit as well
as writing the complete Arduino sketch. The time limit was 120 hours to complete (inclusive documentation).
Swiss law demands for a lockdown of the original work, so this text, measurements and the Arduino / Genuino sketch are
some kind of "Musterlösung" of the webmaster. And yes. Successfully passed :-)
✈ The building Blocks • Functional Description
The mastermind of this design is of course the Arduino Nano Every.
It has to create the correct sequence of charging, counting the pulses and discharging the capacitor.
To achieve that task, we have a precision voltage reference, built around an ADR435ARZ.
With a set of precision Resistors (910 kΩ, 91 kΩ, 9.1 kΩ, 910 Ω and 91 Ω)
the Arduino shall choose a suiteable range to charge the capacitor.
Also derived from the reference are two voltages (1/3 Uref and 2/3 Uref). They are used for a comparator
to open a gate to a counter (74HC4040 x 3), when the charging voltage across the capacitor is in between those values.
This version uses a 64 MHz xtal oscillator as a timebase. (Up to 90 MHz deems possible - if you can get
those fast counters)
The D-Sub-9 connecter allows for connection to our Envico System.
View inside
✈ The Measurement Sequence
Between ⅓ Uref and ⅔ Uref, the comparator opens the gate of the counter
✈ Downloads
✈ Arduino Sketch - The Code
Double click on code to select ...
/* //////////////////////////////////////////////////////////////////
ARDUINO/Genuino Project "IPAMOD 2022", an automatic capaciy meter
*** MUSTERLÖSUNG ***
https://www.changpuak.ch/electronics/Arduino-Ipamod-2022.php
Software Version 9.9
02.04.2022 by ALEXANDER SSE FRANK
////////////////////////////////////////////////////////////////// */
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SH1106.h>
// CONNECTIONS OLED
#define OLED_MOSI 11
#define OLED_CLK 13
#define OLED_DC 4
#define OLED_CS 3
#define OLED_RESET 5
// THE RANGES
int Range = 1 ;
// Range 1 uses 91 R
// Range 2 uses 910 R
// Range 3 uses 9k1
// Range 4 uses 91k
// Range 0 uses 910k, THIS IS ALWAYS "ON"
const int Range1Pin = 10 ;
const int Range2Pin = 9 ;
const int Range3Pin = 8 ;
const int Range4Pin = 7 ;
const int DisChargePin = 12 ;
const int EnableChargPin = 6 ;
// COUNTER
const int Gate = A0 ;
const int Reset = A2 ;
const int OVR0 = A6 ;
const int OVR1 = A3 ;
const int OVR2 = A7 ;
const byte AdrLoBytes = 0x27 ; // MCP 23017
const byte AdrHiBytes = 0x20 ; // MCP 23017
unsigned long Counts = 0 ;
double Capacity = 0.0 ;
int CapUnit = 3 ; // THIS IS ABOVE pF, i.e. 3 -> nF, 6 -> uF, ...
Adafruit_SH1106 display(OLED_MOSI, OLED_CLK, OLED_DC, OLED_RESET, OLED_CS);
#if (SH1106_LCDHEIGHT != 64)
#error("Height incorrect, please fix Adafruit_SH1106.h!");
#endif
boolean debug = false ;
// ZERO OFFSET COMPENSATION VALUES
float ZERO[5] = { 0.0, 0.0, 0.0, 0.0, 0.0 } ;
const int ZEROPin = 2 ;
volatile bool NeedZERO = false ;
// /////////////////////////////////////////////////////////////////////
// SUBROUTINES
// /////////////////////////////////////////////////////////////////////
float Reff = 1.0 ;
void SetR()
{
if(Range < 0 ) Range = 0 ;
if(Range > 4 ) Range = 4 ;
switch(Range)
{
case 0:
digitalWrite(Range1Pin, LOW) ;
digitalWrite(Range2Pin, LOW) ;
digitalWrite(Range3Pin, LOW) ;
digitalWrite(Range4Pin, LOW) ;
digitalWrite(DisChargePin, LOW) ;
digitalWrite(EnableChargPin, HIGH) ;
Reff = 910000 ; // 910k // nüüt
break ;
case 1:
digitalWrite(Range1Pin, HIGH) ;
digitalWrite(Range2Pin, LOW) ;
digitalWrite(Range3Pin, LOW) ;
digitalWrite(Range4Pin, LOW) ;
digitalWrite(DisChargePin, LOW) ;
digitalWrite(EnableChargPin, HIGH) ;
Reff = 82727.27 ; // 910k // 91kR
break ;
case 2:
digitalWrite(Range1Pin, LOW) ;
digitalWrite(Range2Pin, HIGH) ;
digitalWrite(Range3Pin, LOW) ;
digitalWrite(Range4Pin, LOW) ;
digitalWrite(DisChargePin, LOW) ;
digitalWrite(EnableChargPin, HIGH) ;
Reff = 9009.90 ; // 910k // 9k1
break ;
case 3:
digitalWrite(Range1Pin, LOW) ;
digitalWrite(Range2Pin, LOW) ;
digitalWrite(Range3Pin, HIGH) ;
digitalWrite(Range4Pin, LOW) ;
digitalWrite(DisChargePin, LOW) ;
digitalWrite(EnableChargPin, HIGH) ;
Reff = 909.09 ; // 910k // 910R
break ;
case 4:
digitalWrite(Range1Pin, LOW) ;
digitalWrite(Range2Pin, LOW) ;
digitalWrite(Range3Pin, LOW) ;
digitalWrite(Range4Pin, HIGH) ;
digitalWrite(DisChargePin, LOW) ;
digitalWrite(EnableChargPin, HIGH) ;
Reff = 90.99 ; // 910k // 91R
break ;
}
}
void UpDateCounts()
{
byte aux = 0x00 ;
Counts = 0x00000000 ;
Wire.beginTransmission(AdrHiBytes) ; // PORT B COUNTS @ X5
Wire.write(0x13) ;
Wire.endTransmission() ;
Wire.requestFrom(AdrHiBytes, 1) ;
if (Wire.available()) aux = Wire.read() ;
Counts = aux ;
Counts = Counts << 8 ;
Wire.beginTransmission(AdrHiBytes) ; // PORT A COUNTS @ X5
Wire.write(0x12) ;
Wire.endTransmission() ;
Wire.requestFrom(AdrHiBytes, 1) ;
if (Wire.available()) aux = Wire.read() ;
Counts |= aux ;
Counts = Counts << 8 ;
Wire.beginTransmission(AdrLoBytes) ; // PORT B COUNTS @ X4
Wire.write(0x13) ;
Wire.endTransmission() ;
Wire.requestFrom(AdrLoBytes, 1) ;
if (Wire.available()) aux = Wire.read() ;
Counts |= aux ;
Counts = Counts << 8 ;
Wire.beginTransmission(AdrLoBytes) ; // PORT A COUNTS @ X4
Wire.write(0x12) ;
Wire.endTransmission() ;
Wire.requestFrom(AdrLoBytes, 1) ;
if (Wire.available()) aux = Wire.read() ;
Counts |= aux ;
if(debug) Serial.println(Counts,DEC) ;
}
void ResetCounter()
{
digitalWrite(Reset, HIGH) ;
delay(10) ;
digitalWrite(Reset, LOW) ;
delay(10) ;
}
void UpdateCapacity()
{
// ln(2) * tau = counts * 1 / Fosc
// tau = counts / ( Fosc * ln(2))
// R * C = counts / ( Fosc * ln(2))
// C = counts / ( Fosc * ln(2) * R )
// Fosc = 64 MHz, ln(2) = 0.69314718056
// C = counts / ( 44361419.5558 * R )
// C[pF] = 1E12 * counts / ( 44361419.5558 * R )
// C[pF] = counts * 0.02477154946, when using 910kR
switch(Range)
{
case 0 : // 910kR, pF
Capacity = Counts * 24.77154946 / 1000.0 ;
Capacity -= ZERO[0] ;
CapUnit = 0 ;
break;
case 1 : // 91kR, nF
Capacity = Counts * 2.7248704412 / 1000.0 ;
Capacity -= ZERO[1] ;
CapUnit = 3 ;
break;
case 2 : // 9k1, nF
Capacity = Counts * 2.50192649605 / 1000.0 ;
Capacity -= ZERO[2] ;
CapUnit = 3 ;
break;
case 3 : // 910R, nF
Capacity = Counts * 24.79632101528 / 1000.0 ;
Capacity -= ZERO[3] ;
CapUnit = 3 ;
break;
case 4 : // 91R, uF
Capacity = Counts * 247.74026620760 / 1000000.0 ;
Capacity -= ZERO[4] ;
CapUnit = 6 ;
break;
}
// if(debug) Serial.println(Capacity,3) ;
}
void DisCharge(unsigned long HowLong)
{
digitalWrite(DisChargePin, HIGH) ;
digitalWrite(EnableChargPin, LOW) ;
delay(HowLong) ;
}
void CheckRange()
{
const long GearUp = 9999 ; // Counted Pulses
const long GearDown = 120000 ; // Counted Pulses
if(Counts < GearUp)
{
Range -= 1 ; // INCREASE RESISTANCE
SetR() ;
}
if(Counts > GearDown)
{
Range += 1 ; // DECREASE RESISTANCE
SetR() ;
}
if(Counts == 0)
{
Range = 4 ; // MAXIMUM : SHORT OR LARGE
SetR() ;
}
}
void WaitGateFalling(unsigned long timeout)
{
unsigned long StopTime = millis() + timeout ;
int StatusGate = digitalRead(Gate) ;
int LastStatusGate = 0 ;
bool Flag = true ;
while(Flag)
{
LastStatusGate = StatusGate ;
StatusGate = digitalRead(Gate) ;
// CHECK FOR TIMEOUT
if(millis() > StopTime) Flag = false ;
// CHECK FOR TRANSITION
if((StatusGate == 0)&(LastStatusGate == 1)) Flag = false ;
delay(9) ;
}
}
// /////////////////////////////////////////////////////////////////////
// SUBROUTINES DISPLAY.
// /////////////////////////////////////////////////////////////////////
void UpDateDisplay()
{
int PCD = 1 ; // Pre Comma Digits
// LOG10 NEEDS MATH LIBRARY ...
if(Capacity >= 10.0000) PCD = 2 ;
if(Capacity >= 100.000) PCD = 3 ;
if(Capacity >= 1000.00) PCD = 4 ;
if(Capacity >= 10000.0) PCD = 5 ;
int ACD = 5 - PCD ;
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(WHITE);
display.setCursor(1,0);
display.println("*** IPAMOD 2022 ***");
display.drawLine(0, 12, 128, 12, WHITE);
display.setTextSize(2);
// NUMERICAL VALUE
display.setCursor(15,25);
if(Capacity < 0.0) Capacity = 0.0001 ;
display.print(Capacity,ACD);
Serial.println(Capacity, ACD) ;
// UNIT
switch(CapUnit)
{
case 0:
display.setCursor(100,25); display.print("p");
display.setCursor(115,25); display.print("F");
break ;
case 3:
display.setCursor(100,25); display.print("n");
display.setCursor(115,25); display.print("F");
break ;
case 6:
display.setCursor(100,25); display.print("u");
display.setCursor(115,25); display.print("F");
display.drawLine(100, 37, 98, 42, WHITE);
display.drawLine(101, 37, 99, 42, WHITE);
break ;
case 9:
display.setCursor(100,25); display.print("m");
display.setCursor(115,25); display.print("F");
break ;
}
display.drawLine(0, 52, 128, 52, WHITE);
// DISPLAY RESISTANCE USED
display.setCursor(0,56);
display.setTextSize(1);
display.print("RANGE = ");
display.print(Range,DEC);
// DISPLAY COUNTS
display.setCursor(69,56);
display.print(Counts,DEC);
display.display() ;
}
// /////////////////////////////////////////////////////////////
// ZEROing ROUTINES
// /////////////////////////////////////////////////////////////
void ZeroDisplay()
{
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(WHITE);
display.setCursor(1,0);
display.println("*** IPAMOD 2022 ***");
display.drawLine(0, 12, 128, 12, WHITE);
display.setTextSize(2);
display.setCursor(15,25);
display.print("ZERO ...");
display.drawLine(0, 52, 128, 52, WHITE);
// DISPLAY RESISTANCE USED
display.setCursor(0,56);
display.setTextSize(1);
display.print("RANGE = ");
display.print(Range,DEC);
// DISPLAY COUNTS
display.setCursor(69,56);
display.print(Counts,DEC);
display.display() ;
}
void ZEROing()
{
// MEASURE ALL RANGES AND STORE CAPACITY
for(int i=0 ; i<4; i++)
{
Range = i ;
ZeroDisplay() ;
DisCharge(499) ;
ResetCounter() ;
SetR() ;
WaitGateFalling(999) ;
UpDateCounts() ;
UpdateCapacity() ;
ZERO[i] = Capacity ;
delay(999) ;
}
NeedZERO = false ;
}
void setup()
{
Serial.begin(115200) ;
Wire.begin() ;
// INIT PINS FOR REED RELAYS
pinMode(Range1Pin, OUTPUT) ;
pinMode(Range2Pin, OUTPUT) ;
pinMode(Range3Pin, OUTPUT) ;
pinMode(Range4Pin, OUTPUT) ;
// DISCONNECT SOURCE
pinMode(EnableChargPin, OUTPUT) ;
digitalWrite(EnableChargPin, LOW) ;
// DISCHARGE ANYTHING
pinMode(DisChargePin, OUTPUT) ;
digitalWrite(DisChargePin, HIGH) ;
// ZERO
pinMode(ZEROPin, INPUT_PULLUP) ;
// COUNTER / COMPARATOR
// HOUSEKEEPING
pinMode(Gate, INPUT) ;
pinMode(Reset, OUTPUT) ;
pinMode(OVR0, INPUT) ;
pinMode(OVR1, INPUT) ;
pinMode(OVR2, INPUT) ;
// INIT OLED
display.begin(SH1106_SWITCHCAPVCC);
// SHOW STARTUP SCREEN
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(WHITE);
display.setCursor(1,0);
display.println("*** IPAMOD 2022 ***");
display.drawLine(0, 12, 128, 12, WHITE);
display.setTextSize(1);
display.setCursor(0,21);
display.println("AUTOMATIC CAPACITANCE");
display.setCursor(0,33);
display.println("METER FOR LAB USE.");
display.setCursor(0,45);
display.println("(C) ETH QUANTUMOPTICS");
display.setCursor(0,57);
display.println("BUILT 26.03.2022");
display.display();
delay(9) ;
attachInterrupt(digitalPinToInterrupt(ZEROPin), ISRzero, FALLING) ;
Range = 1 ;
SetR() ;
DisCharge(5500) ;
UpDateDisplay() ;
}
void loop()
{
DisCharge(499) ;
ResetCounter() ;
SetR() ;
WaitGateFalling(999) ;
UpDateCounts() ;
UpdateCapacity() ;
UpDateDisplay() ;
CheckRange() ;
delay(999) ;
if(NeedZERO) ZEROing() ;
}
// /////////////////////////////////////////////////////////////
// INTERRUPT SERVICE ROUTINES
// /////////////////////////////////////////////////////////////
void ISRzero()
{
NeedZERO = true ;
}
// /////////////////////////////////////////////////////////////
// END OF FILE.
// /////////////////////////////////////////////////////////////
✈ Share your thoughts
The webmaster does not read these comments regularely. Urgent questions should be send via email.
Ads or links to completely uncorrelated things will be removed.
Your Browser says that you allow tracking. Mayst we suggest that you check that DNT thing ?