サーボモータの無線遠隔操作を目指して、着々と(遅々と?)進行中です。
電源がバッテリーに限られる使用を想定しているので、操作不要のときはCPUを眠らせて超節電したいとマニュアルを読んでいると、そのものずばりSLEEP命令というのがありました。
スリープ・インストラクションの説明は、Enter Sleep mode と簡潔ですが、まずC言語からの呼び出し方法がピンときません。
Cの標準関数とは別ものでしょうし、ま、asm("sleep") とでも書けばよかろうと考えていたら、pic.hの中にdefineマクロによる定義がありました。SLEEP() と書けばいいようです。
説明を読むと、sleep 命令はPICのクロックたる内部オシレータまで止めてしまうものらしく、外部からの割り込みによって通常モードに復帰するも発振が安定して完全復帰するまで時間がかかるということでした。
ウォッチドッグタイマ、IOピン割り込み、リセット、MSSP割り込み、USART割り込み、などにて sleep からの復帰が可能とありましたので使おうとしたのですがいろいろとつまづきました。
IOピン割り込み(Interrupt-on-Change)で sleep から復帰したい場合、こんな記述をします。
sleepの次の命令は割り込み関数より先に実行されてしまうので、紛れを無くすためには、直後に NOP() を書いておくのがいいようです。
これはリモコン側の while ループで、人間のボタン操作で割り込みをかけるのでこれでOKです。
が、サーボモータ側はUSARTシリアル通信着信による割り込みで、最初同様に記述していたところまったく動作しません。
WUE(Auto-WakeUp-Enable)ビットを設定するのが正解でした。これはUSART通信でsleepから復帰させたい場合、必須の設定で、sleep の前に毎回設定しなければなりません。
こんな感じで書くのが正解でした。
シミュレータでは、RCREGにダイレクトメッセージを送るとSLEEPから復帰してうまくいくのですが、実際のUSART通信では、このWUE=1の設定がないと動きませんでした。
さらに、sleep 中に受信する最初のメッセージは、WakeUpシグナル(break character)と見なされるため、0ビットの連続でなければならず(13ビット以上連続推奨)、読み捨てしないとなりません。
送る側は、こんな感じで記述します。
送りたい実際のメッセージの前に’¥0’キャラクタ(この場合9ビット連続になる)を送ります。
受ける側は、こんな感じで書きます。
WUEビットが1のときにRCREGを読み捨て、自動的に0になった次回のRCREG読み込みで本当に欲しかったメッセージを受け取ります。
あまり sleep と USART通信を併用している人が少ないのでしょうか、それともみなさん簡単に理解して使っているのか、日本語での解説を見かけないのでまとめてみました。
動画も撮ってみました。
熟睡中(ただし叩けば起きて働き、またすぐ寝る)の2つのCPU間で有線シリアル通信ができたので、あとは間に XBee をかませて無線化すればサーボモータの遠隔操作が可能になるはずです。