前回端子からの割り込みやってしまいました。普通は先にポーリングだったかなあ、ということで今回は端子のポーリングしてみます。ポーリングはGoroutineにお任せして、結果はchannelで受け取ると。ついでに無関係なLEDもチカチカさせたりして並行に処理している雰囲気をだすってもんかと。ありがち?
※「AT SAMの部屋」 投稿順indexはこちら
※実験は、MicroChip社のATSAMD21マイコン搭載のSeeduino XiaoボードにWindowsPC上でTinyGoが生成したオブジェクトを書き込んで行っています。多分、端子名を変えたソースは他の多くのマイコンで走るんじゃないかと思います。知らんけど。
ポーリング
ソフトウエアループの中で端子などを読み取って処理すべきイベントを検出するポーリングはよく使われるのではないかと思います。しかし、検出待ちループなどではイベント到来まで他の処理が止まるし、他の処理を進めながらにしたい場合は、無関係な処理の中で時々ポーリング関数を呼び出したりと直接的な割には問題も大有りです。
その点、Go言語にはGoroutineあり、疑似的とは言え並行に処理を進められます。ポーリング「待ち」の関数は「待って」いても、他の処理は粛々と進められます。ホントか?
今回は、以下のような設定設定です。
-
- 端子D1に接続してあるタクトスイッチ(プルアップ抵抗付いており、スイッチOFF状態でHighが読める。スイッチONするとLow)のHighからLowへの遷移(ネガティブエッジ)をポーリングで捉えてイベントを発生する。ポーリングの周期はほぼ100m秒毎。前回がHighでその100m秒後にポーリングしたときにLowであったらmain()に知らせる
- main()関数は上記のイベントをGo言語のGoroutine間の通信構造であるchannelを通じて受信する。受信したら青色LEDを1回2秒点灯。
- 上記のポーリング動作と無関係に仕事ができることを赤色LEDのLチカ(毎秒周期)で示す
Channel
GoのChannelは、他のRTOSなどではQueueとかFIFOあるいは EVENT と呼ばれるような構造に似た制御構造じゃないかとおもいます。見やすいのでお世話になっている Go by Exampleのページが以下に。
実験に使用したソースコード
例によって前回のチョイ変に次ぐチョイ変。大して変わっておりませぬ。今回は、main()関数と pollingD1()関数の間にChannelを設置し、bool値、trueがpollingD1()関数からmain()関数に到来したら青色LEDを1回点灯の段取りです。
package main import ( "machine" "time" ) func pollingD1(d1Chan chan bool) { oldValue := true newValue := true pinD1 := machine.D1 pinD1.Configure(machine.PinConfig{Mode: machine.PinInput}) for { time.Sleep(time.Millisecond * 100) newValue = pinD1.Get() if oldValue && (!newValue) { d1Chan <- true } oldValue = newValue } } func redLED() { ledRED := machine.D2 ledRED.Configure(machine.PinConfig{Mode: machine.PinOutput}) for { time.Sleep(time.Millisecond * 500) ledRED.High() time.Sleep(time.Millisecond * 500) ledRED.Low() } } func main() { ledBLUE := machine.D3 ledBLUE.Configure(machine.PinConfig{Mode: machine.PinOutput}) ledBLUE.High() d1Chan := make(chan bool) go pollingD1(d1Chan) go redLED() for { <-d1Chan ledBLUE.Low() time.Sleep(time.Millisecond * 2000) ledBLUE.High() } }
実験結果
オブジェクトをXiaoに書き込めば、赤色LEDがLチカ始めます。そしてタクトスイッチ(テスト回路図は前回をご参照ください)を押すと青色LEDが2秒ほど点灯します。まあいい加減でやっつけだけれど、channelが動いていることは確かめられた?