部品 · 読了まで19分

ACS712電流センサー:ArduinoでDCとACの電流を測る

ACS712電流センサーの使い方:5A/20A/30Aの感度、2.5 Vのゼロ点、ArduinoのDC・AC実効値(RMS)のコード、電力の計算、ESP32用の分圧回路とINA219を解説します。

ACS712電流センサーは、回路を流れる電流をホール効果で検出し、Arduinoが読める電圧に変える小さくて安いモジュールです。電流がないときの出力は約2.5 Vで、電流が一方向に流れると上がり、逆方向に流れると下がります。つまり、1本のアナログピンで直流(DC)と交流(AC)の両方の電流を測れます。モーターがどれだけ電流を消費しているかを見たり、電池の放電を追跡したり、機器が動いているかを検出したり、家庭の電化製品がどれだけ電力を使っているかを調べたりするのに使われます。そのうえ、測定する電流の経路はArduino側から電気的に絶縁されています。

このガイドでは、ACS712の内部構造、5A・20A・30Aモデルの違いとどれを選ぶべきか、モジュールを回路と直列につなぐ方法、DC電流を測る最初のArduinoスケッチ、平均化でふらつく値を落ち着かせる方法、AC電流の実効値(RMS)の計算、電力(W)とエネルギー(Wh)の求め方をステップごとに学びます。そのあと、3.3 VのESP32やRaspberry Pi Picoに分圧回路を通してつなぐ方法、商用電源の電圧になぜ細心の注意が必要か、そして小さな電流にはなぜINA219の方が向いているかを見ていきます。

ACS712電流センサーモジュール(20A版)
ACS712モジュール:チップのELC-20Aという刻印は20アンペア版であることを示します。緑のネジ端子は測定する回路と直列に入れ、VCC、OUT、GNDのピンはArduinoにつなぎます。

ACS712電流センサーとは?そのしくみ

ACS712はAllegro製の8ピンのチップです。測定する電流は、チップ内部の太い銅の経路を1・2番ピンから3・4番ピンへと流れます。この経路の抵抗はわずか1.2 mΩで、10 Aでも電圧降下は12 mV、発熱は0.12 Wにすぎないので、測定する回路にはほとんど影響しません。この導体を電流が流れると、電流に比例した磁界が生まれます。銅の経路のすぐ上にあるホールセンサーがその磁界を検出し、チップ内部の増幅器が電圧に変えます。基本についてはホール効果センサーのガイドで詳しく読めます。

電流が流れる銅の経路とチップに電源を供給する側の間には電気的なつながりがなく、両者を結んでいるのは磁界だけです。そのため、測定するラインとArduinoは互いに絶縁されています(ガルバニック絶縁)。出力電圧は次の式に従います:Vout = VCC / 2 + 感度 × I。電流がIP+からIP−へ流れると出力は2.5 Vより上がり、逆に流れると下がります。ACS712はレシオメトリックでもあり、ゼロ点と感度の両方が電源電圧に比例して変わります。電源が4.8 Vに下がると、ゼロ点は2.4 Vになり、5Aモデルの感度は185から約178 mV/Aに下がります。

項目値
電源電圧4.5〜5.5 V(標準5 V)
消費電流標準10 mA、最大13 mA
電流ゼロのときの出力VCC × 0.5(5 Vのとき2.5 V)
導体の抵抗1.2 mΩ
帯域幅80 kHz(FILTERピンのコンデンサで狭められる)
出力の総合誤差25 °Cで±1.5%
絶縁耐圧2.4 kV RMS(60秒)
出力の負荷4.7 kΩ以上、10 nF以下
短時間の過電流100 A(単発パルス、100 ms)
動作温度−40〜85 °C
モジュールの接続VCC、OUT、GNDと2極のネジ端子

5A・20A・30Aモデル:感度と分解能

ACS712には、外見がまったく同じ3つのバージョンがあります。どれを持っているかは、チップの刻印を読めばわかります。ELC-05Bは±5 A、ELC-20Aは±20 A、ELC-30Aは±30 Aを測ります。感度は、電流1 Aあたり出力が何ミリボルト変わるかを示します。測定範囲が広いほど感度は低くなり、そのおかげで20Aと30Aのモデルでもフルスケールの電流で出力が0.5〜4.5 Vに収まります。下の表には、Unoの10ビットADCの1ステップ(4.88 mV)が各モデルで何ミリアンペアに当たるかも示しています。

モデル(チップの刻印)測定範囲感度フルスケールでの出力UnoのADC 1ステップノイズ(47 nFフィルタ)
ACS712ELCTR-05B±5 A185 mV/A(180〜190)1.58〜3.43 V≈ 26 mA21 mV ≈ 0.11 A(ピークツーピーク)
ACS712ELCTR-20A±20 A100 mV/A(96〜104)0.50〜4.50 V≈ 49 mA11 mV ≈ 0.11 A(ピークツーピーク)
ACS712ELCTR-30A±30 A66 mV/A(63〜69)0.52〜4.48 V≈ 74 mA7 mV ≈ 0.11 A(ピークツーピーク)

この表から2つの大事な結論が出ます。1つ目に、アンペアで表したノイズは3つのモデルとも約0.1 Aです。2 Aの負荷に30Aモデルを使うと、分解能の3分の2を捨てることになります。ルールは簡単で、測定する最大電流(ACならピーク値)を余裕をもってカバーできるいちばん小さいモデルを選びます。たとえば、最大2〜3 Aを消費する12 VのDCモーターには5Aモデル、1500 Wのヒーターには20Aモデルが合います。2つ目に、ACS712は小さな電流向けに設計されていません。数ミリアンペアのLEDやディープスリープ中のESP32は測れません。その用途には、このガイドの最後で紹介するINA219の方がはるかに優れています。

