nobcha23の日記

PICマイコンやArduinoを使う電子回路遊びを紹介します

Arduino C meter 2 option 充電時間計測のCメータ追加 (3/3)

いったん挫折し外付け抵抗2.2MΩでの充電時間計測Cメータを試しました。でもやっぱりもう一度内部プルアップ抵抗利用充電時間計測Cメータをやってみました。

「ATmega内のプルアップ抵抗による充電時間コンデンサー値測定法」です。充電時間(時定数)をATmega内のプルアップ抵抗使い測れるか試しました。 pinMode(DIGITAL_WRITE_PIN, INPUT_PULLUP);コマンドでPULLUPを指定した時に内部で接続されるであろう抵抗です。WEB情報だと大体10~30kΩあるとのことです。実験では手持ちのUNOで約43kΩありました。

測定アプローチですが、次です。
1. 標準C(充電時間とADCのサンプルレートを勘案し104Jを使う)を付け、測定値から内部抵抗値を計算。
2. 覚えておいた内部抵抗値から試験Cの充電時間を計測して、容量値を計算。



I had reported "C meter refered with stray capacitance of Arduino MPU nodes" ever. That can measure small value. This time I tryed the other way to measure charging time( time constant ) by using the internal resister of Arduino. We can use it as command of pinMode(DIGITAL_WRITE_PIN, INPUT_PULLUP);. Someone said the value is 10 - 30 k ohm. Once I failed but I tried again and finished.

My approach is next.
1. To calibrate by the standard capacitor of 104J and draw the value of the internal resister of Arduino.
2. To calculate with gotten time constant of RC circuit.

接続概念図は次です。The block diagram is here.

Internal resiter C meter

まずは内部プルアップ抵抗値がいくらなのか、この容量計試作で標準コンデンサーにする104Jポリプロピレンコンデンサをはじめとし、手持ちコンデンサーで確かめることにします。これは容量計試作のスケッチ内に入れた標準Cでのキャリブレーション関数を利用します。
To divert the function of get_R() in the sketch, I draw the internal pull up resister value out, according with my stock capacitors as below.

部品表記  フランクリン 取得プルアップ
      発振LCM  抵抗値
Part name LCM data Resiter value gotten
104J    102.8nF  42.56kΩ OK
683K    70.7nF  44.47kΩ
473J   49nF  45.46kΩ
333J   32.9nF  44.12kΩ
47μ電解 45.55kΩ
102K   999.5pF  27.39kΩ  NG

τ=63.2%RCになる電圧判定をADC取得値で行っており、ADCのサンプルレートが25kサンプル/秒(40μS)なので、10000pF以下は時間関係からして測れません。また、電解コンの容量がでかいものはかなり時間(1000μFで30秒ぐらい)かかります。 I'm using ADC data for judging to go over tau: time constant value. And ADC is working 25k samples per second so we can not measure less than several thousand pF. It takes half minute to measure 1000μF.

続く試作アイデアとしては、先の浮遊容量利用容量計とこの内部プルアップ抵抗利用容量計をLOWレンジ、HIGHレンジにし「Arduino UNOとLCD Keypadシールドだけで作るC容量計」かなと思います。
There is the other trial idea to combine these capacitance meter for lower and higher range.

                      • 参考スケッチ sketch example ------------------

// Measure time when C is charging up 63.2% of 5V full
// A2 port INPUT-PULL resister shall be calibrated at first
// Created by nobcha 2023.09.04-07
// remain issue: over time?
#include

#define KEYPAD_PIN A0
#define ANALOG_READ_PIN A1
#define DIGITAL_WRITE_PIN A2
#define GND_PIN A3

// Capacitance between ANALOG_READ_PIN and Ground
// DIGITAL_WRITE_PIN will charge and discharge
float capacitance;
//Pullup resistance will vary depending on board.
//Calibrate this with known capacitor.
//const double E = 5.00; // GPIO voltage
//const double V = E * 0.632;

const int MAX_ADC_VALUE = 1023;
double R;
const int TAU = 0.632 * MAX_ADC_VALUE;
int KEY;
//LCD Keypad Shield is used
#include
LiquidCrystal lcd( 8, 9, 4, 5, 6, 7);

