11
0
お題は不問!Qiita Engineer Festa 2024で記事投稿!
Qiita Engineer Festa20242024年7月17日まで開催中!

Nerves Livebook でフォトレジスター(光センサー)からアナログ値を取得してデジタル値に変換する

Last updated at Posted at 2024-07-08

はじめに

Nerves Livebook で Raspberry Pi 用スターター電子工作キットを楽しんでいます

SunFounder Raspberry Pi 用のスターター電子工作キット

これまでの記事

この記事ではフォトレジスターで明るさを検知し、LEDの光の強弱を制御します

また、必要なモジュールを追加するため、 Nerves Livebook をカスタマイズします

実装したノートブックはこちら

フォトレジスター

当たっている光の強さによって抵抗値が変化します

IMG_1644.JPG

ADC0834

ADC0834 は AD 変換器(AD コンバーター)です

IMG_1643.JPG

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 はほんのり光ります

IMG_1645.JPG

ライトを目の前に当てた状態

検出値は 2 でほぼ 0 %

LED はほぼ光りません

IMG_1647.JPG

フォトレジスターを蓋(手持ち扇風機を立てる台)で覆った状態

検出値は 161 でおよそ 63 %

LED は強めに光ります

IMG_1649.JPG

フォトレジスターと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 を連動させて、暗いときは強く光り、明るいときは弱く光るような制御が実装できました

色んなセンサーで試したいですね

11
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
11
0