はじめに
- タクトスイッチが押されたら、LEDを光らせてみます
- もちろんNervesを使います
- 今回は、タクトスイッチがおされたことをGPIO 24で読み取ったら、GPIO 18をHighにしてLEDを光らせてみます
-
押された ということを検知するために待つところは、NervesJPでちらっと聞いたGenServerを使ってみます
- @inachi さんのElixir超初心者が Nerves で心拍数測定アプリを作ってみる
- 参考にしました! ありがとうございます!
作品
- Nervesを使ってRaspberry pi2からTwitterの投稿を行う
- こちらの記事で作り始めたごった煮プロジェクトに追加しています
ソースコード抜粋
- 関連コミット
- circuits_gpioを使っています
lib/hello_nerves/observer.ex
defmodule HelloNerves.Observer do
use GenServer
require Logger
@input_pin HelloNerves.Util.input_pin()
def start_link(state \\ []) do
GenServer.start_link(__MODULE__, state, name: __MODULE__)
end
@impl true
def init(state) do
{:ok, state}
end
@impl true
def handle_info({:circuits_gpio, @input_pin, _timestamp, 1}, state) do
Logger.debug("Received rising event on pin #{@input_pin}")
HelloNerves.Blinker.enable()
{:noreply, state ++ [1]}
end
@impl true
def handle_info({:circuits_gpio, @input_pin, _timestamp, 0}, state) do
Logger.debug("Received falling event on pin #{@input_pin}")
HelloNerves.Blinker.disable()
{:noreply, state ++ [0]}
end
end
- タクトスイッチが押されたり、離されたりすると、handle_info/2がコールバックされます
- タクトスイッチが押されたら、
HelloNerves.Blinker.enable()
をコールして、LEDを点灯させています - 反対に、タクトスイッチの押し込みが離れたら、
HelloNerves.Blinker.disable()
をコールして、LEDを消灯させています
lib/hello_nerves/set_interrupter.ex
defmodule HelloNerves.SetInterrupter do
use GenServer
require Logger
alias Circuits.GPIO
def start_link(state \\ []) do
GenServer.start_link(__MODULE__, state, name: __MODULE__)
end
@impl true
def init(state) do
GPIO.set_interrupts(HelloNerves.Util.input_gpio(), :both, receiver: HelloNerves.Observer)
{:ok, state}
end
end
-
Circuits.GPIO.set_interrupts/3は、
:receive
オプションでHelloNerves.Observer
を指定することで、GPIOの状態変化(スイッチON/OFF)があったときに、HelloNerves.Observer.handle_info/2
が呼び出されるようにしています-
HelloNerves.Observer.init/1
で、Circuits.GPIO.set_interrupts/3を呼び出しておけばよさそうで、はじめはそうしていたのですが、数回のスイッチON/OFFにしか反応しないので、別のモジュールをつくりました - こうすると私のRaspberry Pi 2ではうまくいっています
-
Nerves起動後に立ち上がるIExで、
GPIO.set_interrupts(HelloNerves.Util.input_gpio(), :both, receiver: HelloNerves.Observer)
するとうまくいったので、こうしてみました - 真因がわかりましたら更新します
-
lib/hello_nerves/application.ex
def children(_target) do
[
# Children for all targets except host
# Starts a worker by calling: HelloNerves.Worker.start_link(arg)
# {HelloNerves.Worker, arg},
{HelloNerves.Blinker, name: HelloNerves.Blinker},
{HelloNerves.Observer, name: HelloNerves.Observer},
{HelloNerves.SetInterrupter, name: HelloNerves.SetInterrupter}
]
end
-
List all child processes to be supervised
しています- supervisedされる子プロセスを列挙しています
- 雑に言うと、hello_nervesというアプリケーション with Nerves が起動するときに、自動的に子プロセスが開始される感じです
-
HelloNerves.Blinker
はここには載せていません- https://elixirschool.com/ja/lessons/advanced/nerves/
- の記事にインスパイアされました
- ありがとうございます!
回路
- Raspberry Piで学ぶ電子工作 超小型コンピュータで電子回路を制御する (ブルーバックス)
- こちらの本を参考にしました
- ありがとうございます!
説明というか感想というか
- nerves_examples/hello_gpio/lib/hello_gpio.ex は再帰を使った無限ループで書かれています
-
Circuits.GPIO.set_interrupts(input_gpio, :both)
を呼び出して、receiveでmessageがくるのを待っています- Processesもあわせて読んでみると、なんとなくわかるとおもいます
- こういう構造って、GenServerでできるということを、NervesJPで聞いたので使ってみました
- 自分が実現したいことがあったので、プログラミングElixir(本)に書いてある内容がすんなり入ってきました