ACS712の配線:Arduino Uno、ESP32、Pico

ACS712モジュールには2つの側があります。ネジ端子の側は測定する回路のものです。電流は一方の端子から入ってもう一方から出なければならないので、モジュールは電流計と同じように負荷と直列につなぎます。ふつうは電源のプラス線を切り、電源から来る端を端子の片側に、負荷へ向かう端をもう片側につなぎます。3ピンの側はArduinoにつなぎます。ACS712は5 Vでしか動かないので、ESP32やPicoでも5 Vを出すピンからモジュールに電源を供給し、出力は分圧回路を通して読みます。

ACS712のピンArduino UnoESP32Raspberry Pi Pico
VCC5V5V(ボードによってはVIN)VBUS(40番ピン)
OUTA0GPIO 34(10k/20kの分圧回路経由)GP26(10k/20kの分圧回路経由)
GNDGNDGNDGND
ネジ端子負荷と直列負荷と直列負荷と直列
2つのネジ端子を電源のプラスとマイナスの間に、つまり電圧計のように並列につなぐことは絶対にしないでください。内部の導体はわずか1.2 mΩなので、これは完全なショートです。電源は流せる限りの電流を流し、電池やACアダプターが壊れ、電線やモジュールが焼けることもあります。測定する電流は、必ず負荷(モーター、ランプ、抵抗など)を通して流してください。

モジュールにはチップのほかに部品がほとんどありません。電源ラインのパスコン(デカップリングコンデンサ)、帯域幅を決めるFILTERピンの小さなコンデンサ、電源LED(D1)とその抵抗(R1)だけです。R1に印刷された102は1 kΩを意味します。こうした表示はSMDコード解読ツールで簡単に読み解けます。ACS712は絶縁されているので、電流だけを測る場合は、測定する回路のマイナスをArduinoのGNDにつなぐ必要はありません。

ステップごとに:ArduinoでDC電流を測る

  1. モジュールのVCCピンをArduinoの5Vピンに、GNDをGNDに、OUTをA0につなぎます。基板の電源LEDが点灯するはずです。
  2. 測定したい回路のプラス線を切ります。電源から来る端を端子の片側に、負荷(たとえば12 VのモーターやLEDテープ)へ向かう端をもう片側につなぎます。
  3. 負荷の電源はオフのままにして、下のスケッチを書き込みます。起動時に、電流が流れていない状態でゼロ点を測ります。
  4. シリアルモニタを9600ボーで開きます。電流がないとき、値は0.00 A前後にとどまり、揺れても100分の数アンペア程度のはずです。
  5. 負荷の電源をオンにします。電流がマイナスで表示される場合は、端子の2本の線を入れ替えるか、結果に−1を掛けます。
  6. コードのSENSITIVITYをモデルに合わせて設定します。5Aなら0.185、20Aなら0.100、30Aなら0.066です。
C++ (Arduino IDE)
1// ACS712 ile DC akım ölçme / DC current measurement with ACS712
2const int SENSOR_PIN = A0;            // ACS712 OUT pini / ACS712 OUT pin
3const float SENSITIVITY = 0.185;      // V/A: 5A=0.185, 20A=0.100, 30A=0.066
4const float ADC_STEP = 5.0 / 1024.0;  // bir ADC basamağı (V) / one ADC step (V)
5const int SAMPLES = 200;              // ortalama için örnek sayısı / samples to average
6
7float zeroRaw = 512.0;                // akım yokken ham değer / raw value at zero current
8
9// SAMPLES kez okuyup ortalamayı döndürür / reads SAMPLES times and returns the average
10float readAverageRaw() {
11  long sum = 0;
12  for (int i = 0; i < SAMPLES; i++) {
13    sum += analogRead(SENSOR_PIN);
14  }
15  return sum / (float)SAMPLES;
16}
17
18void setup() {
19  Serial.begin(9600);
20  delay(500);                         // sensörün oturmasını bekle / let the sensor settle
21  zeroRaw = readAverageRaw();         // yük KAPALIYKEN sıfır noktası / zero point with the load OFF
22  Serial.print(F("Sifir noktasi / Zero point: "));
23  Serial.print(zeroRaw * ADC_STEP, 3);
24  Serial.println(F(" V"));
25}
26
27void loop() {
28  float raw = readAverageRaw();
29  float current = (raw - zeroRaw) * ADC_STEP / SENSITIVITY;  // amper / amps
30
31  Serial.print(F("Akim / Current: "));
32  Serial.print(current, 2);
33  Serial.println(F(" A"));
34  delay(500);
35}

このスケッチは1回の読み取りごとにanalogReadの結果を200回平均します。Unoでは1回のanalogReadに約0.11 msかかるので、およそ22 msです。電流はI = (生の値 − ゼロ点) × (5 / 1024) / 感度で求めます。たとえば5Aモデルでゼロ点が512のとき、平均の読み取り値が550なら差は38ステップです。これは38 × 4.88 mV = 185.5 mVに当たるので、電流は185.5 / 185 ≈ 1.00 Aです。2.5 Vと決めつけずに起動時にゼロ点を測るのが大切なのは、チップ自身のオフセットや基板のグラウンドラインのわずかな差でゼロ点が数ステップずれ、その誤差がすべての読み取り値に加わるからです。

Arduino UnoでACS712を読むときは、analogReference(INTERNAL)などで基準電圧を変えず、標準の5 Vの基準のままにしてください。ACS712はレシオメトリックなので、USBの電圧が4.8 Vに下がっても、センサーの出力とADCの基準電圧が同じ割合で小さくなります。生の値は変わらず、コードの5.0もそのまま正しく保たれます。ESP32やPicoはADCの基準電圧が電源から独立しているのでこの利点がなく、そちらではゼロ点をもとに小さな補正をかけます。

ノイズと平均化

