Arduinoでロータリーエンコーダの回転を検出した。
ロータリーエンコーダは可変抵抗と異なり、アナログ値を出すのではなく回転方向を2byteでデジタル出力するので、無限に回転させる事ができる。マウスのホイールもロータリーエンコーダで出来ている。
Source Code (Arduino 0009 Alpha / ATmega8 16MHz)
基本的に回路もプログラムもATMega8でやったのと全く同じ方法でできた。
s.h.log: AVR – mega8でロータリーエンコーダを回す
ロータリーエンコーダーの真ん中の足をGNDに接続し、左右の足をそれぞれマイコンのピンに接続。また、左右の足とマイコンのピンの間で、10kΩの抵抗を使ってプルアップする(VCCに接続する)
まあ写真の通り。インクリメンタル型ロータリーエンコーダーは2本の線で4種類の回転状態を出力する。1クリック回す(カチッと言う)と、4種類の状態が一回りする。
とりあえず状態に0,1,2,3と名前をつけて、10ms毎ぐらいに状態を見に行くと、状態が1増えていたら右に回転、減っていたら左に回転みたいな感じでわかる。
ただし、Arduinoにはタイマーが無いので、メインループ loop() の中で delayMicroseconds(10); を呼んで、10ミリ秒を作っている。
なので、ロータリーエンコーダと同時にタイミングが難しい処理を行うとおかしくなるかもしれない。
例えば赤外線の受信とか。
参考:ControlクラスのInvokeメソッドで匿名メソッドを使うには?[2.0のみ、C#] − @IT
GUI描画とは別スレッドから、GUI要素を書き換える時
this.Invoke((MethodInvoker) delegate() { /* GUIの操作*/});
か
MethodInvoker func = delegate() { /*GUIの操作*/ };
this.Invoke(func);
でいい。
例えば
try{
this.Invoke((MethodInvoker)delegate(){textBoxMsg.Text+="hogehoge";});
}
catch(Exceptionex){
Console.Error.WriteLine(ex.Message);
}
とか。
GUIと別スレッドからGUI要素を書き換える時は(例えばSocket通信を受信するためにThreadを立てて回している時など)
Form.Invoke(Delegate)を使わないとデッドロックが起こってしまうのでC#2.0からは直接スレッド越えのメソッド呼び出しができなくなった。
これは1年ぐらい前に勉強して理解できた。
・s.h.log: C#のDelegateのカプセル化
・s.h.log: C#2.0 – PhidgetRFIDkitを使ってみる (あとDelegateとかInvokeとか)
でも毎度Delegateを使っていると、ちょっとGUI要素を変えたいだけなのにゴミのような関数が大量に必要になってしまう。そこでLLでよくやるように無名関数でInvoke()を実行したかった。
しかし、C#の無名関数(匿名メソッド)の宣言と実行の方法は
delegate d = delegate(){ /* 処理 */ }; // 宣言
Thread th = new Thread(d); // 登録
th.Start(); // 無名関数呼び出し
で、Threadから呼び出す。
参考:MSDN: 匿名メソッド (C#)
これだと、GUIスレッド外からGUI要素を書き換えられない。Thread.Start()ではなくControl.Invoke()を使わなければならない。
Control.Invoke()の引数であるDelegateは無名関数宣言のdelegateとは別の型で、直接キャストができない。
が、なぜかMethodInvoker型にするとできる。
よくわからないけどとにかく
this.Inovoke( (MethodInvoker) delegate(){ /* 処理 */ });
でいける事がわかってコードがすっきりした。