プログラミング素人のはてなブログ

プログラミングも電気回路も専門外の技術屋の末端が勉強したことや作品をアウトプットするブログ。コードに間違いなど見つけられたら、気軽にコメントください。 C#、Python3、ラズパイなど。

オペアンプを使った定電流回路を作ってみる

作って確かめてみた

f:id:s51517765:20220320165813p:plain
オペアンプはNJM2904D、トランジスタは2SC1815です。
akizukidenshi.com

こちらがオペアンプを使った定電流回路です。
この回路はモーターやLEDの駆動によく使われます。
ここでは実験のために可変抵抗VRを置いていますが、実際はLEDなどの負荷をここに載せます。
この回路の左端D3にPWMを入力すると、このDutyに応じてR1の電圧が定電圧にフィードバックされ、負荷に流れる電流が一定になります。

この定電流回路の仕組みを知らないとすると、このように考えられます。
VRが変化する(LEDが発熱等でVfが変化した想定)と5V電源に対してVRとR1の分圧でR1の電圧が変化するので、R1に流れる電流が変わり、つまり負荷(ここではVR)に流れる電流が変わります。(トランジスタのBE間の電流が無視できるほど小さいとすると)

しかしながら、この回路では負荷(VR)が変わってもP点の電圧が一定でR1の電圧が一定、つまりR1、VRの電流が一定になるとされています。
www.nahitech.com
detail-infomation.com
詳細な理論は他のサイトにお任せとして、本当にそのようなことになるのかを実験してみました。

任意の電圧発生原をArduinoで作る

シリアルモニタからPWMを指定してdigitalピンに任意のDutyを発生させるプログラムを作ります。
これによって安定的な電圧を自由に呼び出すことが出来ます。
f:id:s51517765:20220320145836p:plain
シリアルモニタからの入力はAsciiコードとしてByteで受け取られるので

b[digit++] = incomingByte - 48;

のようにして数値に変換できます。(char文字列の1が49)
これを改行毎に受け取り足し合わせるとPWMの値になります。

if (incomingByte == 10)  //改行
{
    inputValue = 100 * b[0] + 10 * b[1] +  b[2];
}

ちなみに、Arduino(AVR)の指数計算にはbugがあります。

int digit = 0;
int b[3];
int inputValue = 0;

int input()
{
  int incomingByte = Serial.read();
  if (incomingByte == 10) {
    if (digit == 2) {
      b[2] = b[1];
      b[1] = b[0];
      b[0] = 0;
    }
    else if (digit == 1) {
      b[2] = b[0];
      b[1] = b[0] = 0;
    }
    inputValue = 0;
    /*   ずれる 
          for (int i = 0; i < 3; i++)  {
          inputValue += pow(10, 2 - i) *  b[i];
        }
    */
    /*   これもずれる
    inputValue = pow(10, 2 ) * b[0] + pow(10, 1) * b[1] + pow(10, 0) * b[2];
    */
    inputValue = 100 * b[0] + 10 * b[1] +  b[2];
    inputValue = min(255, inputValue); //最大値丸める
    Serial.print("PWM= ");
    Serial.println(inputValue);
    analogWrite(3, inputValue );

    digit = 0;
    for (int i = 0; i < 3; i++)      b[i] = 0;
    return (int)inputValue;
  }
  else {
    b[digit++] = incomingByte - 48;
  }
}
void setup() {
  pinMode(3, OUTPUT);
  Serial.begin(9600);
}

void loop() {
  if (Serial.available() > 0) {
    input();
  }
}

測定

まず、ArduinoのPWM特性を見てみます。
回路図でいうとオペアンプの+の入力の位置です。
テスターで測定すると理想的に出力されているように見えます。
一方、オシロスコープでの実効値はやや曲線を描いていますが、ほぼ一致しています。
一方トランジスタのBase入力となる、オペアンプの出力は3.64Vで飽和してしまいました。
(Base電圧はトランジスタの特性よりV-に対して0.7V高くなる。)
何か、回路の定数がよろしくなくて出力が不十分になっているように思います。
ですが、3.64Vまでは評価できるので、これで進めます。
f:id:s51517765:20220320161417p:plain

次に定電流の基準となるP点(トランジスタのエミッタ)の電圧を見ます。
可変抵抗を4水準に変更して、またPWMを変更したときの結果が以下です。
抵抗によらずPWMによってトランジスタのエミッター電圧(基準抵抗R1の電圧)が制御出来ている結果が得られました。
これが、定電流回路の挙動です。
また、定電流電源電圧を変化させても(9Vまで確認)同じであることも確認できました。
f:id:s51517765:20220320162014p:plain

ためしに、オペアンプを使わない(定電流でない)場合、本当にこの電圧が動くのかも確かめておきます。
オペアンプを外して、オペアンプの+に入力していたところをトランジスタのBaseに入力します。
PWM(入力電圧)に対して変な特性が出ていますが、エミッター電圧が抵抗(負荷)によって動き定電流ではなくなっていることがわかります。
f:id:s51517765:20220320162343p:plain

まとめ

オペアンプを使った定電流回路を作成し定電流制御の実験をしました。
実際に作って測定してみるまでは、ある程度電源電圧の影響をうけるのかと思っていましたが、思った以上に安定していました。
また、この他のこの回路の重要な特性としては
オペアンプのV+とV-の電位は同じ
オペアンプのVout電圧はエミッタ電圧(P点電圧)+0.7V(トランジスタのVbe電圧)
といったものがあります。