ACS712の出力は、電流が一定でも揺れ続けます。1つ目の原因はホールセンサー自身のノイズです。メーカーは上のノイズの値をFILTERピンに47 nFのコンデンサを付けた条件で示しており、これは約2 kHzの帯域幅に当たります。しかし多くのモジュールは、メーカーの回路例と同じくそこに1 nFを使っています。帯域幅は80 kHzに広がり、ノイズは何倍にもなります。2つ目の原因はADCです。5AモデルでもUnoは26 mA刻みで測るので、最後の1ステップは常に上下にちらつきます。ランダムなノイズは、平均するサンプル数の平方根に比例して小さくなります。16サンプルで4分の1、256サンプルで16分の1になります。ほかのフィルタの方法はセンサーデータのフィルタリングのガイドをご覧ください。

  • 多サンプル平均:DCでは100〜500サンプルを平均します。サンプルを20 msにわたって取れば、商用電源の50 Hzの干渉も平均の中で打ち消されます(西日本の60 Hzでは1周期が16.7 msなので、100 msにわたって取れば両方で打ち消せます)。
  • 指数移動平均:新しい読み取り値をfiltered = filtered + 0.1 × (new − filtered)で古い値に混ぜていきます。メモリをほとんど使わず、ディスプレイに落ち着いた値を表示できます。
  • 不感帯:何もつないでいないのに0.03 Aのような値が見えるのが嫌なら、絶対値が0.05 A未満の結果を0として扱います。
  • ハードウェアフィルタ:はんだ付けができるなら、FILTERピンのコンデンサに47 nFのコンデンサを並列に加えて、帯域幅を約2 kHzまで下げます。DCや50 Hz(西日本では60 Hz)の商用電源の電流には十分すぎるほどです。
  • 磁界から離す:ACS712はホールセンサーです。近くの磁石やスピーカー、大電流が流れる別の電線があると、読み取り値がずれます。
  • ゼロ点を測り直す:ゼロ点は温度によって数ミリボルトずれます。長時間動かすプロジェクトでは、負荷がオフのときにゼロ点を測り直してください。
テスト棒をつないだデジタルテスター
ACS712をキャリブレーションするには、電流レンジにしたテスターを同じラインに直列につなぎ、2つの読み取り値を比べます。

平均化でノイズは消えますが、系統的な誤差は直りません。感度はチップごとに数パーセント異なることがあり、5Aモデルでは180〜190 mV/Aの範囲です。いちばん正確にするには、電流レンジにしたテスターをACS712と同じラインに直列につなぎ、1〜2 Aのような既知の電流を流して2つの値を比べます。テスターが2.00 A、Arduinoが1.94 Aを示したら、補正係数は2.00 / 1.94 = 1.031です。コードのSENSITIVITYをこの数で割れば(0.185 / 1.031 ≈ 0.179)、読み取り値がテスターと一致します。

AC電流を測る:実効値(RMS)の計算

商用電源の電流は向きが変わり続けます。周波数はヨーロッパと世界の大部分で50 Hz、アメリカで60 Hzです(日本では東日本が50 Hz、西日本が60 Hz)。そのため、ACS712の出力は2.5 Vを中心とした正弦波を描き、その平均は電流ゼロに当たります。DC用のスケッチをACの負荷に使うと、0 Aに近い意味のない値になります。ACで大事なのは実効値(RMS)です。これは同じ熱を生むDC電流に等しく、テスターやヒューズ、電化製品のラベルで使われている値です。計算は名前のとおりです。各サンプルからゼロ点を引いて二乗し(Square)、二乗の平均を取り(Mean)、その平方根を取ります(Root)。

測定窓の長さが重要です。窓に整数個の周期が入っていないと、結果が毎回少しずつ変わります。1周期は50 Hzで20 ms、60 Hzで16.7 msです。100 msの窓なら50 Hzでちょうど5周期、60 Hzでちょうど6周期が入るので、どちらの電力網でも正しく動きます。Unoはその間に約900サンプルを取ります。純粋な正弦波ならピーク値は実効値の1.414倍なので、ピーク値を√2で割ることもできます。しかし、スマートフォンの充電器やLED電球、調光器のような負荷はとがった正弦波でない電流を流すので、この近道では正しく測れません。下のスケッチは真の実効値(True RMS)を計算するので、こうした負荷でもずっと正確です。ピーク値はモデルの測定範囲内に収まる必要があります(下の表の電力は230 Vの場合です。日本の商用電源は100V(50/60Hz)です)。

