仕様はトップダウン、制作はボトムアップ

先週は、時計+タイマーの出力仕様を細かく作成しました。
今週から哲さんの子供は、夏休みです。夏休みの自由研究と
して、LEDを使い何かを子供に作らせようと、哲さんの頭
にはあるのですが、アイデアが浮かびません。で、啓二さん
に聞いてみることにしました。さて、どんなアイデアが出て
くるのでしょうか。
哲  :押忍!今日から、子供は夏休みなんだ。
啓二:そうか。でも、フリーランスの技術者には、休みはないんだ。
哲  :夏休みの自由研究で何かLEDで作らせたいのさ。
      何かアイデアないかな。
啓二:暗くなったら、LEDを点滅させてみるのは、どうだ。
      車に入れておくと、防犯装置になるぞ。それにキャンプに
      行ったときには、自分のテントの位置を示すマーカーに
      なるし。
哲  :そうか。この78kで作れるかな。
啓二:作れるけれど、何でもマイコンでやるのは、関心しないな。
哲  :どうしてだ、簡単だろう。
啓二:お前、SEだろう。同じ結果を得るにも、複数の方法を検討
      しておかなけれりゃ、提案もできないだろさ。
哲  :まあ、そうだが。
啓二:マイコンの場合は、ハードウエアを作って、プログラムを
      入れないと動かない。だから、LEDで作るようなマーカー
      には、大袈裟だし、時間が掛かりすぎる。それに電力を使い
      過ぎてしまう。
哲  :じゃあ、どんな方法があるのか、教えてくれよ。
啓二:トランジスタやコンデンサを使うのさ。これが、その回路だ。


哲  :あれま、懐かしい。高校の文化祭でやった劇のときの灯台だ。
      あの点滅回路じゃないか。
啓二:そうだ。これを、本屋で「初歩のラジオ」か「ラジオの製作」で
      見つけて作っただろう。あのときは、LEDは高かったけれど、
      担任に物理実験で使うのを、拝み倒して譲ってもらった。
哲  :そうそう、結局そのまま点滅回路を、担任のところに置いてきたんだった。
      実験に使ってくださいって。まだあるのかなあ。
啓二:さあ、なあ。これだと、トランジスタが2個、コンデンサが2個、
      LEDが4個、抵抗が2種類5本、電池ホルダー1個に電池2本
      CdSが1個でできる。大体、予算は¥500程度。ワンコインだ。  
哲  :じゃあ、これで作らせてみるか。安上がりの方がいいしなあ。
啓二:現金な奴だな。今日は、時計+タイマーの頭に相当する部分の
      仕様を決めていくぞ。
哲  :先週までのは、下位レベルの部分だったからなあ。
      マイコンのプログラムの決まりきったカタチってあるのか。
啓二:他の人はどうやっているかは知らんが、自分は、次のようにしている。

        void main(void)
        {
            initialize();
            enable_interrupt();
            while ( 1 ) {
                /* ? */
            }
        }

哲  :おっと、C言語できたか。初期化処理して、割込みを許可して、
      あとは無限ループにするのか。
啓二:そう。で、関数に相当する部分を、サブルーチンで作っていくのさ。
      初期化ならば、ポートの出力値を決めて、プルアップの有無、ポートの
      方向設定、さらに内蔵ハードウエアの初期化をする。
      内蔵ハードウエアは、タイマーやA/Dコンバータだ。
      その後、割込みを許可して、最上位のルーチンは、フラグで報告を受けて
      必要な指示を出す。
      これが、自分にとって、最も考えやすい。
哲  :最上位のルーチンは、プロジェクトリーダかマネージャみたいだな。
      会社組織に似ているようにも見えるし。
啓二:まあ、OSが入っていると、無限ループの部分は、OSが
      肩代わりしてくれるから、見えないかもなあ。
哲  :本当は、それじゃ駄目なんだが。
啓二:よしと、それじゃ、まず初期化から考えてこう。
      ポート2の初期化だが、Appliletがやってくれる。
      でも、サポートしてくれるだけだから、予め考えておく。
      全部出力に設定だ。 ポート3は全部入力で、ポート4は、
      P45だけが出力で、他は入力だな。
      入力に設定するときは、プルアップしておけばいい。
      プルアップを指定すると、外付けの抵抗を省略できる。
