抵抗値を周波数に変換する基板「Ω555」を作りました

2023/02/20に公開

抵抗値を矩形波の周波数に変換する基板 Ω555 を作りました。

機能

この基板はタイマIC 555 を使って、センサなどの抵抗値を矩形波の周波数に変換します。コンデンサ、抵抗器は任意の値のものを使用できます。

使いどころ

サーミスタや圧力センサなどのセンサは抵抗値の変化を読み取って計測を行います。いわゆる分圧回路を構成してマイコンのADCに分圧した電圧を入力させることが一般的です。しかし、センサの抵抗値の変化が線形でない場合、マイコンのADCの分解能が不足して精度が低下することがあります。

Ω555では、タイマICである555を用いてセンサの抵抗値を矩形波の周波数に変換します。周波数で読み取ることで、抵抗値の変化が非線形であっても精度は低下しません。

必要なもの

接続するセンサの他に、以下の部品が必要です。

部品番号 部品名 サイズなど 数量 通販サイト
(U1) 555 タイマIC DIP8またはSOP8 1 秋月 千石
R1 金属皮膜抵抗 1/4Wサイズ 1% 1 秋月
R2 炭素皮膜抵抗 1/4W 10kΩ 1 秋月
C1 積層セラミックコンデンサ 0.1μF または 0.01μF 1 秋月
C2 フィルムコンデンサ 5% 1 秋月

555はDIP8とSOP8のどちらのパッケージでも使用できます。R1の金属皮膜抵抗とC2のフィルムコンデンサは誤差の少ないものを使用してください。

R2の炭素皮膜抵抗は周波数出力のプルダウン抵抗です。不要であれば省略できます。
C1の積層セラミックコンデンサは555のコントロール電位安定のために使います。こちらも不要であれば省略できます。

回路図

抵抗とコンデンサの選定

Ω555基板の回路は以下のようになっています。

金属皮膜抵抗の抵抗値を R_1 [Ω]、接続するセンサの抵抗値を R_x [Ω]、センサに接続されるコンデンサの静電容量を C_2 [F] とすると出力される矩形波の周波数 f [Hz] は

f = \frac{\frac{1}{\ln2}}{(R_1+2R_x)C_2}

となります。\frac{1}{\ln2} はしばしば 1.44 という簡略化された数値で計算されます。

555で対応できる周波数とマイコン側で計測できる周波数から、最大でも100kHzを超えないように抵抗とコンデンサは選定してください。

たとえば抵抗を1kΩ、コンデンサを0.1μF、20℃で10kΩのサーミスタを接続すると出力周波数[Hz]は、

\begin{aligned} f &= 687.00 \end{aligned}

となり、サーミスタの抵抗値が85℃で1.451kΩに変化すると、

\begin{aligned} f &= 3697.32 \end{aligned}

となります。

これらの計算は 555 Timer Caluculator などで検証できます。AstableがΩ555と同じ回路になります。ただし \frac{1}{\ln2}1.44 で計算されるようです。

周波数からサーミスタの温度を求める

サーミスタは温度が上がると抵抗値が下がります。温度と抵抗値の近似式と、555を使った周波数変換回路の詳細は サーミスタと555を使った温度測定回路の計算式 にまとめています。

Arduinoの場合、以下のようなスケッチで温度を求めることができます。スケッチはRaspberry Pi Picoを使い、サーミスタは 103JT-025 を使っています。R1は 1kΩ、C2 は 0.1μF を接続しています。

周波数の計測には freqcount を使っています。


回路図

#include <Arduino.h>

#include "freqcount.h"

FreqCountPIO freq_count;  // using PIO
const double K  = 273.15;
const double ta = 25.0;
const double ra = 10e3;
const double tb = 85.0;
const double rb = 1.451e3;

double const_b     = 0.0;
double const_alpha = 0.0;
double const_log2e = 0.0;

double B(double ta, double ra, double tb, double rb) {
  return (log(ra) - log(rb)) / (1 / (ta + K) - 1 / (tb + K));
}

double T(double f, double ta, double c2, double r1) {
  return (const_b * (ta + K)) / ((ta + K) * (log(const_log2e / (f * c2) - r1) + const_alpha) + const_b) - K;
}

void setup() {
  Serial.begin(9600);

  const_b     = B(ta, ra, tb, rb);
  const_alpha = -log(2) - log(ra);
  const_log2e = 1.0 / log(2);

  freq_count.begin(16);
}

void loop() {
  delay(1000);

  if (freq_count.update()) {
    Serial.println(T(freq_count.get_observated_frequency(), 25, 0.1e-6, 1e3), 3);
  }
}

接続された抵抗器の抵抗値を求める

センサの代わりに抵抗器を接続することで、抵抗器の抵抗値を求めることができます。0Ωになると555で対応できない周波数となってしまうため、測定したい抵抗器と直列に10kΩを入れます。

計算式は周波数 f の式を変形すると、

R_x = \frac{\frac{1}{\ln2}}{2C_2f}-\frac{R_1}{2}

と求めることができます。
実際は直列に10kΩを接続しているので、この結果からさらに10kΩ分を引くことで目的の抵抗値が求まります。2点の抵抗値から較正を行うことで正しい抵抗値を出力できます。


回路図

#include <Arduino.h>

#include "freqcount.h"

FreqCountIRQ freq_count;  // using IRQ

const double log2e = 1.0 / log(2);
const double r1        = 1.0e3;
const double rx_series = 10.0e3;
const double c2        = 0.1e-6;

const double correction_a = 0.96841554052085;
const double correction_b = -381.11023443618;

void setup() {
  Serial.begin(9600);
  freq_count.begin(16);
}

void print_value(double value) {
  if (!isfinite(value)) {
    Serial.print("inf");
  } else if (value >= 1.0e6) {
    Serial.print(value / 1.0e6, 2);
    Serial.print("M");
  } else if (value >= 1.0e3) {
    Serial.print(value / 1.0e3, 2);
    Serial.print("k");
  } else {
    Serial.print(value, 2);
    Serial.print(" ");
  }
}

void loop() {
  delay(1000);

  if (freq_count.update()) {
    double f = freq_count.get_observated_frequency();
    double r = abs((log2e / (2.0 * c2 * f) - r1 / 2.0 - rx_series) * correction_a + correction_b);
    print_value(r);
    Serial.println();
  } else {
    Serial.println("inf");
  }
}

参考資料

Discussion