モデルピーク電流の上限最大AC電流(実効値、正弦波)230 Vでのおよその電力
5A±5 A3.5 A≈ 800 W
20A±20 A14.1 A≈ 3250 W
30A±30 A21.2 A≈ 4900 W
C++ (Arduino IDE)
1// ACS712 ile AC akım (RMS) ve görünür güç / AC current (RMS) and apparent power with ACS712
2const int SENSOR_PIN = A0;
3const float SENSITIVITY = 0.100;      // 20A modül: 100 mV/A / 20A module: 100 mV/A
4const float ADC_STEP = 5.0 / 1024.0;
5const unsigned long WINDOW_MS = 100;  // 50 Hz'te 5, 60 Hz'te 6 tam periyot / 5 cycles at 50 Hz, 6 at 60 Hz
6const float MAINS_VOLTAGE = 230.0;    // şebeke gerilimi (V) / mains voltage (V)
7
8float noiseRms = 0.0;                 // yük yokken ölçülen gürültü (A) / noise measured with no load (A)
9
10// Pencere boyunca örnek alır, ortalamayı çıkarıp RMS hesaplar / samples over the window, removes the mean, returns RMS
11float readRmsAmps() {
12  long sum = 0;
13  unsigned long sumSq = 0;
14  unsigned int n = 0;
15  unsigned long start = millis();
16  while (millis() - start < WINDOW_MS) {
17    int d = analogRead(SENSOR_PIN) - 512;  // 2,5 V'u sıfıra yaklaştır / shift 2.5 V to about zero
18    sum += d;
19    sumSq += (long)d * d;
20    n++;
21  }
22  float mean = sum / (float)n;                       // sıfır noktası kayması / zero point offset
23  float variance = sumSq / (float)n - mean * mean;   // yalnız AC kısım / AC part only
24  if (variance < 0) variance = 0;
25  return sqrt(variance) * ADC_STEP / SENSITIVITY;
26}
27
28void setup() {
29  Serial.begin(9600);
30  delay(500);
31  noiseRms = readRmsAmps();           // ilk ölçüm yük KAPALIYKEN / first reading with the load OFF
32  Serial.print(F("Gurultu / Noise: "));
33  Serial.print(noiseRms, 3);
34  Serial.println(F(" A"));
35}
36
37void loop() {
38  float irms = readRmsAmps();
39  float sq = irms * irms - noiseRms * noiseRms;  // gürültüyü karesel çıkar / subtract noise in quadrature
40  irms = (sq > 0) ? sqrt(sq) : 0.0;
41  float apparentPower = MAINS_VOLTAGE * irms;     // VA; dirençli yükte ≈ W / VA; ≈ W for resistive loads
42
43  Serial.print(F("Irms: "));
44  Serial.print(irms, 3);
45  Serial.print(F(" A   Guc / Power: "));
46  Serial.print(apparentPower, 1);
47  Serial.println(F(" VA"));
48  delay(1000);
49}

このスケッチはゼロ点を固定の数として保存しません。窓ごとにサンプルの平均を求めて、それを引きます。数学的には、これは分散の平方根です:RMS² = 二乗の平均 − 平均の二乗。AC電流は整数個の周期で平均するとゼロになるので、求めた平均はちょうどゼロ点の誤差に当たり、ゼロ点が温度でずれても自動的に補正されます。起動時に負荷をオフにして測ったノイズは二乗で差し引きます。ノイズと実際の電流は互いに独立していて、実効値は二乗で足し合わされるからです。この処理がないと、何もつないでいないのに0.1 Aや23 VAといった幽霊のような値が見えます。例を挙げると、1000 Wのアイロンは230 Vで約4.35 Aを流します。ピーク値の6.1 Aは5Aモデルの測定範囲を超えるので、20Aモデルで測ってください。

商用電源の電圧は命に関わります。ACS712チップ内部の絶縁は強力(耐圧2.4 kV RMS)ですが、安いモジュールでは端子台のネジや基板裏のはんだ付け部分が商用電源の電圧になっていて、むき出しです。接続はプラグを抜いた状態でだけ行い、モジュールは閉じたプラスチックケースに入れ、ラインにヒューズを入れ、通電中は何にも触れないでください。ArduinoをUSBでパソコンにつないだまま商用電源を測ると、何か故障したときにパソコンも危険にさらされます。結果をディスプレイに表示するか、ESP32でワイヤレスに送る方が安全です。商用電源の配線の経験がない場合は、この実験を一人で行わないでください。生徒の場合は、必ず電気に詳しい大人と一緒に作業してください。

家庭の電化製品の電流をはるかに安全に測る方法は、SCT-013のような分割型のカレントトランス(CT)を使うことで、電線を切らずに使えます。クランプメーターのようにケーブルを挟み込み、商用電源と金属で接触することはありません。注意点は1つだけで、クランプで挟むのは電圧側(L)か中性線(N)のどちらか1本だけにします。両方を一緒に挟むと、逆向きの電流の磁界が打ち消し合って結果はゼロになります。カレントトランスはACしか測れません。DCにはACS712かINA219が必要です。

電力(W)とエネルギー(Wh)の計算

電流がわかれば、電力は掛け算1つで求まります:P = V × I。12 Vの電池が1.5 Aを消費するモーターに電力を供給しているなら、電力は12 × 1.5 = 18 Wです。オームの法則計算ツールで確かめることもできます。エネルギーは電力に時間を掛けたものです。18 Wのモーターが2時間動けば、36 Whを使います。スケッチは読み取りのたびに電力に経過時間を掛けて足し合わせることでこれを計算します。電圧を測るには、0〜25 V電圧センサーとして売られているモジュールを使えます。30 kΩと7.5 kΩの分圧回路が入っていて、入力電圧を5分の1にします。自分の抵抗値で分圧回路を設計したいなら、分圧計算ツールを使ってください。

C++ (Arduino IDE)
1// ACS712 + gerilim sensörü ile güç (W) ve enerji (Wh) / power (W) and energy (Wh) with ACS712 + voltage sensor
2const int CURRENT_PIN = A0;           // ACS712 OUT
3const int VOLTAGE_PIN = A1;           // 0-25 V gerilim sensörü S pini / 0-25 V voltage sensor S pin
4const float SENSITIVITY = 0.185;      // 5A modül / 5A module (V/A)
5const float DIVIDER_RATIO = 5.0;      // (30k + 7,5k) / 7,5k = 5 / divider ratio
6const float ADC_STEP = 5.0 / 1024.0;
7const int SAMPLES = 200;
8
9float zeroRaw = 512.0;
10float energyWh = 0.0;                 // biriken enerji / accumulated energy
11unsigned long lastMs = 0;
12
13float averageRaw(int pin) {
14  long sum = 0;
15  for (int i = 0; i < SAMPLES; i++) sum += analogRead(pin);
16  return sum / (float)SAMPLES;
17}
18
19void setup() {
20  Serial.begin(9600);
21  delay(500);
22  zeroRaw = averageRaw(CURRENT_PIN);  // yük kapalıyken sıfır noktası / zero point with the load off
23  lastMs = millis();
24}
25
26void loop() {
27  float current = (averageRaw(CURRENT_PIN) - zeroRaw) * ADC_STEP / SENSITIVITY;
28  float voltage = averageRaw(VOLTAGE_PIN) * ADC_STEP * DIVIDER_RATIO;
29  float power = voltage * current;    // P = V x I (W)
30
31  unsigned long now = millis();
32  energyWh += power * (now - lastMs) / 3600000.0;  // W x saat = Wh / W x hours = Wh
33  lastMs = now;
34
35  Serial.print(voltage, 2);  Serial.print(F(" V   "));
36  Serial.print(current, 2);  Serial.print(F(" A   "));
37  Serial.print(power, 1);    Serial.print(F(" W   "));
38  Serial.print(energyWh, 3); Serial.println(F(" Wh"));
39  delay(1000);
40}

