*延々といろいろ書いていますが、オチは「解決策」にあります。
電子機器を作る時、電源スイッチは重要です。
今も昔もスイッチに直接電気を通すタイプはありますが、年々減っています。
主流はどちらかというとモーメンタリースイッチと呼ばれる、押した時だけ通電するタイプです。
これって明らかに昔からあるような電気を通すスイッチじゃないです。
ですから、モーメンタリースイッチが押されたと認識すると、それをトリガーになんらかの方法でオン・オフにする、というのがイマドキなわけです。
たいていはプロセッサーにSLEEPコマンドを発行して寝た状態にします。
寝た状態での消費電力は極端に少なく数マイクロアンペアなんて普通です。
しかし、パワーオフではない。これが結構やっかいです。
まずスイッチの問題
モーメンタリースイッチって人が押すわけですが、スイッチの中では細かいオンオフが繰り返される状態が繰り広げられます。
最大の理由はスイッチといえども電極が動き、バウンドするからです。
通称、こういう現象をチャタリングとか英語ではバウンシングといいます。中途半端な専門家は「チャタる」とか言って得意になってます。
(「る」をつけて英語を日本語化して省略することはかっこ悪いと思う)
チャタリング対策をソフトウェアでやろうとすると、チャタリングの期間、なにもしない(マイコンで[なにもしない]とは、無意味なループをさせること)で最初の信号以外の後続信号を無視するなどの方法を取ることになるのですが、なにか仕事をやっている最中だととってもマズイことになります。
通常はスイッチが押されると割り込みを起こして、処理をします。
スイッチが短い時間内に何度も押される現象を「ソフトウェアで解決しようとするから問題じゃないんじゃないの?」という疑問が当然、出ます。
ハイ、それは正解のひとつ。
スイッチにコンデンサーと抵抗で上のギザギザをなだらかにする、シュミット・トリガー回路をとおしてしきい値を超えた値だけをもらうという方法があります。
スイッチでオフ信号がきたら、どうするか問題
これについてはプロセッサーを作るほうもよく考えていて、スイッチの信号でプロセッサーを「リセット」するという手段を用意しています。
リセットされてすべてを忘れたマクロプロセッサーは頭からプログラムを始めから開始します。
しかし、電池を入れた途端に起動してリセットと同じしか動きができないというのがイヤなわけです。
製品で電源入れたらいきなり動き出す製品のほうが珍しいですよね。
PICではどうするんだろう?と。
しつこく調べました。(英語でも日本語でも例は出てないけど、メーカーはやってると思う)
自分の都合ですから対象機器はPIC12F629です。
いままでの議論を基本とすると、パワーオンをモーメンタリースイッチでやる方法としてはGP3/MCLRでMCLR(リセット)機能を使うことがもっとも自然です。
CONFIGレジスターでMCLRをオンにすると、このピンを10Kオームでプルアップ(電源側につないで1状態にする)する必要があります。ついでながらスイッチの端子間に0.1マイクロファラッドコンデンサを入れることでのチャタリング防止が強く推奨されています。でも、これだけでMCLRピンにはシュミットトリガ回路も入っており、チャタリングは防げる(小さいノイズには反応しない)とデータシートにはあります。
スイッチをつけてGND(ー)とショートするとMCLRリセットがかかり、プログラムの最初から再スタートします。
プログラムでどうやって知るか
面倒なのはMCLRリセットがかかった、という現象をプログラム側で知る方法です。
要件は、単なるパワーオンならSLEEP,MCLRリセットなら仕事をさせなければなりません。
(結論を知りたい人は最後の「解決策は」まで飛ばしてください。以下は教養講座です。)
まずPIC12F629のデータシートのSTATUSレジスターをみます。
一部ですが、ここの議論で大事なビットはTO, PDビットです。TOビットはパワーアップすると立ちます。PDビットはパワーオンリセットなら1, SLEEP中にMCLRリセットがかかった場合は0となります。(データシートのP58の表にも記載されています)
STATUSレジスタは刻々と変わるので、このままではCで書いたプログラムからは確認できません。
MicroChip Developper Helpにどうすればいいか記載されています。
以下、該当ページだけの翻訳。
リセットの原因の発見の仕方
マイクロチップのベースラインおよびミッドレンジPIC®MCUデバイスには、プログラムの再起動後にデバイスリセットの原因を設定できる特別な機能があります。 この機能では、PCONレジスタとSTATUSレジスタにいくつかの命令と特定のイベントによって書き込まれるいくつかのフラグビットを使用し、これらのレジスタをコードで読み取ってデバイスリセットがかかった理由を判断することができます。
STATUSレジスタの2ビットは、パワーアップ時にセットされSLEEPが呼び出されるとクリアされるPDビットと、WDTタイムアウトが発生してデバイスウェイクアップが発生した場合にクリアされるTOビットがあります。 これらのビットの両方は、ソフトウェアによって直接書き込むことはできませんが、ハードウェアイベントによって更新されます。
コードがアクセスできるようになる前にSTATUSレジスタの内容が失われる可能性があるため、XC8 Cコンパイラは、後でCコードからアクセスできる場所にSTATUSレジスタを自動的にコピーできる機能を提供します。 この手順は、コンパイラによって生成されたランタイムスタートアップコードの先頭で行われるため、リセットが行われた直後に実行されます。
STATUSレジスタの保存された内容にアクセスするには、Cコードがシンボル__resetbitsを宣言して、かつ参照する必要があります。 パワーダウンビットとタイムアウトビットのコピーをそれぞれ保持するシンボル__powerdownと__timeoutを宣言して参照します。
extern unsigned char __resetbits; extern bit __powerdown; extern bit __timeout;
このSTATUSレジスタの保存機能は、プロジェクト内の上記のシンボルにアクセスすると自動的に有効になります。 アプリケーションのコード上で実際にシンボルを読む必要があります。シンボルだけを宣言しても、この機能は有効になりません。
以下は、STATUSレジスタコピーを使用して、コピーされたTOビットがセットされ、コピーされたPDビットがクリアされ、通常のPCONレジスタのRMCLRビットがクリアされている16F1xxxデバイスのコード例です。 このような状況はSLEEP中にMCLRが起きた場合を確認しています。(訳注:PIC12F629のPCON内にはMCLRの状態を保持するビットはありません)
if(__timeout && ! __powerdown && ! PCONbits.nRMCLR) { // SLEEP中にMCLRリセットがかかった時の処理 }
これらの検出に使用されるデバイスのリセット条件とフラグに関する詳細については、デバイスのデータシートを参照してください。(上記のPCON)
この機能の動作を確認したい場合は、プロジェクトをビルドし、上記のシンボルを検索した後にstartup.asファイルまたはstartup.lstファイルを開きます(アセンブラでは3つの先頭にアンダースコアが付きます)。 MPLAB X IDEのプロジェクトプロパティにXC8リンカー>ランタイム>生成されたstartup.asを保持していても各ビルド後に通常は削除されるので、このサブオプションを-RUNTIMEオプションに有効にする必要があります。
resetbitsサブオプションを-RUNTIMEオプションに設定するか、MPLAB X IDEプロジェクトプロパティのXC8 linker>Runtime>Backup reset condition flagsをチェックすることにより、起動時に常にSTATUSレジスターがコピーされるように手動で強制できます。
ここまで延々訳しましたが、PIC12F629では役に立ちません。externを書いた時点でコンパイルエラーにひっかかります。他のPIC16F系なら正しいかもしれません。
解決策は
非常に簡単でした。PIC12F629にもPCONというパワーの状況を知らせるレジスターがあります。
肝心なのは括弧()の中の文章です。(must be set in software after a Power-on Reset occurs)
これ、こう解釈するのだそうです。
“パワーオンの場合は POR=0になるので、PORビットに1を書き込んで処理を続行します。
もしその後にMCLRピンがLowになってプログラムが再スタートとした場合は PORビットは1のままになっているのです。”
実際に次のプログラムをmain.cの冒頭に書き込んでみました。
if (nPOR == 0){ nPOR = 1; SLEEP(); NOP(); }
見事に電源つないだらSLEEP。
MCLRにつけたスイッチで一旦GNDにMCLRピンを落とすと、ここをスキップして動作開始しました。
わかれば簡単ですが、教えてもらわなきゃわからなかったなぁ。
じゃぁ、MCLRにスイッチつけてオン、オフするにはどうすればいいんでしょうか?
かなり悩みましたが、答えのひとつは
if (nTO == 1){
nPOR = 0;
}
nTOはSTATUSレジスターにあり、SLEEPから目覚めたら1が入っています。
SLEEPから目覚めたら先程のリセット状態にすればよく、あとは走り続けます。
MCLRリセットがかかったら、パワーアップと同じ状況とみなしてSLEEPします。
つまりここはイニシャライズでしかとおらないことを期待しています。