|
|
≪ボタン及びキー処理≫ |
| キー入力を受け付ける処理であるが、セオリー通り書いておかないと後で面倒な事になる。 やる事は以下の2つ。キー入力の受付は当然割り込み処理で行われる必要がある。 理由はいくつもあるが、チャタリングやキーリピートなど、定期に取得したデータで行う必要があるためである。 図キ-1はキー入力信号がバウンシングしているのを表現している。
図キ-1
メーク時及びブレーク時のチャタリングは発生するものである。 キーの処理を割り込みでなくフォアグラウンドで書く場合、たまに(本当は結構多いが)見受けられるのが、このチャタリングによる過度の反応を避けるためにウェイトを置く処理である。 具体的には、オンを認識した直後のオフを認識したくないため、チャタリング発生時間分だけタイマによるウェイトを行う人がいる。 その結果キー反応がもたつき、非常に操作しにくいファームが出来上がる。
キー入力のデータとは、時間軸で定期的に取得したデータ列である。 チャタリング吸収とは、データ列に載っているノイズを除去する作業である。 キーの信号入力を時系列に格納して言った場合の図キ-2が以下。
図キ-2
図キ-2では最新の信号状態が一番右にあり、更に新しい値の'1'が格納されつつある。 既に格納されているデータは、"00001011"となっていて、この中の最初の"0000"はキーが押されていない状態が安定している事を表す。 次の"1011"に注目、特に"101"に着目すると、これはチャタリングが発生した履歴であるという事に気付く。
ここでチャタリングモデルというものを、"111"であるはずのところが"101"になったり、"000"であるはずのところが"010"になったりするものと仮定する。 "100"の場合はとか、"011"の場合はとかは、ちょっと考えれば意味の無い事であると気付くはずである。(時間軸の情報であるため、現在と前後を比較する事で済む) 2回連続してノイズが載る可能性については、確かにその可能性も残されているが、キー入力の監視の割り込みは_秒単位であるため、この間隔でノイズが載る回路は何か他に問題があると考えるべきである。 結果、チャタリング吸収というものは、図キ-3の様な処理で表すことができる。
図キ-3
この処理を行う事で、前述したチャタリングを含んだデータ列(図キ-2)は、次の様になる
図キ-4
この処理の後、図キ-2の状態は図キ-4の"00001111"となり、前半の"0000"はオフで安定、後半の"1111"はオンで安定している様になる。
キーの押下はイベントである。すなわち状態変化であるが、大抵の処理はキーが押された時と放された時に行われるからである。(たまに起動時に押されていたら、というレベル判定が必要になる場合があるが、その話は次の機会に譲る) 変化点で捕らえると、チャタリング吸収後のデータ列(図キ-4)において、"011"と"100"の2種類の状態しかない事がわかる。
図キ-5
図キ-5の「オン確定」でメークコードを生成し、「オフ確定」でブレークコードを生成すればよい事になる。
履歴としては、キー1つ当たり最低3ビットのデータを持てば、チャタリング吸収とキーコード生成がシフトと比較でできる事になる。 |
|
≪イベント≫ |
| ソフトウェアの動作とは結局、「イベントのハンドリング」なので(言い切って良いのか?)、事象においてのイベントの定義がキッチリされていれば、ハンドリングするのは容易な事。
図イ-1
図イ-1は、あらゆるソフトが持つメインループの構造。 WindwosなどのイベントドリブンなOSのプログラミングは、図イ-1の右側の「イベント処理」だけをコーディングする事を要求される。(実際はWinMain()があるけど隠されている) じゃあ、実際何を待つの?って事がイベントの定義がキッチリされているかどうかという事になる。
よくあるのが(本当か?)、グローバル変数によるフラグ監視のやり方。 メインループは、このフラグの監視とフラグ変化の応答処理で構成される。筆者も15年以上前はこのやり方だった。非常に小さいシステムは、これで十分機能するし目も行き届く。 しかし、フラグによるイベントの伝達はレベルトルガであるためフラグを立てた側が要求を取り下げる必要がある。また多重イベントを処理できない。等の不都合がある。 FPGAとかのプログラミングの場合には、1を書くリクエストが実は書き込みをしないという様な事が可能である。しかしマイコンのメモリシステムでは1を書くと1が書かれてしまうのでうまくない。また、FPGAにおいても多重イベントを許可するためにはFIFOを採用することになる。
図イ-2
イベントはFIFOの様なキューと親和性がある。というのも、イベントはほとんどの場合において、発生した事が意味を持つからで、発生している事には意味が無いからである。 イベントの取りこぼしさえ起こさなければ、ちょうどオルタネートプッシュスイッチのようなもので、内部ステートで管理すれば、イベントが発生している事を認識する事ができる。
図イ-3
図イ-3は、キーの押下と開放が2回発生し、新たにキーの押下が発生しているイベントFIFOである。 イベントの取り出しが間に合わない時、多重イベントとなる。FIFOによるバッファリングは多重イベントをうまく処理できる。たとえば、ダブルクリックの様なものは特別な処理も無く対応できる。 ただし、多重イベントの蓄積によるバッファオーバーフローには注意する必要がある。 テクニック的にはバッファ以上のイベントは無視するしかなく、クリティカルな条件では破綻するのは理解できると思う。これに対する特効薬は無く、破綻させないようにすべきである。(図イ-4)
図イ-4
FIFOによるイベントの実装は、多重イベントの処理に向いているが、多重にしたくないものも多重で受けてしまうという欠点もある。 その場合、イベントの発生を抑えるか、イベントFIFOから取り出す時に無視するかのいずれかで対応する。 前者の場合イベント発生源がイベントをどう処理しているかの情報を持つ必要があるので好ましくなく、後者の場合、FIFOには溜まってしまうので、破綻させないFIFOの長さが必要になる。
FIFOを使う際の問題点として、FIFOは常に一方通行であるという事実もある。 つまり書く側から読む事はできず、読む側から書く事ができない。もちろん決してできない訳ではない。 しない方が安全という事である。なぜ、しない方が安全かは後述する「キュー」で説明する。 では、書く側と読む側とは何か。書く側はイベント発生源であり、読む側がイベント処理側である。 組込の場合、イベントには「割り込みイベント」と「非割り込みイベント」がある。 |
|
≪割り込みイベント≫ |
| 「ボタン及びキー処理」の様なイベントは、割り込みイベントであるのが理想である。割り込みイベントと言っても割り込み入力を使う訳ではなく、割り込み(キーの場合はタイマ割り込み)の中でイベントキューに追加される。
図割イ-1
イベントキューへの書き込みは、全割り込みで共有されるため、割り込みは多重割り込みを禁止しなければならない。(割り込み中は割り込みがかからない) 割り込み中のイベントは全てイベントキューに追加されるので、適切にキューから引き上げる事ができれば、イベントのハンドリングは簡単になる。 通常はフォアグラウンドでイベントキューから取り出し、適切なアクションを行う事になる。
注意しなければならない事が1つ。割り込みイベントに対するアクションの中でタイムクリティカルなものは、割り込みの中で処理しなければならない事。 この場合、「処理しましたイベント」をイベントキューに追加して、フォアグラウンドで認識する事になる。 |
|
≪非割り込みイベント≫ |
| イベントを処理する事に連動して、新たなイベントが発生する事がある。たとえば、キーのイベントに連動して、内部シーケンスを進めて行く様な場合、シーケンス変更イベントが発生する。 この場合は、非割り込みにおいてイベントが発生するため、先のイベントキューと同一のキューに追加する事ができない。 このため、イベントキューを2つ持ち、「割り込みイベント」を「イベント」、「非割り込みイベント」を「メッセージ」として区別する。
図非イ-1
メッセージを処理する側はフォアグラウンド、追加する側もフォアグラウンドなので、読み書きの区別が保たれる。 イベントキューは書き込み側が割り込み、読み出し側がフォアグラウンドとなる。 |
|
≪イベントハンドリング≫ |
| 割込み、非割込みなどの様々なイベントを処理する部分がないとソフトとしては機能しない。 オーソドックスなのはシーケンス制御の様なループ構造のメインループ。
図メ−1
正しくはオーソドックスかどうか不明。筆者はよっぽど非力なCPUでないと、この方法は使わない。 OSを使わない場合、ほとんどの皆さんはコレではないだろうか。
実は制御ソフトというのはその処理のほとんどにおいて、イベントハンドリングばっかりしている。 イベントは前の状態と今の状態の差で発動させる。 具体的には、前の状態を保持する変数があって、今の状態と違っていれば、サブルーチンを呼ぶとかする事になる。 変数への保存や比較する部分をメインループやサブルーチン部分に記述する事になる。 これでも小規模なモノは十分うまく動く。 ただ、この部分は本来したい動作ではない。 本来したかった事は『何か外部の制御』であって、『イベントハンドリングなどの制御構造』ではない。 ソフトの規模を大きくするためには、制御構造を単純化させる必要がある。 具体的には制御構造が必然的に機能を表す様な構造を採用する必要がある。
OSレスでイベントハンドリングを行うには、メッセージモデルが最適だと、筆者は思う。 |
|
≪メッセージ≫ |
| 筆者がメッセージモデルと出会ったのは、Windows3.0からである。 組込の話をしているのに、Windowsは関係無いと思われるかもしれないが、「イベントドリブン」という考え方は、それ以前の組込モデルには見られなかった。(筆者が知らかっただけだとも思われるが) 前述した様に、非割り込みのイベントを処理するのがメッセージという事になる。 メッセージというのは今の生活に例えると、メールに似ている。そして割り込みは電話に似ている。 メールは送ってさえ置けば、相手がいつ見るかは大した問題ではない。反対に電話はかけた時に相手が出る事が前提となる。
|
|
≪キュー
≫ |
| |
|
≪テキスト表示≫ |
| |
|
≪静的記憶
≫ |
| |