電圧モジュールは測定する回路のプラスとマイナスの間につなぐので、今度は回路のマイナスとArduinoのGNDをつなぐ必要があります。理由は共通GNDのガイドでわかります。電池が何時間もつかを見積もるには、測った平均電流をmAhとWhの計算や電池寿命計算ツールと組み合わせます。AC側では少し事情が違います。Vrms × Irmsは皮相電力で、単位はVAです。有効電力(W)はそれに力率を掛けたものです。電気ケトル、アイロン、白熱電球のような抵抗負荷では力率がほぼ1なので、VA ≈ Wです。モーター、ACアダプター、LED電球では0.5〜0.9になることがあり、有効電力を測るには電圧の波形も同時にサンプリングする必要があります。それにはZMPT101Bのような絶縁型の電圧センサーモジュールを使います。

ESP32でACS712を使う:分圧回路を通して読む

ESP32は3.3 Vで動き、アナログ入力で測れるのは約3.1 Vまでです。ピンに3.6 Vを超える電圧をかけるとボードが壊れることがあります。一方ACS712は5 Vでしか動かず、20Aと30Aのモデルでは出力が4.5 V、過電流時にはほぼ5 Vに達することがあります。そこで、センサーはESP32ボードの5Vピン(ボードによってはVIN)から電源を取り、OUTは分圧回路を通します。10 kΩ + 20 kΩがよい組み合わせです。OUTから10 kΩを通ってESP32のピンへ、その同じ点から20 kΩを通ってGNDへつなぎます。比は20 / 30 = 0.667で、合計30 kΩはACS712の最小負荷4.7 kΩを余裕で満たします。

ACS712の出力意味ESP32のピンでの電圧
0.50 V20Aモデルで−20 A0.33 V
2.50 V電流ゼロ1.67 V
4.50 V20Aモデルで+20 A3.00 V
5.00 V過電流で飽和3.33 V

コードには2つのポイントがあります。1つ目に、ESP32のADCは両端付近で直線的でないので、生の値ではなく、工場でチップに書き込まれたキャリブレーションデータを使うanalogReadMilliVolts()を使います。GPIO 34はADC1にあり、Wi-Fiがオンでも使えます。ADC2のピンはWi-Fiと同時には使えません。2つ目に、Unoのレシオメトリックの便利さはここにはありません。ESP32のADCの基準電圧は固定ですが、ACS712の感度はUSBから来る5 Vによって変わります。対策は簡単な工夫です。電流ゼロのとき出力はVCCの半分に等しいので、起動時に測ったゼロ点を2倍すればセンサーの実際の電源電圧がわかり、それに合わせて感度を補正できます。ゼロ点と測定信号の両方に同じ誤差が含まれるので、この方法は分圧回路の抵抗の誤差も補正します。スケッチは100 msの間サンプリングし、2つの結果をまとめて返します。DCの負荷なら1つ目の数を、商用電源の電化製品なら2つ目の数を見てください。

C++ (Arduino IDE)
1// ESP32 + ACS712 (10k/20k gerilim bölücüyle) / ESP32 + ACS712 (with a 10k/20k voltage divider)
2const int SENSOR_PIN = 34;            // ADC1_CH6, Wi-Fi açıkken de çalışır / works while Wi-Fi is on
3const float DIVIDER = 20.0 / 30.0;    // R2 / (R1 + R2) = 20k / 30k
4const float SENS_AT_5V = 185.0;       // mV/A: 5A=185, 20A=100, 30A=66
5const unsigned long WINDOW_MS = 100;  // 50 Hz'te 5 tam periyot / 5 full cycles at 50 Hz
6
7float zeroMv = 2500.0;                // akım yokken sensör çıkışı (mV) / sensor output at zero current (mV)
8float sensMv = SENS_AT_5V;            // düzeltilmiş hassasiyet (mV/A) / corrected sensitivity (mV/A)
9
10// Bölücüden önceki gerilimin ortalaması (mV) / average voltage before the divider (mV)
11float averageMv(int samples) {
12  uint32_t sum = 0;
13  for (int i = 0; i < samples; i++) sum += analogReadMilliVolts(SENSOR_PIN);
14  return sum / (float)samples / DIVIDER;
15}
16
17// Pencere boyunca okur: DC (ortalama) ve AC (RMS) akım / reads over the window: DC (mean) and AC (RMS) current
18void measure(float &dcAmps, float &acAmps) {
19  double sum = 0, sumSq = 0;
20  uint32_t n = 0;
21  uint32_t start = millis();
22  while (millis() - start < WINDOW_MS) {
23    double d = analogReadMilliVolts(SENSOR_PIN) / DIVIDER - zeroMv;
24    sum += d;
25    sumSq += d * d;
26    n++;
27  }
28  double mean = sum / n;
29  double variance = sumSq / n - mean * mean;
30  if (variance < 0) variance = 0;
31  dcAmps = mean / sensMv;
32  acAmps = sqrt(variance) / sensMv;
33}
34
35void setup() {
36  Serial.begin(115200);
37  analogReadResolution(12);
38  delay(500);
39  zeroMv = averageMv(1000);                    // yük KAPALIYKEN / with the load OFF
40  sensMv = SENS_AT_5V * (2.0 * zeroMv) / 5000.0;  // oransal düzeltme: VCC = 2 x sıfır / ratiometric fix: VCC = 2 x zero
41  Serial.printf("Sifir / Zero: %.0f mV  Hassasiyet / Sensitivity: %.1f mV/A\n", zeroMv, sensMv);
42}
43
44void loop() {
45  float dc, ac;
46  measure(dc, ac);
47  Serial.printf("DC: %.2f A   AC (RMS): %.2f A\n", dc, ac);
48  delay(1000);
49}