哲  :残りは、何かあるかな。
啓二:あるある、タイマー割り込みを利用するのだから、どの
      タイマーを使うかを考える。時計用タイマーとスイッチの
      チャタリング除去にで2個必要だな。
哲  :クロックその他も決めないとならないじゃないか。
啓二:そうだな、内蔵の8MHzのクロックを利用しよう。
      システム設定のところで指定すればよい。
哲  :78kのようなマイコンのプログラムは、ファームウエアって
      呼ぶが、作成手順のイロハはあるのか。
啓二:特にないと思うが、やはりトップダウンで作っていくことが
      多いなあ。ボトムアップだと、先が見えないから。
      じゃあ、まずは、スイッチから割込みが入ったとして、動作
      を記述してみてくれ。
哲  :いきなりかい。まずは、スイッチ入力があったことをフラグで
      知って、何かすればいいんだな。
      じゃあ、こうしよう。
        while ( 1 ) {

            if ( swi_flg == ON ) {
                swi_flg = OFF ;
                /* ? */
            }

        }
      モードを確認して、対応する処理に分岐すればいいな。
      switch文で、分岐するようにしよう。
        while ( 1 ) {
            if ( swi_flg == ON ) {
                swi_flg = OFF ;

                mode = get_mode();
                /* シフトボタン処理 */
                /* +1ボタン処理 */
                /* 確定 */

            }
        }
啓二:これじゃ、頭が重くなるぞ。関数を定義してしまえよ。
哲  :そうだな、じゃ、関数sw_handlingとでもしておくか。
        while ( 1 ) {
            if ( swi_flg == ON ) {
                swi_flg = OFF ;
                sw_handling();
            }
        }
啓二:おお、すっきりしたじゃないか。
      先に作ったswitch文の内容を、新しい関数で定義しようぜ。
哲  :わかった。

      void sw_handling(void)
      {
          unsigned char mode ;

          mode = get_mode();
          /* シフトボタン処理 */
          /* +1ボタン処理 */
          /* 確定 */

      }

      処理ごとに、すでに関数が定義されていると仮定するか。
      void sw_handling(void)
      {
          unsigned char mode ;

          mode = get_mode();

          /* シフトボタン処理 */
          if ( (sw_state & 1) == 0 ) update_digit_logation();
          /* +1ボタン処理 */
          if ( (sw_state & 2) == 0 ) increment_digit();
          /* 確定 */
          if ( (sw_state & 4) == 0 ) confirm_digit();

      }
啓二:モードによって、表示する内容も違うから、メイン処理の
      中に、表示処理が必要だな。
        while ( 1 ) {
            if ( swi_flg == ON ) {
                swi_flg = OFF ;
                sw_handling();
            }
            show_digit();
        }
      とでもしておくか。
      関数show_digitの内部では、表示するデータを生成するだけにして
      実際の処理は、タイマー割込みに任せてしまおう。
哲  :確か、ブリンクをするとか言っていたよなあ。どうやればいいんだ。
啓二:難しく考えなくていいよ。対応けたのビットパターンを、すべて
      0にするか、スルーするかを、タイマー割込みごとに変えればいい。
      こんな風にさ。

          *(qdigit+0) = *(pdigit+0);
          *(qdigit+1) = *(pdigit+1);
          *(qdigit+2) = *(pdigit+2);
          *(qdigit+3) = *(pdigit+3);
          blk_cnt++;
          blk_cnt %= 2 ;
          if ( blk_flg == ON && blk_cnt > 0 ) {
              *(qdigit+index) = 0 ;
          }
          send_pattern();

      出力する4バイトを、最初に決めてしまう。
      ブリンク指定かつカウンタの値が正ならば、対応けたのパターンを
      すべて0にしておく。そして、出力する。簡単だろう。
      変数indexで、ブリンクするけたを指定すると、何も難しくない。
哲  :indexは、タクトスイッチで変更するだけか。
      例によって、一度スイッチを押すとインクリメントして、剰余系で
      サイクリックになるようにするんだ。やっぱり、理系の頭だよなあ。
啓二:そうかなあ、通信でリングバッファを使うときには、出てくると
      思うけれどなあ。
哲  :確かに出てきそうだが、256とかで、2のべき乗にしてカウンタ
      が自動的に0に戻るようにしちゃうからなあ。
啓二:なるほど。じゃあ、また来週にしようぜ。

戻る