// Momorize internal resister value
#include
#define R_ADDR 0
unsigned int internal_r;
unsigned long charge_time, start_time;

void setup(){
pinMode(DIGITAL_WRITE_PIN, OUTPUT);
digitalWrite(DIGITAL_WRITE_PIN, LOW); // discharge
pinMode(GND_PIN, OUTPUT);
digitalWrite(GND_PIN, LOW); // Ground

Serial.begin(9600);
Serial.println("C meter 2 V2.0") ;
lcd.begin(16,2);
lcd.setCursor(0,0);
lcd.print("C meter 2 V2.0  ") ;
delay(2000);
EEPROM.get( R_ADDR, R ); // recover R value

if ( R<10000 | R>60000){ // Reasonable value?
get_R_print();
}
Serial.print("R=") ;
Serial.print(R, 03l) ;
Serial.println("ohm") ;

lcd.setCursor(0,1); // Note the internal resiter
lcd.print("R=");
lcd.print(R,03l);
lcd.print("ohm ");
}

void loop() {
lcd.setCursor(0,0);
lcd.print("Set C A1&A2--A3 ") ;
Serial.println("Set C A1&A2--A3") ;

while( (KEY=analogRead( KEYPAD_PIN))>880); // Get key input

lcd.setCursor(0,1);
lcd.print("wait ") ;
Serial.println("wait") ;
if (KEY<80){ // If right arrow key, to calibrate
get_R_print(); // Shall be set the standard capacitor of 0.1uF
Serial.print("R=") ;
Serial.print(R, 03l) ;
Serial.println("ohm") ;

lcd.setCursor(0,1);
lcd.print("R=");
lcd.print(R,03l);
lcd.print("ohm ");
}
else{
capacitance = get_C();

Serial.print("C=") ;
Serial.print(capacitance, 3) ;
Serial.println("uF");

lcd.setCursor(0,1);
lcd.print("C = ");

if(capacitance>0.01){
lcd.print(capacitance , 3);
lcd.print(" uF ");
}
else{
lcd.print(capacitance*1000000, 0);
lcd.print(" pF ");
}
}
}

float get_C(void){
//Capacitor under test between OUT_PIN and IN_PIN
//Rising high edge on OUT_PIN
pinMode(ANALOG_READ_PIN, OUTPUT);
digitalWrite(ANALOG_READ_PIN, LOW);

digitalWrite(GND_PIN, LOW); // Ground
delay(100);
pinMode(DIGITAL_WRITE_PIN, INPUT_PULLUP);
pinMode(ANALOG_READ_PIN, INPUT);

start_time = micros();
while*1 < TAU); // wait time constant
charge_time = micros() - start_time ;

pinMode(DIGITAL_WRITE_PIN, OUTPUT);
digitalWrite(DIGITAL_WRITE_PIN, LOW);
pinMode(ANALOG_READ_PIN, OUTPUT);
digitalWrite(ANALOG_READ_PIN, LOW);
return charge_time / R;

}

unsigned int get_R(void){
pinMode(ANALOG_READ_PIN, OUTPUT);
digitalWrite(ANALOG_READ_PIN, LOW);
delay(100);
pinMode(DIGITAL_WRITE_PIN, INPUT_PULLUP);
pinMode(ANALOG_READ_PIN, INPUT);
start_time = micros();

while( (KEY=analogRead(ANALOG_READ_PIN)) < TAU); // wait time constant
charge_time = micros() - start_time ; // micro second

Serial.print("ADC") ;
Serial.println( KEY) ;
Serial.print("time") ;
Serial.println(charge_time ) ;

return *2>800);
R = get_R();
EEPROM.put( R_ADDR, R ); // recover R value

delay(2000);
}


www.youtube.com

*1: analogRead(ANALOG_READ_PIN

*2:float)charge_time /(float)0.1); // 0.1uF } // get R ane print void get_R_print(void){ lcd.setCursor(0,1); lcd.print("Set STD-C&SELECT") ; Serial.println("Set STD-C&SELECT ") ; while( (KEY=analogRead( KEYPAD_PIN