Nerves Livebook でボタンとLEDを連動させる

## はじめに

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

[SunFounder Raspberry Pi 用のスターター電子工作キット](https://amzn.asia/d/04vHhGKQ)

これまでの記事

- [Nerves Livebook で Raspberry Pi 4 のLチカ](https://qiita.com/RyoWakabayashi/items/8119260ceeea462d6b7b)
- [Nerves Livebook + Delux で簡単Lチカ](https://qiita.com/RyoWakabayashi/items/281afab89249dbf68cd5)
- [MacBook 上の Livebook から Raspberry Pi 上の Livebook に接続してLチカする](https://qiita.com/RyoWakabayashi/private/844da38ff24efa3b923c)
- [Nerves Livebook から GPIO 拡張ボードの LED を点滅させる](https://qiita.com/RyoWakabayashi/private/bda56ee6987b30857266)
- [Nerves Livebook から RGB LED を制御する（ソフトPWMもやってみる）](https://qiita.com/RyoWakabayashi/private/143fda67a1798bd788b7)
- [Nerves Livebook から LED 棒グラフを制御する](https://qiita.com/RyoWakabayashi/items/a6e8b712388d68bdca44)

この記事では、ボタンを押すと LED が光るように制御します

こちらの記事を参考にしました

https://qiita.com/dimanche/items/e8678657ba06c6c2fa26

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

https://github.com/RyoWakabayashi/elixir-learning/blob/main/livebooks/nerves_livebook/button.livemd

## 回路の組み立て

今回使うのはこのボタンです

![IMG_1573.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1485835/838cf210-dd46-8fd3-c9bc-0795802c3224.jpeg)

オンライン説明書を見ながら回路を組みますが、例によって電流の向きを逆にするため 3V3 と GND を入れ替えます

https://docs.sunfounder.com/projects/davinci-kit/ja/latest/2.1.1_button.html

![IMG_1572.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1485835/573337d7-e726-f611-beb3-e7b60b996886.jpeg)

## ピンを開く

GPIO の各ピンを開きます

GPIO17 が LED 、 GPIO18 がボタンに繋がっています

```elixir
{:ok, led} = Circuits.GPIO.open("GPIO17", :output)
{:ok, btn} = Circuits.GPIO.open("GPIO18", :input)
```

GPIO17 は出力に使うので、第2引数 `direction` （方向）に `:output` を指定します

GPIO18 は入力に使うので、第2引数に `:input` を指定します

## LED の点灯

LED のピンに `1` を書き込むと LED が光り、 0 を書き込むと LED が消えます

```elixir
Circuits.GPIO.write(led, 1)
```

```elixir
Circuits.GPIO.write(led, 0)
```

## ボタンのON/OFF入力

ボタンのピンを読んだとき、押されていれば 1 、押されていなければ 0 が返ってきます

```elixir
Circuits.GPIO.read(btn)
```

![btn_read.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1485835/6d1929a7-7a66-9ee5-2c32-204e61cdd16f.gif)

## ピンを閉じる

一旦、ピンを閉じます

```elixir
Circuits.GPIO.close(led)
Circuits.GPIO.close(btn)
```

## ボタンとLEDの連動

ボタンを押している間だけ LED が光るようにします

また、ノートブック上に用意したフレームにボタンの状態が出力されるようにしています

```elixir
defmodule LEDButton do
  use GenServer

  require Logger

  alias Circuits.GPIO

  @btn "GPIO18"
  @led "GPIO17"

  def start_link(frame) do
    GenServer.start_link(__MODULE__, %{frame: frame}, [])
  end

  def init(state) do
    {:ok, btn} = GPIO.open(@btn, :input, pull_mode: :pullup)
    GPIO.set_interrupts(btn, :both)

    {:ok, led} = GPIO.open(@led, :output)

    {:ok, %{btn: btn, led: led, frame: state.frame}}
  end

  def handle_info({:circuits_gpio, @btn, _timestamp, value}, state) do
    Kino.Frame.render(state.frame, value) # フレームの値を更新

    GPIO.write(state.led, value) # LED の状態を更新

    {:noreply, state}
  end

  def handle_info(:stop, state) do
    Circuits.GPIO.close(state.led)
    Circuits.GPIO.close(state.btn)

    {:stop, "stopped", state}
  end
end
```

フレームを用意します

```elixir
frame = Kino.Frame.new()
```

連動プロセスを開始します

```elixir
{:ok, pid} = LEDButton.start_link(frame)
```

![btn.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1485835/20e6e2f8-0469-dead-b3ec-0ee8f57b9f9e.gif)

ボタンを押すと LED が光り、フレーム内の値も 1 になっています

ボタンを離すと LED が消え、フレーム内の値も 0 になりました

遊び終わったらプロセスを止めておきます

```elixir
GenServer.stop(pid)
```

## まとめ

ボタン入力による制御が実装できました

Livebook を使うことで、ブラウザ上の表示ともキレイに連携させることができます