はじめに
Nerves Livebook で Raspberry Pi 用スターター電子工作キットを楽しんでいます
SunFounder Raspberry Pi 用のスターター電子工作キット
これまでの記事
- Nerves Livebook で Raspberry Pi 4 のLチカ
- Nerves Livebook + Delux で簡単Lチカ
- MacBook 上の Livebook から Raspberry Pi 上の Livebook に接続してLチカする
- Nerves Livebook から GPIO 拡張ボードの LED を点滅させる
- Nerves Livebook から RGB LED を制御する(ソフトPWMもやってみる)
- Nerves Livebook から LED 棒グラフを制御する
- Nerves Livebook でボタンとLEDを連動させる
- Nerves Livebook で 7 セグメントディスプレイに文字を表示する
- Nerves Livebook で 4 桁 7 セグメントディスプレイに文字を表示する
- Nerves Livebook で LED ドットマトリックスにアニメーションを表示する
- Nerves Livebook でアクティブブザーを鳴らす
- Nerves Livebook でパッシブブザーを演奏しドレミの歌を奏でる
- Nerves Livebook でポテンショメーターからアナログ値を取得してデジタル値に変換する
この記事ではフォトレジスターで明るさを検知し、LEDの光の強弱を制御します
また、必要なモジュールを追加するため、 Nerves Livebook をカスタマイズします
実装したノートブックはこちら
フォトレジスター
当たっている光の強さによって抵抗値が変化します
ADC0834
ADC0834 は AD 変換器(AD コンバーター)です
REF の電圧(5V)を基準として、CH0〜3の入力電圧(アナログ値)がどの程度なのか 0 〜 255 の 256 段階(8 bit)のデジタル値に変換します
回路の組み立て
オンライン説明書の通りに回路を組みます
ただし、 LED に接続するピンはPWM対応が必須であるため、 GPIO22 ではなく GPIO12 を使います
Nerves Livebook のカスタマイズ
以下の記事に従って Pigpiox 追加済の Nerves Livebook を使用します
ノートブックの実装
Nerves Livebook を開き、以降のコードを実行していきます
コードの内容は前回の記事と全く同じです
ピンを開く
ADC0834 を制御するためのピンを開きます
{:ok, cs} = Circuits.GPIO.open("GPIO17", :output)
{:ok, clk} = Circuits.GPIO.open("GPIO18", :output)
{:ok, dio} = Circuits.GPIO.open("GPIO27", :output)
dio
は DI と DO の両方に接続し、必要に応じて入出力を切り替えて使用します
モジュール定義
ADC0834 を制御するモジュールを定義します
defmodule ADC do
import Bitwise
def get_result(dio, clk, cs, channel \\ 0) do
sel = if channel > 1, do: 1, else: 0
odd = channel &&& 1
# AD 変換開始
Circuits.GPIO.write(cs, 0)
start_adc(dio, clk)
# シングルエンド信号を使用(1本の信号だけを読む)
single_end_mode(dio, clk)
# チャンネル設定(デフォルトは CH0 を使用)
set_odd(dio, clk, odd)
set_sel(dio, clk, sel)
# dio を入力に設定
Circuits.GPIO.set_direction(dio, :input)
# AD変換を実行し、各桁の値を取得
dat1 =
0..7
|> Enum.reduce(0, fn _i, acc ->
Circuits.GPIO.write(clk, 1)
:timer.sleep(2)
Circuits.GPIO.write(clk, 0)
:timer.sleep(2)
Circuits.GPIO.set_direction(dio, :input)
bit = Circuits.GPIO.read(dio)
acc = acc <<< 1 ||| bit
acc
end)
# AD変換完了後に改めて逆順で各桁の値を取得
dat2 =
0..7
|> Enum.reduce(0, fn i, acc ->
bit = Circuits.GPIO.read(dio)
acc = acc ||| bit <<< i
Circuits.GPIO.write(clk, 1)
:timer.sleep(2)
Circuits.GPIO.write(clk, 0)
:timer.sleep(2)
acc
end)
# AD 変換終了
Circuits.GPIO.write(cs, 1)
Circuits.GPIO.set_direction(dio, :output)
# 変換中と変換後の値が等しければ出力する
if dat1 == dat2, do: dat1, else: 0
end
defp start_adc(dio, clk) do
Circuits.GPIO.write(clk, 0)
Circuits.GPIO.write(dio, 1)
:timer.sleep(2)
Circuits.GPIO.write(clk, 1)
:timer.sleep(2)
end
defp single_end_mode(dio, clk) do
Circuits.GPIO.write(clk, 0)
Circuits.GPIO.write(dio, 1)
:timer.sleep(2)
Circuits.GPIO.write(clk, 1)
:timer.sleep(2)
end
defp set_odd(dio, clk, odd) do
Circuits.GPIO.write(clk, 0)
Circuits.GPIO.write(dio, odd)
:timer.sleep(2)
Circuits.GPIO.write(clk, 1)
:timer.sleep(2)
end
defp set_sel(dio, clk, sel) do
Circuits.GPIO.write(clk, 0)
Circuits.GPIO.write(dio, sel)
:timer.sleep(2)
Circuits.GPIO.write(clk, 1)
:timer.sleep(2)
Circuits.GPIO.write(clk, 0)
:timer.sleep(2)
end
end
AD変換した結果を取得する
ADC.get_result
でフォトレジスターのアナログ値を ADC0834 がデジタル値に変換した結果の値を取得します
analog_val = ADC.get_result(dio, clk, cs)
LEDの点灯
0 〜 255 の値をデューティー比として PWM を実行し、 LED の光の強弱を制御します
duty = round(analog_val * 1_000_000 / 255)
duty / 10000
Pigpiox.Pwm.hardware_pwm(12, 2000, duty)
自然光の場合(7月の正午、窓からの光のみ)
検出値は 38 = 約 15 %
LED はほんのり光ります
ライトを目の前に当てた状態
検出値は 2 でほぼ 0 %
LED はほぼ光りません
フォトレジスターを蓋(手持ち扇風機を立てる台)で覆った状態
検出値は 161 でおよそ 63 %
LED は強めに光ります
フォトレジスターとLEDを連動させる
一定期間ポテンショメーターの値を取得してLEDを光らせる処理を繰り返し、連動させます
1..300
|> Enum.map(fn _i ->
analog_val = ADC.get_result(dio, clk, cs)
duty = round(analog_val * 1_000_000 / 255)
IO.inspect(duty / 10000)
Pigpiox.Pwm.hardware_pwm(12, 2000, duty)
end)
フォトレジスターにライトを近づけると LED が暗くなり、フォトレジスターを指でつまむと LED が明るくなります
ピンを閉じる
遊び終わったらピンを閉じます
Circuits.GPIO.close(cs)
Circuits.GPIO.close(clk)
Circuits.GPIO.close(dio)
まとめ
フォトレジスターと LED を連動させて、暗いときは強く光り、明るいときは弱く光るような制御が実装できました
色んなセンサーで試したいですね