Raspberry Pi PicoとMicroPythonでACS712を使う

Raspberry Pi Picoも3.3 Vで動くので、配線はESP32と同じです。ACS712のVCCを、PicoがUSBから給電されているときに5 Vを出すVBUS(40番ピン)に、OUTを同じ10k/20kの分圧回路を通してGP26(ADC0、31番ピン)につなぎます。MicroPythonではread_u16()が0〜65535の値を返し、電圧 = 生の値 × 3.3 / 65535です。PicoのADCは12ビットで、分圧回路と合わせると、計算上は5Aモデルで約6.5 mA刻みで測れます。Unoのおよそ4倍細かい刻みです。下のコードは起動時にゼロ点を測り、レシオメトリック補正をかけ、そのあと1秒ごとにDCとACの実効値の電流を表示します。

MicroPython
1from machine import ADC
2import time
3import math
4
5adc = ADC(26)            # GP26 = ADC0, fiziksel pin 31 / physical pin 31
6VREF = 3.3               # ADC referansı (V) / ADC reference (V)
7DIVIDER = 20 / 30        # 10k/20k bölücü oranı / 10k/20k divider ratio
8SENS_AT_5V = 0.185       # V/A: 5A=0.185, 20A=0.100, 30A=0.066
9
10
11def read_volts(samples=200):
12    # bölücüden önceki ortalama gerilim / average voltage before the divider
13    total = 0
14    for _ in range(samples):
15        total += adc.read_u16()          # 0-65535
16    return total / samples * VREF / 65535 / DIVIDER
17
18
19zero = read_volts(1000)                  # yük KAPALIYKEN / with the load OFF
20sens = SENS_AT_5V * (2 * zero) / 5.0     # oransal düzeltme / ratiometric correction
21print("Sifir / Zero: {:.3f} V".format(zero))
22
23
24def read_rms(window_ms=100):
25    # 100 ms = 50 Hz'te 5 periyot / 5 cycles at 50 Hz
26    n = 0
27    s = 0.0
28    s2 = 0.0
29    start = time.ticks_ms()
30    while time.ticks_diff(time.ticks_ms(), start) < window_ms:
31        v = adc.read_u16() * VREF / 65535 / DIVIDER - zero
32        s += v
33        s2 += v * v
34        n += 1
35    mean = s / n
36    return math.sqrt(max(s2 / n - mean * mean, 0)) / sens
37
38
39while True:
40    dc = (read_volts() - zero) / sens
41    print("DC: {:.2f} A   AC (RMS): {:.2f} A".format(dc, read_rms()))
42    time.sleep(1)

ACS712とINA219のどちらを使う?

INA219はTexas Instruments製の電流・電圧監視チップで、I2Cで通信します。ホール効果ではなく、電流が流れる小さなシャント抵抗(モジュールではふつう0.1 Ω)の電圧降下を測ります。よく使われるモジュールは、約0.8 mAの分解能で±3.2 Aまで測り、26 Vまでのバス電圧を自分で読み取り、電力もチップ内で計算します。つまり、1つのI2C接続で電圧、電流、電力がまとめて得られ、ADCや平均化、ゼロ点のキャリブレーションに手間をかける必要がありません。その代わり、測定する回路とArduinoの間の絶縁がなく、AC電流は測れず、26 Vを超える電圧には使えません。

項目ACS712INA219モジュール
測定方式ホール効果(磁気)シャント抵抗(0.1 Ω)
電流の範囲±5 / ±20 / ±30 A±3.2 A(シャント抵抗による)
分解能Unoで26〜74 mA≈ 0.8 mA
AC電流測れる測れない
電圧と電力測れない(別に分圧回路が必要)測れる(26 Vまで)
絶縁ありなし
インターフェースアナログ出力I2C(アドレス0x40〜0x4F)
電源5 Vのみ3〜5.5 V
向いている用途モーター、ヒーター、商用電源の電化製品、大電流電池、ソーラーパネル、センサーやボードの消費電流
C++ (Arduino IDE)
1#include <Wire.h>
2#include <Adafruit_INA219.h>
3
4Adafruit_INA219 ina219;               // varsayılan adres 0x40 / default address 0x40
5
6void setup() {
7  Serial.begin(9600);
8  if (!ina219.begin()) {
9    Serial.println(F("INA219 bulunamadi / INA219 not found"));
10    while (true) delay(10);
11  }
12  // ina219.setCalibration_16V_400mA();  // küçük akımda daha ince çözünürlük / finer resolution for small currents
13}
14
15void loop() {
16  float busV = ina219.getBusVoltage_V();        // yük tarafındaki gerilim / voltage on the load side
17  float current_mA = ina219.getCurrent_mA();    // akım (mA) / current (mA)
18  float power_mW = ina219.getPower_mW();        // güç (mW) / power (mW)
19
20  Serial.print(busV, 2);       Serial.print(F(" V   "));
21  Serial.print(current_mA, 1); Serial.print(F(" mA   "));
22  Serial.print(power_mW, 0);   Serial.println(F(" mW"));
23  delay(1000);
24}

