注釈
こんにちは、SunFounderのRaspberry Pi & Arduino & ESP32愛好家コミュニティへようこそ!Facebook上でRaspberry Pi、Arduino、ESP32についてもっと深く掘り下げ、他の愛好家と交流しましょう。
参加する理由は?
エキスパートサポート:コミュニティやチームの助けを借りて、販売後の問題や技術的な課題を解決します。
学び&共有:ヒントやチュートリアルを交換してスキルを向上させましょう。
独占的なプレビュー:新製品の発表や先行プレビューに早期アクセスしましょう。
特別割引:最新製品の独占割引をお楽しみください。
祭りのプロモーションとギフト:ギフトや祝日のプロモーションに参加しましょう。
👉 私たちと一緒に探索し、創造する準備はできていますか?[ここ]をクリックして今すぐ参加しましょう!
3.1.5 電池残量表示器(MCP3008)
はじめに
この課題では、電池の電圧を測定し、LEDバーグラフで残量を目に見える形で表示する装置を作ります。
警告
3.3Vを超える電池部品を使用しないでください。過負荷によりチップやRaspberry Piが損傷する可能性があります。
必要な部品
この課題には以下の部品を使います。
回路図
T-Board 名 |
物理 |
wiringPi |
BCM |
SPICE0 |
Pin 24 |
10 |
8 |
SPIMOSI |
Pin 19 |
12 |
10 |
SPIMISO |
Pin 21 |
13 |
9 |
SPISCLK |
Pin 23 |
14 |
11 |
GPIO25 |
Pin 22 |
6 |
25 |
GPIO12 |
Pin 32 |
26 |
12 |
GPIO16 |
Pin 36 |
27 |
16 |
GPIO20 |
Pin 38 |
28 |
20 |
GPIO21 |
Pin 40 |
29 |
21 |
GPIO5 |
Pin 29 |
21 |
5 |
GPIO6 |
Pin 31 |
22 |
6 |
GPIO13 |
Pin 33 |
23 |
13 |
GPIO19 |
Pin 35 |
24 |
19 |
GPIO26 |
Pin 37 |
25 |
26 |
実験手順
手順1: 回路を組み立てます。
C言語利用者向け
手順2: コードのある場所に移動します。
cd ~/davinci-kit-for-raspberry-pi/c/3.1.5-2/
手順3: コードをコンパイルします。
gcc 3.1.5_BatteryIndicator.c -lwiringPi
手順4: 実行ファイルを実行します。
sudo ./a.out
プログラムが動作したら、MCP3008の3番ピンとGNDからそれぞれ導線を引き出し、電池の両極に接続します。LEDバーグラフ上の対応するLEDが点灯し、電圧レベル(測定範囲: 0–5V)が表示されます。
注釈
実行後に動作しない、あるいは「wiringPi.h: No such file or directory」と表示される場合は、wiringPi のインストールと確認 を参照してください。
コード
#include <wiringPi.h>
#include <wiringPiSPI.h>
#include <stdio.h>
#define SPI_CHANNEL 0
#define SPI_SPEED 1000000 // 1MHz
#define VREF 3.3
int pins[10] = {6, 26, 27, 28, 29, 21, 22, 23, 24, 25};
int read_ADC(int channel)
{
if (channel < 0 || channel > 7) return -1;
unsigned char buffer[3];
buffer[0] = 1; // 開始ビット
buffer[1] = (8 + channel) << 4; // 単端入力モード
buffer[2] = 0;
wiringPiSPIDataRW(SPI_CHANNEL, buffer, 3);
int value = ((buffer[1] & 3) << 8) | buffer[2];
return value;
}
void LedBarGraph(int value) {
for (int i = 0; i < 10; i++) {
if (i < value)
digitalWrite(pins[i], HIGH);
else
digitalWrite(pins[i],LOW);
}
}
int main(void)
{
if (wiringPiSetup() == -1) {
printf("setup wiringPi failed!\n");
return 1;
}
if (wiringPiSPISetup(SPI_CHANNEL, SPI_SPEED) == -1) {
printf("SPI setup failed!\n");
return 1;
}
for (int i = 0; i < 10; i++) {
pinMode(pins[i], OUTPUT);
digitalWrite(pins[i], HIGH);
}
while (1) {
int analogVal = read_ADC(0); // MCP3008 CH0
if (analogVal < 0) continue;
float voltage = analogVal * VREF / 1023.0;
int level = analogVal * 10 / 1024;
if (level > 10) level = 10;
LedBarGraph(level);
printf("ADC Value: %d\tVoltage: %.2f V\tLevel: %d\n", analogVal, voltage, level);
delay(200);
}
return 0;
}
コード解説
int read_ADC(int channel)
{
if (channel < 0 || channel > 7) return -1;
unsigned char buffer[3];
buffer[0] = 1; // 開始ビット
buffer[1] = (8 + channel) << 4; // 単端入力モード, CH0~CH7
buffer[2] = 0;
wiringPiSPIDataRW(SPI_CHANNEL, buffer, 3);
int value = ((buffer[1] & 3) << 8) | buffer[2]; // 10bitの結果を結合
return value;
}
この関数は、SPIを介してMCP3008からアナログ値を読み取ります。 channel 引数で 8つの入力端子(CH0–CH7)のいずれかを選択します。 MCP3008は0~1023の範囲の10bitの値を返し、これはアナログ電圧を表します。
void LedBarGraph(int value) {
for (int i = 0; i < 10; i++) {
if (i < value)
digitalWrite(pins[i], HIGH); // LEDを点灯(アクティブHIGH配線を仮定)
else
digitalWrite(pins[i], LOW); // LEDを消灯
}
}
この関数は10個のLEDで構成されたバーグラフを制御します。 各LEDは電圧範囲の1/10を表します。 指定されたレベルまで順にLEDが点灯します。
注意: この実装は、LEDアノードがGPIO、カソードがGNDに接続されている(アクティブHIGH)の場合を想定しています。
int main(void)
{
if (wiringPiSetup() == -1) {
printf("setup wiringPi failed!\n");
return 1;
}
if (wiringPiSPISetup(SPI_CHANNEL, SPI_SPEED) == -1) {
printf("SPI setup failed!\n");
return 1;
}
for (int i = 0; i < 10; i++) {
pinMode(pins[i], OUTPUT);
digitalWrite(pins[i], HIGH); // 初期状態で全LEDを点灯
}
while (1) {
int analogVal = read_ADC(0); // CH0の電圧を読み取る
if (analogVal < 0) continue;
float voltage = analogVal * VREF / 1023.0;
int level = analogVal * 10 / 1024; // 0~10段階に変換
if (level > 10) level = 10;
LedBarGraph(level); // LEDでレベルを表示
printf("ADC Value: %d\tVoltage: %.2f V\tLevel: %d\n", analogVal, voltage, level);
delay(200); // 更新速度: 5 Hz
}
return 0;
}
主な処理の流れ:
wiringPiとSPI通信を初期化する
10個のLED制御用にGPIOを出力に設定する
MCP3008(CH0)でアナログ電圧を読み取る
読み取った値を基準電圧
VREF = 3.3Vで電圧に換算する電圧を0~10段階に割り当ててLEDバーグラフに表示する
シリアル画面にADC値・電圧(V単位)・LEDレベルを表示する
これにより、電池残量表示器または簡易電圧計として動作します。
Python利用者向け
手順2: SPIインターフェースを有効化し、 spidev ライブラリを導入します(詳細は SPI 設定 を参照)。すでに済んでいる場合は省略できます。
手順3: コードのある場所に移動します。
cd ~/davinci-kit-for-raspberry-pi/python
手順4: 実行ファイルを実行します。
sudo python3 3.1.5-2_BatteryIndicator.py
プログラムを実行したら、ADC0834の3番ピンとGNDからそれぞれ導線を引き出し、電池の両極に接続します。LEDバーグラフ上の対応するLEDが点灯し、電圧レベル(測定範囲: 0–5V)が表示されます。
警告
もし RuntimeError: Cannot determine SOC peripheral base address という誤りが出た場合は、「gpiozero」が動作しない場合。 を参照してください。
コード
注釈
以下のコードは 修正/リセット/コピー/実行/停止 が可能です。ただしその前に davinci-kit-for-raspberry-pi/python のようなソースコードの場所に移動しておく必要があります。修正後は直接実行して動作を確認できます。
#!/usr/bin/env python3
import RPi.GPIO as GPIO
import spidev
import time
# 左から右に並んだ10個のLEDに接続されたGPIOピン
led_pins = [25, 12, 16, 20, 21, 5, 6, 13, 19, 26] # BCM番号
# GPIO設定
GPIO.setmode(GPIO.BCM)
for pin in led_pins:
GPIO.setup(pin, GPIO.OUT)
GPIO.output(pin, GPIO.LOW)
# SPI初期化
spi = spidev.SpiDev()
spi.open(0, 0) # バス0, CE0
spi.max_speed_hz = 1000000 # 1 MHz
# MCP3008のチャネルから値を読み取る
def read_adc(channel):
if channel < 0 or channel > 7:
return -1
r = spi.xfer2([1, (8 + channel) << 4, 0])
value = ((r[1] & 0x03) << 8) | r[2]
return value
# 値に応じてLEDバーグラフを点灯
def led_bar_graph(level):
for i, pin in enumerate(led_pins):
if i < level:
GPIO.output(pin, GPIO.HIGH)
else:
GPIO.output(pin, GPIO.LOW)
# 主ループ
try:
while True:
analog_val = read_adc(0) # MCP3008 CH0から読み取る
level = int(analog_val * 10 / 1023)
led_bar_graph(level)
print(f"ADC: {analog_val}, Level: {level}")
time.sleep(0.2)
except KeyboardInterrupt:
pass
finally:
for pin in led_pins:
GPIO.output(pin, GPIO.LOW)
GPIO.cleanup()
spi.close()
コード解説
このプログラムは、MCP3008からアナログ電圧を読み取り、その結果をRaspberry Pi(BCMピン配置)で10個のLEDバーグラフに表示します。
モジュールを導入
RPi.GPIO… Raspberry PiのGPIO制御spidev… SPIを介してMCP3008と通信time… 待機/スリープ処理
#!/usr/bin/env python3 import RPi.GPIO as GPIO import spidev import time
GPIO LED設定
10個のGPIOピンをLED制御用に定義。出力に設定し、初期状態はLOW(消灯)。
led_pins = [25, 12, 16, 20, 21, 5, 6, 13, 19, 26] GPIO.setmode(GPIO.BCM) for pin in led_pins: GPIO.setup(pin, GPIO.OUT) GPIO.output(pin, GPIO.LOW)
SPI初期化
MCP3008と通信するためにバス0、CE0を使用。通信速度は1 MHzに設定。
spi = spidev.SpiDev() spi.open(0, 0) spi.max_speed_hz = 1000000
ADC読み取り関数
MCP3008の指定チャネル(0–7)から値を読み取る。3バイトのSPI信号を送り、10bitの結果を取得。
def read_adc(channel): if channel < 0 or channel > 7: return -1 r = spi.xfer2([1, (8 + channel) << 4, 0]) value = ((r[1] & 0x03) << 8) | r[2] return value
LEDバーグラフ関数
アナログ値に応じてLEDを点灯。例えばレベル7なら最初の7個が点灯し、残りは消灯。
def led_bar_graph(level): for i, pin in enumerate(led_pins): if i < level: GPIO.output(pin, GPIO.HIGH) else: GPIO.output(pin, GPIO.LOW)
主ループ
CH0からアナログ値を読み取り、0~10の範囲にスケーリングし、LEDに表示。シリアルにADC値とレベルを出力。
try: while True: analog_val = read_adc(0) level = int(analog_val * 10 / 1023) led_bar_graph(level) print(f"ADC: {analog_val}, Level: {level}") time.sleep(0.2)
終了処理
Ctrl+Cで停止したとき、すべてのLEDを消灯し、GPIOを解放し、SPIを閉じる。
except KeyboardInterrupt: pass finally: for pin in led_pins: GPIO.output(pin, GPIO.LOW) GPIO.cleanup() spi.close()