.. note::
こんにちは、SunFounder Raspberry Pi & Arduino & ESP32 愛好者コミュニティ (Facebook) へようこそ!
Raspberry Pi、Arduino、ESP32 を仲間と共にさらに深く学びましょう。
**参加する理由**
- **専門サポート**: 購入後の問題や技術的課題をコミュニティとチームで解決
- **学びと共有**: ヒントやチュートリアルを交換し、スキルを向上
- **限定プレビュー**: 新製品発表や先行情報に早期アクセス
- **特別割引**: 新製品を特別価格で購入可能
- **イベントとプレゼント企画**: プレゼントや季節ごとのキャンペーンに参加
👉 一緒に探求し、創造しましょう。今すぐ [|link_sf_facebook|] をクリックして参加!
.. _4.1.10_py_mcp3008:
4.1.10 スマートファン (MCP3008)
================================
.. note::
.. image:: ../img/mcp3008_and_adc0834.jpg
:width: 25%
:align: left
キットのバージョンにより **ADC0834** または **MCP3008** が含まれています。自分のキットに対応するセクションに従ってください。
概要
----
このプロジェクトでは、モーター、ボタン、サーミスタを使用して、手動 + 自動制御が可能で風速を調整できるスマートファンを作成します。
必要な部品
----------
このプロジェクトで必要な部品は以下の通りです。
.. image:: ../img/list2_Smart_Fan.png
:width: 800
:align: center
キット一式を購入するのが便利です。リンクはこちら:
.. list-table::
:widths: 20 20 20
:header-rows: 1
* - 名前
- キット内の部品数
- リンク
* - Raphael Kit
- 337
- |link_Raphael_kit|
個別購入する場合は以下のリンクを参照してください。
.. list-table::
:widths: 30 20
:header-rows: 1
* - 部品名
- 購入リンク
* - :ref:`cpn_gpio_extension_board`
- |link_gpio_board_buy|
* - :ref:`cpn_breadboard`
- |link_breadboard_buy|
* - :ref:`cpn_wires`
- |link_wires_buy|
* - :ref:`cpn_resistor`
- |link_resistor_buy|
* - :ref:`cpn_power_module`
- \-
* - :ref:`cpn_thermistor`
- |link_thermistor_buy|
* - :ref:`cpn_l293d`
- \-
* - :ref:`cpn_mcp3008`
- \-
* - :ref:`cpn_button`
- |link_button_buy|
* - :ref:`cpn_motor`
- |link_motor_buy|
回路図
------
============ ======== ======== ===
T-Board 名 physical wiringPi BCM
SPICE0 Pin 24 10 8
SPIMOSI Pin 19 12 10
SPIMISO Pin 21 13 9
SPISCLK Pin 23 14 11
GPIO22 Pin 15 3 22
GPIO5 Pin 29 21 5
GPIO6 Pin 31 22 6
GPIO13 Pin 33 23 13
============ ======== ======== ===
.. image:: ../img/schematic_3.1.4_smart_fan_mcp3008.png
:align: center
実験手順
--------
**ステップ 1:** 回路を組み立てます。
.. image:: ../img/july24_3.1.4_smart_fan_mcp3008.png
.. note::
電源モジュールには付属の9V電池と9V電池スナップを使用できます。
電源モジュールのジャンパキャップをブレッドボードの5Vバスストリップに差し込みます。
.. image:: ../img/image118.jpeg
:align: center
**ステップ 2:** SPIインターフェースを設定し、 ``spidev`` ライブラリをインストールします(詳細は :ref:`spi_configuration` を参照)。すでに設定済みの場合はこのステップを省略できます。
**ステップ 3:** コードのフォルダに移動します。
.. raw:: html
.. code-block::
cd ~/raphael-kit/python
**ステップ 4:** 実行します。
.. raw:: html
.. code-block::
sudo python3 4.1.10-2_SmartFan.py
コードを実行すると、ボタンを押すことでファンが始動します。押すたびに速度が1段階ずつ変化します。
速度段階は **0~4** の5段階です。4段階目でさらにボタンを押すと、ファンは停止(速度0)します。
温度が±2℃以上変化すると、速度は自動的に1段階上昇または下降します。
コード
------
.. raw:: html
.. code-block:: python
#!/usr/bin/env python3
import RPi.GPIO as GPIO
import spidev
import time
import math
# Pin configuration
BTN_PIN = 22 # Button GPIO (physical pin 15)
MOTOR_IN1 = 5 # Motor forward
MOTOR_IN2 = 6 # Motor backward
MOTOR_EN = 13 # PWM enable pin
# GPIO setup
GPIO.setmode(GPIO.BCM)
GPIO.setup(BTN_PIN, GPIO.IN, pull_up_down=GPIO.PUD_UP)
GPIO.setup(MOTOR_IN1, GPIO.OUT)
GPIO.setup(MOTOR_IN2, GPIO.OUT)
GPIO.setup(MOTOR_EN, GPIO.OUT)
# PWM setup for motor speed control
pwm = GPIO.PWM(MOTOR_EN, 1000) # 1kHz frequency
pwm.start(0)
# Initialize SPI for MCP3008
spi = spidev.SpiDev()
spi.open(0, 0) # Bus 0, CE0
spi.max_speed_hz = 1000000 # 1 MHz
# Global variables
level = 0
currentTemp = 0
markTemp = 0
def read_adc(channel):
if channel < 0 or channel > 7:
return -1
adc = spi.xfer2([1, (8 + channel) << 4, 0])
value = ((adc[1] & 0x03) << 8) | adc[2]
return value
def temperature():
analogVal = read_adc(0)
Vr = 3.3 * analogVal / 1023.0
Rt = 10000.0 * Vr / (3.3 - Vr)
tempK = 1.0 / (((math.log(Rt / 10000.0)) / 3950.0) + (1.0 / (273.15 + 25.0)))
Cel = tempK - 273.15
return Cel
def motor_run(level):
if level == 0:
GPIO.output(MOTOR_IN1, GPIO.LOW)
GPIO.output(MOTOR_IN2, GPIO.LOW)
pwm.ChangeDutyCycle(0)
return 0
if level >= 4:
level = 4
GPIO.output(MOTOR_IN1, GPIO.HIGH)
GPIO.output(MOTOR_IN2, GPIO.LOW)
pwm.ChangeDutyCycle(level * 25) # Map level (1–4) to 25%–100%
return level
def changeLevel(channel):
global level, currentTemp, markTemp
print("Button pressed")
level = (level + 1) % 5
markTemp = currentTemp
# Add event detection for button press
GPIO.add_event_detect(BTN_PIN, GPIO.FALLING, callback=changeLevel, bouncetime=300)
def main():
global level, currentTemp, markTemp
markTemp = temperature()
while True:
currentTemp = temperature()
if level != 0:
if currentTemp - markTemp <= -2:
level -= 1
markTemp = currentTemp
elif currentTemp - markTemp >= 2:
if level < 4:
level += 1
markTemp = currentTemp
level = motor_run(level)
time.sleep(0.2)
try:
main()
except KeyboardInterrupt:
pass
finally:
pwm.stop()
GPIO.cleanup()
spi.close()
コード解説
----------
1. 必要なモジュールをインポート:
- ``RPi.GPIO`` (ボタンとモーターのGPIO制御)
- ``spidev`` (MCP3008 ADCとの通信)
- ``time`` (待機処理)
- ``math`` (温度計算用の対数演算)
.. code-block:: python
#!/usr/bin/env python3
import RPi.GPIO as GPIO
import spidev
import time
import math
2. GPIOピン設定:
- ボタン: GPIO22(内部プルアップ付き)
- モーター制御: GPIO5(前進)、GPIO6(後退)、GPIO13(PWMイネーブル)
.. code-block:: python
BTN_PIN = 22
MOTOR_IN1 = 5
MOTOR_IN2 = 6
MOTOR_EN = 13
GPIO.setmode(GPIO.BCM)
GPIO.setup(BTN_PIN, GPIO.IN, pull_up_down=GPIO.PUD_UP)
GPIO.setup(MOTOR_IN1, GPIO.OUT)
GPIO.setup(MOTOR_IN2, GPIO.OUT)
GPIO.setup(MOTOR_EN, GPIO.OUT)
pwm = GPIO.PWM(MOTOR_EN, 1000)
pwm.start(0)
3. SPI通信設定(MCP3008をバス0, CE0, 1MHzで接続)。
.. code-block:: python
spi = spidev.SpiDev()
spi.open(0, 0)
spi.max_speed_hz = 1000000
4. ``read_adc()`` 関数: MCP3008の指定チャネル(0~7)から10ビット値(0~1023)を読み取る。
.. code-block:: python
def read_adc(channel):
if channel < 0 or channel > 7:
return -1
adc = spi.xfer2([1, (8 + channel) << 4, 0])
value = ((adc[1] & 0x03) << 8) | adc[2]
return value
5. ``temperature()`` 関数:
- アナログ電圧を抵抗値に変換
- Steinhart–Hart式で摂氏温度に変換
.. code-block:: python
def temperature():
analogVal = read_adc(0)
Vr = 3.3 * analogVal / 1023.0
Rt = 10000.0 * Vr / (3.3 - Vr)
tempK = 1.0 / (((math.log(Rt / 10000.0)) / 3950.0) + (1.0 / (273.15 + 25.0)))
Cel = tempK - 273.15
return Cel
6. ``motor_run()`` 関数:
- レベル0で停止
- レベル1~4でPWM 25%~100%に対応させ速度調整
.. code-block:: python
def motor_run(level):
if level == 0:
GPIO.output(MOTOR_IN1, GPIO.LOW)
GPIO.output(MOTOR_IN2, GPIO.LOW)
pwm.ChangeDutyCycle(0)
return 0
if level >= 4:
level = 4
GPIO.output(MOTOR_IN1, GPIO.HIGH)
GPIO.output(MOTOR_IN2, GPIO.LOW)
pwm.ChangeDutyCycle(level * 25)
return level
7. ``changeLevel()`` コールバック:
- ボタンを押すたびに速度レベルを1段階変更(0~4をループ)
- 基準温度を現在温度に更新
.. code-block:: python
def changeLevel(channel):
global level, currentTemp, markTemp
print("Button pressed")
level = (level + 1) % 5
markTemp = currentTemp
GPIO.add_event_detect(BTN_PIN, GPIO.FALLING, callback=changeLevel, bouncetime=300)
8. ``main()`` ループ:
- 温度変化が±2℃を超えたら速度を自動調整
- 0.2秒ごとにモーター速度を更新
.. code-block:: python
def main():
global level, currentTemp, markTemp
markTemp = temperature()
while True:
currentTemp = temperature()
if level != 0:
if currentTemp - markTemp <= -2:
level -= 1
markTemp = currentTemp
elif currentTemp - markTemp >= 2:
if level < 4:
level += 1
markTemp = currentTemp
level = motor_run(level)
time.sleep(0.2)
9. Ctrl+Cで停止した場合のクリーンアップ:
- モーター停止、GPIO解放、SPI終了
.. code-block:: python
try:
main()
except KeyboardInterrupt:
pass
finally:
pwm.stop()
GPIO.cleanup()
spi.close()