コードには、ライブラリマネージャからAdafruit INA219ライブラリをインストールします。モジュールのSDAとSCLのピンをUnoのA4とA5につなぎます。測定する電流はVIN+から入ってVIN−から負荷へ出ていく必要があり、INA219のGNDは測定する回路と共通にしなければなりません。まとめると、数ミリアンペアから3 AまでのDC電流を電圧と一緒に測るならINA219を、もっと大きな電流やAC電流、絶縁が必要ならACS712を選ぶのが正解です。

ACS712のプロジェクトのアイデア

  • モーターの過電流保護:L298Nで駆動するDCモーターが拘束されると、電流が急に上がります。しきい値を超えたらモーターを止めて警報を鳴らします。
  • 電池とソーラーパネルのモニター:充電と放電の電流を向きも含めて測り、電圧を掛けてWhを積算し、結果をOLEDディスプレイに表示します。
  • スマートプラグ:リレーモジュールでコンセントを切り替え、ACS712で電化製品が本当に動いているかを確かめ、データをMQTTでHome Assistantに送ります。
  • 洗濯機の終了通知:電流が設定値より低い状態が数分続いたら、ESP32からTelegramでメッセージを送ります。
  • ポンプの空運転アラーム:水がなくなるとポンプの消費電流が下がります。それを検出してポンプを止めます。
  • エネルギーロガー:電流と電力を1分に1回SDカードやGoogleスプレッドシートに記録し、1日の消費電力のグラフを描きます。
  • 卓上の電力計:Arduinoで電圧計を作るプロジェクトにACS712を加えて、電圧、電流、電力を1つの画面に表示する測定器を作ります。

よくある失敗と対策

症状考えられる原因対策
電流がないのに0.1〜0.3 Aと表示されるコードがゼロ点を2.5 Vまたは512と決めつけている起動時に負荷をオフにしてゼロ点を測り、小さな不感帯を加える
値が跳び続ける1サンプルだけの読み取り、1 nFフィルタの広い帯域幅100〜500サンプルを平均する。必要ならFILTERに47 nFを追加する
電流がマイナスになる電流が端子を逆向きに流れている線を入れ替えるか、結果に−1を掛ける
ACの負荷で0 Aに近い値になるDC用のコードを使っている。正弦波は平均するとゼロになる実効値(RMS)を計算するスケッチを使う
値がいつも数パーセント高い、または低いモデルの値が間違っている、または感度の個体差チップの刻印から0.185、0.100、0.066を選び、テスターでキャリブレーションする
生の値が0か1023のまま動かないOUTが違うピンにつながっているかVCCにつながっている、電流がモデルの測定範囲を超えている配線を確認し、必要なら大きいモデルを使う
電源が落ちる、電線が熱くなる端子を電源と並列につないでいる(ショート)モジュールを負荷と直列につなぐ
ESP32で値が安定しない分圧回路がない、ADC2のピンを使っている、または生のanalogRead10k/20kの分圧回路、GPIO 34、analogReadMilliVoltsを使う
磁石の近くで読み取り値が変わるホールセンサーが外部の磁界を拾っているモジュールを磁石、スピーカー、大電流の電線から離す
電流センサーが動いているかを確かめるいちばん簡単な方法は、既知の負荷を使うことです。たとえば12 Vにつないだ10 Ωの抵抗は、オームの法則により1.2 Aを流し、14.4 Wを熱に変えるので、定格20〜25 W以上の大電力用の抵抗を選んでください。1.2 Aに近い値が測れれば、配線とコードは正しいということです。

ACS712は電流の測定を学び始めるのにぴったりです。1本のアナログピンでDCとACの電流を測れ、数行のコードで電力とエネルギーも求められます。正しいモデルを選び、ゼロ点を測り、サンプルを平均し、テスターでキャリブレーションすれば、誤差数パーセント以内の信頼できる結果が得られます。アナログの読み取りの基本はADCのガイドでしっかり固められます。BlueGraysアプリには、アナログセンサーの読み取り、LCDディスプレイ付きデジタル電圧計、リレーで商用電源の電球を制御するプロジェクト、ESP32のデータロガーなどがあり、それぞれステップごとの回路図とコードが付いています。

よくある質問

ACS712は何アンペアまで測れますか?どのモデルを選べばいいですか?

ACS712には±5 A、±20 A、±30 Aを測る3つのモデルがあり、感度はそれぞれ185、100、66 mV/Aです。測定する最大電流(ACならピーク値)をカバーできるいちばん小さいモデルを選んでください。小さいモデルほど、同じ電流で出力の振れ幅が大きく、分解能も高くなります。モデルはチップのELC-05B、ELC-20A、ELC-30Aという刻印でわかります。

ACS712は電流がないのになぜ2.5 Vを出力するのですか?

ACS712が両方向の電流を測れるように、出力は電源電圧の半分から始まります。電流が一方向に流れると出力は2.5 Vより上がり、逆方向に流れると下がります。電源がちょうど5 Vでない場合、ゼロ点はVCC / 2にずれるので、起動時に測るのがいちばんよい方法です。

ACS712で商用電源の電流を測れますか?

はい。チップの絶縁耐圧は2.4 kV RMSで、230 Vなら5Aモデルは約800 Wまで、20Aモデルは約3250 Wまでの負荷に向いています(日本の100 Vでは、同じ電流での電力はこの半分以下になります)。ただし、モジュールのネジ端子とはんだ付け部分は商用電源の電圧になるので、配線はプラグを抜いた状態でだけ行い、閉じたケースに入れ、経験がない場合は一人で作業しないでください。より安全なのは、電線を切る必要のないSCT-013のようなクランプ式のカレントトランスです。

