Categories
Statistics
Flag Counter
Since 08.08.2014
Counts only, if "DNT = disabled".

Your IP is 44.213.60.33
ec2-44-213-60-33.compute-1.a
Info
Valid HTML 4.01 Transitional Creative Commons Lizenzvertrag
rss
เราจะทำแบบวิศวกรผู้ยิ่งใหญ่
We love the King
15. July 2024
Your valuable opinion :
3.5 stars

Avg. 3.58 from 12 votes.



Arduino-Ipamod_2022.php    19106 Bytes    04-06-2024 19:54:28


Arduino Automatic Capacitance Meter : Ipamod 2022


A final Thesis of my apprentice





Arduino Automatic Capacitance Meter


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




Arduino IPAmod2022

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.


Arduino IPAmod2022

View inside




✈ The Measurement Sequence




Arduino IPAmod2022

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 ?

 
t1 = 6577 d

t2 = 589 ms

★ ★ ★  Copyright © 2006 - 2024 by changpuak.ch  ★ ★ ★

Impressum