はじめに
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 でパッシブブザーを演奏しドレミの歌を奏でる
この記事ではポテンショメーターのアナログ値を取得し、LEDの光の強弱を制御します
また、必要なモジュールを追加するため、 Nerves Livebook をカスタマイズします
実装したノートブックはこちら
ポテンショメーター
矢印が描かれたツマミを回すことで抵抗値が変化します
ADC0834
ADC0834 は AD 変換器(AD コンバーター)です
REF の電圧(5V)を基準として、CH0〜3の入力電圧(アナログ値)がどの程度なのか 0 〜 255 の 256 段階(8 bit)のデジタル値に変換します
回路の組み立て
オンライン説明書の通りに回路を組みます
ただし、 LED に接続するピンはPWM対応が必須であるため、 GPIO22 ではなく GPIO12 を使います
元の通りに回路を組むと、 LED への PWM 出力実行時に以下のエラーが返されます
{:error, :not_hpwm_gpio}
- CS: AD 変換の開始終了を制御する
- CLK: 0 -> 1 に変化したタイミングで DI/DO の値を入出力する
- DI: データ入力
- DO: データ出力
- CH0: ポテンショメーターからの入力
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)
ポテンショメーターを一番右に回している状態では AD 変換結果が 0 になり、 LED は光ません
少し左に回すと値が少し増え、 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)
ピンを閉じる
遊び終わったらピンを閉じます
Circuits.GPIO.close(cs)
Circuits.GPIO.close(clk)
Circuits.GPIO.close(dio)
まとめ
ポテンショメーターと AD 変換器によって、アナログ操作をデジタル値に変換して制御することができました
AD 変換は IoT でも重要な役割を果たしますね