.. note:: こんにちは、SunFounderのRaspberry Pi & Arduino & ESP32愛好家コミュニティへようこそ!Facebook上でRaspberry Pi、Arduino、ESP32についてもっと深く掘り下げ、他の愛好家と交流しましょう。 **参加する理由は?** - **エキスパートサポート**:コミュニティやチームの助けを借りて、販売後の問題や技術的な課題を解決します。 - **学び&共有**:ヒントやチュートリアルを交換してスキルを向上させましょう。 - **独占的なプレビュー**:新製品の発表や先行プレビューに早期アクセスしましょう。 - **特別割引**:最新製品の独占割引をお楽しみください。 - **祭りのプロモーションとギフト**:ギフトや祝日のプロモーションに参加しましょう。 👉 私たちと一緒に探索し、創造する準備はできていますか?[|link_sf_facebook|]をクリックして今すぐ参加しましょう! .. _3.1.5_c_mcp3008: 3.1.5 電池残量表示器(MCP3008) ================================== .. note:: .. image:: img/mcp3008_and_adc0834.jpg :width: 25% :align: left お持ちのキットの種類に応じて、 **ADC0834** か **MCP3008** を確認し、対応する節を参照してください。 はじめに -------------- この課題では、電池の電圧を測定し、LEDバーグラフで残量を目に見える形で表示する装置を作ります。 .. warning:: 3.3Vを超える電池部品を使用しないでください。過負荷によりチップやRaspberry Piが損傷する可能性があります。 必要な部品 ------------------------------ この課題には以下の部品を使います。 .. image:: img/list2_Battery_Indicator.png :align: center 回路図 ------------------- ============ ======== ======== === 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 ============ ======== ======== === .. image:: img/schematic_battery_indicator_mcp3008.png :align: center 実験手順 ------------------------- **手順1:** 回路を組み立てます。 .. image:: img/july24_3.1.5_battery_indicator_mcp3008.png **C言語利用者向け** ^^^^^^^^^^^^^^^^^^^^^^^^^ **手順2:** コードのある場所に移動します。 .. code-block:: cd ~/davinci-kit-for-raspberry-pi/c/3.1.5-2/ **手順3:** コードをコンパイルします。 .. code-block:: gcc 3.1.5_BatteryIndicator.c -lwiringPi **手順4:** 実行ファイルを実行します。 .. code-block:: sudo ./a.out プログラムが動作したら、MCP3008の3番ピンとGNDからそれぞれ導線を引き出し、電池の両極に接続します。LEDバーグラフ上の対応するLEDが点灯し、電圧レベル(測定範囲: 0–5V)が表示されます。 .. note:: 実行後に動作しない、あるいは「wiringPi.h: No such file or directory」と表示される場合は、:ref:`install_wiringpi` を参照してください。 コード -------- .. code-block:: c #include #include #include #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; } コード解説 ---------------------- .. code-block:: c 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の値を返し、これはアナログ電圧を表します。 .. code-block:: c 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)の場合を想定しています。 .. code-block:: c 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`` ライブラリを導入します(詳細は :ref:`spi_configuration` を参照)。すでに済んでいる場合は省略できます。 **手順3:** コードのある場所に移動します。 .. code-block:: cd ~/davinci-kit-for-raspberry-pi/python **手順4:** 実行ファイルを実行します。 .. code-block:: sudo python3 3.1.5-2_BatteryIndicator.py プログラムを実行したら、ADC0834の3番ピンとGNDからそれぞれ導線を引き出し、電池の両極に接続します。LEDバーグラフ上の対応するLEDが点灯し、電圧レベル(測定範囲: 0–5V)が表示されます。 .. warning:: もし ``RuntimeError: Cannot determine SOC peripheral base address`` という誤りが出た場合は、:ref:`faq_soc` を参照してください。 **コード** .. note:: 以下のコードは **修正/リセット/コピー/実行/停止** が可能です。ただしその前に ``davinci-kit-for-raspberry-pi/python`` のようなソースコードの場所に移動しておく必要があります。修正後は直接実行して動作を確認できます。 .. code-block:: 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バーグラフに表示します。 1. **モジュールを導入** - ``RPi.GPIO`` … Raspberry PiのGPIO制御 - ``spidev`` … SPIを介してMCP3008と通信 - ``time`` … 待機/スリープ処理 .. code-block:: python #!/usr/bin/env python3 import RPi.GPIO as GPIO import spidev import time 2. **GPIO LED設定** 10個のGPIOピンをLED制御用に定義。出力に設定し、初期状態はLOW(消灯)。 .. code-block:: python 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) 3. **SPI初期化** MCP3008と通信するためにバス0、CE0を使用。通信速度は1 MHzに設定。 .. code-block:: python spi = spidev.SpiDev() spi.open(0, 0) spi.max_speed_hz = 1000000 4. **ADC読み取り関数** MCP3008の指定チャネル(0–7)から値を読み取る。3バイトのSPI信号を送り、10bitの結果を取得。 .. code-block:: python 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 5. **LEDバーグラフ関数** アナログ値に応じてLEDを点灯。例えばレベル7なら最初の7個が点灯し、残りは消灯。 .. code-block:: python 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) 6. **主ループ** CH0からアナログ値を読み取り、0~10の範囲にスケーリングし、LEDに表示。シリアルにADC値とレベルを出力。 .. code-block:: python 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) 7. **終了処理** Ctrl+Cで停止したとき、すべてのLEDを消灯し、GPIOを解放し、SPIを閉じる。 .. code-block:: python except KeyboardInterrupt: pass finally: for pin in led_pins: GPIO.output(pin, GPIO.LOW) GPIO.cleanup() spi.close()