4
7

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

ラズベリーパイ用の簡易UPS基板で安全にシャットダウンできるようにしてみた

Last updated at Posted at 2024-11-16

2025/8/9 追記 改良しました!

追記場所へジャンプ

今回設計する基板

ラズベリーパイ用のUPS(無停電電源装置)HAT基板です。
停電等で電源が遮断された場合にバッテリーからラズベリーパイに5Vを供給します。
その間にシャットダウンを実行することで、SDカードやデータの破損を防ぐことが可能です。
IMG_1531.jpg

ラズパイ工房 RaspberryPi用 UPS(無停電電源)HAT基板 (https://raspikoubou.theshop.jp/items/94650013)


ラズベリーパイの電源をブチ切りすると壊れることがある

ラズベリーパイでシャットダウンをせず電源をブチ切りすると、稀にSDカードが壊れることがあります。
自分が経験したのは、SDカード自体が壊れたのではなく、OS起動に大事なファイルが壊れたことで起動しないことがありました。
色々調べましたが、SDカードに新たにOSを焼き直すしかありませんでした...(windowsのセーフモードみたいなうやつ無いんですかね?)

そこで、今回はラズパイで簡易UPS基板を作成し、うっかりブチ切りしたしまった場合や停電した場合に、ラズベリーパイが安全にシャットダウンを行えるようにしようと思います。


UPS(無停電電源装置)とは

UPSとは無停電電源装置の略称です。
工場で生産した製品のデータを収集しているサーバーなど、データ壊れてしまうと困る物に使用します。無停電電源装置(UPS)を使うと、停電や電圧の変動が起きた際に電力を一時的に供給し、機器を安全にシャットダウンする時間を確保できます。これにより、作業中のデータが失われたり、機器が故障するリスクを軽減でき、重要なデータや機器を守ることができます。
下図のようなしっかりした物だと、ピンキリですが、うん十万円します。
UPSとは.jpg

NTTファシリティーズ(https://www.ntt-f.co.jp/service/ups/about/)


今回作った回路図

いきなりですが、今回作成した回路概要を下図に載せます。
一般的なUPSだと、電源正常時の電源ルートと、電源異常時の電源ルートを作成して、電源遮断時に即座に電源異常時のルートに切り替えるような回路だと思いますが、今回はできる限り簡素な構成にして、安価なUPS回路を目指しました。

今回作成した回路では、電源正常時と電源異常時のルートを共通にしています。そうすることで、電源異常時にFET等でルートを切り替える必要がなく部品点数が減っています。また、切替時の瞬間的な電源遮断が起こりません。

また、常にバッテリからの電力供給が可能なので、数秒間であれば入力電源の出力可能電力以上の電力を供給できたり、電源安定の効果も期待できます。

ですが、その代わりに常に昇圧回路が働いているなど、無駄な消費電力が増えてしまっています。

では、以下回路の各ブロックの設計を説明していきます。

一般的なUPS回路.jpg
バックアップ時.jpg

OMRON UPS回路(https://www.fa.omron.co.jp/products/family/3450/network.html)

回路概要.jpg

今回作成した回路概要


バッテリは電気二重層コンデンサ

普段スマホをよく使う皆さんが"バッテリー"と聞いてイメージするのはスマホを充電するモバイルバッテリーじゃないでしょうか。あれはリチウムイオン電池という電池を使っています。リチウムイオン電池は他には電気自動車やノートPCにも使われていますね。

ですが、今回はリチウムイオン電池ではなく、電気二重層コンデンサを使うことにしました。電気二重層コンデンサはパソコンのマザーボードや商業用電源についているアルミ電解コンデンサの大容量版のような物です。
電気二重層コンデンサ.jpg

電気二重層コンデンサ

コンデンサ特徴.jpg

日本ケミコン株式会社 電気二重層キャパシタの基礎知識(https://www.chemi-con.co.jp/products/edlc/knowledge.html)


今回は下記の理由で電気二重層コンデンサを使うことにしました。
・ラズパイのシャットダウンの時間稼ぎができればよいので、コンデンサのエネルギー密度で十分。
・コンデンサの方が短絡等が発生した時に発火や爆発のリスクが少ない。
・寿命が来てUPSが働かなかったなんてことが無いようにしたい。コンデンサなら5~10年持つ。
・コストが低い。
・充電が間に合わずUPSが働かなかったなんてことは避けたい。コンデンサなら充電が早い。

コンデンサ特徴.jpg

電気二重層キャパシタの基礎知識(https://jp.rs-online.com/web/content/discovery/ideas-and-advice/electric-double-layer-capacitors-guide?srsltid=AfmBOorYYJrAc2Mc_UG8-aB5nhc3GuvU5_BXF2SRTl2ttXjYocxTRZhX)



UPS回路

充電電流制限抵抗

電気二重層コンデンサの充放電カーブは下図のようになります。電源投入時のコンデンサは空で0Vとなります。
ですので、下図の回路図で電流制限抵抗が無いと、入力電源(ACアダプタ等)の5Vが0Vのコンデンサに直結するので、大きな突入電流が流れ、さらに充電が溜まるまでラズベリーパイへの電源が5V未満になってしまいます。

電流制限抵抗は20Ωとしました。コンデンサが空の時の充電電流は 5V/20Ω = 250mA となります。コンデンサの電圧は充電されるにつれて上がっていきますので、(5V-Vc)/20Ω と充電電流は小さくなっていきます。

この充電に必要な電力に加え、同時にラズベリーパイへの電力も必要ですので、入力電源は多少余力のある物を選ぶ必要があります。

入力電源遮断時にこのコンデンサから電力供給する場合、この電流制限抵抗が出力抵抗になってしまうのでまともに電力供給ができなくなってしまいます。
ですので、出力用にショットキーバリアダイオードを実装しています。ダイオードでの損失は避けられませんが、FET等で制御する必要が無いので楽ちんです。

放電特性.jpg

放電特性 (https://jp.rs-online.com/web/content/discovery/ideas-and-advice/electric-double-layer-capacitors-guide?srsltid=AfmBOorYYJrAc2Mc_UG8-aB5nhc3GuvU5_BXF2SRTl2ttXjYocxTRZhX)

説明回路1.jpg

回路概要 再UP


昇圧回路

コンデンサは満充電時に約5Vとなりますが、入力電源遮断時にコンデンサから電力供給するにつれて電圧が下がっていきます。ですので、単純にコンデンサをラズベリーパイの電源に繋ぐだけではすぐにラズベリーパイの必要電圧未満になりシャットダウンまでの時間を稼ぐことが出来ません。

そこで昇圧回路を実装しています。これでコンデンサが5V未満になっても電力を引き出してラズベリーパイに5Vを供給することができます。ですが、前述した通り、簡素化のため入力電源正常時も常にこの昇圧回路が働くような回路にしているため損失が発生し、定常的な消費電力が少し大きくなってしまっています。

昇圧回路にはTexas InstrumentsのTPS61230Aを使用しています。
これなら入力電源正常時は最大5V6A、電源遮断時はコンデンサが2.5Vでも2.4A供給することが出来ます。ラズベリーパイには十分でしょう。

電源IC.jpg

使用している昇圧コンバータIC TPS61230A (https://www.ti.com/product/ja-jp/TPS61230A?utm_source=google&utm_medium=cpc&utm_campaign=app-null-null-gpn_jp-cpc-pf-google-jp_jp_cons&utm_content=TPS61230A&ds_k=TPS61230A&DCM=yes&gad_source=1&gclid=Cj0KCQiArby5BhCDARIsAIJvjITZGZ_ZKy-mwrW0TlHqpkfHNSrW9qMX4Lo9ByixSdyci9nG4DYRhDcaAhmzEALw_wcB&gclsrc=aw.ds#description)

昇圧回路.jpg

データシートより


このIC、TPS61230Aは下図の通りデータシートに推奨部品の型式が載っており、推奨パターンまで載っています。
この通りに作ればいいだけ...なんて楽なんだ。
この型式の部品が入手できなくても、データシートにそれぞれの部品をどのように選定すればよいかが記載されていますので、しっかり読んで代替品を選べば問題ありません。

image.png

データシートより 推奨部品

推奨パターン.jpg

データシートより 推奨パターン


電源遮断検知

UPS回路があっても、電源遮断を検知してシャットダウンを実行することができなければ意味がありません。
この基板では下図のようにGPIO27で電源が入っているか入っていないかを知ることができるようにしてあります。
GPIOの定格は3.3Vですので、5VをR8,9(下図回路図参照)で分圧してGPIOに入力しています。C11は瞬間的な電源のブレでシャットダウンしないようにするための対策(おまじない)です。

D2は電源遮断を検知するための大事なショットキーバリアダイオードです。このダイオードが無いと、電源遮断が起きてもUPS回路が働き5Vが維持されてしまい、GPIO27にHIGHが入力され電源遮断を検知することができません。このダイオードがあることで、電源遮断時にGPIO27がLOWになります。

ショットキーバリアダイオードは順方向電圧が低く損失が小さいですが、リーク電流が大きいデメリットがあります。ですので分圧抵抗には2kΩと少し小さめの抵抗にしています。大きい抵抗値にしてしまうとリーク電流で電圧が発生し電源遮断を検知できなくなってしまいます。

ダイオードには他にもいくつか役割があります。
・電源の逆接続防止
・電圧降下することで電気二重層コンデンサの定格に対して余裕ができる(蓄積できるエネルギーも小さくなるが)
・昇圧ICの推奨入力電圧が4.5Vなので電圧を下げる

電源遮断検知回路.jpg

回路図の電源遮断を検知する部分


完成した回路図

作成した詳細の回路図が下図になります。
今まで説明した各要素を組み合わせたものになります。興味あればご覧ください。

回路図.jpg

完成した回路図


完成した基板で色々実験

完成した基板が下図になります。大分簡素になったかなと思います。
電気二重層コンデンサは立てると邪魔なので、横に曲げて実装しています。
電源用の端子は利便性のためにネジ端子とUSB-Cの2つを付けました。もちろん使うのは片方だけです。USB-Cの方はPDには対応していませんので、電源によっては5V給電できないので注意です。

ネジ端子とUSB-Cの間のパッドは何かって?ただのオシャレですよ(白目)。

これから下記の実験をしてみようと思います。
・UPS基板有り無しでの消費電力の差
・電源正常時/遮断時の出力電圧
・バックアップ可能時間
・充電にかかる時間
・電源遮断を検知してシャットダウンを実行

IMG_1531.jpg

完成した基板をラズベリーパイ5に載せた写真


UPS基板有り無しでの消費電力の差

ラズベリーパイ5にUPS基板を載せた場合と載せない場合(つまりどノーマル)で、直流安定化電源から5Vを供給し、直流安定化電源に表示される消費電力を比較しました。
UPS基板ありの場合は、バッテリーの電気二重層コンデンサが満充電になるまで待機し、コンデンサへの充電電力は除いています。

結果が下図です。予想通り、昇圧回路が常に働いていたりダイオードでの損失があるため、UPS基板ありですと10~20%程度消費電力が大きくなってしまっています。

消費電力グラフ.jpg

UPS基板使った場合とノーマルラズベリーパイ5の消費電力


電源正常時/遮断時の出力電圧

ちゃんと安定した5V電源が昇圧回路から出力されているか調べてみました。
下図は電源正常時と遮断時の出力電圧をオシロスコープで見てみた結果です。

電源正常時に高周波のスイッチングノイズのようなものが見られますが、バックアップ時には見られないので、恐らくUPS基板に5Vを入力している直流安定化電源からのノイズかと思われます。

電源遮断時の波形は、直流安定化電源をOFFにしてかつラズベリーパイがデスクトップ画面を映している時に取った波形です。安定して5Vを出力できていて、大きなノイズも見られません。

電源正常時.jpg

電源正常時の昇圧回路の出力電圧波形

バックアップ時.jpg

電源遮断(バックアップ)時の出力電圧波形


バックアップ可能時間

電源遮断時にどの程度の時間ラズベリーパイが動作し続けられるかストップウォッチで測定してみました。
特に何もアプリを立ち上げずデスクトップ画面を映しているだけの状態、CPU負荷を100%にした状態で測定しました。
UPS基板に繋がっている直流安定化電源をOFFにしたらストップウォッチをスタートし、ラズベリーパイが死んで画面が真っ暗になったら停止します。

写真では分かりにくいですが、下図のようにUPS基板の電力だけでラズパイが動いています。
UPSが切れると電源ランプが赤に変わります。

IMG_1537.jpg

UPS基板の電力だけで動いている写真 ラズパイにはHDMIしか繋がっていません。

IMG_1538.jpg

あ、死んだ


結果は下表です。
CPU100%だと2secです。間に合うかちょっと不安かなという感じでしょうか?即座にシャットダウンすれば間に合いそうですが、シャットダウンする前にデータの保存とか処理をしてたら間に合わないかもしれませんね。
デスクトップ表示だけの5secでしたら色々処理をしても余裕で間に合いそうです。

ラズベリーパイが動作停止した後バッテリのコンデンサには2.73V残っていました。バッテリ放電時はダイオードを通るので昇圧ICに入る電圧はおよそ 2.73V-0.5V = 2.13Vとなってしまい昇圧の限界になってしまった様です。

しばらくキャパシタ電圧を見ていましたが、完全放電には時間がかかりそうでしたのでキャパシタの残存電圧には注意ですね。
ちなみにキャパシタを完全放電したい場合はキャパシタの両端を短絡させればできます。

バックアップ時間.jpg

UPS基板の電力でどれだけ持つかの実験結果


充電にかかる時間

バッテリーのキャパシタを空の状態から充電するのにかかる時間も測定してみました。
5Vの入力電源がダイオードで電圧降下するので、キャパシタは最大約4.5Vまで充電されます。

測定した結果が下表です。充電開始時が最も充電速度が速く、段々と遅くなっていきます。
4Vまでは約170秒で充電できるのですが、そこからは大分遅くなり、4.4Vのほぼフル充電までには390秒かかりました。

充電時間.jpg

充電にかかる時間


電源遮断を検知してシャットダウンを実行

下記のようなPRGで実験を行いました。
GPIO27を監視し、GPIO27がLOWになったらシャットダウンを実行します。シャットダウンを実行した証拠にlogを残しています。
UPS基板に直流安定化電源から5Vを供給し、PRGを実行したら電源をOFFにします。

from gpiozero import DigitalInputDevice
from time import sleep
import logging
import os
import subprocess

# ログ設定
logging.basicConfig(
    filename="/var/log/power_monitor.log",  # ログの保存先
    level=logging.INFO,
    format="%(asctime)s - %(levelname)s - %(message)s"
)

# GPIO27 を入力ピンとして設定
input_pin = DigitalInputDevice(27)

def shutdown_system():
    """システムをシャットダウンする"""
    logging.info("シャットダウンを実行します。")
    try:
        subprocess.run(["sudo", "shutdown", "-h", "now"], check=True)
    except Exception as e:
        logging.error(f"シャットダウン中にエラー: {e}")

print("Monitoring GPIO27...")

try:
    while True:
        # 現在の状態を取得
        if input_pin.value:  # HIGH の場合
            print("電源正常")
        else:  # LOW の場合
            logging.warning("電源遮断検知、シャットダウン開始")
            shutdown_system()
            break  # シャットダウンプロセスを開始後、ループ終了
        sleep(1)  # 1秒待機
except KeyboardInterrupt:
    print("Program terminated.")

IMG_1539.jpg

実験の様子


結果が下図です。
電源をOFFしてラズベリーパイがシャットダウンを実行してOFFになったことを確認した後、再度ラズベリーパイを起動してみると、下図のようにちゃんとログが残っていることが確認できました。
CPU負荷100%でも同様に実験を行い、ログが残っていることが確認できました。

ちなみに、シャットダウン後に再度電源供給をしただけではラズベリーパイは起動しません。UPSが5Vを供給し続けているため、ラズパイからして見ると電源の立ち上がりが見えないからです。
電源供給した後に、ラズベリーパイの電源ボタンを押す必要があります。ラズベリーパイ5以外には電源ボタンが無いので、3,4だとこのUPS基板は大分扱いにくいです。

ちなみに起動時に「低電力イベント~」という電源の警告が表示されてしまいますが、「vcgencmd get_throttled」で調べられる電源のエラーコードをみると「0x0」と表示されるので問題は無さそうです。

電源実験.jpg

電源正常時

シャットダウンログ.jpg

ちゃんとログが残ってました


2025/8/9 色々不満点があったので改良してみた

使っているうちに、欲しい機能があれこれ出てきたので改良しました。

不満その1 LEDで視覚的に電力状態を知りたい

基板にLEDが付いていないので、電気の状態を目で確認できません。
電源投入中にうっかり導体を触ってしまったら危険ですし、電源投入していなくても、バッテリ(コンデンサ)に電力が残っていたら危険です。危険といっても電圧が低いので感電はしないですが、基板やその他機器が壊れる可能性があります。
LEDを追加して、バッテリに電力があるか一目で分かるようにします。

不満その2 放電スイッチが欲しい

電源を切った状態でも、バッテリにはだいたい2.5Vくらいの電圧が残っています。
所詮2.5Vですが、上記と同じく導体が触れてしまったら基板やその他機器が破損する可能性があります。
バッテリをワニ口クリップで短絡すれば放電できるんですが、毎回やるのは正直面倒…。
そこで、スイッチで簡単に「充電モード」と「放電モード」を切り替えられるようにしようと思います。

不満その3 バッテリの残存電圧を取得できるようにしたい

実験にてラズベリーパイが機能停止するまでの時間を測定しました。が、推定にしか使えません。
世界中のラズベリーパイはそれぞれ使い方(消費電力)が違うので、何秒までならセーフかなんて分かりません。
今のままだと、電源遮断を検知してからX秒でシャットダウンするというようなプログラムを作成するしかありません。そのX秒も保険で小さい数字にする必要があります。
そこで、ADコンバータを追加して、ラズベリーパイがいつでもバッテリの残存電圧を測定できるようにしたいと思います。

不満その4 USB-Cいらなくね

この基板は、バッテリを充電しながら動作する仕様のため、通常の Raspberry Pi よりも多くの電力を必要とします。
特に、バッテリが空の状態で起動する際は消費電力が増え、電源の供給能力が不足すると起動が不安定になります。

そのため、安定動作には 5V・1.5A 以上 を出力できる電源が必須です。
USB-C 電源でも条件を満たせば起動しますが、安定して使える電源を探すのが手間です。


改良版の基板作成

改良した回路図がこちらです。
一つずつ、改良ポイントを紹介していきます。
無題.jpg

改良したバッテリ周りの回路図

回路図.jpg

回路図全体

LEDの追加

バッテリの充電状態をひと目で確認できるよう、LED(LED1)を追加しました。
このLEDは順方向電圧が 約2.6V のため、バッテリがそれ以上に充電されると点灯します。

本当は「バッテリが少しでも残っていたら光る」仕様にしたかったのですが、電源が遮断されていたらラズベリーパイも動かないですし、そのために昇圧回路を設けたらバックアップ時間が減っちゃいますし…

また後ほど記載しますが、ラズベリーパイをバッテリでバックアップできる最低電圧は 約2.8V 程度。
そのため、LEDが点灯していれば「バックアップ可能な電圧まで充電されている」という目安にもなります。


バッテリの容量を増やしました

LEDやADコンバータを追加すると、バックアップ中の電力消費が多少増えていると思われます。
そこで、バッテリ容量を 3.5F → 5.0F に増量しました。これで少し余裕が持てます。


「放電」「充電」切替スイッチの追加

「SW1」が新しく追加したスイッチです。

・充電モード(回路図の通り1-2番が導通) → 従来通りの動作
・放電モード(2-3番が導通) → 120Ωの抵抗を介してバッテリをGNDに接続し、放電

ちなみに放電にかかる時間は、仮にバッテリが4.4Vまで充電されていたとすると、単純計算で時定数(120Ω x 5F)が600secになるので、3RCとすると30分かかることになります。
めっちゃ時間がかかりますが、これは基板を使い終わった後に行う想定なので特に問題なしです。

1.jpg

時定数カリキュレーター(https://www.digikey.jp/ja/resources/conversion-calculators/conversion-calculator-time-constant)

放電モード中に電源投入されても問題ない設計にしています。
放電モード中に電源投入されても、ダイオード(D1)がバッテリに電流が流れていかないように防いでくれます。これがないと、充電しながら放電することになるので、120Ωの抵抗が発熱してしまいます。


ADコンバータ

回路図の「IC1」が追加したADコンバーター、「ADS1110A0IDBVR」になります。
ADS1110A0IDBVR は、Texas Instruments社製の16ビット分解能のアナログ-デジタルコンバータです。
I²Cインターフェースを搭載し、基準電圧、プログラマブルゲインアンプ(PGA)、発振器までも内蔵した“ほぼワンチップ”のデータ計測ICです。低消費電力かつ高精度な計測が可能です。

  • 16ビット分解能(最大 ±2.048V 入力、PGAで最大8倍ゲイン)
  • オンボード基準電圧:2.048V ±0.05%、ドリフト5ppm/°C
  • オンボードPGA:ゲイン1/2/4/8切り替え
  • データレート設定:15 / 30 / 60 / 240 サンプル毎秒
  • I²C通信対応(8種類のアドレスバリエーション)
  • 動作電圧:2.7〜5.5V
  • 低消費電力:動作時 240µA、スリープ時 0.05µA
  • 自動セルフキャリブレーション機能搭載
  • シングル変換モードで計測後に自動パワーダウン

このADコンバータへの電源は、Raspberry Pi の GPIO1 ピン(3.3V)から供給しています。
ADS1110A0IDBVR のロジック閾値は電源電圧に依存するため、電源を3.3Vにすることで、同じく3.3Vロジックの Raspberry Pi と直接通信できます。

Raspberry Pi との通信は I²C を使用し、GPIO2(SDA)と GPIO3(SCL)に接続しています。
データシートでは I²C ラインにプルアップ抵抗を接続するよう記載されていますが、Raspberry Pi の GPIO2, GPIO3 には標準でプルアップ抵抗が内蔵されているため、外付けは不要です。
2.jpg

ADS1110A0IDBVRのデータシートより抜粋

測定できる電圧は±2.048Vなので、測定対象であるバッテリ電圧は、2/5 に分圧して VIN+ に入力しています。
ADS1110A0IDBVR は差動入力に対応していますが、今回は VIN− を GND に接続し、シングルエンド入力として使用しています。

完成した基板

完成した基板が下図です。まあ、見た目はそんなに大きく変わってませんね。
充電/放電切替スイッチと充電確認LEDは分かりやすいように大きなシルクで印字しています。

IMG_2730.jpg

完成した基板。光っているのがバッテリに電力が残っていることを示すLEDです。


改良した基板のスペックをチェックしてみる

それでは、改良した基板の各スペックを実際に計測して確認していきます。

バッテリー電力を示すLEDの動作

まず、バッテリーの充電と放電を試してみました。すると、電圧が約2.4Vに達した時点でLEDがうっすらと点灯し始めます。これにより、電源が供給されていることがひと目で分かります。
充電した後に電源供給を切り、ラズベリーパイが停止したタイミングでも、バッテリーの電圧は約2.9V残っていました。
LEDは2.4V以上で点灯するため、思惑通り「バッテリーがまだ残っている」と一目で判断できます。

充電速度

バッテリー容量が増えたぶん、充電にかかる時間もそれなりに長くなっていました。これはまあ、当然の結果ですね。

4.0Vまで充電 4.4Vまで充電
改良前 170sec 390sec
改良後 210sec 410sec

バックアップ時間

測定方法は従来と同じく、電源遮断からディスプレイが消えるまでの時間を基準にしています。
LED等によって多少消費電力は増えているものの、バッテリー容量の増加によりバックアップ時間は延びています。

デスクトップ画面 CPU使用率100%
改良前 5sec 2sec
改良後 9.6sec 2.7sec

放電モード

新たに追加した放電モードを試してみました。
電源遮断後、ラズベリーパイが停止するとバッテリー電圧は約2.9Vとなります。
そこから放電モードに切り替えたところ、0.35Vに達するまでに約20分かかりました。
(0.0Vになるまで測りたかったですが耐えられませんでしたw)
6.jpg

これが切替スイッチです。放電モードになってます。

ADコンバータ

下記のプログラムでADコンバータを動作しました。(サンキュー、GPT-5)

import smbus2
import time
import RPi.GPIO as GPIO

# --- 設定値 ---
I2C_BUS = 1                  # I2Cバス番号(Raspberry Pi 5では通常1)
ADS1110_ADDR = 0x48          # ADS1110のI2Cアドレス
POWER_OFF_PIN = 27           # 電源遮断検知用のGPIO番号(BCM番号で指定)

# --- GPIOの初期設定 ---
GPIO.setmode(GPIO.BCM)       # GPIOの番号指定方式をBCMに設定
GPIO.setup(POWER_OFF_PIN, GPIO.IN, pull_up_down=GPIO.PUD_UP)  # プルアップ入力に設定

# --- I2Cバスの初期化 ---
bus = smbus2.SMBus(I2C_BUS)

# --- データレート設定値からビット数を求める関数 ---
def nbits_from_dr(dr_bits):
    # データレート設定値(2ビット)から分解能ビット数を返す
    return {0b00: 12, 0b01: 14, 0b10: 15, 0b11: 16}[dr_bits]

# --- ADS1110から電圧を読み取る関数 ---
def read_ads1110():
    while True:
        # ADS1110から3バイト読み出す(上位8bit, 下位8bit, 設定バイト)
        data = bus.read_i2c_block_data(ADS1110_ADDR, 0, 3)
        msb, lsb, cfg = data

        # ST/DRDYビット(bit7)が1の場合は変換中なので少し待って再取得
        if (cfg >> 7) & 0x01 != 0:
            time.sleep(0.005)
            continue

        # 16bitの生データを結合
        raw16 = (msb << 8) | lsb

        # 符号付き整数に変換(負の値対応)
        if raw16 & 0x8000:
            raw_signed = raw16 - (1 << 16)
        else:
            raw_signed = raw16

        # データレート設定から分解能を決定
        dr_bits = (cfg >> 2) & 0x03
        max_code = 1 << (nbits_from_dr(dr_bits) - 1)

        # ADCの入力電圧を計算(ADS1110の基準電圧は2.048V)
        adc_voltage = (raw_signed / float(max_code)) * 2.048

        # 入力は5V系を2/5に分圧しているため、元の電圧に換算
        original_voltage = adc_voltage * (5.0 / 2.0)

        return raw_signed, adc_voltage, original_voltage

# --- 電源遮断検知フラグと時間 ---
power_off_detected = False
power_off_time = None

try:
    time.sleep(0.07)  # ADS1110の初回変換待ち
    while True:
        # 電圧測定
        raw, vin_adc, vin_orig = read_ads1110()

        # 測定結果を表示
        print(f"ADC_in: {vin_adc:.4f} V, Original: {vin_orig:.4f} V")

        # 電源遮断の検知
        if GPIO.input(POWER_OFF_PIN) == GPIO.LOW:
            if not power_off_detected:
                # 初回検知時
                print("電源遮断検知")
                power_off_detected = True
                power_off_time = time.time()
            else:
                # 経過時間を表示
                elapsed = time.time() - power_off_time
                msg = f"電源遮断から {elapsed:.1f} 秒経過"
                print(msg)

        # 1秒ごとの測定
        time.sleep(1.0)

except KeyboardInterrupt:
    # Ctrl+Cで終了した場合
    pass

finally:
    # 終了処理(I2CバスとGPIOを解放)
    bus.close()
    GPIO.cleanup()



ADコンバータの出力値とデジタルマルチメータの値を比較したのが下図になります。
マルチメータが4.514Vに対して、ADコンバータは4.525Vとなっておりほぼ一致しています。
IMG_2729.jpg


電源遮断してからラズベリーパイが機能停止するまでADコンバータを動作させて所、バッテリ電圧2.84Vくらいが動作の限界のようです。
電源遮断を検知後、限界電圧になるまでにシャットダウンを完了するようにすれば良いということです。


最後に

ご覧いただきありがとうございました。
この記事で設計した基板は「らずぱい工房」HPで販売しています。
興味がありましたら是非ご覧ください。
https://raspikoubou.theshop.jp/items/94650013

4
7
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
7

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?