はじめに
こちらはRaspberry Pi と LINE messaging API で作る監視カメラシリーズ第15弾です。
今回はみんな大好き、Lチカの会です。
内容は、2つのLEDと、2つのボタンを使用し、
Aボタンが押されている間は、A LEDが点灯する
Bボタンが押されている間は、B LEDが点滅する Lチカです。
※私が使用しているのはRaspberry Pi4 Model B ですので、その内容で解説します。
※今回は、技術記事っぽくLEDとプルアップ・プルダウンについて解説しております。
回路解説
まず、今回の回路イメージです。
下記イメージはWokwiで作成しましたが、RaspberryPi4Bが無かったため、Picoでのイメージになっています。
※Picoは使ったことがないので、解説できません。
Raspberry Pi 4Bに配線を接続するピン番号はこちらです。
(配線の色 → 物理ピン番号 / GPIOピン番号 または電源・GND)
赤 → 物理 1 / 3.3V | 黄 → 物理 13 / GPIO 27
黒 → 物理 6 / GND | 白 → 物理 16 / GPIO 23
橙 → 物理 11 / GPIO 17 | 茶 → 物理 18 / GPIO 24
LED の回路
まず、LED(発光ダイオード)を扱う際に知っておかないといけない事が主に2つあります。
1つ目に、LED(発光ダイオード)は、ダイオードの一種であり、ダイオード最大の特徴である、電流の流れる向きが決まっている(一方通行)という性質がある事です。
LEDをよく見ると片方の端子が少し長くなっています。
長い方は「アノード」と呼び、+の電源側(今回はGPIO)に繋ぎます。
短い方は「カソード」と呼び、ーの接地側(GND)に繋ぎます。
逆方向に電圧をかけても、電流は流れません。ですが、あまりに電圧が大きい場合は壊れます。
2つ目に、「電流が流れすぎると壊れる」という性質があります。
そのため、電源側からLED(アノード)の間には適切な抵抗を入れて、電流を制限してあげる必要があります。
適切な抵抗を選ぶ際には、順方向電圧を知る必要があります。
順方向電圧とは、使用するLEDが発光するために必要な電圧の事です。
まずは、LEDのデータシートを確認しましょう。
ここからは、私が使用する赤色LEDを例に解説します。
赤色LEDの順方向電圧は約2V(1.9-2.2V)で、最大電流は20mA、推奨電流は10mAです。
この場合、次のように考えます。
電源電圧 ー 順方向電圧
抵抗 = -------------------------
流したい電流
※GPIOを出力に設定した場合、3.3Vが流れます。
まず、最大電流以上の電流を流すと壊れる可能性が非常に高いので、こちらの抵抗を求めてみます。
3.3V ー 2V
抵抗 = -------------------
20mA(0.02A)
1.3 ÷ 0.02 = 65Ω となります。なので、最低でも65Ω以上の抵抗が必要です。
そして推奨電流を流す場合は、
3.3V ー 2V
130Ω = -------------------
10mA(0.01A)
なので、データシート上の推奨電流を流す場合、選ぶ抵抗は130Ωになります。
ですが、基本的にはもっと大きな抵抗を入れる方が安全と考えられます。
これに関しては、実際に試した経験が無いので、次の記事をオススメします。
今回、私は220Ωの抵抗を使用します。
220Ωなので約6mAが流れます。結構明るく光ります。
※私が持っている抵抗は、220Ωの次に大きいのが1kΩで、1kΩでは青色LEDの発光が小さかったので赤色LEDも220Ωで説明を統一します。
GPIOでLEDを操作する回路図はこちらです。
LEDの電源側(アノード)とGND側(カソード)の向きに気をつけてください。
プルアップ抵抗・プルダウン抵抗とは
ここでボタンの回路に進む前に前提知識として
プルアップ抵抗と、プルダウン抵抗について解説します。
まず、プルアップ抵抗とプルダウン抵抗とは、
GPIOピンやデジタル回路の入力状態が不安定にならないようにするため使われます。
簡単にいうと、ノイズ(意図しない電気のゆらぎ)の影響でピンへの入力がHIGHとLOWを行き来してしまうような、ふわふわした状態を防ぐために使用します。
次の回路はふわふわの状態をイメージした、スイッチONでHIGHを検知する回路です。
少し分かり難いかもしれませんが、スイッチを押すとVccからの電圧でGPIOはHIGHになります。
しかし、スイッチが押されていない(OFF)状態では、電源(HIGH)にも接地(LOW)にも接続されていない「浮いている」状態です。
この浮いている状態がノイズの影響を受けやすいため、回路の信頼性を低下させます。
ノイズのイメージがわからない場合は、LED単体の端子を手で触ってみてください。
ふわっと一瞬光る現象が確認できます。これは人間の体で発生している微弱な電流が流れるからです。
このような認識できていない微弱な電流が周囲の電線や電波、Wi-Fiなどからも発生しています。
ノイズによる影響を防ぐために通常時、「HIGH」に引っ張ってあげるのが「プルアップ抵抗」であり、「LOW」に引っ張ってあげるのが「プルダウン抵抗」です。
つまり、どちらかに引っ張ってあげることで「ノイズに影響されない状態を作る」のがプルアップ抵抗とプルダウン抵抗なのです。
プルアップ回路
ではまず、プルアップ回路について解説します。
プルアップは通常状態をHIGHにし、必要な時だけLOWに引き落とす回路です。
プルアップでもプルダウンでもVccとGNDの間には必ず抵抗を入れます。
VccとGNDが直接つながると大電流が流れショートして壊れてしまいます。
スイッチ OFF:GPIOは抵抗を通してVccと繋がっているため、HIGHに引っ張られる
スイッチ ON:GPIOは直接GNDと繋がり、LOWに引っ張られる
GPIO(入力)は電圧を見ています。そしてGPIOはインピーダンス(電気の通りにくさ)が低い方に引っ張られます。
分かり易くするためにもう一度深掘りして解説します。
スイッチ OFF:
・GPIOから見てVccは抵抗が10kΩ
・GPIOから見てGNDは回路が開いている(繋がっていない)ため、抵抗は∞Ω(無限大)
そのため、抵抗が低い方(低インピーダンス)のVccに引っ張られてHIGHになります。
スイッチ ON:
・GPIOから見てVccは抵抗が10kΩ
・GPIOから見てGNDは回路が繋がり、抵抗はほぼ0Ω(スイッチや配線にわずかな抵抗はあります)
そのため、抵抗がほぼ0Ωで電気が通りやすい(インピーダンスが低い)GND側に引っ張られてLOWになります。
もう1つ・・・ もし、抵抗がGND側にあったら・・・
スイッチをONにしても、電気の通りやすいVcc側(抵抗がほぼ0Ω)に引っ張られるのでHIGHのままになってしまい、プルアップになりません。(必要な時にLOWに引き落とせない)
つまり、抵抗でどちらを弱くするか、が重要です。
プルアップする場合は、スイッチをONにするとGNDに引っ張って欲しいので、Vcc側を弱くしたいです。なので、弱くしたいVcc側に抵抗を入れます。
プルダウン回路
次にプルダウン回路について解説します。
プルダウンはプルアップの逆で通常状態をLOWにし、必要な時だけHIGHに引き上げる回路です。
プルアップで細かく解説したので、ざっくり書きます。
スイッチ OFF:GPIOは抵抗を通してGNDと繋がっているため、LOWに引っ張られる
スイッチ ON:GPIOは直接Vccと繋がり、HIGHに引っ張られる
プルダウンもプルアップと同じく、抵抗でどちらを弱くするか、が重要です。
プルダウンする場合は、スイッチをONにするとVccに引っ張って欲しいので、GND側を弱くしたいです。なので、弱くしたいGND側に抵抗を入れます。
ボタンの回路
そして、今回のボタンの回路は、外部プルアップを使用します。
Raspberry Pi 4B は内部プルアップを使用できますが、理解を深めるために外部で実装しています。
こちらがボタンON/OFFを検知する回路図(外部プルアップ)です。
そして、ボタンをOFF・ONのイメージも記載します。
ボタンOFF
ボタンON
実物
私の実物はこんな感じです。
ダイソーで購入した箱に、はんだごてを使い溶かして穴を開けてます。
ちょっと大きいですが、結構気に入ってます。
ボタンを使ってLEDをチカチカするコードです。
line_botディレクトリに移動し
cd /home/pi/projects/line_bot
main.cppを作成します
vim main.cpp
テキストエディタに次のコードを貼り付けます。
#include <iostream>
#include <pigpio.h> // pigpioライブラリのヘッダー
#include <unistd.h> // usleep()のために必要
// GPIOピン番号の定義(BCM番号)
#define LED_BLUE 17
#define LED_RED 27
#define BTN_GREEN 23
#define BTN_RED 24
using namespace std;
int main(){
// pigpioライブラリの初期化
// gpioInitialise()は正常に初期化すれば0以上を、失敗すれば0未満を返す
if (gpioInitialise() < 0) {
cerr << "pigpio の初期化に失敗しました。" << endl;
return 1;
}
// 出力ピンの設定
gpioSetMode(LED_BLUE, PI_OUTPUT);
gpioSetMode(LED_RED, PI_OUTPUT);
// 入力ピンの設定
gpioSetMode(BTN_GREEN, PI_INPUT);
gpioSetMode(BTN_RED, PI_INPUT);
cout << "GPIO制御を開始しました。終了は Ctrl + C" << endl;
// メインループ
while (true) {
// ボタンの読み取りとLEDの制御
// 緑ボタンが押されているか確認
if (gpioRead(BTN_GREEN) == PI_LOW) {
// 緑ボタンが押されたら青LEDを点灯
gpioWrite(LED_BLUE, PI_HIGH);
} else {
// 押されていなければ消灯
gpioWrite(LED_BLUE, PI_LOW);
}
// 赤ボタンが押されているか確認
if (gpioRead(BTN_RED) == PI_LOW) {
// 赤ボタンが押されたら赤LEDを点滅
gpioWrite(LED_RED, PI_HIGH);
usleep(250000); // 250ms待機
gpioWrite(LED_RED, PI_LOW);
usleep(250000); // 250ms待機
} else {
// 押されていなければ消灯(チカチカしない)
gpioWrite(LED_RED, PI_LOW);
usleep(10000); // 少し待機してCPUの負荷を軽減
}
}
// プログラム終了時のクリーンアップ
gpioTerminate();
return 0;
}
ESCキーを押して、:wqを入力してEnterで保存して閉じます。
buildディレクトリに移動し、
cd build
makeコマンドでビルドします。
make
実行ファイルのmain_appをsudoコマンドと./で実行します。
sudo ./main_app
ボタンを押してみてLEDが点灯・点滅するか確認しましょう。
さいごに
組み込みの勉強で必ず通るLチカです。
記事を書くことにだいぶ疲れていましたが、この会は筆が乗って気持ちよく書けましたので、詳細に解説してみました。が、やっぱり途中で疲れました。
ですが、プルアップ・ダウン抵抗について改めて調べ、より理解が深まったのでよかったです。