ACS712はESP32や3.3 Vで使えますか?

ACS712には4.5〜5.5 Vが必要で、3.3 Vでは正しい結果が出ません。ESP32やRaspberry Pi Picoでは、5V、VIN、VBUSのいずれかのピンからモジュールに電源を供給し、出力を10 kΩ + 20 kΩの分圧回路を通してアナログピンにつなぎます。そうすれば、5 V近い出力でもピンでは3.33 V未満に収まります。

ACS712は電流がないのになぜゼロにならないのですか?

理由は2つあります。コードがゼロ点をちょうど2.5 Vまたは512と決めつけていることと、センサー自身にノイズがあることです。起動時に負荷をオフにしてゼロ点を測り、100〜500サンプルを平均し、0.05 Aのような小さな不感帯を加えてください。ACでは、ノイズを二乗で差し引くと、待機中に表示される幽霊のような電流が消えます。

ACS712とINA219、どちらがよいですか?

用途によります。INA219はI2Cで動き、±3.2 Aまでの範囲で約0.8 mAの分解能で電流、電圧、電力をまとめて得られるので、電池や小さなDC回路にははるかに精密です。ACS712は30 Aまで測れ、AC電流も読め、測定する回路をArduinoから絶縁します。

全プロジェクトを見る
LDRで光の強さを測定
#11初級

LDRで光の強さを測定

部屋の明るさを数値で見てみませんか?光に反応する小さな部品、LDRで周囲の光を測定し、Arduinoが0.5秒ごとにその値をコンピューターの画面に表示します。手で覆うと数値が変わる様子を確認できます。自動で点灯する常夜灯などのプロジェクトへの第一歩です。

4.6(81)
139
ESP32とLDRモジュールで光の強さを読み取る
#113初級

ESP32とLDRモジュールで光の強さを読み取る

LDRモジュールの生のADC値と、暗い状態・明るい状態の基準値から計算した相対的な明るさの割合を、シリアルモニタでリアルタイムに確認します。この割合はルクスの測定値ではありません。モジュールの校正の仕組みを学べます。しきい値の決定に使うため、プロジェクト10の前に取り組むのが適しています。

4.6(36)
55
LCDディスプレイ付きデジタル電圧計
#56中級
プレミアム

LCDディスプレイ付きデジタル電圧計

自作の測定器で、電池や電源アダプターが出力する電圧を調べます。2つの抵抗で作る分圧回路が、高い電圧をボードで読み取れるレベルまで下げます。Arduinoが元の電圧を計算し、2行のLCDディスプレイにボルト単位で表示します。この回路では約55ボルトまでの直流電圧を測定できます。コンセントの商用電源には絶対に接続しないでください。

4.5(27)
36
ボタンを押している間だけ220V電球を点灯
#19上級
プレミアム

ボタンを押している間だけ220V電球を点灯

ボタンを押している間は実際の220ボルトの電球が点灯し、離すとすぐに消灯します。Arduinoの小さな信号では電球を直接点灯できないため、電気で動くスイッチであるリレーを間に入れ、電球の回路を開閉します。ボードで家庭の照明を操作するための第一歩です。家庭用電源を扱う際は十分に注意し、不安がある場合は詳しい人に手伝ってもらってください。

4.4(30)
38
ESP32と可変抵抗でLEDの明るさを制御(アナログ→PWM)
#115中級
プレミアム

ESP32と可変抵抗でLEDの明るさを制御(アナログ→PWM)

可変抵抗を使ってLEDの明るさをアナログ操作で調整します。ESP32のADCピンで可変抵抗からの0-3.3Vの電圧を読み取り、PWM(パルス幅変調)信号に変換してLEDに出力します。可変抵抗を回すと、LEDが徐々に明るくなったり暗くなったりします。Arduino Core 3.0+ではanalogWrite()を直接使えます。ESP32-S2/S3ではADCの分解能を12ビットに固定します。

4.5(19)
32
I2CでLCDディスプレイを使う
#32初級
プレミアム

I2CでLCDディスプレイを使う

Arduinoにディスプレイを接続し、最初のメッセージを表示します。2行のLCDディスプレイは数本の配線だけで接続できます。まず上の行にあいさつを表示し、次に下の行にもう1つのメッセージを表示します。その後、表示を消去して最初から繰り返します。温度や時刻、スコアを表示するプロジェクトは、すべてこのステップから始まります。

4.8(53)
70
ESP32 I2C LCDディスプレイ(16x2)
#119中級
プレミアム

ESP32 I2C LCDディスプレイ(16x2)

このプロジェクトでは、16x2文字のLCDをI2CでESP32に接続して文字を表示します。I2Cならデータ用の2本のピン(SDAとSCL)だけで制御でき、従来のパラレル接続のように6本以上のピンを使わずに済みます。コードでは1行目に固定メッセージ、2行目に毎秒増えるカウンターを表示します。また、起動時にI2Cスキャナーを実行し、ディスプレイのアドレス(通常は0x27または0x3F)をシリアルモニタに表示します。

4.9(23)
40
ESP32温度データロガー(DHT22 + DS1307 RTC + microSD + OLED)
#144上級
プレミアム

ESP32温度データロガー(DHT22 + DS1307 RTC + microSD + OLED)

ESP32で日時付きの温度・湿度記録システムを作ります!DHT22で1分ごとに温度と湿度を読み取り、DS1307 RTCから取得した日時とともにmicroSDカードへCSV形式で記録します。OLEDには最新の温度を大きな文字で表示し、湿度のパーセント値、日時、総記録数も表示します。SDカードの/temp_log.csvファイルはExcel、Google Sheets、Pythonのpandasで開いて分析できます。温室の監視、家や部屋の温度管理、実験室のデータ収集、食品の保管環境や養蜂箱の監視に適しています。

4.7(7)
12