<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
   <title>PIC,78K,R8,HC(S)08/RS08,AVR,MSP430などのマイコン活用</title>
   <link rel="alternate" type="text/html" href="http://www.eleki-jack.com/mycom2/" />
   <link rel="self" type="application/atom+xml" href="http://www.eleki-jack.com/mycom2/atom.xml" />
   <id>tag:www.eleki-jack.com,2010:/mycom2//4</id>
   <updated>2010-08-20T10:08:58Z</updated>
   <subtitle>PIC,78K,R8,HC08,AVR,MSP430などのマイコン活用</subtitle>
   <generator uri="http://www.sixapart.com/movabletype/">Movable Type 4.1</generator>


<entry>
   <title>HC08マイコンの使い方QY4A編 -《91》【書籍】パワーダウン処理（2）</title>
   <link rel="alternate" type="text/html" href="http://www.eleki-jack.com/mycom2/2010/08/hc08qy4a_912.html" />
   <id>tag:www.eleki-jack.com,2010:/mycom2//4.4596</id>
   
   <published>2010-08-20T10:27:37Z</published>
   <updated>2010-08-20T10:08:58Z</updated>
   
   <summary>　前回 の続きで、HC08ミニマイコン扇風機のハードウェアを使って低電力モードを...</summary>
   <author>
      <name>kawano</name>
      <uri>http://www.cts-net.ne.jp/~kawano-r/</uri>
   </author>
   
      <category term="HC08マイコンの使い方QY4A編" scheme="http://www.sixapart.com/ns/types#category" />
   
   <category term="3320" label="HC08ミニマイコン扇風機" scheme="http://www.sixapart.com/ns/types#tag" />
   <category term="5599" label="ウェイクアップ" scheme="http://www.sixapart.com/ns/types#tag" />
   <category term="2598" label="キーボード割り込み" scheme="http://www.sixapart.com/ns/types#tag" />
   <category term="4411" label="ストップ・モード" scheme="http://www.sixapart.com/ns/types#tag" />
   <category term="5601" label="スリープ" scheme="http://www.sixapart.com/ns/types#tag" />
   <category term="5961" label="パワーダウン" scheme="http://www.sixapart.com/ns/types#tag" />
   <category term="5602" label="低電力モード" scheme="http://www.sixapart.com/ns/types#tag" />
   
   <content type="html" xml:lang="ja" xml:base="http://www.eleki-jack.com/mycom2/">
      <![CDATA[<p>　<a href="http://www.eleki-jack.com/mycom2/2010/08/hc08qy4a_901.html" target="_blank">前回</a> の続きで、HC08ミニマイコン扇風機のハードウェアを使って低電力モードを利用するシンプルなテスト・プログラムを紹介します。 低電力モードに関しては、<a href="http://www.eleki-jack.com/mycom2/hcs08hc08/hc08qy4a_2/" target="_blank">第79回～第81回</a> を参照してください。<br />　</p><embed src="http://www.youtube.com/v/-svCJGmu5PQ&amp;hl=ja&amp;fs=1" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="344"> 
<p align="center">HC08ミニマイコン扇風機のハードウェアをそのまま使って<br />テスト・プログラム test3-2 を動かすようす （クリックで再生）</p>]]>
      <![CDATA[<p><strong><font color="#0000cc">　<br />◆ HC08ミニマイコン扇風機を使って簡単なプログラムを試してみる</font></strong><br />　低電力の扱いに少しは慣れてきたでしょうか。 それでは <a href="http://www.eleki-jack.com/mycom2/2009/05/hc08qy4a_48ad.html" target="_blank">第48回</a> で作ったテスト・プログラムを基にして、パワーダウン（スリープ）を取り入れたテスト・プログラムを作ってみましょう。 test2-1、test2-2 を基に、それぞれ少し手を加えて test3-1、test3-2 を作ります。</p>
<p>　下記に示すのが test3-1 の仕様です。 赤字の部分が test2-1 からの変更点です。</p>
<blockquote>
<p><font color="#ff8000">【 test3-1 仕様 】</font><br />　入出力ポートだけを使ったシンプルなプログラムに、<font color="#ff0000">ストップ・モードと<br />　キーボード割り込みによるストップ・モード解除を組み込んだ</font>テスト・プログラム</p>
<p>　　　スイッチ、ツマミの機能は次の通り。<br />　　　　　　ON スイッチ　・・・・・　モータ「強」 になる。<br />　　　　　　OFF スイッチ　・・・・・　モータ「オフ」 になる。<br />　　　　　　　　　　　　　　　　　　　<font color="#ff0000">マイコンはストップ・モードになりパワーダウンする。</font><br />　　　　　　TIMER スイッチ　・・・・・　機能なし。<br />　　　　　　TIMER LED　・・・・・　機能なし。<br />　　　　　　YURAGI スイッチ　・・・・・　モータ「弱」 になる。<br />　　　　　　&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 　　　　　　　ただしモータ「オフ」 のときは機能しない。<br />　　　　　　SPEED ツマミ　・・・・・　機能なし。<br />　　電源を入れたときはモータ「強」 とする。<br />　　<font color="#ff0000">POWER LED は動作時点灯、パワーダウン時消灯とする。</font></p>
<p></p>
<p></p></blockquote>
<p>　これを基に設計を行うと次のようになります。赤字の部分が test2-1 からの変更点です。</p>
<blockquote>
<p><font color="#00a000">【 test3-1 設計 】</font><br />　状態は 三つ。 初期状態は 「モータ強状態」。<br />　　<br />　　　　モータ強状態の処理<br />　　　　　　　<font color="#ff0000">POWER LED を点灯する。</font><br />　　　　　　　モータに 「強」 出力する。<br />　　　　　　　OFF スイッチが押されたら、<font color="#ff0000">停止</font>状態へ遷移。<br />　　　　　　　YURAGI スイッチが押されたら、モータ弱状態へ遷移。<br />　　　　<font color="#ff0000">停止</font>状態の処理<br />　　　　　　　<font color="#ff0000">POWER LED を消灯する。</font><br />　　　　　　　モータに 「停止」 出力する。<br />　　　　　　　<font color="#ff0000">スリープの準備を行う。<br />　　　　　　　マイコンをストップ・モードに移行する。<br />　　　　　　　ストップ・モードが解除されたら</font>、モータ強状態へ遷移。<br />　　　　モータ弱状態の処理<br />　　　　　　　<font color="#ff0000">POWER LED を点灯する。</font><br />　　　　　　　モータに 「弱」 出力する。<br />　　　　　　　OFF スイッチが押されたら、<font color="#ff0000">停止</font>状態へ遷移。<br />　　　　　　　ON スイッチが押されたら、モータ強状態へ遷移。</p>
<p></p>
<p></p></blockquote>
<p>　<font color="#00a000">【 test3-1 設計の補足 】</font>　<a href="http://www.eleki-jack.com/mycom2/2009/07/hc08qy4a_57cop2.html" target="_blank">第57回</a> の COP の説明に従って、ここでも <font color="#ff0000">COPクリア</font>を入れることにします。 それから、CONFIG1，CONFIG2 レジスタにも変更があります。 <font color="#ff0000">STOP 命令 と COP を有効</font> にするのを忘れないようにしましょう。 できあがったテスト・プログラムをプロジェクトごと圧縮し、<a href="http://micon.arrow.jp/uploads/files/test3-1.zip" target="_blank">test3-1.zip</a> として保存したのでご利用ください。 </p>
<p><br />　テスト・プログラム test3-1 の主な部分を抜き出しておきます。</p>
<p></p>
<blockquote>
<p>//*************************<br />// リセット後の初期化処理<br />//*************************</p>
<p>void init_hardware( void ) {<br />&nbsp;&nbsp;&nbsp; CONFIG2 = 0x00;&nbsp;&nbsp;&nbsp;&nbsp; // IRQピン無効、RSTピン無効<br />&nbsp;&nbsp;&nbsp; <font color="#ff8000">CONFIG1 = 0x02;&nbsp;&nbsp;&nbsp;&nbsp; // LVI(3V)有効、STOP有効、COP有効</font><br />&nbsp;&nbsp;&nbsp; OSCTRIM = Optional; <br />}</p>
<p></p>
<p></p></blockquote>
<p><br /></p>
<blockquote>
<p>void main( void ) {<br />&nbsp;&nbsp;&nbsp; U1 state = STATE_MAX;<br />&nbsp;&nbsp;&nbsp; <br />&nbsp;&nbsp;&nbsp; init_hardware( );<br />&nbsp;&nbsp;&nbsp; init_PORT( );<br />&nbsp;&nbsp;&nbsp; <br />&nbsp;&nbsp;&nbsp; for ( ; ; ){<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <font color="#ff8000">__RESET_WATCHDOG( );</font><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; switch ( state ){<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; case STATE_MAX:<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <font color="#ff8000">PORT_POWER_LED = LED_ON;</font><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; PORT_DAC = MORTOR_MAX;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if ( PORT_OFF_SW == PHY_ON ){<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; state = <font color="#ff8000">STATE_STOP</font>;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } else if ( PORT_YURAGI_SW == PHY_ON ){<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; state = STATE_MIN;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; break;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; case <font color="#ff8000">STATE_STOP</font>:<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <font color="#ff8000">PORT_POWER_LED = LED_OFF;</font><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; PORT_DAC = MORTOR_OFF;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <font color="#ff8000">KBIER_KBIE3 = 1;&nbsp;&nbsp;&nbsp; // POWER ON SW 設定<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; KBSCR_ACKK = 1;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; KBSCR_IMASKK = 0;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; asm( "STOP" );<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; KBSCR_IMASKK = 1;</font><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; state = STATE_MAX;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; break;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; case STATE_MIN:<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <font color="#ff8000">PORT_POWER_LED = LED_ON;</font><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; PORT_DAC = MORTOR_MIN;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if ( PORT_OFF_SW == PHY_ON ){<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; state = <font color="#ff8000">STATE_STOP</font>;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } else if ( PORT_ON_SW == PHY_ON ){<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; state = STATE_MAX;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />&nbsp;&nbsp;&nbsp; }<br />}</p>
<p></p>
<p></p></blockquote>
<p><br /></p>
<blockquote>
<p>// Keyboard Wakeup<br />#pragma TRAP_PROC<br />void _KBD_Interrupt( void ) {<br />&nbsp;&nbsp;&nbsp; <font color="#ff8000">// 処理なし、STOP解除に利用する</font><br />}</p>
<p></p>
<p></p></blockquote>
<p>　先ほどの <font color="#00a000">【 test3-1 設計 】</font> と <font color="#00a000">【 test3-1 設計の補足 】</font> を参考にして、オレンジ色の部分にどのような変更が行われたのか読み取ってみてください。 そう難しくはないはずです。 中身が理解できたところで、実際に書き込んでみましょう（書き込む手順は書籍が最も参考になる）。</p>
<p>　この test3-1 ではマイコンの STOP 命令を使いますので、そのままでは CodeWarrior のデバッガ画面で動かしながら動作確認をすることができません。 いったん書き込みが済んだら HC08デバッグ・ツールの電源を切り、ターゲット・ボードから特殊コネクタを外して JP1 の 1-2間にジャンパ・リンクを付けて 3V のACアダプタまたは単二乾電池 4本を使って動作確認を行ってください。</p>
<p><br />　もう一つ、<a href="http://www.eleki-jack.com/mycom2/2009/05/hc08qy4a_48ad.html" target="_blank">第48回</a> の test2-2 を基にしたテスト・プログラム test3-2 を作ります。<br />下記に示すのが test3-2 の仕様です。 赤字の部分が test2-2 からの変更点です。</p>
<blockquote>
<p><font color="#ff8000">【 test3-2 仕様 】</font><br />　入出力ポートと A-D変換器を使ったシンプルなプログラムに、<font color="#ff0000">ストップ・モードと<br />　キーボード割り込みによるストップ・モード解除を組み込んだ</font>テスト・プログラム</p>
<p>　　　スイッチ、ツマミの機能は次のとおり。<br />　　　　　　ON スイッチ　・・・・・　モータ「オン」 になる。<br />　　　　　　OFF スイッチ　・・・・・　モータ「オフ」 になる。<br />　　　　　　　　　　　　　　　　　　　<font color="#ff0000">マイコンはストップ・モードになりパワーダウンする。</font><br />　　　　　　TIMER スイッチ　・・・・・　機能なし。<br />　　　　　　TIMER LED　・・・・・　機能なし。<br />　　　　　　YURAGI スイッチ　・・・・・　機能なし。<br />　　　　　　SPEED ツマミ　・・・・・　モータ「オン」 のとき、モータの速さを決める。<br />　　電源を入れたときはモータ「オン」 とする。<br />　　<font color="#ff0000">POWER LED は動作時点灯、パワーダウン時消灯とする。<br />　　モータ「オン」のとき、ツマミを左いっぱいに回してもモータが止まらないこと。</font></p>
<p></p>
<p></p></blockquote>
<p>　これを基に設計を行うと次のようになります。赤字の部分が test2-2 からの変更点です。</p>
<blockquote>
<p><font color="#00a000">【 test3-2 設計 】</font><br />　　以下の処理を繰り返す。<br />　　　　POWER LED を点灯する。<font color="#ff0000">（ただしモータ「オフ」時は消灯）</font><br />　　　　<br />　　　　可変抵抗器の電圧を 8ビットA-D変換する。<br />　　　　得られたデータを 4ビット右シフトして 4ビット・データとする。<br />　　　　<font color="#ff0000">得られた 4ビット・データに下限保障を行う。</font><br />　　　　モータに 4ビット・データを出力する。<br />　　　　もしも OFF スイッチが押されたらモータに 「停止」 出力して、<br />　　　　　　　<font color="#ff0000">スリープの準備を行う。<br />　　　　　　　マイコンをストップ・モードに移行する。<br />　　　　　　　ストップ・モードが解除されたら</font>、処理を続行する。</p>
<p></p>
<p></p></blockquote>
<p>　<font color="#00a000">【 test3-2 設計の補足 】</font>　先ほどの test3-1 と同様、ここでも <font color="#ff0000">COPクリア</font>を入れることにします。 それから CONFIG1，CONFIG2 レジスタにも変更があります。 <font color="#ff0000">STOP 命令 と COP を有効</font> にするのを忘れないようにしましょう。 できあがったテスト・プログラムをプロジェクトごと圧縮し、<a href="http://micon.arrow.jp/uploads/files/test3-2.zip" target="_blank">test3-2.zip</a> として保存したのでご利用ください。 </p>
<p><br />　テスト・プログラム test3-2 の主な部分を抜き出しておきます。</p>
<blockquote>
<p>//*************************<br />// マクロの定義<br />//*************************</p>
<p>#define PORT_DAC&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; PTB<br /><font color="#ff8000">#define MORTOR_MIN&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ( 0x06 )</font><br />#define MORTOR_OFF&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ( 0x00 )</p>
<p></p>
<p></p></blockquote>
<p><br /></p>
<blockquote>
<p>//*************************<br />// リセット後の初期化処理<br />//*************************<br />void init_hardware( void ) {<br />&nbsp;&nbsp;&nbsp; CONFIG2 = 0x00;&nbsp;&nbsp;&nbsp;&nbsp; // IRQピン無効、RSTピン無効<br />&nbsp;&nbsp;&nbsp; <font color="#ff8000">CONFIG1 = 0x02;&nbsp;&nbsp;&nbsp;&nbsp; // LVI(3V)有効、STOP有効、COP有効</font><br />&nbsp;&nbsp;&nbsp; OSCTRIM = Optional; <br />}</p>
<p></p>
<p></p></blockquote>
<p><br /></p>
<blockquote>
<p>void main( void ) {<br />&nbsp;&nbsp;&nbsp; <font color="#ff8000">U1 U1t_temp = 0;</font><br />&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp; init_hardware( );<br />&nbsp;&nbsp;&nbsp; init_PORT( );<br />&nbsp;&nbsp;&nbsp; init_ADC( );<br />&nbsp;&nbsp;&nbsp; <br />&nbsp;&nbsp;&nbsp; for ( ; ; ){<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <font color="#ff8000">__RESET_WATCHDOG( );</font><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; PORT_POWER_LED = LED_ON;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ADSCR_ADCH = ADCH_VR;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; while ( !ADSCR_COCO );<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <font color="#ff8000">U1t_temp = ( ADRL &gt;&gt; 4 );<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if ( U1t_temp &lt; MORTOR_MIN ){<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; U1t_temp = MORTOR_MIN;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; PORT_DAC = U1t_temp;</font><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if ( PORT_OFF_SW == PHY_ON ){<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <font color="#ff8000">PORT_POWER_LED = LED_OFF;</font><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; PORT_DAC = MORTOR_OFF;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <font color="#ff8000">KBIER_KBIE3 = 1;&nbsp;&nbsp;&nbsp; // POWER ON SW 設定<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; KBSCR_ACKK = 1;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; KBSCR_IMASKK = 0;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; asm( "STOP" );<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; KBSCR_IMASKK = 1;</font><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />&nbsp;&nbsp;&nbsp; }<br />}</p>
<p></p>
<p></p></blockquote>
<p><br /></p>
<blockquote>
<p>// Keyboard Wakeup<br />#pragma TRAP_PROC<br />void _KBD_Interrupt( void ) {<br />&nbsp;&nbsp;&nbsp; <font color="#ff8000">// 処理なし、STOP解除に利用する</font><br />}</p>
<p></p>
<p></p></blockquote>
<p>　先ほどの <font color="#00a000">【 test3-2 設計 】</font> と <font color="#00a000">【 test3-2 設計の補足 】</font> を参考にして、オレンジ色の部分にどのような変更が行われたのか読み取ってみてください。 そう難しくはないはずです。 中身が理解できたところで、実際に書き込んでみましょう。</p>
<p>　この test3-2 ではマイコンの STOP 命令を使いますので、そのままでは CodeWarrior のデバッガ画面で動かしながら動作確認をすることができません。 いったん書き込みが済んだら HC08デバッグ・ツールの電源を切り、ターゲット・ボードから特殊コネクタを外して JP1 の 1-2間にジャンパ・リンクを付けて 3V のACアダプタまたは単二乾電池 4本を使って動作確認を行ってください。</p>
<p><br />　以上、二つのテスト・プログラムを動かすことによって簡単な低電力モードの利用法を学習しました。 これを応用すればテレビのリモコンなどのように <font color="#ff8000">「電源スイッチのない電子機器」</font> を作れるようになります。</p>
<p><br />　次回からは、「タイマ」 の説明に入る予定です。<br />　</p>
<p>　『関連宣伝』<br />マルツパーツ館では下記の関連商品を販売中です。 併せて購入されると便利です。<br />　 <a href="http://www.marutsu.co.jp/user/shohin.php?p=46738" target="_blank">【CQBUHIN-FAN】ミニマイコン扇風機製作部品セット</a><br />　 <a href="http://www.marutsu.co.jp/user/shohin.php?p=42908" target="_blank">【KMC908QY4A】ユーザーモード入りマイコン</a><br />　 <a href="http://www.marutsu.co.jp/user/shohin.php?p=35600" target="_blank">HC08スターター・ボード・キット Ver.2</a><br />　 <a href="http://www.marutsu.co.jp/user/shohin.php?p=46742" target="_blank">プリント基板付き書籍 「試しながら学ぶHC08マイコン入門」</a></p>
<p>　<br />　『参考文献』<br /><font color="#00008b"><a href="http://shop.cqpub.co.jp/hanbai/books/46/46051.html" target="_blank"><font color="#00008b">「試しながら学ぶHC08マイコン入門」</font></a>&nbsp;</font>（CQ出版）<br />　　第9章　USB-HC08デバッグ・ツールを自作する<br />　　第10章　統合開発環境CodeWarriorを使ってみる<br />　　Appendix F　KMC908QY4Aユーザ・モード・モニタ入りマイコンの知識<br />筆者のホームページ　<a href="http://www.cts-net.ne.jp/%7Ekawano-r/" target="_blank"><font color="#00008b">『マイコン工作の実験室』</font></a> </p>
<p align="right">組み込みエンジニア　KAWANO<br /></p>]]>
   </content>
</entry>

<entry>
   <title>HC08マイコンの使い方QY4A編 -《90》【書籍】パワーダウン処理（1）</title>
   <link rel="alternate" type="text/html" href="http://www.eleki-jack.com/mycom2/2010/08/hc08qy4a_901.html" />
   <id>tag:www.eleki-jack.com,2010:/mycom2//4.4588</id>
   
   <published>2010-08-16T02:18:01Z</published>
   <updated>2010-08-16T02:18:39Z</updated>
   
   <summary>　HC08ミニマイコン扇風機における 低電力モードの使い方を説明します。 QY4...</summary>
   <author>
      <name>kawano</name>
      <uri>http://www.cts-net.ne.jp/~kawano-r/</uri>
   </author>
   
      <category term="HC08マイコンの使い方QY4A編" scheme="http://www.sixapart.com/ns/types#category" />
   
   <category term="3320" label="HC08ミニマイコン扇風機" scheme="http://www.sixapart.com/ns/types#tag" />
   <category term="5947" label="enum" scheme="http://www.sixapart.com/ns/types#tag" />
   <category term="5599" label="ウェイクアップ" scheme="http://www.sixapart.com/ns/types#tag" />
   <category term="5601" label="スリープ" scheme="http://www.sixapart.com/ns/types#tag" />
   <category term="5948" label="データフロー" scheme="http://www.sixapart.com/ns/types#tag" />
   <category term="5602" label="低電力モード" scheme="http://www.sixapart.com/ns/types#tag" />
   <category term="5949" label="列挙型" scheme="http://www.sixapart.com/ns/types#tag" />
   <category term="4292" label="状態遷移" scheme="http://www.sixapart.com/ns/types#tag" />
   
   <content type="html" xml:lang="ja" xml:base="http://www.eleki-jack.com/mycom2/">
      <![CDATA[<p>　HC08ミニマイコン扇風機における 低電力モードの使い方を説明します。 QY4A マイコンの低電力モードに関しては、<a href="http://www.eleki-jack.com/mycom2/hcs08hc08/hc08qy4a_2/" target="_blank">第79回～第81回</a> を参照してください。</p>
<p>&nbsp; </p>
<p>
</p><span class="mt-enclosure mt-enclosure-image" style="display: inline;"><a onclick="window.open('http://www.eleki-jack.com/mycom2/qy4a_dac01.html','popup','width=500,height=406,scrollbars=no,resizable=no,toolbar=no,directories=no,location=no,menubar=no,status=no,left=0,top=0'); return false" href="http://www.eleki-jack.com/mycom2/qy4a_dac01.html"><img class="mt-image-center" style="display: block; margin: 0px auto 20px; text-align: center;" alt="qy4a_dac01.gif" src="http://www.eleki-jack.com/mycom2/qy4a_dac01-thumb-400x324.gif" width="400" height="324" /></a></span>
<p align="center"><a href="http://shop.cqpub.co.jp/hanbai/books/46/46051.html" target="_blank"><font color="#00008b">内容見本</font></a> p.28　図3-1 操作の面から見たブロック図</p>
<p>&nbsp;</p>]]>
      <![CDATA[<p>　今回の内容は書籍 <a href="http://shop.cqpub.co.jp/hanbai/books/46/46051.html" target="_blank"><font color="#00008b">「試しながら学ぶHC08マイコン入門」</font></a> （CQ出版） のサポート記事です。 第2部と第3部を一通り実施したあとで、改めてプログラムについて勉強したい、という方にピッタリです。<br />　上の図にある D-A変換回路については、この連載の <a href="http://www.eleki-jack.com/mycom2/hcs08hc08/hc08qy4a_2/" target="_blank">第20回～第25回</a> で詳しく説明しました。 <a href="http://www.eleki-jack.com/mycom2/2009/05/hc08qy4a_48ad.html" target="_blank">第48回</a> では A-D変換器の使い方を説明し、簡単なテストプログラムを紹介しています。 これらを復習しておいてから、この後の解説を読むと理解が早いでしょう。 圧電サウンダについては、もっと後の方でタイマの学習をするときに取り上げます。<br />　</p><strong><font color="#0000cc">◆ HC08ミニマイコン扇風機における 低電力モード の使い方<br /></font></strong>
<p><strong><font color="#00a000"><br />低電力モードに関する初期化処理</font><br /></strong>　HC08ミニマイコン扇風機のプログラムから、低電力モードに関する初期設定の部分を抜き出してみます（プログラム全体については書籍を参照してください）。</p>
<blockquote>
<p>void init_hardware( void ) {<br />&nbsp;&nbsp;&nbsp; <font color="#ff8000">CONFIG2 = 0x00;</font>&nbsp;&nbsp;&nbsp;&nbsp; // IRQピン無効、RSTピン無効<br />&nbsp;&nbsp;&nbsp; <font color="#ff8000">CONFIG1 = 0x02;</font>&nbsp;&nbsp;&nbsp;&nbsp; // LVI(3V)有効、STOP有効、COP有効<br />&nbsp;&nbsp;&nbsp; OSCTRIM = Optional; <br />}</p>
<p></p>
<p></p></blockquote>
<p>　<strong><font color="#0000cc">コンフィギュレーション・レジスタ２（CONFIG2）</font></strong> については <a href="http://www.eleki-jack.com/mycom2/2009/06/hc08qy4a_53rst.html" target="_blank">第53回</a> で説明しました。 この作品における低電力動作に関係するビットの設定値を見ておきましょう。<br /><strong><font color="#0000cc">　</font></strong></p>
<p></p>
<p>
</p><span class="mt-enclosure mt-enclosure-image" style="display: inline;"><strong><font color="#0000cc"><img class="mt-image-center" style="display: block; margin: 0px auto 20px; text-align: center;" alt="qy4a_register_config2.gif" src="http://www.eleki-jack.com/mycom2/qy4a_register_config2.gif" width="460" height="130" /></font></strong></span>
<p><strong><font color="#ff8000">・ OSCENINSTOP　ストップ・モードでの発振器有効ビット</font></strong><br />　　　0 ： ストップ・モードでの発振器の動作は無効<br />　ストップ・モードのとき周期的なウェイクアップ（AWU） を使わないので、発振器を止める設定にしています。</p>
<p><br />　<strong><font color="#0000cc">コンフィギュレーション・レジスタ１</font></strong><strong><font color="#0000cc">（CONFIG1）</font></strong> については <a href="http://www.eleki-jack.com/mycom2/2009/06/hc08qy4a_53rst.html" target="_blank">第53回</a> で説明しました。 この作品における低電力動作に関係するビットの設定値を見ておきましょう。<br />　</p>
<p></p>
<p>
</p><span class="mt-enclosure mt-enclosure-image" style="display: inline;"><strong><font color="#0000cc"><img class="mt-image-center" style="display: block; margin: 0px auto 20px; text-align: center;" alt="qy4a_register_config1.gif" src="http://www.eleki-jack.com/mycom2/qy4a_register_config1.gif" width="430" height="130" /></font></strong></span>
<p><strong><font color="#ff8000">・ COPRS （ストップ・モードのとき）　自動ウェイクアップ周期の選択ビット</font></strong><br />　　　0 ：&nbsp; 自動ウェイクアップ長期サイクル<br />　自動ウェイクアップ（AWU） を使わないので、このビットはストップ・モードにおいては意味をもちません。 ストップ・モード以外のときは別の機能になります（第53回 参照）。</p>
<p><strong><font color="#ff8000">・ LVISTOP　ストップ・モードでのLVI 許可ビット</font></strong><br />　　　0 ： ストップ・モードでLVI を禁止<br />　乾電池を使用するため、ストップ・モードで放置しておくとそのうち電源電圧がじわじわと下がってきます。 LVI 有効にしていると早めに電池を交換しなければならないため、無効にしています。 LVI 無効だと電源電圧がずっと下がったときに暴走しないかという心配がありますが、動き始めれば LVI も COP も働くのでおもちゃとして実用上は問題ありません。<br />　また、ストップ・モードで LVI を有効にすると、ストップ・モードでの電源電流が増えることも忘れてはなりません（<a href="http://www.eleki-jack.com/mycom2/2010/04/hc08qy4a_79_1.html" target="_blank">第79回</a>）。</p>
<p><strong><font color="#ff8000">・ SSREC　短期ストップ復帰ビット</font></strong><br />　　　0 ： 4096 BUSCLKX4 サイクル後にストップ・モードから復帰 （長期ストップ復帰）<br />　よほど早く復帰させたい場合を除いて SSREC = 0 長期ストップ復帰 の設定のままで問題ありません。</p>
<p><strong><font color="#ff8000">・ STOP　STOP 命令有効ビット</font></strong><br />　　　1 ： STOP命令を有効にする<br />　この作品ではストップ・モードを使うので、STOP命令を有効にします。</p>
<p>&nbsp;</p>
<p><strong><font color="#00a000">HC08ミニマイコン扇風機のスリープ、ウェイクアップに関する処理</font></strong><br />　スリープ、ウェイクアップに関する処理は、「パワー状態処理」 で行っています。 以下に状態遷移図を示します。 状態遷移の手法については、<a href="http://www.eleki-jack.com/mycom2/2009/05/hc08qy4a_48ad.html" target="_blank">第48回</a> <a href="http://www.eleki-jack.com/mycom2/2009/07/hc08qy4a_56cop1.html" target="_blank">第56回</a> <a href="http://www.eleki-jack.com/mycom2/2010/01/hc08qy4a_693.html" target="_blank">第69回</a> を参照してください。<br />　</p>
<p>
</p><span class="mt-enclosure mt-enclosure-image" style="display: inline;"><a href="http://www.eleki-jack.com/mycom2/hc08_power_ctrl_smd.gif"><img class="mt-image-center" style="display: block; margin: 0px auto 20px; text-align: center;" alt="hc08_power_ctrl_smd.gif" src="http://www.eleki-jack.com/mycom2/hc08_power_ctrl_smd-thumb-480x296.gif" width="480" height="296" /></a></span>
<p align="center"><br />「パワー状態処理」 の状態遷移図 （クリックで拡大）</p>
<p><br />　マイコンに電源が与えられ、リセット解除してプログラムが動き始めたとき、この 「パワー状態処理」 では最初に 「パワーオフ状態」 になります。 これには次のような意図があります。</p>
<p><font color="#00a000">&nbsp;・ 電池を入れたとき、いきなり動き始めるのは不自然なので停止させている。<br />&nbsp;・ スリープ中つまりパワーオフ状態のとき、なんらかの原因で不意にリセットが<br />　 かかった場合、リセット解除時に動き始めないようにしている。</font></p>
<p>&nbsp;</p>
<p>　HC08ミニマイコン扇風機のプログラムより、「パワー状態処理」 の部分を抜き出します。 プログラム全体については書籍を参照してください。</p>
<blockquote>
<p>//*************************<br />// パワー状態処理<br />//*************************<br />void power_mode( void ){<br />&nbsp;&nbsp;&nbsp; <font color="#ff8000">static enum {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; STATE_POWER_OFF,<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; STATE_POWER_ON,<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; STATE_WAIT_POWER_OFF<br />&nbsp;&nbsp;&nbsp; } ens_power_state;</font></p>
<p><font color="#ff8000">&nbsp;&nbsp;&nbsp; switch ( ens_power_state ){<br />&nbsp;&nbsp;&nbsp;&nbsp;case STATE_POWER_OFF:</font><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; init_PORT( );<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; U1_timer_mode = MODE_TIMER_INIT;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; U1_yuragi_mode = MODE_YURAGI_OFF;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; U1_buzzer_mode = MODE_BZ_NONE;<br />#ifdef DEBUG<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; while ( PORT_ON_SW == PHY_OFF ){<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // モニタ使用中は COP は無効<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />#else<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; PORT_CHECK = 0;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; KBIER_KBIE3 = 1;&nbsp;&nbsp;&nbsp; // POWER ON SW 設定<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; KBSCR_ACKK = 1;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; KBSCR_IMASKK = 0;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; asm( "STOP" );<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 【条件１】 STOP解除<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; KBSCR_IMASKK = 1;<br />#endif<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; init_ADC( );<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; U1_buzzer_cmd = CMD_BZ_ON;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ens_power_state = STATE_POWER_ON;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; break;<br />&nbsp;&nbsp;&nbsp; <font color="#ff8000">case STATE_POWER_ON:</font><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; PORT_POWER = 1;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 【条件２】<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if ( ( PORT_OFF_SW == PHY_ON )<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; || ( U1_timer_mode == MODE_TIMER_TIMEUP ) ){<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; U1_buzzer_cmd = CMD_BZ_OFF;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ens_power_state = STATE_WAIT_POWER_OFF;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; break;<br />&nbsp;&nbsp;&nbsp; <font color="#ff8000">case STATE_WAIT_POWER_OFF:</font><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; PORT_POWER = 1;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 【条件３】<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if ( U1_buzzer_mode == MODE_BZ_NONE ){<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ens_power_state = STATE_POWER_OFF;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; break;<br />&nbsp;&nbsp;&nbsp; default:<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ens_power_state = STATE_POWER_OFF;<br />&nbsp;&nbsp;&nbsp; }<br />}</p>
<p></p>
<p></p></blockquote>
<p>　見慣れないものがあるので、そこから説明します。</p>
<p><font color="#ff8000">static enum {<br />&nbsp;&nbsp;&nbsp; STATE_POWER_OFF,<br />&nbsp;&nbsp;&nbsp; STATE_POWER_ON,<br />&nbsp;&nbsp;&nbsp; STATE_WAIT_POWER_OFF<br />} ens_power_state;</font></p>
<p>　このように enum と書くと、<font color="#00a000">列挙型の変数</font> を意味します。 列挙型というのはANSI C でも規定されている一般的な C 言語の要素です。 ここでは、<font color="#ff8000">ens_power_state</font> という名前の変数を宣言しています。 static を付けているので、これは静的変数になります。 <br />　列挙型ということで、定義する識別子には整数を順番に割り付けますから、原則として、<br /><font color="#ff8000">STATE_POWER_OFF</font>　は　0<br /><font color="#ff8000">STATE_POWER_ON</font>　 は　1<br /><font color="#ff8000">STATE_WAIT_POWER_OFF</font>　は　2<br />となります。<br />　そして、ここが面白いポイントなのですが、<font color="#00a000">この変数に対して代入または比較する値は、型宣言で決めた種類の識別子の中から選ぶ</font>、ということになっています。<br />　つまり、この例では、<br />　ens_power_state = 1;<br />ではなく、<br />　ens_power_state = STATE_POWER_ON;<br />と書くのが正しい、ということになります。<br />　このようにするメリットには次のようなものがあります。</p>
<p><font color="#00a000">&nbsp;・ 普通の変数として数字を直接使った場合には、後でそれがどんな意味だった<br />　 のかわからなくなる可能性があるが、 列挙型の変数を使えばそれが防げる。<br />&nbsp;・ 状態遷移を管理する switch 文の case 節で、直接数字を使ったり、状態遷移<br />　 を起こすときに状態管理用変数に数字を代入する方法だと、どこかとどこかの<br />　 状態の間に新しい状態を追加したくなったときに数字を書き換えるのが大変<br />　 だが、列挙型の変数を使えば途中に挿入してもまったく問題ない。</font></p>
<p><br />　それでは、上記のプログラムを見てください。</p>
<p><font color="#ff8000">switch ( ens_power_state ){<br />case STATE_POWER_OFF:</font><br />上の状態遷移図で示した 「パワーオフ状態」 の処理を記述しています。<br /><font color="#ff8000">case STATE_POWER_ON:</font><br />「パワーオン状態」 の処理を記述しています。<br /><font color="#ff8000">case STATE_WAIT_POWER_OFF:</font><br />「パワーオフ待ち状態」 の処理を記述しています。</p>
<p>　それぞれの処理内容は、状態遷移図に書いてあることをそのまま記述しています。 念のために言葉で説明すると、次のような流れになります。</p>
<p><font color="#00a000">&nbsp;・ <strong>リセット解除時</strong>、パワー・オフ状態になる。</font></p>
<p><font color="#00a000">&nbsp;・ <strong>パワー・オフ状態</strong>に入るとき、entry と書かれたところに並べられた処理を一通り<br />　　実施する。 その結果、マイコンはストップ・モードに移行する。<br />&nbsp;・ オン・スイッチが押されると、キーボード割り込みが発生してマイコンはストップ・<br />　　モードから抜け出し、パワー状態処理はパワー・オフ状態から抜け出す。【条件１】<br />　　そのとき、exit と書かれたところに並べられた処理を一通り実施する。<br />&nbsp;・ パワー・オフ状態を抜け出すと、パワー・オン状態に遷移する。</font></p>
<p><font color="#00a000">&nbsp;・ <strong>パワー・オン状態</strong>にあるときは、POWERポートに 1を出力する。<br />&nbsp;・ パワー・オン状態のとき、オフ・スイッチが押されるか、またはタイマ機能の規定<br />　　時間が経過したときにパワー・オン状態を抜け出す。【条件２】<br />&nbsp;・ パワー・オン状態を抜け出すとき、exit と書かれたところに並べられた処理<br />　　「オフブザー発行」 を実施する。 これはブザー吹鳴処理に渡され、ピーピ！ と<br />　　いう音を発生させる効果がある。<br />&nbsp;・ パワー・オン状態を抜け出すと、パワー・オフ待ち状態に遷移する。</font></p>
<p><font color="#00a000">&nbsp;・ <strong>パワー・オフ待ち状態</strong>にあるときは、POWERポートに 1を出力する。<br />&nbsp;・ パワー・オフ待ち状態のとき、ブザー吹鳴処理がブザー音を鳴らしている間は<br />　　状態遷移を起こさず、ブザー音を鳴らし終わったとき（鳴らしていないとき）に<br />　　パワー・オフ待ち状態を抜け出す。【条件３】<br />&nbsp;・ パワー・オフ待ち状態を抜け出すと、パワー・オフ状態に遷移する。</font></p>
<p>　<br />　データの流れを確認するためには、書籍の p.112 にある 図11-A HC08ミニマイコン扇風機ソフトウェアのデータ・フロー図 を参照してください。</p>
<p><br />　簡単ですが HC08ミニマイコン扇風機プログラムの低電力モードに関する解説は以上です。 次回は HC08ミニマイコン扇風機のハードウェアを使って、低電力モードを使用するシンプルなテスト・プログラムを作成します。<br />　</p>
<p>　『関連宣伝』<br />マルツパーツ館では下記の関連商品を販売中です。 併せて購入されると便利です。<br />　 <a href="http://www.marutsu.co.jp/user/shohin.php?p=46738" target="_blank">【CQBUHIN-FAN】ミニマイコン扇風機製作部品セット</a><br />　 <a href="http://www.marutsu.co.jp/user/shohin.php?p=42908" target="_blank">【KMC908QY4A】ユーザーモード入りマイコン</a><br />　 <a href="http://www.marutsu.co.jp/user/shohin.php?p=35600" target="_blank">HC08スターター・ボード・キット Ver.2</a><br />　 <a href="http://www.marutsu.co.jp/user/shohin.php?p=46742" target="_blank">プリント基板付き書籍 「試しながら学ぶHC08マイコン入門」</a></p>
<p>　<br />　『参考文献』<br /><font color="#00008b"><a href="http://shop.cqpub.co.jp/hanbai/books/46/46051.html" target="_blank"><font color="#00008b">「試しながら学ぶHC08マイコン入門」</font></a>&nbsp;</font>（CQ出版）<br />　　第9章　USB-HC08デバッグ・ツールを自作する<br />　　第10章　統合開発環境CodeWarriorを使ってみる<br />　　Appendix F　KMC908QY4Aユーザ・モード・モニタ入りマイコンの知識<br />筆者のホームページ　<a href="http://www.cts-net.ne.jp/%7Ekawano-r/" target="_blank"><font color="#00008b">『マイコン工作の実験室』</font></a> </p>
<p align="right">組み込みエンジニア　KAWANO<br /></p>]]>
   </content>
</entry>

<entry>
   <title>HC08マイコンの使い方QY4A編 -《89》 キー・マトリクス・スイッチと低電力（4）</title>
   <link rel="alternate" type="text/html" href="http://www.eleki-jack.com/mycom2/2010/08/hc08qy4a_89_4.html" />
   <id>tag:www.eleki-jack.com,2010:/mycom2//4.4547</id>
   
   <published>2010-08-06T07:58:06Z</published>
   <updated>2010-08-06T07:09:23Z</updated>
   
   <summary>◆ キー・マトリクス・スイッチを使ったテスト・プログラム（続き）　前回 と今回で...</summary>
   <author>
      <name>kawano</name>
      <uri>http://www.cts-net.ne.jp/~kawano-r/</uri>
   </author>
   
      <category term="HC08マイコンの使い方QY4A編" scheme="http://www.sixapart.com/ns/types#category" />
   
   <category term="5550" label="74HC595" scheme="http://www.sixapart.com/ns/types#tag" />
   <category term="5839" label="キー・マトリクス・スイッチ" scheme="http://www.sixapart.com/ns/types#tag" />
   <category term="5840" label="シリアル・パラレル・シフトレジスタ" scheme="http://www.sixapart.com/ns/types#tag" />
   <category term="5895" label="タイムド・ループ方式" scheme="http://www.sixapart.com/ns/types#tag" />
   <category term="5896" label="複数押し" scheme="http://www.sixapart.com/ns/types#tag" />
   
   <content type="html" xml:lang="ja" xml:base="http://www.eleki-jack.com/mycom2/">
      <![CDATA[<p><strong><font color="#0000cc">◆ キー・マトリクス・スイッチを使ったテスト・プログラム（続き）</font></strong><br />　<a href="http://www.eleki-jack.com/mycom2/2010/08/hc08qy4a_88_3.html" target="_blank">前回</a> と今回でテスト・プログラムの解説を行い、実際に動かしてみます。</p><embed src="http://www.youtube.com/v/zJugtdti_IY&amp;hl=ja&amp;fs=1" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="344"> 
<p align="center">テスト・プログラムを動かすようす （クリックで再生） 再掲載</p>]]>
      <![CDATA[<p>　<br />　プログラム解説の続きです。</p>
<blockquote>
<p>//*************************<br />// キー・マトリクス入力処理<br />//*************************<br />void key_matrix_in( void ){<br />&nbsp;&nbsp;&nbsp; static U1 U1s_scan;<br />&nbsp;&nbsp;&nbsp; static U1 U1s_counter;<br />&nbsp;&nbsp;&nbsp; static U1 U1s_on_counter;<br />&nbsp;&nbsp;&nbsp; static U1 U1s_sw_data;<br />&nbsp;&nbsp;&nbsp; static U1 U1s_sw_data_old;<br />&nbsp;&nbsp;&nbsp; static U1 U1s_temp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // デバッグしやすくする<br />&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp; <font color="#ff8000">if ( ( U1_power_ctrl == POWER_INITIAL )<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; || ( U1_power_ctrl == POWER_WAKEUP ) ){</font><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; U1s_scan = 0;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; U1s_counter = 0;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; U1s_on_counter = 0;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; U1s_sw_data = NUM_MTX_SW_OFF;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; U1s_sw_data_old = NUM_MTX_SW_OFF;<br />&nbsp;&nbsp;&nbsp; }<br />&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp; <font color="#ff8000">U1s_temp = ( ~( PORT_MTX_IN &gt;&gt; 1 ) ) &amp; 0x0F;</font><br />&nbsp;&nbsp;&nbsp; switch ( U1s_temp ){<br />&nbsp;&nbsp;&nbsp; case 1:<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; U1s_sw_data = 0;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; U1s_sw_data += U1s_scan;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; U1s_on_counter++;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; break;<br />&nbsp;&nbsp;&nbsp; case 2:<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; U1s_sw_data = 4;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; U1s_sw_data += U1s_scan;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; U1s_on_counter++;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; break;<br />&nbsp;&nbsp;&nbsp; case 4:<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; U1s_sw_data = 8;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; U1s_sw_data += U1s_scan;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; U1s_on_counter++;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; break;<br />&nbsp;&nbsp;&nbsp; case 8:<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; U1s_sw_data = 12;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; U1s_sw_data += U1s_scan;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; U1s_on_counter++;<br />&nbsp;&nbsp;&nbsp; }<br />&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp; <font color="#ff8000">PTB &amp;= 0x0F;</font><br />&nbsp;&nbsp;&nbsp; switch ( U1s_scan ){<br />&nbsp;&nbsp;&nbsp; case 0:<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DIR_SCAN0 = DIR_INPUT;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DIR_SCAN1 = DIR_OUTPUT;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; U1s_scan++;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; break;<br />&nbsp;&nbsp;&nbsp; case 1:<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DIR_SCAN1 = DIR_INPUT;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DIR_SCAN2 = DIR_OUTPUT;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; U1s_scan++;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; break;<br />&nbsp;&nbsp;&nbsp; case 2:<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DIR_SCAN2 = DIR_INPUT;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DIR_SCAN3 = DIR_OUTPUT;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; U1s_scan++;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; break;<br />&nbsp;&nbsp;&nbsp;&nbsp;<font color="#ff8000">case 3:</font><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DIR_SCAN3 = DIR_INPUT;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DIR_SCAN0 = DIR_OUTPUT;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; U1s_scan = 0;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if ( U1s_on_counter != 1 ){<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; U1s_sw_data = NUM_MTX_SW_OFF;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if ( U1s_counter &lt; INPUT_TIMES ){<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; U1s_counter++;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if ( U1s_sw_data != U1s_sw_data_old ){<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; U1s_counter = 0;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; U1s_sw_data_old = U1s_sw_data;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if ( U1s_counter &gt;= INPUT_TIMES ){<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; U1_indata = U1s_sw_data;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; U1s_on_counter = 0;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; break;<br />&nbsp;&nbsp;&nbsp; default:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // ガード処理<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; U1s_scan = 0;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DIR_SCAN0 = DIR_OUTPUT;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DIR_SCAN1 = DIR_INPUT;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DIR_SCAN2 = DIR_INPUT;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DIR_SCAN3 = DIR_INPUT;<br />&nbsp;&nbsp;&nbsp; }<br />}<br /></p></blockquote>
<p><font color="#ff8000">if ( ( U1_power_ctrl == POWER_INITIAL )<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; || ( U1_power_ctrl == POWER_WAKEUP ) ){</font><br />これにより、リセット解除後の1回と、ウェイクアップ時の1回だけ 「キー・マトリクス・入力処理」 の初期化を行います。</p>
<p>　キー・マトリクス・スイッチの読み取りは、縦の列で順番に見ていきます。 最初は　0　4　8　C　を調べます。 次に　1　5　9　D　を調べ、続いて　2　6　A　E　を調べ、最後に　3　7　B　F　という具合です。 この順番を管理するのは U1s_scan　という変数です。</p>
<p><font color="#ff8000">U1s_temp = ( ~( PORT_MTX_IN &gt;&gt; 1 ) ) &amp; 0x0F;</font><br />PORT_MTX_IN は PTA4～PTA1 なので、PORT A を 1バイト丸ごと取り込みます。<br />それを 1ビット右にシフトすると、欲しい情報が bit3 ～ bit0 の位置に移動します。<br />全ビットを反転して、各ビットが 0 のときオフ、1 のときオンになるようにします。<br />下位 4ビットだけを取り出して、U1s_temp に入れています。<br />この変数は本来なら自動変数でよいのですが、デバッグするときに変数を見やすくするためスタティック変数にしています。</p>
<p>　その直後の switch 文により、どれかキーが押されているかどうか調べています。 たとえば U1s_scan が 2 のときは　2　6　A　E　の列を調べているので、U1s_temp　が 4 だとすると<br />case 4:　の処理によって　U1s_sw_data = 8;　さらに　U1s_sw_data += U1s_scan;　ですから　U1s_sw_data は 0x0A になります。 ここで気付くことは、縦の列で複数押しがあった場合はどの case 節にも該当しないので、キーが押されていないのと同じことになります。</p>
<p><font color="#ff8000">PTB &amp;= 0x0F;</font><br />この後で PTB7 ～ PTB4 のいずれかのポートを入力方向から出力方向に切り替える処理があります。 そのときの出力レベルを Ｌ にしたいので、データ・レジスタの上位 4ビットをクリアしています。 メイン・ループの PTB = 0x01; や PTB = 0X00; がその役割を果たしてくれていますが、これは本来デバッグ用のチェック出力なので、削除する可能性もあります。 そこで、本当に必要なこの場所できちんとクリアをしています。</p>
<p>　このプログラムは、いつもと同じタイムド・ループ方式で構成されていますが、メイン1周の時間を 5ms にしています。なぜかと言うと、１回の処理でキー・マトリクス・スイッチの縦一列を読み込んでいるので、10ms ではちょっと遅くなってしまうからです。<br />　実際には、1回に 4個のスイッチを読み取るということで、全部のキーを読み取るためにはこの関数が 4回呼ばれる必要があるわけです。 つまり 5ms × 4 ＝ 20ms となっています。 さらに、<font color="#00a000">同じキー入力が 2回連続で確認されたときに初めてキー入力確定としてあるので、20ms × 2 ＝ 40ms が認識に必要な時間</font>です。 人間が指で操作して、それを読み込む時間として適切な時間となっています。</p>
<p><font color="#ff8000">case 3:</font><br />U1s_scan = 0 から数えて 4回目（U1s_scan = 3）のとき、16個のキー入力がどうだったか確認する処理があります。 U1s_on_counter が 1 でないときは、入力がなかったものとします。 U1s_on_counter が 0 のときは本当にキー入力がない、または縦の列の中で複数押しがあった場合です。 1 のときは正常にどれかのキーが押されたことを意味します。 2以上であれば、複数の縦の列にまたがる複数押しがあったことを意味します。 そうして読み取った　U1s_sw_data　と　U1s_sw_data_old　が 2回連続して一致したとき、キー入力確定です。<br />　</p>
<blockquote>
<p>//*********************************<br />// テスト・アプリケーション処理<br />//*********************************<br />void test_application( void ){<br />&nbsp;&nbsp;&nbsp; if ( U1_power_ctrl == POWER_SLEEP ){<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <font color="#ff8000">U1_outdata = led_7seg_tbl[ NUM_LED_BLANK ];</font><br />&nbsp;&nbsp;&nbsp; } else {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if ( U1_indata != NUM_MTX_SW_OFF ){<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <font color="#ff8000">U1_outdata = led_7seg_tbl[ U1_indata ];</font><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <font color="#ff8000">U1_appli_sleep_ready = 0;</font><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } else {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <font color="#ff8000">U1_appli_sleep_ready = 1;</font><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />&nbsp;&nbsp;&nbsp; }<br />}<br /></p></blockquote>
<p><font color="#ff8000">U1_outdata = led_7seg_tbl[ NUM_LED_BLANK ];</font><br />スリープ移行時は、7セグメントLED にブランクのデータを指定します。</p>
<p><font color="#ff8000">U1_outdata = led_7seg_tbl[ U1_indata ];<br /></font><font color="#ff8000">U1_appli_sleep_ready = 0;</font><br />スリープ移行時以外のとき、キーが押されている場合はその数字を 7セグメントLEDへ送ります。そして、スリープしてはいけないという信号を出します。</p>
<p><font color="#ff8000">U1_appli_sleep_ready = 1;</font><br />スリープ移行時以外のとき、キーが押されていない場合はスリープしてもよいという信号を出します（これをパワー状態処理で監視して時間を計っている）。</p>
<p>　なお、本来は <font color="#00a000">ここがアプリケーション処理を書くべき場所になります。アプリケーションとは、 例えば 「電子ロック」 とか 「数当てゲーム」 とか、そういった制御</font> を書くわけです。 すると必然的に 「今はスリープしてはいけないときだ」 という判断は、主にここで行われることになります。<br />　</p>
<blockquote>
<p>//*************************<br />// シリパラ出力処理<br />//*************************<br />void serial_parallel_out( void ){<br />&nbsp;&nbsp;&nbsp; U1 U1t_cnt, U1t_data;<br />&nbsp;&nbsp;&nbsp; <br />&nbsp;&nbsp;&nbsp; U1t_data = <font color="#ff8000">U1_outdata;</font><br />&nbsp;&nbsp;&nbsp; for ( U1t_cnt = 0 ; U1t_cnt &lt; 8 ; U1t_cnt++ ){<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if ( U1t_data &amp; 0x80 ){<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <font color="#ff8000">PORT_SDATA = 1;</font><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } else {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <font color="#ff8000">PORT_SDATA = 0;</font><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <font color="#ff8000">PORT_SCLK = 1;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; PORT_SCLK = 0;</font><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; U1t_data &lt;&lt;= 1;<br />&nbsp;&nbsp;&nbsp; }<br />&nbsp;&nbsp;&nbsp; <font color="#ff8000">PORT_LATCH = 1;<br />&nbsp;&nbsp;&nbsp; PORT_LATCH = 0;</font><br />}<br /></p></blockquote>
<p>　<a href="http://www.eleki-jack.com/mycom2/2010/07/hc08qy4a_86_1.html" target="_blank">第86回</a> で示したシリアル・パラレル・シフトレジスタ IC の 74HC595 を駆動するための処理です。 変数 <font color="#ff8000">U1_outdata</font> に出力したい 1バイト・データを入れてから、この関数を呼び出してください。 <font color="#ff8000">PORT_SDATA&nbsp;</font>，<font color="#ff8000">PORT_SCLK</font> ，<font color="#ff8000">PORT_LATCH</font> の 3本をぱたぱたと動かして、自動的に 74HC595 へデータを転送します。 制御の方法については、第86回 に記載しています。<br />　</p>
<blockquote>
<p>//*************************<br />// 割り込み処理<br />//*************************</p>
<p>// Keyboard Wakeup<br />#pragma TRAP_PROC<br />void _KBD_Interrupt( void ) {<br />&nbsp;&nbsp;&nbsp; // 処理なし、STOP解除に利用する<br /><font color="#ff8000">#ifdef DEBUG_STOP_MODE<br />&nbsp;&nbsp;&nbsp; U1_kbd_flag = 1;<br />#endif</font><br />}<br /></p></blockquote>
<p>　キーボード割り込み（KBI 割り込み）処理は、フローチャートにも書かれているように中身がありません。 しかしデバッグ中は STOPモードにするわけにいかないので、通常モードのまま単純なループを回して足踏みをさせます（パワー状態処理を参照）。 <br /><font color="#ff8000">#ifdef DEBUG_STOP_MODE<br />&nbsp;&nbsp;&nbsp; U1_kbd_flag = 1;<br />#endif</font><br />によって、STOPモードになったと同様の擬似状態（単純なループ） から抜け出すための手段を提供しています。</p>
<p>　テスト・プログラムは以上で完成です。 さっそく動かしてみましょう。</p>
<p>　<br /><strong><font color="#0000cc">◆ キー・マトリクス・スイッチを使ったテスト・プログラムを動かしてみる</font></strong><br />　最初に、CodeWarrior のデバッガを使って実機を動かしながらデバッグするのか、それともデバッグは終わったものとしてスタンドアロンで動かすのか、選ぶ必要があります。<br />　圧縮して公開した状態のプロジェクトでは、後者にしてあります。 もしも前者にする場合は、マクロの設定を一か所だけ変更しなくてはなりません。</p>
<p>// ↓デバッグが終わったらコメント化して書き込むこと<br /><font color="#ff8000">//#define DEBUG_STOP_MODE</font></p>
<p>の部分を、</p>
<p>// ↓デバッグが終わったらコメント化して書き込むこと<br /><font color="#ff8000">#define DEBUG_STOP_MODE</font></p>
<p>に変更してから、デバッグを行ってください。</p>
<p>　<br />　それではデバッグを行う場合として説明を続けます。 ブレッド・ボード上に回路を組んだまま、ブレッド・ボードに挿した状態の HC08スタータ・ボードを使って、ユーザ・モード・モニタ入り QY4Aマイコン（KMC908QY4A）に書き込みを行います。<br />　ジャンパ類の設定は次のとおりです。 JP1 ジャンパあり、JP2 ジャンパなし（スタンドアロンの場合も書き込み時はジャンパなし）、JP3は 1-2間ジャンパあり（またはなし）、JP4 は 1-2間ジャンパあり、JP5～JP8 すべてジャンパなし にすること。 VR1 は自由です。<br />　デバッグを選んだ場合は、書き込みが済んだら HC08スタータ・ボードの電源を切らず、そのまま CodeWarrior のデバッガで動作確認をすることができます。 スタンドアロンを選んだ場合はデバッガを終了させて、いったん HC08スタータ・ボードの電源を切り、JP2 をジャンパありにしてから再度電源をオンにして動かしてみてください。</p>
<p>　ユーザ・モード・モニタ入りでない普通の MC908QY4A マイコンのためのプログラムを、プロジェクトごと圧縮して <a href="http://micon.arrow.jp/uploads/files/hc08_keymatrix01.zip" target="_blank">hc08_keymatrix01.zip</a> に保存しました。 ご利用ください。 こちらはプログラムの書き込みの際に、ブレッド・ボードから HC08スタータ・ボードをいったん抜き取る必要がありますので、ご注意ください。 書き込み時のジャンパ類の設定は、デフォルトのセッティングです。 書き込みが済んでからいったん電源をオフにして、HC08スタータ・ボードをブレッド・ボードに差し込んでください。 ジャンパ類は次のようにします。 JP1 ジャンパあり、JP2 ジャンパなし、JP3は 1-2間ジャンパあり（またはなし）、JP4 は 1-2間ジャンパあり（またはなし）、JP5～JP8 すべてジャンパなし にすること。 VR1 は自由です。</p>
<p>　</p>
<p>　次回は、 HC08ミニマイコン扇風機のパワー・ダウン処理を解説する予定です。</p>
<p>　</p>
<p>　『参考文献』<br /><font color="#00008b"><a href="http://shop.cqpub.co.jp/hanbai/books/46/46051.html" target="_blank"><font color="#00008b">「試しながら学ぶHC08マイコン入門」</font></a>&nbsp;</font>（CQ出版）<br />　　第9章　USB-HC08デバッグ・ツールを自作する<br />　　第10章　統合開発環境CodeWarriorを使ってみる<br />　　Appendix F　KMC908QY4Aユーザ・モード・モニタ入りマイコンの知識<br />筆者のホームページ　<a href="http://www.cts-net.ne.jp/%7Ekawano-r/" target="_blank"><font color="#00008b">『マイコン工作の実験室』</font></a> </p>
<p align="right">組み込みエンジニア　KAWANO<br /></p>]]>
   </content>
</entry>

<entry>
   <title>HC08マイコンの使い方QY4A編 -《88》 キー・マトリクス・スイッチと低電力（3）</title>
   <link rel="alternate" type="text/html" href="http://www.eleki-jack.com/mycom2/2010/08/hc08qy4a_88_3.html" />
   <id>tag:www.eleki-jack.com,2010:/mycom2//4.4539</id>
   
   <published>2010-08-02T03:45:58Z</published>
   <updated>2010-08-02T04:59:10Z</updated>
   
   <summary>◆ キー・マトリクス・スイッチを使ったテスト・プログラム　今回と次回でテスト・プ...</summary>
   <author>
      <name>kawano</name>
      <uri>http://www.cts-net.ne.jp/~kawano-r/</uri>
   </author>
   
      <category term="HC08マイコンの使い方QY4A編" scheme="http://www.sixapart.com/ns/types#category" />
   
   <category term="5599" label="ウェイクアップ" scheme="http://www.sixapart.com/ns/types#tag" />
   <category term="5839" label="キー・マトリクス・スイッチ" scheme="http://www.sixapart.com/ns/types#tag" />
   <category term="5840" label="シリアル・パラレル・シフトレジスタ" scheme="http://www.sixapart.com/ns/types#tag" />
   <category term="5601" label="スリープ" scheme="http://www.sixapart.com/ns/types#tag" />
   <category term="5602" label="低電力モード" scheme="http://www.sixapart.com/ns/types#tag" />
   <category term="5842" label="７セグメントLED" scheme="http://www.sixapart.com/ns/types#tag" />
   
   <content type="html" xml:lang="ja" xml:base="http://www.eleki-jack.com/mycom2/">
      <![CDATA[<p><strong><font color="#0000cc">◆ キー・マトリクス・スイッチを使ったテスト・プログラム</font></strong><br />　今回と次回でテスト・プログラムの解説を行い、実際に動かしてみます。</p><embed src="http://www.youtube.com/v/zJugtdti_IY&amp;hl=ja&amp;fs=1" width="425" height="344" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true"> 
<p align="center">テスト・プログラムを動かすようす （クリックで再生）</p>]]>
      <![CDATA[<p>　<br />　<a href="http://www.eleki-jack.com/mycom2/2010/07/hc08qy4a_87_2.html" target="_blank">前回</a> の最後に示したキーマトリクスの読み取り方法で、一部訂正があります。<br />　SCAN0 ～ SCAN3 の出力を Ｈ にする、というところをすべて Ｈｉ-Ｚ （ハイ・インピーダンス）に変更します。（*1）　これは、複数のキーを同時に押したときに Ｈ 出力と Ｌ 出力がぶつかってしまわないようにするためです。 前回の記述はすでに修正しましたが、ここでもまた再掲載します。<br />　<br /></p>
<span class="mt-enclosure mt-enclosure-image" style="DISPLAY: inline"><a href="http://www.eleki-jack.com/mycom2/flow_chart_keymatrix.gif"><img class="mt-image-center" style="DISPLAY: block; MARGIN: 0px auto 20px; TEXT-ALIGN: center" height="451" alt="flow_chart_keymatrix.gif" src="http://www.eleki-jack.com/mycom2/assets_c/2010/07/flow_chart_keymatrix-thumb-420x451.gif" width="420" /></a></span>
<p align="center">全体のフローチャート （クリックで拡大）</p>
<p>　<br /><strong><font color="#0000cc">◆ ユーザ・モード・モニタ入りマイコン用 C言語プログラム</font></strong><br />　ユーザ・モード・モニタ入りマイコンのためのプログラムをプロジェクトごと圧縮して <a href="http://micon.arrow.jp/uploads/files/hc08_keymatrix01u.zip" target="_blank">hc08_keymatrix01u.zip</a> に保存しましたので ご利用ください （<a href="http://www.eleki-jack.com/mycom2/2010/04/hc08qy4a_81_3.html">第81回</a> で紹介した ”裏技” は使えない）。（*2）　main.c の主要部分を書き出し、必要に応じて解説します。<br />　</p>
<blockquote>
<p>//*************************<br />// マクロの定義<br />//*************************</p>
<p>// ↓デバッグが終わったらコメント化して書き込むこと<br /><font color="#ff8000">//#define DEBUG_STOP_MODE</font></p>
<p><font color="#ff8000">#define WAIT_MAIN&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ( 551 )</font></p>
<p>#define DISABLE&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ( 0 )<br />#define ENABLE&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ( 1 )</p>
<p>#define PORT_ALWAYSHIGH ( PTA_PTA5 )</p>
<p>// パワー状態処理<br />#define POWER_OFF_TIME&nbsp; ( ( U2 )( 2. * 1000. / 5. ) )&nbsp;&nbsp; // 5msカウンタで 2秒<br />#define POWER_INITIAL&nbsp;&nbsp; ( 0 )<br />#define POWER_NORMAL&nbsp;&nbsp;&nbsp; ( 1 )<br />#define POWER_SLEEP&nbsp;&nbsp;&nbsp;&nbsp; ( 2 )<br />#define POWER_WAKEUP&nbsp;&nbsp;&nbsp; ( 3 )</p>
<p>// キー・マトリクス入力処理<br />#define PORT_MTX_IN&nbsp;&nbsp;&nbsp;&nbsp; ( PTA )&nbsp;&nbsp;&nbsp;&nbsp; // PTA4-1<br /><font color="#ff8000">#define DIR_SCAN0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ( DDRB_DDRB4 )<br />#define DIR_SCAN1&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ( DDRB_DDRB5 )<br />#define DIR_SCAN2&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ( DDRB_DDRB6 )<br />#define DIR_SCAN3&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ( DDRB_DDRB7 )</font></p>
<p>#define DIR_INPUT&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ( 0 )<br />#define DIR_OUTPUT&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ( 1 )</p>
<p>#define NUM_MTX_SW_OFF&nbsp; ( 0xFF )<br />#define INPUT_TIMES&nbsp;&nbsp;&nbsp;&nbsp; ( 2 )&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // この回数連続して同一のとき確定</p>
<p>// テスト・アプリケーション処理<br />#define NUM_LED_BLANK&nbsp;&nbsp; ( 16 )&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // led_7seg_tbl 用（変更不可）</p>
<p>// シリパラ出力処理<br />#define PORT_SDATA&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ( PTB_PTB1 )<br />#define PORT_SCLK&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ( PTB_PTB2 )<br />#define PORT_LATCH&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ( PTB_PTB3 )<br /></p></blockquote>
<p><font color="#ff8000">//#define DEBUG_STOP_MODE</font><br />については <a href="http://www.eleki-jack.com/mycom2/2010/05/hc08qy4a_83_brkmon2.html" target="_blank">第83回</a> を参照してください。</p>
<p><font color="#ff8000">#define WAIT_MAIN&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ( 551 )</font><br />の数値は、メイン・ループの一周を約 5ms に調整しています。 これは内蔵 OSC が 12．8MHz に調整されていることを前提にしています。 ユーザ・モード・モニタ入りマイコンではすでに調整されているので、このまま使うことができます。</p>
<p><font color="#ff8000">#define DIR_SCAN0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ( DDRB_DDRB4 )</font><br />SCAN0 から SCAN3 は入出力方向を切り替えながら使用します。 そのための準備です。<br />　</p>
<blockquote>
<p>//*************************<br />// データの定義<br />//*************************</p>
<p><font color="#ff8000">volatile U1 U1_power_ctrl = POWER_INITIAL;&nbsp; // デバッグしやすくする</font></p>
<p>volatile U1&nbsp; U1_kbd_flag;</p>
<p>U1 U1_indata = NUM_MTX_SW_OFF;</p>
<p>U1 U1_appli_sleep_ready;</p>
<p>U1 U1_outdata;</p>
<p><font color="#ff8000">const U1 led_7seg_tbl[ 17 ] = {<br />&nbsp;&nbsp;&nbsp; 0x40,&nbsp;&nbsp; // 0&nbsp;&nbsp;&nbsp; -Gfedcba<br />&nbsp;&nbsp;&nbsp; 0x79,&nbsp;&nbsp; // 1&nbsp;&nbsp;&nbsp; -GFEDcbA<br />&nbsp;&nbsp;&nbsp; 0x24,&nbsp;&nbsp; // 2&nbsp;&nbsp;&nbsp; -gFedCba<br />&nbsp;&nbsp;&nbsp; 0x30,&nbsp;&nbsp; // 3&nbsp;&nbsp;&nbsp; -gFEdcba<br />&nbsp;&nbsp;&nbsp; 0x19,&nbsp;&nbsp; // 4&nbsp;&nbsp;&nbsp; -gfEDcbA<br />&nbsp;&nbsp;&nbsp; 0x12,&nbsp;&nbsp; // 5&nbsp;&nbsp;&nbsp; -gfEdcBa<br />&nbsp;&nbsp;&nbsp; 0x02,&nbsp;&nbsp; // 6&nbsp;&nbsp;&nbsp; -gfedcBa<br />&nbsp;&nbsp;&nbsp; 0x78,&nbsp;&nbsp; // 7&nbsp;&nbsp;&nbsp; -GFEDcba<br />&nbsp;&nbsp;&nbsp; 0x00,&nbsp;&nbsp; // 8&nbsp;&nbsp;&nbsp; -gfedcba<br />&nbsp;&nbsp;&nbsp; 0x10,&nbsp;&nbsp; // 9&nbsp;&nbsp;&nbsp; -gfEdcba<br />&nbsp;&nbsp;&nbsp; 0x08,&nbsp;&nbsp; // A&nbsp;&nbsp;&nbsp; -gfeDcba<br />&nbsp;&nbsp;&nbsp; 0x03,&nbsp;&nbsp; // B&nbsp;&nbsp;&nbsp; -gfedcBA<br />&nbsp;&nbsp;&nbsp; 0x46,&nbsp;&nbsp; // C&nbsp;&nbsp;&nbsp; -GfedCBa<br />&nbsp;&nbsp;&nbsp; 0x21,&nbsp;&nbsp; // D&nbsp;&nbsp;&nbsp; -gFedcbA<br />&nbsp;&nbsp;&nbsp; 0x06,&nbsp;&nbsp; // E&nbsp;&nbsp;&nbsp; -gfedCBa<br />&nbsp;&nbsp;&nbsp; 0x0E,&nbsp;&nbsp; // F&nbsp;&nbsp;&nbsp; -gfeDCBa<br />&nbsp;&nbsp;&nbsp; 0x7F&nbsp;&nbsp;&nbsp; //&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; -GFEDCBA<br />};</font><br /></p></blockquote>
<p><font color="#ff8000">volatile U1 U1_power_ctrl = POWER_INITIAL;&nbsp; // デバッグしやすくする<br /></font>volatile を付けないと、最適化処理によってこの変数が見難い場所に生成されたり、途中の動きを省略化されたりするので、変数を見ながらデバッグしやすくするために volatile を付けています。</p>
<p><font color="#ff8000">const U1 led_7seg_tbl[ 17 ]</font><br />7セグメントLED のための定義です。 <a href="http://www.eleki-jack.com/mycom2/2009/05/hc08qy4a_46ad7led1.html" target="_blank">第46回</a> のときと基本的には同じことですが、使用しているポートが1本ずつずれているので、定義内容もこのように変わっています。<br />　</p>
<blockquote>
<p>//*************************<br />// メイン処理<br />//*************************</p>
<p>void main( void ) {<br />&nbsp;&nbsp;&nbsp; U2 U2t_cnt = 0;<br />&nbsp;&nbsp;&nbsp; <br />&nbsp;&nbsp;&nbsp; init_hardware( );<br />&nbsp;&nbsp;&nbsp; init_PORT( );<br />&nbsp;&nbsp;&nbsp; DIR_SCAN1 = DIR_INPUT;<br />&nbsp;&nbsp;&nbsp; DIR_SCAN2 = DIR_INPUT;<br />&nbsp;&nbsp;&nbsp; DIR_SCAN3 = DIR_INPUT;<br />&nbsp;&nbsp;&nbsp; init_KBD( DISABLE );<br />&nbsp;&nbsp;&nbsp; <br />&nbsp;&nbsp;&nbsp; EnableInterrupts;<br />&nbsp;&nbsp;&nbsp; <br />&nbsp;&nbsp;&nbsp; for ( ; ; ){<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for ( U2t_cnt = 0 ; U2t_cnt &lt; WAIT_MAIN ; U2t_cnt++ ){<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __RESET_WATCHDOG( );<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 約5msごとに実行<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <font color="#ff8000">PTB = 0x01;</font><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; power_mode( );&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // パワー状態処理<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; key_matrix_in( );&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // キー・マトリクス入力処理<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; test_application( );&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // テスト・アプリケーション処理<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; serial_parallel_out( );&nbsp;&nbsp;&nbsp;&nbsp; // シリパラ出力処理<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <font color="#ff8000">PTB = 0x00;</font><br />&nbsp;&nbsp;&nbsp; }<br />}<br /></p></blockquote>
<p>　メイン処理は先ほどのフローチャートを見れば内容がわかるでしょう。<br /><font color="#ff8000">　PTB = 0x01;</font>　と　<font color="#ff8000">PTB = 0x00;</font>　　については解説が必要です。 それぞれフローチャートの　CHECK出力 = 1　と　CHECK出力 = 0　に相当するわけですが、なぜビット操作命令を使わなかったか、というところが問題です。</p>
<p>　CHECK出力が PTB0 に配置されており、ほかにも PORT B にはシリアル・パラレル・シフトレジスタ出力と SCAN0 ～ SCAN3 があります。 SCAN0 ～ SCAN3 はタイミングによって入力に設定されている場合があって、そのとき PTB0 に対してビット操作命令を使うと、そのタイミングの SCAN0 ～ SCAN3 の入力端子のレベルがデータ・ビットに取り込まれてしまうのです。</p>
<p>　SCAN0 ～ SCAN3 はプルアップされていますから、多くの場合データ・ビットが 1 になってしまうでしょう。 しかし、その後で SCAN0 ～ SCAN3 のどれかを出力方向にしたときには Ｌ レベルを出力したいわけですから、データ・ビットは 0 でなければなりません。 そう考えると、PTB0 を 1 または 0 にするときに PORT B をバイトごと 0x01 または 0x00 出力するのが簡単です。 このタイミングでシリアル・パラレル・シフトレジスタ出力の各ビットに 0 を書き込むことは問題ありません。 詳しくは各関数の中身を読んでみてください。<br />　</p>
<blockquote>
<p>//*************************<br />// パワー状態処理<br />//*************************<br />void power_mode( void ){<br />&nbsp;&nbsp;&nbsp; static U2 U2s_power_timer = 0;<br />&nbsp;&nbsp;&nbsp; <br />&nbsp;&nbsp;&nbsp; PORT_ALWAYSHIGH = 1;<br />&nbsp;&nbsp;&nbsp; <br />&nbsp;&nbsp;&nbsp; switch ( U1_power_ctrl ){<br />&nbsp;&nbsp;&nbsp; <font color="#ff8000">case POWER_INITIAL:</font><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; U2s_power_timer++;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if ( U2s_power_timer &gt;= 2 ){&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 2回目でNORMALにする<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; U1_power_ctrl = POWER_NORMAL;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; U2s_power_timer = 0;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; break;<br />&nbsp;&nbsp;&nbsp; <font color="#ff8000">case POWER_NORMAL:</font><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; U2s_power_timer++;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if ( U1_appli_sleep_ready == 0 ){<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; U2s_power_timer = 0;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if ( U2s_power_timer &gt;= POWER_OFF_TIME ){<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; U1_power_ctrl = POWER_SLEEP;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; break;<br />&nbsp;&nbsp;&nbsp; <font color="#ff8000">case POWER_SLEEP:</font><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; init_PORT( );<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; init_KBD( ENABLE );<br /><font color="#ff8000">#ifdef DEBUG_STOP_MODE</font><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; U1_kbd_flag = 0;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; while ( !U1_kbd_flag ){<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // モニタ使用中は COP は無効<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />#else<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; asm( "STOP" );<br />#endif<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // KBD割り込みでウェイクアップ<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; init_KBD( DISABLE );<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DIR_SCAN1 = DIR_INPUT;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DIR_SCAN2 = DIR_INPUT;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DIR_SCAN3 = DIR_INPUT;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; U1_power_ctrl = POWER_WAKEUP;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; break;<br />&nbsp;&nbsp;&nbsp; <font color="#ff8000">case POWER_WAKEUP:</font><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; U1_power_ctrl = POWER_NORMAL;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; U2s_power_timer = 0;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; break;<br />&nbsp;&nbsp;&nbsp; default:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // ガード処理<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; U1_power_ctrl = POWER_NORMAL;<br />&nbsp;&nbsp;&nbsp; }<br />}<br /></p></blockquote>
<p>　パワー状態処理は、大まかなところはフローチャートを見ればわかるでしょう。 また、フローチャートに記載のある 「ウェイクアップ移行時」 とか 「スリープ移行時」 という情報を出力するのもこの処理の仕事です。</p>
<p><font color="#ff8000">case POWER_INITIAL:</font><br />1回目のみ、初期状態になります。2回目から通常状態になります。</p>
<p><font color="#ff8000">case POWER_NORMAL:</font><br />通常状態では、アプリケーションが出力する 「スリープできるよ」 という情報を監視して、2秒間連続してスリープ可能な状態のときスリープ状態に移行します。 実際にはメイン・ループを1周回ってからスリープします。</p>
<p><font color="#ff8000">case POWER_SLEEP:</font><br />スリープ状態のとき、ウェイクアップの準備をしてからスリープします。</p>
<p><font color="#ff8000">#ifdef DEBUG_STOP_MODE</font><br />からの数行については <a href="http://www.eleki-jack.com/mycom2/2010/05/hc08qy4a_83_brkmon2.html" target="_blank">第83回</a> を参照してください。<br />ストップ状態を抜けるときはウェイクアップ状態になります。</p>
<p><font color="#ff8000">case POWER_WAKEUP:</font><br />メイン・ループ1周だけウェイクアップ状態で、その次には通常状態になります。</p>
<p>　<br />　（続く）</p>
<p><br />（*1）　SCAN0 ～ SCAN3 は内部プルアップを有効に設定したので正確にはハイ・インピーダンスではないのですが、ここでは Ｈ出力も Ｌ出力も やめるという意味でハイ・インピーダンスという言葉を使いました。<br />　</p>
<p>（*2）　ジャンパ類の設定は次の通りです。 JP1 ジャンパ有り、JP2 ジャンパ無し（デバッグ終了後スタンドアロンで動作時はジャンパ有り）、JP3は 1-2間ジャンパ有り（または無し）、JP4 は 1-2間ジャンパ有り、JP5～JP8 すべてジャンパ無し にすること。 VR1 は自由です。</p>
<p>　</p>
<p>　『参考文献』<br /><font color="#00008b"><a href="http://shop.cqpub.co.jp/hanbai/books/46/46051.html" target="_blank"><font color="#00008b">「試しながら学ぶHC08マイコン入門」</font></a>&nbsp;</font>（CQ出版）<br />　　第9章　USB-HC08デバッグ・ツールを自作する<br />　　第10章　統合開発環境CodeWarriorを使ってみる<br />　　Appendix F　KMC908QY4Aユーザ・モード・モニタ入りマイコンの知識<br />筆者のホームページ　<a href="http://www.cts-net.ne.jp/~kawano-r/" target="_blank"><font color="#00008b">『マイコン工作の実験室』</font></a> </p>
<p align="right">組み込みエンジニア　KAWANO<br /></p>]]>
   </content>
</entry>

<entry>
   <title>HC08マイコンの使い方QY4A編 -《87》 キー・マトリクス・スイッチと低電力（2）</title>
   <link rel="alternate" type="text/html" href="http://www.eleki-jack.com/mycom2/2010/07/hc08qy4a_87_2.html" />
   <id>tag:www.eleki-jack.com,2010:/mycom2//4.4505</id>
   
   <published>2010-07-22T03:40:15Z</published>
   <updated>2010-07-31T01:41:52Z</updated>
   
   <summary>◆ キー・マトリクス・スイッチを使った実験回路の組み立て（続き）　下の 4枚の写...</summary>
   <author>
      <name>kawano</name>
      <uri>http://www.cts-net.ne.jp/~kawano-r/</uri>
   </author>
   
      <category term="HC08マイコンの使い方QY4A編" scheme="http://www.sixapart.com/ns/types#category" />
   
   <category term="5550" label="74HC595" scheme="http://www.sixapart.com/ns/types#tag" />
   <category term="5839" label="キー・マトリクス・スイッチ" scheme="http://www.sixapart.com/ns/types#tag" />
   <category term="5840" label="シリアル・パラレル・シフトレジスタ" scheme="http://www.sixapart.com/ns/types#tag" />
   <category term="5602" label="低電力モード" scheme="http://www.sixapart.com/ns/types#tag" />
   <category term="5842" label="７セグメントLED" scheme="http://www.sixapart.com/ns/types#tag" />
   
   <content type="html" xml:lang="ja" xml:base="http://www.eleki-jack.com/mycom2/">
      <![CDATA[<p><strong><font color="#0000cc">◆ キー・マトリクス・スイッチを使った実験回路の組み立て（続き）<br /></font></strong>　下の 4枚の写真を参考にして、<a href="http://www.eleki-jack.com/mycom2/2010/07/hc08qy4a_86_1.html" target="_blank">前回</a> の回路図（変更後）をよく見ながらブレッドボード上に回路を組み立ててください。<br />　<br /></p>
<span class="mt-enclosure mt-enclosure-image" style="DISPLAY: inline"><a href="http://www.eleki-jack.com/mycom2/hc08_keymatrix07.jpg"><img class="mt-image-center" style="DISPLAY: block; MARGIN: 0px auto 20px; TEXT-ALIGN: center" height="419" alt="hc08_keymatrix07.jpg" src="http://www.eleki-jack.com/mycom2/hc08_keymatrix07-thumb-400x419.jpg" width="400" /></a></span>]]>
      <![CDATA[<p align="center">ブレッドボードの配線のようす （クリックで拡大）</p>
<p>　<br />　HC08スタータ・ボードの CN2、CN3 には、Ｌ字型（アングル）のピン・ヘッダを実装しています。 これについては <a href="http://www.eleki-jack.com/mycom2/2008/11/hc08qy4a_19.html" target="_blank">第19回</a> で説明しました。 <a href="http://6811.teacup.com/miconfan/shop" target="_blank">マイコン工作ファンSHOP</a> でも購入できます。</p>
<p>　<br />　<a href="http://www.eleki-jack.com/mycom2/2010/07/hc08qy4a_86_1.html" target="_blank">前回</a> キー・マトリクス・スイッチに接続したフラット・ケーブルは、HC08スタータ・ボードの後ろ側に差し込みました。 なお、フラット・ケーブルのビニール被覆をむいただけではブレッドボードには刺さらないので、芯線をよって予備はんだをしてから使用してください。<br />　</p>
<p></p>
<span class="mt-enclosure mt-enclosure-image" style="DISPLAY: inline"><a href="http://www.eleki-jack.com/mycom2/hc08_keymatrix08.jpg"><img class="mt-image-center" style="DISPLAY: block; MARGIN: 0px auto 20px; TEXT-ALIGN: center" height="304" alt="hc08_keymatrix08.jpg" src="http://www.eleki-jack.com/mycom2/hc08_keymatrix08-thumb-400x304.jpg" width="400" /></a></span>
<p>　<br />　HC08スタータ・ボードを挿したままだと細かいところがよく見えないので、一時的に取り外した状態をお見せします。<br />　</p>
<p></p>
<span class="mt-enclosure mt-enclosure-image" style="DISPLAY: inline"><a href="http://www.eleki-jack.com/mycom2/hc08_keymatrix09.jpg"><img class="mt-image-center" style="DISPLAY: block; MARGIN: 0px auto 20px; TEXT-ALIGN: center" height="269" alt="hc08_keymatrix09.jpg" src="http://www.eleki-jack.com/mycom2/hc08_keymatrix09-thumb-400x269.jpg" width="400" /></a></span>
<p align="center">上方から見たところ（クリックで拡大）</p>
<p>　<br />　黄色い数字で CN2、CN3 のピン番号を示しました。 向かって右側が CN2 です。 8番ピンと IC（74HC595） の 16ピンが同じ列になっているのがわかります。<br />　</p>
<p></p>
<span class="mt-enclosure mt-enclosure-image" style="DISPLAY: inline"><a href="http://www.eleki-jack.com/mycom2/hc08_keymatrix10.jpg"><img class="mt-image-center" style="DISPLAY: block; MARGIN: 0px auto 20px; TEXT-ALIGN: center" height="230" alt="hc08_keymatrix10.jpg" src="http://www.eleki-jack.com/mycom2/hc08_keymatrix10-thumb-400x230.jpg" width="400" /></a></span>
<p align="center">後方から見たところ（クリックで拡大）</p>
<p>　<br />　写真ではところどころ抵抗の足が接触しているように見えますが、実際には適当に浮かせてあって接触しないようになっています。 組み立ての際はご注意ください。</p>
<p>　</p>
<p>&nbsp;<strong><font color="#0000cc">◆ テスト・プログラムの構成<br /></font></strong>　前回示した仕様を再掲載します。</p>
<blockquote>　<font color="#00a000">【 プログラムの動き 】</font><br />&nbsp;・ 電源を入れると 7セグメントLED に 8 と表示します。<br />&nbsp;・ どのキーも押さないと 2秒後に 7セグメントLED の表示を消してスリープします。<br />&nbsp;・ スリープ状態でキー・マトリクス・スイッチのいずれかのキーを押すと直ちに<br />　　ウェイクアップし、その数字を表示します。<br />&nbsp;・ スリープに至る前（またはウェイクアップ後）にいずれかのキーを押すと、直ちに<br />　　今押した数字に表示が切り替わります。</blockquote>
<p>　数字と書いていますが、16進数を想定しており 0～9 および A～F が有効です。</p>
<p><strong><font color="#0000cc">　<br /></font></strong>　これを実現するためのプログラム構成はいくつか考えられますが、ここでは、いつもと同じ タイムド・ループ方式 で構成します。 全体のフローチャートは次のようになります。<br />　<br /></p>
<span class="mt-enclosure mt-enclosure-image" style="DISPLAY: inline"><a href="http://www.eleki-jack.com/mycom2/flow_chart_keymatrix.gif"><img class="mt-image-center" style="DISPLAY: block; MARGIN: 0px auto 20px; TEXT-ALIGN: center" height="451" alt="flow_chart_keymatrix.gif" src="http://www.eleki-jack.com/mycom2/assets_c/2010/07/flow_chart_keymatrix-thumb-420x451.gif" width="420" /></a></span>
<p align="center">全体のフローチャート （クリックで拡大）</p>
<p>　<br />　<br />　ポイントとなるのは、キー・マトリクス・スイッチの取り扱い方法です。 今回の製作物では、次のような手順で利用します。 フラット・ケーブルと 16個のキー・スイッチの接続は <a href="http://www.eleki-jack.com/mycom2/2010/07/hc08qy4a_86_1.html" target="_blank">前回</a> の図を参照してください。</p>
<p>&nbsp;・ フラット・ケーブルの 1～4 番ピンをマイコンの出力ポートに接続。<br />　　　それぞれ <font color="#ff8000">SCAN0 ～ SCAN3</font> と呼ぶ。<br />　　　<font color="#8080ff">この 4本は入力方向にも設定するため、内部プルアップを有効にする。</font><br />&nbsp;・ フラット・ケーブルの 5～8 番ピンをマイコンの入力ポートに接続。<br />　　　まとめて <font color="#ff8000">MTX_IN</font> と呼ぶ。 この 4本は<font color="#00a000">内部プルアップを有効</font>にする。</p>
<p>&nbsp;・ 最初は&nbsp;<font color="#ff8000">SCAN0</font> を Ｌ に、その他を <font color="#8080ff">Ｈｉ-Z</font> にする。<br />&nbsp;・ <font color="#ff8000">MTX_IN</font> の状況を調べて、下記のパターンでキー入力を確認する。<br />　　　1111b　キー入力なし<br />　　　1110b　「0」 キーオン<br />　　　1101b　「4」 キーオン<br />　　　1011b　「8」 キーオン<br />　　　0111b　「C」 キーオン<br />　　　その他　複数キーオン（キー入力なしとみなす）<br />&nbsp;・ 次の準備として、<font color="#ff8000">SCAN1</font> を Ｌ に、その他を <font color="#8080ff">Ｈｉ-Z</font> にする。<br />&nbsp;・&nbsp;<font color="#ff8000">MTX_IN</font> の状況を調べて、下記のパターンでキー入力を確認する。<br />　　　1111b　キー入力なし<br />　　　1110b　「1」 キーオン<br />　　　1101b　「5」 キーオン<br />　　　1011b　「9」 キーオン<br />　　　0111b　「D」 キーオン<br />　　　その他　複数キーオン（キー入力なしとみなす）<br />&nbsp;・ 次の準備として、<font color="#ff8000">SCAN2</font> を Ｌ に、その他を <font color="#8080ff">Ｈｉ-Z</font> にする。<br />&nbsp;・&nbsp;<font color="#ff8000">MTX_IN</font> の状況を調べて、下記のパターンでキー入力を確認する。<br />　　　1111b　キー入力なし<br />　　　1110b　「2」 キーオン<br />　　　1101b　「6」 キーオン<br />　　　1011b　「A」 キーオン<br />　　　0111b　「E」 キーオン<br />　　　その他　複数キーオン（キー入力なしとみなす）<br />&nbsp;・ 次の準備として、<font color="#ff8000">SCAN3</font> を Ｌ に、その他を <font color="#8080ff">Ｈｉ-Z</font> にする。<br />&nbsp;・&nbsp;<font color="#ff8000">MTX_IN</font> の状況を調べて、下記のパターンでキー入力を確認する。<br />　　　1111b　キー入力なし<br />　　　1110b　「3」 キーオン<br />　　　1101b　「7」 キーオン<br />　　　1011b　「B」 キーオン<br />　　　0111b　「F」 キーオン<br />　　　その他　複数キーオン（キー入力なしとみなす）<br />&nbsp;・ 次の準備として、<font color="#ff8000">SCAN0</font> を Ｌ に、その他を <font color="#8080ff">Ｈｉ-Z</font> にする。<br />&nbsp;・ <font color="#00a000">複数のキーがオンになっている場合は、キー入力なし</font>とみなす。<br />&nbsp;・ <font color="#ff8000">キー入力が一つだけあり、同じ状態が 2回続いたとき（40msかかる）、<br />　　そのキー入力を確定</font>する。<br />&nbsp;・ 煩雑に見える上記処理を、繰り返し制御を使ってスマートに実現する。</p>
<p>&nbsp;・ キー入力なしの状態が 2秒続くと、パワーダウン（スリープ）する。</p>
<p>&nbsp;・ パワーダウン中（スリープ中）は&nbsp;<font color="#ff8000">SCAN0 ～ SCAN3</font> をすべて Ｌ にする。<br />&nbsp;・ どのスイッチも押されていないとき、<font color="#ff8000">MTX_IN</font> はプルアップにより全て Ｈ になる。<br />&nbsp;・ いずれかのスイッチを押すと、<font color="#ff8000">SCAN0 ～ SCAN3</font> の 4本すべてが Ｌ なので<br />　　<font color="#ff8000">MTX_IN</font> のいずれかがＬになる。<br />&nbsp;・ そこでキーボード割り込みが発生してパワーダウン（スリープ）を解除する。</p>
<p>　<br />　次回は実際のプログラムを紹介し、動くところをお見せします。</p>
<p>&nbsp;</p>
<p><font color="#8080ff">[2010-07-31]　SCAN0～3 の Ｈ 出力を、Hi-Z に変更した。 Hi-Z はハイインピーダンスの設定、具体的には入力方向に再設定する。内部プルアップを有効にしているため、実際には Ｈ レベルになる。</font>　</p>
<p>　<br />　『参考文献』<br /><font color="#00008b"><a href="http://shop.cqpub.co.jp/hanbai/books/46/46051.html" target="_blank"><font color="#00008b">「試しながら学ぶHC08マイコン入門」</font></a>&nbsp;</font>（CQ出版）<br />　　第1章　 マイコン電子工作を始めよう<br />　　第10章　統合開発環境CodeWarriorを使ってみる<br />筆者のホームページ　<a href="http://www.cts-net.ne.jp/~kawano-r/" target="_blank"><font color="#00008b">『マイコン工作の実験室』</font></a> </p>
<p align="right">組み込みエンジニア　KAWANO<br /></p>]]>
   </content>
</entry>

<entry>
   <title>HC08マイコンの使い方QY4A編 -《86》 キー・マトリクス・スイッチと低電力（1）</title>
   <link rel="alternate" type="text/html" href="http://www.eleki-jack.com/mycom2/2010/07/hc08qy4a_86_1.html" />
   <id>tag:www.eleki-jack.com,2010:/mycom2//4.4469</id>
   
   <published>2010-07-12T01:30:34Z</published>
   <updated>2010-07-12T01:12:02Z</updated>
   
   <summary>　キー・マトリクス・スイッチの使用例を示します。 凝った動きではないのですが、低...</summary>
   <author>
      <name>kawano</name>
      <uri>http://www.cts-net.ne.jp/~kawano-r/</uri>
   </author>
   
      <category term="HC08マイコンの使い方QY4A編" scheme="http://www.sixapart.com/ns/types#category" />
   
   <category term="5550" label="74HC595" scheme="http://www.sixapart.com/ns/types#tag" />
   <category term="5839" label="キー・マトリクス・スイッチ" scheme="http://www.sixapart.com/ns/types#tag" />
   <category term="5840" label="シリアル・パラレル・シフトレジスタ" scheme="http://www.sixapart.com/ns/types#tag" />
   <category term="5602" label="低電力モード" scheme="http://www.sixapart.com/ns/types#tag" />
   <category term="5842" label="７セグメントLED" scheme="http://www.sixapart.com/ns/types#tag" />
   
   <content type="html" xml:lang="ja" xml:base="http://www.eleki-jack.com/mycom2/">
      <![CDATA[<p>　キー・マトリクス・スイッチの使用例を示します。 凝った動きではないのですが、低電力モードへの移行・復帰も織り込みましたから、実際の製作物への応用も可能です。<br />　今回は７セグメント LED を用いたので、入出力ポートの数が不足しました。 それを補うためにシリアル・パラレル・シフトレジスタという IC を使っています。 その部分だけを参考にすることも可能です。<br />　<br />
</p><span class="mt-enclosure mt-enclosure-image" style="display: inline;"><a href="http://www.eleki-jack.com/mycom2/hc08_keymatrix01.jpg"><img class="mt-image-center" style="display: block; margin: 0px auto 20px; text-align: center;" alt="hc08_keymatrix01.jpg" src="http://www.eleki-jack.com/mycom2/hc08_keymatrix01-thumb-400x328.jpg" width="400" height="328" /></a></span>]]>
      <![CDATA[<p align="center">キー・マトリクス・スイッチと 7セグメントLED の使用例（クリックで拡大）<br />カード挿入タイプなので好きな文字を紙に印刷して入れてある</p>
<p>　<br /><strong><font color="#0000cc">◆ キー・マトリクス・スイッチを使ったテスト・プログラムの仕様</font></strong><br />　<a href="http://www.eleki-jack.com/mycom2/2010/03/hc08qy4a_77_kbi1.html" target="_blank">第77回</a> での予告どおり、キー・マトリクス・スイッチの使用例をお見せします。<br />　作業を簡単にするため、HC08スタータ・ボードとブレッドボードを使って製作します。 作ろうとしているものの動きを大雑把に書くと、次のようになります。</p>
<blockquote>　<font color="#00a000">【 プログラムの動き 】</font><br />&nbsp;・ 電源を入れると 7セグメントLED に 8 と表示します。<br />&nbsp;・ どのキーも押さないと 2秒後に 7セグメントLED の表示を消してスリープします。<br />&nbsp;・ スリープ状態でキー・マトリクス・スイッチのいずれかのキーを押すと直ちに<br />　　ウェイクアップし、その数字を表示します。<br />&nbsp;・ スリープに至る前（またはウェイクアップ後）にいずれかのキーを押すと、直ちに<br />　　今押した数字に表示が切り替わります。</blockquote>
<p>　数字と書いていますが、16進数を想定しており 0～9 および A～F が有効です。</p>
<p><strong><font color="#0000cc">　<br />◆ キー・マトリクス・スイッチを使った実験の回路図<br /></font></strong>　この実験のために最初に書いた回路図を示します。 やりたいこととしては、このような構成になります。<br />　</p>
<p>
</p><span class="mt-enclosure mt-enclosure-image" style="display: inline;"><a href="http://www.eleki-jack.com/mycom2/hc08_keymatrix_sch1.gif"></a></span>
<span class="mt-enclosure mt-enclosure-image" style="display: inline;"><a href="http://www.eleki-jack.com/mycom2/hc08_keymatrix_sch1.gif"><img class="mt-image-center" style="display: block; margin: 0px auto 20px; text-align: center;" alt="hc08_keymatrix_sch1.gif" src="http://www.eleki-jack.com/mycom2/assets_c/2010/07/hc08_keymatrix_sch1-thumb-480x264.gif" width="480" height="264" /></a></span>
<p align="center">最初に書いた回路図（クリックで拡大）</p>
<p>　<br />　右上の <font color="#00a000">to Key Matrix Switch</font> というところには、市販品のキー・マトリクス・スイッチ（後述）を接続します。 ここでは PTB4～7 を出力、PTA1～4 （正確には KBI1～4）を入力とした 4 × 4 マトリクスを構成しています。</p>
<p>　今回使用した 7セグメントLED は、アノード・コモンです（<a href="http://www.eleki-jack.com/mycom2/2009/05/hc08qy4a_46ad7led1.html" target="_blank">第46回</a>）。 IC の出力が L 側のとき、<font color="#ff8000">IC の出力端子に電流が流れ込んで点灯</font>します。</p>
<p>　7セグメントLED のための出力ポートは、普通なら 7本必要です（ドット・ポイントも点灯させたければさらにもう 1本必要）。 今回はポートが不足するので、74HC595 というシリアル・パラレル・シフトレジスタ IC を使いました。 74HC595 というのは複数の半導体メーカが製造販売しており、どれを使ってもかまいません（LSやLVCではなくHCを使うこと）。</p>
<p>　ところで 74HC595 の QH’は、あまり使われることはないと思いますが、QH は今回たまたま使っていないだけです。 使おうと思えば普通に使うことができます。</p>
<blockquote>　上記回路図における 74HC595 の使い方を説明します。 まず QH～QA を 1バイトの出力と考えてください。 QH が最上位ビット、QA が最下位ビットです。 QH に出力したいレベルを PTB1（SI）にセットして、PTB2（SCK）を H 、L とします。 これで最上位ビットが IC 内部の QA の位置に取り込まれました。 まだ IC の出力には反映されません。 続いて QG&nbsp; に出力したいレベルを PTB1（SI）にセットして、PTB2（SCK）を H 、L とします。 すると先ほどの内部 QA が内部 QB にコピーされ、今新しく入ってきたデータが内部 QA に入ります。 これを 8 回繰り返すと、IC の内部には出力したいデータが QH から QA まできちんと並んで入ったことになります。 そこで PTB3（RCK）を H 、L とすることで、内部データから出力用のフリップ・フロップにまとめてコピーされ、ICの出力レベルに反映することができます。</blockquote>
<p>　<br />　さて、回路図を書いて組み立てようとしたところで、ちょっと困ったことが起こりました。 ブレッドボードにギリギリ収まらないのです。 <a href="http://shop.cqpub.co.jp/hanbai/books/MCQ/MCQZ200810.html" target="_blank">エレキジャック No.8</a> の付録に付いていた、あのブレッドボード（*1）です。 このコンパクトさが気に入っているのですが、あと 1列だけ足りないのです。 どうしたものでしょう。 解決策として、次の三つが挙げられます。</p>
<p>　<font color="#00a000">１、あきらめてひとまわり大きいブレッドボードを使う。 または同型のブレッドボード<br />　　　を連結してサイズを大きくする。<br />　２、74HC595 の 16ピン（VDD）を短くカットし、10ピン（SCLR）に空中配線する。<br />　３、74HC595 の 16ピン（VDD）を PTA5 に接続するよう回路を変更する。</font>　</p>
<p>　２または３により、1列不足していたのが解消されます。 しかし２のように IC の足をカットして空中配線（はんだ付け）というのはブレッドボードの利用法としては邪道でしょうから、今回は３の方法で行くことにします。 変更した回路図を示します。<br />　</p>
<p>
</p><span class="mt-enclosure mt-enclosure-image" style="display: inline;"><a href="http://www.eleki-jack.com/mycom2/hc08_keymatrix_sch2.gif"><img class="mt-image-center" style="display: block; margin: 0px auto 20px; text-align: center;" alt="hc08_keymatrix_sch2.gif" src="http://www.eleki-jack.com/mycom2/hc08_keymatrix_sch2-thumb-480x264.gif" width="480" height="264" /></a></span>
<p align="center">変更後の回路図（クリックで拡大）</p>
<p>　<br />　太線で示した部分は、ブレッドボード上で同一の列に配置します。 そして <font color="#ff0000">PTA5 を常に H 出力</font> することにより、IC 電源の VDD として使用しています。 これでなんとかブレッドボード上にすべて配置することができました。</p>
<blockquote>　図中のアノード・コモン型 7セグメントLED を点灯させる電流は、電流制限抵抗の 330Ωを左向きに流れます。 そして、IC 内部を通って IC の GND ピンへと流れます。 このことからわかるように、IC の VDD ピンには LED を駆動するための電流は流れないので、今回のような使い方が可能なのです。 もしこれがカソード・コモン型の 7セグメント LED だった場合には、電流制限抵抗に流れる電流の向きが逆になるので LED を駆動するための電流が全て IC の VDD ピンに流れるため、PTA5 が定格オーバしてしまいます。</blockquote>
<p><strong><font color="#0000cc">　<br />◆ 使用したキー・マトリクス・スイッチについて<br /></font></strong>　キー・マトリクス・スイッチは、手持ちの関係で 日本開閉器工業（NKK） の <font color="#00a000">FM-AN16BD</font> を使いました（*2）。 このスイッチの回路図を示します。<br />　</p>
<p>
</p><span class="mt-enclosure mt-enclosure-image" style="display: inline;"><img class="mt-image-center" style="display: block; margin: 0px auto 20px; text-align: center;" alt="hc08_keypad01.gif" src="http://www.eleki-jack.com/mycom2/hc08_keypad01.gif" width="250" height="350" /></span>
<p align="center">使用したキー・マトリクス・スイッチの回路図<br />（キー・スイッチの番号は製作物に合わせて筆者が振った）</p>
<p>　<br />　仮に単体のスイッチが16個あった場合、1本ずつ線を延ばせば配線数は 32本になります。 各スイッチの片側を共通にすればずっと少なくなりますが、それでも 17本。 上図のように縦横にマトリクス状に配置・接続した場合は、延ばす線はわずか 8本で済むのですから、大変有効な構成法といえます。</p>
<p>　1mmピッチの 8芯 FPC（フレキシブル・プリント基板）ケーブルは、そのままではブレッドボードに利用できないので、適合するコネクタ（*3）を使用することにします。 今回は、そのコネクタの端子に普通のフラット・ケーブルの端をバラしたものをはんだ付けしました。 少し難易度が高いかもしれませんが、丁寧に作業すれば大丈夫でしょう。</p>
<p>　<br />　写真ではちょうど見えませんが、端子は互い違いに上下二段になっています。<br />部品は上下を間違えないように確認してください。（クリックで拡大、以下も同様）<br />　<br />
</p><span class="mt-enclosure mt-enclosure-image" style="display: inline;"><a href="http://www.eleki-jack.com/mycom2/hc08_keymatrix02.jpg"><img class="mt-image-center" style="display: block; margin: 0px auto 20px; text-align: center;" alt="hc08_keymatrix02.jpg" src="http://www.eleki-jack.com/mycom2/hc08_keymatrix02-thumb-400x300.jpg" width="400" height="300" /></a></span>
<p>　<br />FPC ケーブルを差し込む前に、ロック部を引き出しておきます。<br />　</p>
<p>
</p><span class="mt-enclosure mt-enclosure-image" style="display: inline;"><a href="http://www.eleki-jack.com/mycom2/hc08_keymatrix03.jpg"><img class="mt-image-center" style="display: block; margin: 0px auto 20px; text-align: center;" alt="hc08_keymatrix03.jpg" src="http://www.eleki-jack.com/mycom2/hc08_keymatrix03-thumb-400x300.jpg" width="400" height="300" /></a></span>
<p>　<br />裏表を間違えないよう、奥まで差し込みます。<br />　</p>
<p>
</p><span class="mt-enclosure mt-enclosure-image" style="display: inline;"><a href="http://www.eleki-jack.com/mycom2/hc08_keymatrix04.jpg"><img class="mt-image-center" style="display: block; margin: 0px auto 20px; text-align: center;" alt="hc08_keymatrix04.jpg" src="http://www.eleki-jack.com/mycom2/hc08_keymatrix04-thumb-400x300.jpg" width="400" height="300" /></a></span>
<p>　<br />奥まで差し込んだら、ロック部を押し込んでロックします。<br />　</p>
<p>
</p><span class="mt-enclosure mt-enclosure-image" style="display: inline;"><a href="http://www.eleki-jack.com/mycom2/hc08_keymatrix05.jpg"><img class="mt-image-center" style="display: block; margin: 0px auto 20px; text-align: center;" alt="hc08_keymatrix05.jpg" src="http://www.eleki-jack.com/mycom2/hc08_keymatrix05-thumb-400x300.jpg" width="400" height="300" /></a></span>
<p>　<br />フラット・ケーブルの先をバラしたものを、コネクタの端子にはんだ付けします。<br />　</p>
<p>
</p><span class="mt-enclosure mt-enclosure-image" style="display: inline;"><a href="http://www.eleki-jack.com/mycom2/hc08_keymatrix06.jpg"><img class="mt-image-center" style="display: block; margin: 0px auto 20px; text-align: center;" alt="hc08_keymatrix06.jpg" src="http://www.eleki-jack.com/mycom2/hc08_keymatrix06-thumb-400x300.jpg" width="400" height="300" /></a></span>
<p>　<br />　この写真をよく見て、先に上段の端子に偶数番号（８灰　６青　４黄　２赤）の線をはんだ付けします。 その際、コネクタをセロハン・テープなどでテーブルに固定すると作業しやすくなります。 その後、裏表をひっくり返して奇数番号（１茶　３橙　５緑　７紫）をはんだ付けしてください。 フラット・ケーブルの長さは 20cm くらいでよいです。</p>
<p><br />　（続く）</p>
<p>&nbsp;</p>
<p>（*1） このブレッドボード <a href="http://akizukidenshi.com/catalog/g/gP-00315/" target="_blank">EIC-801</a>（400穴） は秋月電子通商で入手可能（250円）。<br />　<br />（*2） 下記に示すスイッチはいずれも日本開閉器工業の同一シリーズで、どれでも同じように使用可能です。 今回実際に使用したのは一番上の部品です。 アールエスコンポーネンツにて通販で購入しました。<br />　<br />　FM-AN16BD,16キー,無クリック,カード挿入,黒<br />　　　<a href="http://jp.rs-online.com/web/search/searchBrowseAction.html?method=getProduct&amp;R=0548741" target="_blank">RS品番 548-741</a>　参考価格 ￥1,170</p>
<p>　FM-AN16BE,16キー,無クリック,カード挿入,灰<br />　　　<a href="http://jp.rs-online.com/web/search/searchBrowseAction.html?method=getProduct&amp;R=0548757" target="_blank">RS品番 548-757</a>　参考価格 ￥1,170</p>
<p>　FM-BN16BD,16キー,有クリック,カード挿入,黒<br />　　　<a href="http://jp.rs-online.com/web/search/searchBrowseAction.html?method=getProduct&amp;R=0548785" target="_blank">RS品番 548-785</a>　参考価格 ￥1,650</p>
<p>　FM-BN16BE,16キー,有クリック,カード挿入,灰<br />　　　<a href="http://jp.rs-online.com/web/search/searchBrowseAction.html?method=getProduct&amp;R=0548791" target="_blank">RS品番 548-791</a>　参考価格 ￥1,650</p>
<p>　<br />（*3） 上記スイッチ共通の適合コネクタです。 アールエスコンポーネンツにて通販で購入しました。</p>
<p>　コネクタ　08FMZ-BT (LF)(SN),FFC,zIF,1.0mm,Top,8P<br />　　　<a href="http://jp.rs-online.com/web/search/searchBrowseAction.html?method=getProduct&amp;R=638-8817" target="_blank">RS品番 638-8817</a>　参考価格 ￥47<br />　</p>
<p>　</p>
<p>　『参考文献』<br /><font color="#00008b"><a href="http://shop.cqpub.co.jp/hanbai/books/46/46051.html" target="_blank"><font color="#00008b">「試しながら学ぶHC08マイコン入門」</font></a>&nbsp;</font>（CQ出版）<br />　　第1章　 マイコン電子工作を始めよう<br />　　第10章　統合開発環境CodeWarriorを使ってみる<br />筆者のホームページ　<a href="http://www.cts-net.ne.jp/%7Ekawano-r/" target="_blank"><font color="#00008b">『マイコン工作の実験室』</font></a> </p>
<p align="right">組み込みエンジニア　KAWANO<br /></p>]]>
   </content>
</entry>

<entry>
   <title>書籍「動かして学ぶCAN通信」番外編Arduino用自作ライブラリの作成(5)</title>
   <link rel="alternate" type="text/html" href="http://www.eleki-jack.com/mycom2/2010/06/canarduino5.html" />
   <id>tag:www.eleki-jack.com,2010:/mycom2//4.4404</id>
   
   <published>2010-06-25T04:30:27Z</published>
   <updated>2010-06-25T04:07:52Z</updated>
   
   <summary>　今回は、WSN258基板用クラスのコードを説明します。...</summary>
   <author>
      <name>nakao</name>
      <uri>http://www.wsnak.com/index2.html</uri>
   </author>
   
      <category term="Arduino入門" scheme="http://www.sixapart.com/ns/types#category" />
   
      <category term="動かして学ぶCAN通信" scheme="http://www.sixapart.com/ns/types#category" />
   
   <category term="263" label="AVR" scheme="http://www.sixapart.com/ns/types#tag" />
   <category term="3112" label="Arduino" scheme="http://www.sixapart.com/ns/types#tag" />
   <category term="1514" label="ライブラリ" scheme="http://www.sixapart.com/ns/types#tag" />
   
   <content type="html" xml:lang="ja" xml:base="http://www.eleki-jack.com/mycom2/">
      <![CDATA[　今回は、WSN258基板用クラスのコードを説明します。<br />]]>
      <![CDATA[<p style="margin-right: 0px;" dir="ltr"><font style="font-size: 1.25em;"><strong>●オブジェクト・コードの説明 "wsn258.h"</strong></font></p>
<p>　このファイルは、クラスの型、マクロなどを定義したヘッダ・ファイルです。ソース・リスト順に説明します。</p>
<p>　#ifndef～#endifはこのヘッダ・ファイルが複数のソースから呼び出されたときに重複して定義しないようにするためのプリプロセッサです。このブロック内の定義は、まだ全ソース・ファイルを通してまだ一度も定義されていないときにだけ有効になります。</p>
<blockquote style="margin-right: 0px;" dir="ltr">
<p>#ifndef WSN258_h<br />#define WSN258_h</p>
<p>#include &lt;inttypes.h&gt;</p></blockquote>
<p><br />　次はシフトレジスタの制御に使用する出力ポート関係の定義です。当オブジェクトでは直接AVRのレジスタを操作しています。#258以外を使用する場合で、接続ポートを変更したいときは、この部分の定義を変更すれるだけで対応できます。</p>
<p>　もしポートを変更する場合は、Arduinoの論理ポート番号（D1など）と、実際のAVRのどのポートが対応しているかをArduinoの回路図などで調べてください。</p>
<blockquote style="margin-right: 0px;" dir="ltr">
<p>#define bitSRDAT 3&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // PD3(D3)<br />#define bitSRCLK 2&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // PD2(D2)<br />#define bitSRLAT 4&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // PB4(D12)</p>
<p>#define DDR_SRDAT DDRD<br />#define DDR_SRCLK DDRD<br />#define DDR_SRLAT DDRB</p>
<p>#define PORT_SRDAT PORTD<br />#define PORT_SRCLK PORTD<br />#define PORT_SRLAT PORTB</p>
<p>#define SR_DAT_1 PORT_SRDAT|= (1&lt;&lt;bitSRDAT)<br />#define SR_DAT_0 PORT_SRDAT&amp;=~(1&lt;&lt;bitSRDAT)<br />#define SR_LAT_H PORT_SRLAT|= (1&lt;&lt;bitSRLAT)<br />#define SR_LAT_L PORT_SRLAT&amp;=~(1&lt;&lt;bitSRLAT)<br />#define SR_CLK_H PORT_SRCLK|= (1&lt;&lt;bitSRCLK)<br />#define SR_CLK_L PORT_SRCLK&amp;=~(1&lt;&lt;bitSRCLK)</p></blockquote>
<p>&nbsp;</p>
<p>　次はスイッチ入力関係の入力ポートとスイッチ・ポートの入力用マクロの定義です。</p>
<blockquote style="margin-right: 0px;" dir="ltr">
<p>// SW入力関係<br />#define DDR_SW1&nbsp; DDRC&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // PORTB<br />#define DDR_SW2&nbsp; DDRC&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // PORTB<br />#define bitSW1&nbsp;&nbsp; 2&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // PB2<br />#define bitSW2&nbsp;&nbsp; 3&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // PB3<br />#define PIN_SW1&nbsp; PINC<br />#define PIN_SW2&nbsp; PINC<br />#define PORT_SW1 PORTC<br />#define PORT_SW2 PORTC</p>
<p>// スイッチ入力マクロ<br />#define GET_SW1 !(PINC&amp;(1&lt;&lt;bitSW1))<br />#define GET_SW2 !(PINC&amp;(1&lt;&lt;bitSW2))</p></blockquote>
<p><br />　次はWSN258オブジェクトのクラスの定義です。</p>
<blockquote style="margin-right: 0px;" dir="ltr">
<p>class WSN258<br />{<br />public:<br />&nbsp;&nbsp;&nbsp; WSN258();&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // コンストラクタ<br />&nbsp;&nbsp;&nbsp; void LedOut(uint8_t);<br />&nbsp;&nbsp;&nbsp; void LedClear(void);<br />&nbsp;&nbsp;&nbsp; uint8_t SenseSw1(void);<br />&nbsp;&nbsp;&nbsp; uint8_t SenseSw2(void);<br />&nbsp;&nbsp;&nbsp; uint8_t KeyProc(void);<br />&nbsp;&nbsp;&nbsp; //<br />&nbsp;&nbsp;&nbsp; uint8_t SRBuf;<br />&nbsp;&nbsp;&nbsp; uint8_t KeySts;<br />&nbsp;&nbsp;&nbsp; uint8_t MaxCount;<br />private:<br />&nbsp;&nbsp;&nbsp; uint8_t key_cnt1;<br />&nbsp;&nbsp;&nbsp; uint8_t key_cnt2;<br />&nbsp;&nbsp;&nbsp; uint8_t bef_key1;<br />&nbsp;&nbsp;&nbsp; uint8_t bef_key2;<br />};</p>
<p><br />#endif</p></blockquote>
<p dir="ltr">&nbsp;&nbsp;</p>
<p dir="ltr"><font style="font-size: 1.25em;"><strong>●オブジェクト・コードの説明 "wsn258.cpp"</strong></font></p>
<p dir="ltr">　このファイルはオブジェクトの本体です。最初にヘッダファイルをインクルードします。"avr/io.h"はAVRのレジスタ関係の定義ファイルです。</p>
<blockquote style="margin-right: 0px;" dir="ltr">
<p>#include &lt;avr/io.h&gt;<br />#include "WSN258.h"</p></blockquote>
<p><br />　コンストラクタで関係するディジタルI/Oポートの入出力を設定します。</p>
<p>　スイッチ入力として使用するポートは、Arduinoの初期化時にアナログ入力として設定されているため、省電力化のためディジタル入力用のバッファが停止状態になっています。このバッファを使用可能に再設定しています。また、プルアップも有効にしています。</p>
<blockquote style="margin-right: 0px;" dir="ltr">
<p>//---------------------------------------------------<br />//&nbsp; コンストラクタ<br />//---------------------------------------------------<br />WSN258::WSN258()<br />{<br />&nbsp;&nbsp;&nbsp; // シフトレジスタ制御ポート 出力に設定<br />&nbsp;&nbsp;&nbsp; DDR_SRDAT |= (1&lt;&lt;bitSRDAT);<br />&nbsp;&nbsp;&nbsp; DDR_SRCLK |= (1&lt;&lt;bitSRCLK);<br />&nbsp;&nbsp;&nbsp; DDR_SRLAT |= (1&lt;&lt;bitSRLAT);<br />&nbsp;&nbsp;&nbsp; //SRBuf = 0;<br />&nbsp;&nbsp;&nbsp; LedOut(0);</p>
<p>&nbsp;&nbsp;&nbsp; // SW1,SW2用入力ポートのデジタルバッファをイネーブルにする<br />&nbsp;&nbsp;&nbsp; DIDR0 &amp;= ~(1&lt;&lt;ADC2D);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // ADC2(SW1)<br />&nbsp;&nbsp;&nbsp; DIDR0 &amp;= ~(1&lt;&lt;ADC3D);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // ADC3(SW2)</p>
<p>&nbsp;&nbsp;&nbsp; DDR_SW1 &amp;= ~(1&lt;&lt;bitSW1);<br />&nbsp;&nbsp;&nbsp; DDR_SW2 &amp;= ~(1&lt;&lt;bitSW2);<br />&nbsp;&nbsp;&nbsp; PORT_SW1 |= (1&lt;&lt;bitSW1);&nbsp;&nbsp;&nbsp; // pullup ON<br />&nbsp;&nbsp;&nbsp; PORT_SW2 |= (1&lt;&lt;bitSW2);&nbsp;&nbsp;&nbsp; // pullup ON</p></blockquote>
<p dir="ltr">　内部使用のフィールド、公開されたフィールドを初期化します。</p>
<blockquote style="margin-right: 0px;" dir="ltr">
<p>&nbsp;&nbsp;&nbsp; key_cnt1 = 0;<br />&nbsp;&nbsp;&nbsp; key_cnt2 = 0;<br />&nbsp;&nbsp;&nbsp; bef_key1 = 0;<br />&nbsp;&nbsp;&nbsp; bef_key2 = 0;<br />&nbsp;&nbsp;&nbsp; KeySts&nbsp;&nbsp; = 0;<br />&nbsp;&nbsp;&nbsp; MaxCount = 4;<br />}</p></blockquote>
<p dir="ltr">&nbsp;</p>
<p dir="ltr">　次はキー入力処理の本体です。同じ形のものが、SW1用、SW2用それぞれにあります。ポートやフラグの設定位置が違うだけで、動作は同じです。</p>
<blockquote style="margin-right: 0px;" dir="ltr">
<p>//---------------------------------------------------<br />//&nbsp; キー処理 チャタリングキャンセル、確定処理<br />//&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; メインループに入れる<br />//---------------------------------------------------<br />uint8_t WSN258::KeyProc(void) {<br />&nbsp;&nbsp;&nbsp; uint8_t key;</p></blockquote>
<p dir="ltr">　最初にスイッチ状態を読み出して、前サイクルの内容と同じかどうか判定します。</p>
<p>　スイッチの状態を読み出して、前サイクルの状態と一致している場合は、確定回数のカウンタ"key_cnt1"を＋1します。不一致の場合は、同カウンタを0にリセットします。</p>
<p>　同じ状態が続いて、"key_cnt1"の値が"MaxCount"の値（N回）に達したとき、スイッチの状態が確定します。このとき、スイッチが押されている場合は、"KeySts"のSW1フラグをセットします。</p>
<p>　いったん押下状態が確定した後に、再びこのメソッドがコールされた場合（N+1回目以降）は、カウンタがN回以上大きくならないようにカウンタを一つ戻し、"KeySts"のSW1フラグをリセットします。このリセット操作により、スイッチを押した直後の一度だけSW1フラグがセットされることになります。</p>
<blockquote style="margin-right: 0px;" dir="ltr">
<p>&nbsp;&nbsp;&nbsp; key = GET_SW1;<br />&nbsp;&nbsp;&nbsp; if(bef_key1 != key) {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; key_cnt1 = 0;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; bef_key1 = key;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; KeySts &amp;= ~(1&lt;&lt;0);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // SW1フラグリセット<br />&nbsp;&nbsp;&nbsp; } else {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; key_cnt1++;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(key_cnt1 == MaxCount) {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 確定 N回目<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(key) {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; KeySts |= (1&lt;&lt;0);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // SW1フラグセット<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } else if(key_cnt1 &gt; MaxCount) {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // N+1回目<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; key_cnt1--;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // これ以上カウントさせないために戻す<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; KeySts &amp;= ~(1&lt;&lt;0);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // SW1フラグリセット<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />&nbsp;&nbsp;&nbsp; }</p></blockquote>
<p dir="ltr">&nbsp;</p>
<p dir="ltr">　スイッチ2に関してもスイッチ1と同様の処理です。読み出すポートとカウンタ、フラグが異なるだけです。</p>
<blockquote style="margin-right: 0px;" dir="ltr">
<p>&nbsp;&nbsp;&nbsp; key = GET_SW2;<br />&nbsp;&nbsp;&nbsp; if(bef_key2 != key) {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; key_cnt2 = 0;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; bef_key2 = key;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; KeySts &amp;= ~(1&lt;&lt;1);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // SW2フラグリセット<br />&nbsp;&nbsp;&nbsp; } else {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; key_cnt2++;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(key_cnt2 == MaxCount) {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 確定 N回目<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(key) {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; KeySts |= (1&lt;&lt;1);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // SW2フラグセット<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } else if(key_cnt2 &gt; MaxCount) {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // N+1回目<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; key_cnt2--;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // これ以上カウントさせないために戻す<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; KeySts &amp;= ~(1&lt;&lt;1);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // SW2フラグリセット<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />&nbsp;&nbsp;&nbsp; }</p></blockquote>
<p dir="ltr">　スイッチ状態はメソッドの戻り値として呼び出し元に渡します。</p>
<blockquote style="margin-right: 0px;" dir="ltr">
<p>&nbsp;&nbsp;&nbsp; return KeySts;<br />}</p></blockquote>
<p dir="ltr">&nbsp;</p>
<p dir="ltr">　次はスイッチ状態の読み出し処理です。マクロを使用していますが、単純にポートから読み出しているだけです。&nbsp;</p>
<blockquote style="margin-right: 0px;" dir="ltr">
<p dir="ltr">//---------------------------------------------------<br />//&nbsp; SW1の状態を読み出す<br />//---------------------------------------------------<br />uint8_t WSN258::SenseSw1(void) {<br />&nbsp;&nbsp;&nbsp; return GET_SW1;<br />}</p>
<p><br />//---------------------------------------------------<br />//&nbsp; SW2の状態を読み出す<br />//---------------------------------------------------<br />uint8_t WSN258::SenseSw2(void) {<br />&nbsp;&nbsp;&nbsp; return GET_SW2;<br />}</p></blockquote>
<p dir="ltr">&nbsp;</p>
<p dir="ltr">全LEDを消灯するメソッドです。シフトレジスタの8ビットに"0"を書き込んでいます。</p>
<blockquote style="margin-right: 0px;" dir="ltr">
<p dir="ltr">//---------------------------------------------------<br />//&nbsp; 全LEDを消灯<br />//---------------------------------------------------<br />void WSN258::LedClear(void) {<br />&nbsp;&nbsp;&nbsp; LedOut(0);<br />}　</p></blockquote>
<p dir="ltr">&nbsp;</p>
<p dir="ltr">　次はシフトレジスタ(HC595)に8ビットのデータを設定して、LEDを点消灯させるメソッドです。<br />　8ビットのデータをMSBから1ビットずつ取り出してシフトレジスタに入力し、8ビット入力し終わったら出力ラッチを更新して状態を確定させます。</p>
<p>　"SR_xxx_x"は、シフト・レジスタのクロック、データ、出力ラッチの三つの信号を"H"または"L"レベルに設定するマクロです。</p>
<blockquote style="margin-right: 0px;" dir="ltr">
<p>//---------------------------------------------------<br />//&nbsp; LEDに8ビット表示<br />//---------------------------------------------------<br />void WSN258::LedOut(uint8_t val) {<br />&nbsp;&nbsp;&nbsp; uint8_t i;</p>
<p>&nbsp;&nbsp;&nbsp; SRBuf = val;<br />&nbsp;&nbsp;&nbsp; for(i = 0; i &lt; 8; i++) {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if((val &amp; 0x80) != 0) {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SR_DAT_1;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } else {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SR_DAT_0;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; val &lt;&lt;= 1;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SR_CLK_H;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // シフトパルス<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SR_CLK_L;<br />&nbsp;&nbsp;&nbsp; }<br />&nbsp;&nbsp;&nbsp; SR_LAT_H;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // ラッチパルス<br />&nbsp;&nbsp;&nbsp; SR_LAT_L;<br />}</p></blockquote>
<p dir="ltr">&nbsp;</p>
<p dir="ltr">　次回は、もう一つのタイマ・オブジェクト "wCtcTimer1A"について説明します。</p>
<p dir="ltr">　また、本連載で掲載した全オブジェクトのソースファイル、サンプル・スケッチもまとめてアップする予定です。</p>
<hr>

<p>参考文献など<br />CQ出版社刊 「動かして学ぶCAN通信」： <a href="http://shop.cqpub.co.jp/hanbai/books/42/42141.html" target="_blank" ywaonclickoverride="true"><font color="#00008b">書籍案内ページ </font></a><br />WSN258基板のページ（筆者WEBサイト）： <a href="http://www.wsnak.com/kit/258/" target="_blank" ywaonclickoverride="true"><font color="#00008b">http://www.wsnak.com/kit/258/</font></a> </p>
<p align="right"><a href="http://www.wsnak.com/index2.html" target="_blank" ywaonclickoverride="true"><font color="#00008b">nakao</font></a></p>
<p align="right">&nbsp;</p>]]>
   </content>
</entry>

<entry>
   <title>書籍「動かして学ぶCAN通信」番外編Arduino用自作ライブラリの作成(4)</title>
   <link rel="alternate" type="text/html" href="http://www.eleki-jack.com/mycom2/2010/06/canarduino4.html" />
   <id>tag:www.eleki-jack.com,2010:/mycom2//4.4403</id>
   
   <published>2010-06-24T01:36:42Z</published>
   <updated>2010-06-24T04:17:09Z</updated>
   
   <summary>　今回は、#258基板専用のドライバとなるオブジェクトを説明します。 　ここで紹...</summary>
   <author>
      <name>nakao</name>
      <uri>http://www.wsnak.com/index2.html</uri>
   </author>
   
      <category term="Arduino入門" scheme="http://www.sixapart.com/ns/types#category" />
   
      <category term="動かして学ぶCAN通信" scheme="http://www.sixapart.com/ns/types#category" />
   
   <category term="263" label="AVR" scheme="http://www.sixapart.com/ns/types#tag" />
   <category term="3112" label="Arduino" scheme="http://www.sixapart.com/ns/types#tag" />
   <category term="1514" label="ライブラリ" scheme="http://www.sixapart.com/ns/types#tag" />
   
   <content type="html" xml:lang="ja" xml:base="http://www.eleki-jack.com/mycom2/">
      <![CDATA[<p>　今回は、#258基板専用のドライバとなるオブジェクトを説明します。</p>
<p>　ここで紹介するのは、二つのスイッチ入力と8個のLEDの制御ドライバです。#258基板専用なので、入出力ポート番号は基板に合わせて固定してありますが、この部分を修正すれば汎用になります。<br /></p>]]>
      <![CDATA[<p>　使用例として、前回説明したタイマ・オブジェクト"wCtcTimer2A"と組み合わせたサンプル・スケッチで説明します。</p>
<p><br /><font style="font-size: 1.25em;"><strong>●制御内容</strong></font></p>
<p>　#258基板には、シフトレジスタHC595に接続された8個のLEDと、ArduinoのA2、A3ポートに接続された2個のタクト・スイッチが実装されています。この二つをドライバで制御します。</p>
<p>　A2、A3は本来はアナログ入力ポートですが、ディジタル・ポートとして使用しています。</p>
<p><br /><font style="font-size: 1.25em;"><strong>●LED制御の動作</strong></font></p>
<p>　#258基板で使っているシフトレジスタは、シリアル信号をパラレル信号に変換するタイプの74HC595です。8本のパラレル出力のそれぞれにLEDが接続されています。</p>
<p>　シフトレジスタはクロック、データ、出力ラッチの3本の信号で制御します。8ビットのデータを最上位ビットから1ビットずつ順番に取り出してデータ信号に出力し、クロック・パルスを出力します。これを8回繰り返します。最後に出力ラッチにパルスを加えて出力を確定します。HC595は出力段にラッチがあるおかげで、シフトしている途中のデータがパラレル出力に出力されることはありません。</p>
<p>　Arduinoの標準ライブラリに"shiftOut()"というメソッドがありますが、出力ラッチの制御がないのと、ほかの機能ももたせるために、基板専用に独自にドライバとして作成しました。</p>
<p><br /><font style="font-size: 1.25em;"><strong>●スイッチ入力の動作</strong></font></p>
<p>　単純にポートの内容を読み出すだけなら簡単なのですが、メカニカル・スイッチにはチャタリング（機械的な振動により発生するノイズ）がつきものです。用途によっては問題ない場合もありますが、たとえば、スイッチを押したときにカウンタの値を+1させるような場合など、チャタリングが発生すると、何度もスイッチが押されたような状態になり、誤カウントしてしまうことがあります。</p>
<p>　チャタリングをキャンセルする方法には、C、Rによる遅延回路とシュミット・トリガICを組み合わせるなどの、ハードウェアを使った方法もありますが、#258基板には特別な回路は設けていないため、ソフトウェアだけで制御します。</p>
<p>　チャタリング・キャンセルの仕組みは、何度かスイッチの状態を読み出して、同じ状態が継続していることで、入力を確定させるというものです。通常、20ms前後の周期で数回読み出して、押された状態が確定したときに、確定した時だけイベントが発生して、何らかの処理を実行するようにします。</p>
<p>　この20ms前後の周期というのを生成するのが、前回説明したタイマ・オブジェクト"wCtcTimer2A"などです。今回は、このオブジェクトで16msの周期を作っています。</p>
<p><br /><font style="font-size: 1.25em;"><strong>●WSN258クラスのパブリック・メンバ</strong></font></p>
<p>　クラスのおもなメンバを説明します。パブリックな変数はユーザ・プログラムからの参照、設定が可能です。いわゆるプロパティというものと同等です。本来は、直接ではなく、参照、設定用のメソッドを作ってそれで操作するのがよい場合もありますが、わざわざメソッドにするまでもないのでプロパティとして直接アクセスするようにしています。</p>
<p><strong>(1) WSN258() コンストラクタ<br /></strong>　コンストラクタです。I/Oポートの初期化、フィールドの初期化などを行います。直接ユーザが呼び出すことはありません。使用するポートは#258基板に合わせて固定してあります。</p>
<p><strong>(2) void LedOut(uint8_t) シリアルLED出力<br /></strong>　8ビットのデータを8個のlEDの点消灯データとして出力します。"1"のビットが点灯、"0"のビットが消灯で、最下位ビットがLED1に、それ以降順番に対応しています。</p>
<p><strong>(3) void LedClear(void) 全LED消灯<br /></strong>　全LEDを消灯します。LedOut(0)と同じ働きをします。</p>
<p><strong>(4) uint8_t SenseSw1(void) SW1状態読み出し<br /></strong>　SW1ポートの現在の状態を読み出します。SW1が押下されているときにtrueを返します。単純にポートを読み出しているだけです。</p>
<p><strong>(5) uint8_t SenseSw2(void) SW2状態読み出し<br /></strong>　SW2ポートの現在の状態を読み出します。SW2が押下されているときにtrueを返します。単純にポートを読み出しているだけです。</p>
<p><strong>(6) uint8_t KeyProc(void) キー入力処理<br /></strong>　チャタリング解除処理の本体です。メイン・ループの周期処理の中に置きます。規定回数、押下状態が続いた時に、"KeySts"のスイッチに対応するビットをセットします。</p>
<p>　実行結果として"KeySts"の内容を返します。この値で押下されたSWを判定します。スイッチが押下されていない、または、押下した後の2サイクル目の場合は該当ビットが"0"になります（押された直後の1サイクル目だけ"1"にセットされる）。</p>
<p><strong>(7) uint8_t SRBuf シフトレジスタ出力バッファ<br /></strong>　現在シフトレジスタに出力している値を記憶する変数です。特定のLEDだけON/OFFを切り替えたい時にビット演算するのに使用します。</p>
<p><strong>(8) uint8_t KeySts キー状態<br /></strong>　押下されたスイッチの状態を示すフラグです。b0がSW1、B1がSW2に対応し、押下されたSWの対応ビットが"1"にセットされます。</p>
<p>　"KeyProc()"の実行直後に設定されますが、SWが押下され続けていても、次回のループで再び"KeyProc()"が実行されるとクリアされます。</p>
<p><strong>(9) uint8_t MaxCount 確定回数<br /></strong>　チャタリングキャンセル処理で、状態を確定させるまでの回数を指定します。デフォルト値は4です。この場合、"KeyProc()"メソッドが4回コールされて、その都度、同じ状態が継続しているときに状態が確定することになります。</p>
<p><br /><font style="font-size: 1.25em;"><strong>●使用例</strong></font></p>
<p>　押されたスイッチに応じた処理を行うサンプル・スケッチを掲載します。このサンプルはSW2を押すとカウンタが+1されて、その結果が8個のLEDに2進数で表示されます（点灯が"1"、消灯が"0"を示す）。SW2を押すたびにカウント値が更新されます。</p>
<p>　SW1を押すとカウント値をクリアして0を表示（全LED消灯）します。もし、チャタリングがあると、SW2を押したときに一つ以上カウントされることがありますので、チャタリング・キャンセラによりそのような誤カウントが起こらないことが確認できます。</p>
<blockquote style="margin-right: 0px;" dir="ltr">
<p><br />#include &lt;WSN258.h&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // WSN258オブジェクトのリンク<br />#include &lt;wCtcTimer2A.h&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // wCtcTimer2Aオブジェクトのリンク</p>
<p>WSN258 wsn258;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // WSN258オブジェクトのインスタンス化<br />wCtcTimer2A CtcTm;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // wCtcTimer2Aオブジェクトのインスタンス化</p>
<p>// 初期化関数<br />void setup(void) {<br />&nbsp;&nbsp;&nbsp; CtcTm.Init();&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // タイマの初期化 周期はデフォルトの16ms<br />&nbsp;&nbsp;&nbsp; wsn258.LedClear();&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // LED全OFF<br />}</p>
<p>// カウンタ<br />byte Count = 0;</p>
<p>// メインループ<br />void loop(void) {<br />&nbsp;&nbsp;&nbsp; byte keysts;</p>
<p>&nbsp;&nbsp;&nbsp; if(CtcTm.CheckTimeup()) {&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // (1)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 16ms周期</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // キー入力<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; keysts = wsn258.KeyProc();&nbsp; // (2)キー入力処理,入力判定<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(keysts &amp; 1) {&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // b0チェック<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // (3) SW1が押下されたとき<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Count = 0;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; wsn258.LedOut(0);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(keysts &amp; 2) {&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // b1チェック<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // (4) SW2が押下されたとき<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Count++;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; wsn258.LedOut(Count);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />&nbsp;&nbsp;&nbsp; }<br />}</p></blockquote>
<p><br />　(1)のifブロックはタイマ・オブジェクトによって16msごとに実行されます。従って(2)のキー入力処理"wsn258.KeyProc()"も16msごとに実行されます。</p>
<p>　チャタリング・キャンセルの入力確定回数はデフォルトの4回ですので、16msのスキャンで4回同じ状態が続いたら状態が確定するということになります。</p>
<p>　SW1が押下された直後は、"keysts"のb0が"1"にセットされているため、(3)のifブロック内の処理が実行されます。ここではカウント値を0にリセットし、それをLEDに出力します。</p>
<p>　SW2が押下された直後は、"keysts"のb1が"1"にセットされているため、(4)のifブロック内の処理が実行されます。ここではカウント値を＋1して、それをLEDに出力します。</p>
<p>※uint8_t、byteはいずれもunsigned char型を再定義したデータタイプです（符号なし8ビット）。</p>
<p><br />　次回は、WSN258オブジェクトのコードなどについて説明します。<br /></p>
<hr>

<p>参考文献など<br />CQ出版社刊 「動かして学ぶCAN通信」： <a href="http://shop.cqpub.co.jp/hanbai/books/42/42141.html" target="_blank" ywaonclickoverride="true"><font color="#00008b">書籍案内ページ </font></a><br />WSN258基板のページ（筆者WEBサイト）： <a href="http://www.wsnak.com/kit/258/" target="_blank" ywaonclickoverride="true"><font color="#00008b">http://www.wsnak.com/kit/258/</font></a> </p>
<p align="right"><a href="http://www.wsnak.com/index2.html" target="_blank" ywaonclickoverride="true"><font color="#00008b">nakao</font></a></p>
<p>&nbsp;</p>]]>
   </content>
</entry>

<entry>
   <title>書籍「動かして学ぶCAN通信」番外編Arduino用自作ライブラリの作成(3)</title>
   <link rel="alternate" type="text/html" href="http://www.eleki-jack.com/mycom2/2010/06/canarduino3.html" />
   <id>tag:www.eleki-jack.com,2010:/mycom2//4.4375</id>
   
   <published>2010-06-21T02:01:59Z</published>
   <updated>2010-06-21T01:36:12Z</updated>
   
   <summary>　今回は、タイマ・オブジェクト&quot;wCtcTimer2A&quot;のコードについて説明しま...</summary>
   <author>
      <name>nakao</name>
      <uri>http://www.wsnak.com/index2.html</uri>
   </author>
   
      <category term="Arduino入門" scheme="http://www.sixapart.com/ns/types#category" />
   
      <category term="動かして学ぶCAN通信" scheme="http://www.sixapart.com/ns/types#category" />
   
   <category term="263" label="AVR" scheme="http://www.sixapart.com/ns/types#tag" />
   <category term="3112" label="Arduino" scheme="http://www.sixapart.com/ns/types#tag" />
   <category term="5782" label="CTC" scheme="http://www.sixapart.com/ns/types#tag" />
   <category term="680" label="PWM" scheme="http://www.sixapart.com/ns/types#tag" />
   <category term="717" label="タイマ" scheme="http://www.sixapart.com/ns/types#tag" />
   <category term="1514" label="ライブラリ" scheme="http://www.sixapart.com/ns/types#tag" />
   
   <content type="html" xml:lang="ja" xml:base="http://www.eleki-jack.com/mycom2/">
      <![CDATA[<p>　今回は、タイマ・オブジェクト"wCtcTimer2A"のコードについて説明します。</p>
<p>　ライブラリ内の個々のオブジェクトは、前述のように、オブジェクトごとのフォルダの中に、クラス定義のヘッダ・ファイル（*.h）とクラスのプログラム本体（*.cpp）の二つが必要です。</p>]]>
      <![CDATA[<p><font style="font-size: 1em;">　オブジェクト・フォルダ内のコードは、スケッチがコンパイルされるときに一緒にコンパイルされるため、あらかじめコンパイルするなどの処理は一切不要です。</font></p>
<p>　従って、オブジェクトのコードにコンパイル・エラーがある場合は、スケッチのコンパイル時に発覚します。</p>
<p>&nbsp;次から、オブジェクトのコードをファイルごとに説明します。</p>
<p><font style="font-size: 1.25em;"><strong>●オブジェクト・コードの説明 "wCtcTimer2A.h"</strong></font></p>
<p>　"wCtcTimer2A.h"はクラスの型、マクロなどの定義ファイルです。次からコードの内容を順に説明していきます。</p>
<p>　"intypes.h"は"uint8_t"などの型を定義しているヘッダ・ファイルです。</p>
<p>　次に、AVRの"OCR2A"レジスタとTIMER2レジスタのコンペア・マッチ割り込み要因フラグの操作マクロを定義しています。</p>
<blockquote style="margin-right: 0px;" dir="ltr">
<p>#include &lt;inttypes.h&gt;</p>
<p>// タイマ1コンペアマッチ割り込みフラグ操作<br />#define CLR_TMR2_CMPA_IF&nbsp;&nbsp;&nbsp; TIFR2|=(1&lt;&lt;OCF2A)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 割り込みフラグクリア<br />#define TST_TMR2_CMPA_IF&nbsp;&nbsp;&nbsp; TIFR2&amp;(1&lt;&lt;OCF2A)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 割り込みフラグテスト</p></blockquote>
<p dir="ltr">&nbsp;</p>
<p dir="ltr">　次は、タイマ・クラスの定義です。"Init()"メソッドはデフォルト値付きの定義で、メソッド呼び出し時に引数を省略するとデフォルト値が設定されます。</p>
<p dir="ltr">　"onTimer();"はハンドラ（ユーザ・メソッド）を登録するためのメソッドです。引数は、void型の関数のアドレスを渡すため、voidのポインタになっています。変な形になっていますが、これは、関数のアドレスを渡すときに使う書式です。</p>
<p dir="ltr">　"void (*user_onTimer)(void)"はメソッドのアドレスを保持するポインタ変数のようなものですが、保持したアドレスをコールすることができるメソッドでもあります。</p>
<p dir="ltr">　具体的にいうと、あるメソッドのアドレスをあらかじめこのポインタへ定義しておけば、そのメソッドを"user_onTimer()"という名前のメソッドとしてコールできます。</p>
<blockquote style="margin-right: 0px;" dir="ltr">
<p dir="ltr">class wCtcTimer2A<br />{<br />public:<br />&nbsp;&nbsp;&nbsp; wCtcTimer2A();&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // コンストラクタ<br />&nbsp;&nbsp;&nbsp; void SetTimeVal(uint8_t cntv);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// タイマ値設定<br />&nbsp;&nbsp;&nbsp; uint8_t CheckTimeup(void);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // タイムアップチェック<br />&nbsp;&nbsp;&nbsp; void Init(uint8_t cntv=250);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 初期化<br />&nbsp;&nbsp;&nbsp; void onTimer(void (*)(void));&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;// タイムアップ時のハンドラ登録<br />private:<br />&nbsp;&nbsp;&nbsp; static void (*user_onTimer)(void);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // ハンドラのアドレスを保持するメソッドのポインタ<br />&nbsp;&nbsp;&nbsp; uint8_t Pend;<br />};</p></blockquote>
<p dir="ltr"><br /><font style="font-size: 1.25em;"><strong>●オブジェクト・コードの説明 "wCtcTimer2A.cpp"</strong></font></p>
<p>　オブジェクトのメインとなるコードを、ソース・リストの順に説明します。</p>
<p>　はじめにクラス定義（"wCtcTimer2A.h"）をインクルードします。"io.h"はAVRのレジスタのアドレスなどを定義したヘッダ・ファイルです。</p>
<blockquote style="margin-right: 0px;" dir="ltr">
<p>#include &lt;avr/io.h&gt;<br />#include "wCtcTimer2A.h"</p></blockquote>
<p>　次はハンドラ（後述）のポインタ・メソッドのプロトタイプ宣言です。ユーザ・メソッドを登録メソッド（"onTimer()"）で登録したあとは、ユーザ・メソッドは"user_onTimer()"としてアクセスできるようになります。</p>
<blockquote style="margin-right: 0px;" dir="ltr">
<p>void (*wCtcTimer2A::user_onTimer)(void);</p></blockquote>
<p><br />　次は、コンストラクタの定義です。ここで"Init()"で初期化しています。本来はこれでよいはずですが、コンストラクタが呼び出されたあとに、ArduinoのシステムがPWM制御用に設定を上書きしてしまうので、結局ここでの初期化は意味がありません。</p>
<blockquote style="margin-right: 0px;" dir="ltr">
<p>// コンストラクタ<br />wCtcTimer2A::wCtcTimer2A() {<br />&nbsp;&nbsp;&nbsp; Init();&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // システムによりオーバライドされるため<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 意味がないが、念のため<br />}</p></blockquote>
<p dir="ltr"><br />　次はタイマ関係のレジスタや変数の初期化処理です。TIMER2とアウトプット・コンペア・レジスタ2A（OCR2A）をCTCモードで作動するように設定しています。</p>
<p dir="ltr">　"cntv"変数はクラス定義時にデフォルト値を設定してあるので、引数を省略すると、自動的にデフォルト値が設定されます。引数で値を渡せば、通常とおりその値が設定されます。</p>
<p dir="ltr">　"CLR_TMR2_CMPA_IF"はコードの冒頭で定義してある、コンペア一致の割り込み要因フラグをクリアするマクロです。</p>
<blockquote style="margin-right: 0px;" dir="ltr">
<p>// <br />// cntvは省略可能(省略時は250:16ms)<br />//<br />void wCtcTimer2A::Init(uint8_t cntv) {</p>
<p>&nbsp;&nbsp;&nbsp; // TIMER2 CTCモード CLK/1024<br />&nbsp;&nbsp;&nbsp; //<br />&nbsp;&nbsp;&nbsp; TCCR2A &amp;= ~(1&lt;&lt;COM2A1);&nbsp;&nbsp;&nbsp;&nbsp; // 0<br />&nbsp;&nbsp;&nbsp; TCCR2A &amp;= ~(1&lt;&lt;COM2A0);&nbsp;&nbsp;&nbsp;&nbsp; // 0<br />&nbsp;&nbsp;&nbsp; TCCR2B &amp;= ~(1&lt;&lt;WGM22);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 0<br />&nbsp;&nbsp;&nbsp; TCCR2A |=&nbsp; (1&lt;&lt;WGM21);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 1<br />&nbsp;&nbsp;&nbsp; TCCR2A &amp;= ~(1&lt;&lt;WGM20);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 0<br />&nbsp;&nbsp;&nbsp; TCCR2B |=&nbsp; (1&lt;&lt;CS22);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 1<br />&nbsp;&nbsp;&nbsp; TCCR2B |=&nbsp; (1&lt;&lt;CS21);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 1<br />&nbsp;&nbsp;&nbsp; TCCR2B |=&nbsp; (1&lt;&lt;CS20);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 1</p>
<p>&nbsp;&nbsp;&nbsp; TCNT2 = 0;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // タイマ値</p>
<p>&nbsp;&nbsp;&nbsp; OCR2A = cntv;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // デフォルト コンペア値 (250: 16ms)<br />&nbsp;&nbsp;&nbsp; CLR_TMR2_CMPA_IF;</p>
<p>&nbsp;&nbsp;&nbsp; Pend = false;&nbsp;&nbsp;&nbsp;// タイムアップ状態の保留フラグ<br />}&nbsp;</p></blockquote>
<p>&nbsp;</p>
<p>　次は、タイマ値を設定するメソッドです。コンペア・レジスタAに値を設定、タイマをクリアしています。</p>
<blockquote style="margin-right: 0px;" dir="ltr">
<p>&nbsp;void wCtcTimer2A::SetTimeVal(uint8_t cntv) {<br />&nbsp;&nbsp;&nbsp; OCR2A = cntv;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 0.064ms/ibit<br />&nbsp;&nbsp;&nbsp; TCNT2 = 0;<br />&nbsp;&nbsp;&nbsp; CLR_TMR2_CMPA_IF;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 割り込みフラグクリア<br />}&nbsp;</p></blockquote>
<p>&nbsp;</p>
<p>　次は、タイマがタイムアップしているかどうかを調べるメソッドです。このメソッドはメイン・ループに配置して、繰り返しコールします。</p>
<p>　メソッドの戻り値として、割り込み要因フラグの状態を返します。このフラグがセットされているときは、タイマがタイムアップしていることを表しています。</p>
<blockquote style="margin-right: 0px;" dir="ltr">
<p>uint8_t wCtcTimer2A::CheckTimeup(void) {<br />&nbsp;&nbsp;&nbsp; uint8_t sts;</p></blockquote>
<p>　前サイクルで割り込み要因フラグがセットされていた場合（"Pend"がtrue）、割り込み要因フラグと"Pend"をクリアしていったんメソッドを終了します。</p>
<blockquote style="margin-right: 0px;" dir="ltr">
<p>&nbsp;&nbsp;&nbsp; if(Pend) {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 前サイクルで要因フラグがセットされているとき<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Pend = false;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;CLR_TMR2_CMPA_IF;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 割り込み要因フラグをクリア<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return false;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // いったん終了<br />&nbsp;&nbsp;&nbsp; }</p></blockquote>
<p dir="ltr"><br />　"TST_TMR2_CMPA_IF"は割り込み要因フラグの状態を読み出すマクロで、trueの場合は、要因フラグがセットされていることを示します。ハンドラ・コールの処理が入っているので少々複雑ですが、ハンドラを使わない場合はelseの方にだけ注目してください。</p>
<p dir="ltr">　ここでタイムアップしている場合は、"Pend"をセットしてそれをメソッドの戻り値として終了します。呼び出し元では、この状態をうけて、タイマ処理を実行します。</p>
<p dir="ltr">　ハンドラが定義されている場合（ポインタの内容がNULLでないとき）は、ハンドラをコールして割り込み要因フラグをリセットします。</p>
<blockquote style="margin-right: 0px;" dir="ltr">
<p>&nbsp;&nbsp;&nbsp; sts = TST_TMR2_CMPA_IF;&nbsp;&nbsp;// 割り込み要因フラグの読み出し</p>
<p>&nbsp;&nbsp;&nbsp; if(sts) {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(user_onTimer) {&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // ハンドラが定義されているかどうか<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; user_onTimer();&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // ハンドラコール<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; CLR_TMR2_CMPA_IF;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 割り込み要因フラグをクリア<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} else {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Pend = true;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />&nbsp;&nbsp;&nbsp; }</p>
<p>&nbsp;&nbsp;&nbsp; return sts;<br />}</p></blockquote>
<p dir="ltr"><br />　次は、タイムアップしたときに実行されるハンドラ（ユーザ・メソッド）を登録するメソッドです。ハンドラを使用する場合は初期化時などにユーザ・メソッドを登録しておきます。</p>
<p dir="ltr">　メソッドのポインタに引数で渡されたメソッドのアドレスを設定します。</p>
<blockquote style="margin-right: 0px;" dir="ltr">
<p>// タイムアップ時のハンドラ登録<br />void wCtcTimer2A::onTimer(void (*function)(void)) {<br />&nbsp;user_onTimer = function;<br />}&nbsp;</p></blockquote>
<p>&nbsp;</p>
<p>　今回説明したタイマ・オブジェクトは、次回説明するオブジェクトのスイッチ入力処理で利用します。実際の使用例はそちらに示します。　</p>
<p></p>
<hr>
参考文献など<br />CQ出版社刊 「動かして学ぶCAN通信」： <a href="http://shop.cqpub.co.jp/hanbai/books/42/42141.html" target="_blank">書籍案内ページ </a><br />WSN258基板のページ（筆者WEBサイト）： <a href="http://www.wsnak.com/kit/258/" target="_blank">http://www.wsnak.com/kit/258/</a> 
<p></p>
<p align="right"><a href="http://www.wsnak.com/index2.html" target="_blank">nakao</a></p>]]>
   </content>
</entry>

<entry>
   <title>書籍「動かして学ぶCAN通信」番外編Arduino用自作ライブラリの作成(2)</title>
   <link rel="alternate" type="text/html" href="http://www.eleki-jack.com/mycom2/2010/06/canarduino2.html" />
   <id>tag:www.eleki-jack.com,2010:/mycom2//4.4373</id>
   
   <published>2010-06-16T00:53:23Z</published>
   <updated>2010-06-16T00:42:06Z</updated>
   
   <summary>　今回はインターバル・タイマのオブジェクト&quot;wCtcTimer2A&quot;について説明...</summary>
   <author>
      <name>nakao</name>
      <uri>http://www.wsnak.com/index2.html</uri>
   </author>
   
      <category term="Arduino入門" scheme="http://www.sixapart.com/ns/types#category" />
   
      <category term="動かして学ぶCAN通信" scheme="http://www.sixapart.com/ns/types#category" />
   
   <category term="263" label="AVR" scheme="http://www.sixapart.com/ns/types#tag" />
   <category term="3112" label="Arduino" scheme="http://www.sixapart.com/ns/types#tag" />
   <category term="5782" label="CTC" scheme="http://www.sixapart.com/ns/types#tag" />
   <category term="680" label="PWM" scheme="http://www.sixapart.com/ns/types#tag" />
   <category term="717" label="タイマ" scheme="http://www.sixapart.com/ns/types#tag" />
   <category term="1514" label="ライブラリ" scheme="http://www.sixapart.com/ns/types#tag" />
   
   <content type="html" xml:lang="ja" xml:base="http://www.eleki-jack.com/mycom2/">
      <![CDATA[　今回はインターバル・タイマのオブジェクト"wCtcTimer2A"について説明します。このオブジェクトは汎用ですので、#258基板を使っていない場合でも利用可能です。<br />]]>
      <![CDATA[<p>　このタイマ・オブジェクトは、AVRのTIMER/COUNTER2（8ビット・タイマ/カウンタ）とコンペア・レジスタ2A(OCR2A)を使ったCTCモードで作動します。</p>
<p>　CTCモードとは、カウンタ値がある条件になるとカウンタがリセットされて、一定周期の遅延動作を繰り返すような働きをするモードです。リセットされる直前に割り込み要因フラグでタイムアップしたことがわかります。</p>
<p>　このフラグを判定して周期処理を起動します。割り込みが許可されている場合は、このフラグがセットされたときに割り込みが発生しますが、今回は割り込みは使用していません。</p>
<p>　今回作成した第一の目的は、スイッチ入力のチャタリング・キャンセル処理で使うためですが、周期的に実行したい処理にも利用できます。</p>
<p><br /><font style="font-size: 1.25em;"><strong>●タイマの動作</strong></font></p>
<p>　このタイマ・オブジェクトで使用しているTIMER2は、システム・クロック（16MHz）をプリスケーラで1/1024にして、それをコンペア・レジスタ"OCR2A"で数える（同レジスタと比較する）というような動作をさせています。</p>
<p>分周した周波数Fは、</p>
<blockquote style="margin-right: 0px;" dir="ltr">
<p>&nbsp;F = 16MHz / 1024 = 15625Hz</p></blockquote>
<p>1クロックの周期Tは、</p>
<blockquote style="margin-right: 0px;" dir="ltr">
<p>T = 1/F = 1/15625Hz = 0.000064s = 0.064ms</p></blockquote>
<p>　つまり、タイマ（カウンタ）の1カウントで0.064msかかるということです。</p>
<p>　CTCモードではTIMER2の値とコンペア値を比較して一致したときに割り込み要因フラグがセットされます。つまり、コンペア値に設定した数値でタイマ時間を変えることができます。</p>
<p>　具体的には、コンペア値に250を設定すると、0.064msを250回カウントすることになり、遅延時間は0.064×250＝16msとなります。</p>
<p>　CTCモードではタイムアップすると自動的にカウンタがリセットされるため、この遅延を繰り返すことになります。これがインターバル・タイマの動作です。</p>
<p>　ちなみに、設定を変更して、AVRの出力ピンを切り替える（トグル動作）ようにすると、そのピンから矩形波を出力することができます。オシレータとして利用する場合は、そのようにします。また、PWM出力はこの動作の変形と考えることができます。</p>
<p>　タイムアップのタイミングは、タイムアップしたときにセットされる割り込み要因フラグをメイン・ループでポーリングすることで知ります（今回は割り込みは不使用）。インターバル・タイマが次の周期で再び同フラグをセットしますので、その前に同フラグをクリアしておく必要があります。</p>
<p>　このタイマは、前述の計算式を見るとわかるように、分周比とカウント値の制限の関係で、10msちょうどとか、100msちょうどといったきりのよい時間は作れません。これができるのが、後述する16ビットのTIMER1を使用した"wCtcTimer1A"です。</p>
<p>　"wCtcTimer2A"オブジェクトを時計に利用する際は、周期を8msにして、それをソフトウェアで125回カウントすれば、1秒の周期が作られます。</p>
<p><br /><font style="font-size: 1.25em;"><strong>●wCtcTimer2Aクラスのパブリック・メンバ</strong></font></p>
<p>　クラスのおもなメンバを説明します。</p>
<p><strong>(1)wCtcTimer2A() コンストラクタ</strong></p>
<p>　コンストラクタ（インスタンス化されたときに実行される初期化メソッド）です。直接ユーザが呼び出すことはありません。</p>
<p><strong>(2) void Init() 初期化メソッド</strong></p>
<p>　void Init();&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // デフォルト値 250(16ms)<br />　void init(byte val);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 設定時間 0.064ms×val</p>
<p>　本来は、クラスをインスタンス（実体）化するときに、コンストラクタ（初期化メソッド）で初期化されるのですが、Arduinoのシステムにより、タイマ設定などがオーバライド（上書き）されるため、setup()関数内で再初期化するのに使用します。</p>
<p>　引数を省略すると、インターバル・タイマの周期のデフォルトとして、16msに相当する"250"が設定されます。ここに設定できる値は、1～255で、タイマ値は0.064msをかけた値になります。具体的には8msにしたいときは、"125"を設定します（0.064ms×125＝8ms）。</p>
<p><strong>(3) void SetTimeVal(byte val) タイマ周期設定メソッド</strong></p>
<p>　インターバル・タイマの周期を設定します。設定値は1～255で0.064ms単位です。</p>
<p><strong>(4) uint8_t CheckTimeup(void) タイムアップ・チェック・メソッド</strong></p>
<p>　タイマがタイムアップしているかを調べるメソッドです。このメソッドがtrueを返すとタイムアップしています。このとき、周期処理を実行します。</p>
<p>　TIMER2がコンペア値(OCR2A)と一致したときに、割り込み要因フラグ"OCF2A"がセットされます。この状態を返します。</p>
<p>　このメソッドがtrueを返したときは、直ちに（現在のサイクル内で）処理を実行する必要があります。次のサイクルで、再びこのメソッドが呼び出されたときは、falseが返ります。</p>
<p>&nbsp;</p>
<p><font style="font-size: 1.25em;"><strong>●使用例1</strong></font></p>
<p>　ハンドラ（後述）を使わない場合の使用例です。"CheckTimeup()"メソッドがtrueを返したらタイマ処理を実行します。</p>
<blockquote style="margin-right: 0px;" dir="ltr">
<p>wCtcTimer2A CtcTm;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // クラスのインスタンス化</p>
<p>void loop(void) {<br />&nbsp; if(CtcTm.CheckTimeup()) {<br />&nbsp;&nbsp;&nbsp; // タイムアップあり<br />&nbsp;&nbsp;&nbsp; // ToDo:タイマ処理<br />&nbsp; }<br />}</p></blockquote>
<p>&nbsp;</p>
<p><strong><font style="font-size: 1.25em;">●使用例2</font></strong></p>
<p>ハンドラを使った場合の使用例です。</p>
<blockquote style="margin-right: 0px;" dir="ltr">
<p>wCtcTimer2A tm;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // クラスのインスタンス化</p>
<p>// 初期化<br />void setup(void) {<br />&nbsp; tm.onTimer(OnTimer);&nbsp;&nbsp;&nbsp; // ハンドラ登録<br />}</p>
<p>// メインループ<br />void loop(void) {<br />&nbsp; tm.CheckTimeup();<br />}</p>
<p>// タイマハンドラ(16ms)<br />void OnTimer(void) {<br />&nbsp; // ToDo:タイマ処理<br />}</p></blockquote>
<p><br /><font style="font-size: 1.25em;"><strong>●ハンドラについて</strong></font></p>
<p>　このオブジェクトではタイムアップの検出の仕方に2通りの方法があります。一つは、"CheckTimeup()"メソッドの実行結果としてタイムアップを検出し、その状態を受けてタイマ処理を実行する方法、もう一つは、ハンドラを定義して、タイムアップしたときにハンドラをコールして、そのハンドラでタイマ処理する方法です。</p>
<p>　初期化時などにハンドラ（ユーザ・メソッド）を定義しておけば、タイムアップしたときにユーザ・メソッドが呼び出されます。このメソッドがいわゆるイベント・ハンドラです。</p>
<p>　なお、ハンドラを使用する場合もメイン・ループ内に"CheckTimeup()"メソッドを入れておく必要がありますが、この場合は、実行結果は不要ですので、単にメソッドをコールするだけでかまいません（状態判定のif文などは不要）。</p>
<p>&nbsp;</p>
<p>　次回は、タイマ・オブジェクトのコードについて説明します。</p>
<hr>
参考文献など<br />CQ出版社刊 「動かして学ぶCAN通信」： <a href="http://shop.cqpub.co.jp/hanbai/books/42/42141.html" target="_blank">書籍案内ページ </a><br />WSN258基板のページ（筆者WEBサイト）： <a href="http://www.wsnak.com/kit/258/" target="_blank">http://www.wsnak.com/kit/258/</a> 
<p align="right"><a href="http://www.wsnak.com/index2.html" target="_blank">nakao</a></p>
<p align="right">&nbsp;</p>]]>
   </content>
</entry>

<entry>
   <title>拡張PIC16Fマイコン 16F1827のPWMを試す(5)</title>
   <link rel="alternate" type="text/html" href="http://www.eleki-jack.com/mycom2/2010/06/pic16f_16f1827pwm5.html" />
   <id>tag:www.eleki-jack.com,2010:/mycom2//4.4362</id>
   
   <published>2010-06-11T04:17:24Z</published>
   <updated>2010-06-11T04:04:16Z</updated>
   
   <summary>　拡張PIC16マイコン（PIC16F1827）とその評価基板でアセンブリ言語を...</summary>
   <author>
      <name>goda</name>
      
   </author>
   
      <category term="MPLAB" scheme="http://www.sixapart.com/ns/types#category" />
   
      <category term="PIC" scheme="http://www.sixapart.com/ns/types#category" />
   
      <category term="PICkit-3" scheme="http://www.sixapart.com/ns/types#category" />
   
      <category term="拡張PIC16マイコン" scheme="http://www.sixapart.com/ns/types#category" />
   
   
   <content type="html" xml:lang="ja" xml:base="http://www.eleki-jack.com/mycom2/">
      <![CDATA[　拡張PIC16マイコン（PIC16F1827）とその評価基板でアセンブリ言語を使ったプログラムを作成し、PWM機能を確認してみます（最終回）。<br />　輝度変化実験の最後は、PWMによるLEDの輝度データをRAMエリアに移しそのデータ変更を行ってみます。RAMエリアにおけばデバッガにより実際に動かしながら輝度データを変更、変更結果の確認ができます。<br />　記事内容は、16F1827データシートがREV.BそしてMPLABがV8.50をそれぞれ使った執筆時点のものです。<br />]]>
      <![CDATA[<p>&nbsp;</p>
<p>●<b>拡張PIC16マイコンのメモリ構造について</b><br />　拡張PIC16マイコンはメモリ関係が簡素化されて、わかりやすくなりました。</p>
<p>　PIC16F1827メモリはデータEEPROM（256バイト）、プログラム・メモリが4Kワード（2ページ）、データ・メモリが348バイト（バンク切り替え）の構成になっています。</p>
<p>　データ・メモリは少し大きくなったほか、バンク・メモリ構成がすっきりしました。<br />　・ 最初の12バイトは各バンクとも同じレジスタが割り当て<br />　・ 各マイコンごとのレジスタ(SFR)が20バイト単位で各バンクに割り当て <br />　・ 一般的なRAM(GPR)として20hから80バイト(6f)が各バンクに割り当て<br />　・ 後ろ16バイトは各バンクとも同じRAMメモリ（common RAM）割り当て</p>
<p>　 
</p><span class="mt-enclosure mt-enclosure-image" style="display: inline;"><img class="mt-image-center" style="display: block; margin: 0px auto 20px; text-align: center;" alt="j91bankedmemory.JPG" src="http://www.eleki-jack.com/mycom2/goda/j91bankedmemory.JPG" width="283" height="469" /></span>　各バンクは次のようにきれいに配置されました（クリックで拡大）。
<p>
</p><span class="mt-enclosure mt-enclosure-image" style="display: inline;"><a href="http://www.eleki-jack.com/mycom2/goda/j92bankedmemo2.JPG"><img class="mt-image-center" style="display: block; margin: 0px auto 20px; text-align: center;" alt="j92bankedmemo2.JPG" src="http://www.eleki-jack.com/mycom2/goda/j92bankedmemo2-thumb-400x254.jpg" width="400" height="254" /></a></span>　従来のPIC16では80バイト以上のバッファやテーブルの作成がかなり難しい状態でした。拡張PICマイコンではこの各バンクにある「一般的なユーザRAM」をリニアに結合したリニア・メモリ（仮想メモリ）ができました。これにより書き換え可能な変数テーブルやデータ受信バッファなどに使用できます。
<p><br />　PIC16F1827のユーザが変数やバッファとして使えるデータ・メモリは384バイトで、次のようにバンクに分かれています。バンク切り替えで使用できます。</p>
<p>　バンク0　　バンク1　バンク2　バンク3　バンク4<br />　　96　　　　80　　　　80　　　　80　　　　48　　　　の計384バイト</p>
<p>　また、これらは下図に示すように仮想メモリ2000h番地から連続に、バンク0は後ろの共有16バイトを除く80バイト、バンク1～3の各80バイト、そしてバンク4の48バイトが順に配置されています。また、バンク4の後ろ数バイトはデバッガの予約エリアになっています。</p>
<p>&nbsp;</p>
<p>
</p><span class="mt-enclosure mt-enclosure-image" style="display: inline;"><img class="mt-image-center" style="display: block; margin: 0px auto 20px; text-align: center;" alt="j93dataLinea.JPG" src="http://www.eleki-jack.com/mycom2/goda/j93dataLinea.JPG" width="434" height="547" /></span>●<b>RAMエリアにテーブルを置くプログラム</b><br />　今回のプログラムはこの2000番地からの仮想メモリにプログラム・メモリ内テーブルの輝度データを移動させて動かします。つまり、RAMエリアにテーブルを置きます。<br />　希望の明るさや動作にならないとき、今までは輝度データを何度も値を変えてアセンブルして実行し、最適な輝度データを決める必要があり、大変でした。<br />　そこで、値を決めるため変更不可能なプログラム・エリアの輝度データ・テーブルから変更可能なRAMエリアに移します。拡張PICマイコンは連続したRAMエリアとなる仮想メモリがありますので、バンクの境界を意識せず、テーブルを作れるようになりました。ここでMPLABのデバッガを使い、値を変更し、実際に動かしてLED点灯状態を確認し、値を決めます。<br /><br />
<p>　プログラム 　<a href="http://www.eleki-jack.com/mycom2/goda/j94test15.txt">test15.asm</a></p>
<p>　次のコーディングは、新しい命令を使ったプログラム・エリアのデータをRAMエリアに移動するものです。</p><pre>bank1area	 equ	2000h+80	;リニアメモリのバンク1部分（＊＊＊）
;　ProgramエリアのデータをRAMエリア（バンク1）に移動する
	movlw	HIGH bank1area
	movwf	FSR0H
	movlw	LOW bank1area
	movwf	FSR0L		;FSR０をテーブル(TO)の先頭へ
	movlw	HIGH table+80h	;説明書ではこの「+80h」が不要となっている
	movwf	FSR1H
	movlw	LOW table
	movwf	FSR1L		;FSR１をテーブル(FROM)の先頭へ
	clrf	movecnt		;データ移動数
Movearea
	moviw	INDF1++
	movwi	INDF0++

	decfsz	movecnt,f
	 bra	Movearea


</pre>
<p>　バンク1からバンク3まで240バイト、そしてバンク4の16バイトが結合された状態で仮想メモリ（リニア・メモリ）の16進数2000番地＋80以降に割り当てとなります。ただ、このエリアはバンク指定でも参照できますので、変数領域などが重複する可能性があります。これを防止するには、何か別の指定方法がありそうです。</p><p>　今回、このリニア・メモリの指定方法は問い合わせしても明確な回答がなかったので、上記のコーディングにしてあります。</p>
<p><br />●<b>しかし、デバッガが、、</b><br />　では、テーブルデータ移動した結果を確認してみます。それにはMPLABデバッガ・モードで動かし、リニアの仮想メモリに移動した後にの位置にブレークポイントでプログラムを停止させます。<br />　ここで仮想メモリの内容を表示しようとしても、現在のデバッガはこの仮想メモリが表示できません。とりあえずサポートされるまでは、バンク1からのRAMエリアに換算して位置を見つける必要があります。そこの輝度データ値を変更し、実際の点灯動作を行おうとするデバッグはちょっと大変です。</p>
<p>　このデバッガのメモリ表示機能は80バイトを超えるような受信バッファ設定などで、受信データを確認するなど有効なものです。この不具合は次のバージョンでサポートするような回答でしたので、今回の実験はここで中止し、サポートを待ちましょう。<br /><br />　下記の画面はとりあえず、「File Registers」表示で各バンクに移動した内容を確認したもの。移動したテーブル先頭は0A0番地からで、そこから80バイト（4行分）、次に120番地に続く。<br />　この値を変更することで、蛍の光のような感じや,ろうそくの明かりになるようにできます。最終的な値が確定したら、ソース・コードを修正して完成となります。</p>
<p>&nbsp;</p>
<p>
</p><span class="mt-enclosure mt-enclosure-image" style="display: inline;"><img class="mt-image-center" style="display: block; margin: 0px auto 20px; text-align: center;" alt="j95debugemrpc.jpg" src="http://www.eleki-jack.com/mycom2/goda/j95debugemrpc.jpg" width="487" height="331" /></span>&nbsp;
<p>　これで5回にわたって行った「拡張PIC16Fマイコン 16F1827のPWMを試す」の実験レポートは終了です。今回のPIC16F1827は今までのPIC16の多くの制限がなくなり、使いやすくなっています。これを機会に、従来のPICマイコンから、このマイコンに移ってはいかがでしょうか？</p>
<p>（おことわり）<br />　記事内で公開したテスト・プログラムは、今後のデータシートやMPLAB IDEの状況により間違った例題となる可能性があります。</p>
<p>&nbsp;</p>
<p><br />過去のPWM実験記事</p>
<p>１．PWMでLEDをON/OFF（点滅）実験<br />　拡張PIC16Fマイコン 16F1827のPWMを試す(1)<br />&nbsp; 　<a href="http://www.eleki-jack.com/mycom2/2010/05/pic16f_16f1827pwm1.html">http://www.eleki-jack.com/mycom2/2010/05/pic16f_16f1827pwm1.html</a><br />　拡張PIC16Fマイコン 16F1827のPWMを試す(2)<br />　　<a href="http://www.eleki-jack.com/mycom2/2010/05/pic16f_16f1827pwm2.html">http://www.eleki-jack.com/mycom2/2010/05/pic16f_16f1827pwm2.html</a></p>
<p>２．PWMでLEDの明るさ変化実験<br />　拡張PIC16Fマイコン 16F1827のPWMを試す(3)<br />&nbsp;&nbsp; <a href="http://www.eleki-jack.com/mycom2/2010/06/pic16f_16f1827pwm3.html">http://www.eleki-jack.com/mycom2/2010/06/pic16f_16f1827pwm3.html</a><br />　拡張PIC16Fマイコン 16F1827のPWMを試す(4)<br />　<a href="http://www.eleki-jack.com/mycom2/2010/06/pic16f_16f1827pwm4.html">http://www.eleki-jack.com/mycom2/2010/06/pic16f_16f1827pwm4.html</a></p>
<p>&nbsp;　</p>
<p>&nbsp;</p>
<p align="right">後田　敏</p>]]>
   </content>
</entry>

<entry>
   <title>書籍「動かして学ぶCAN通信」番外編Arduino用自作ライブラリの作成(1)</title>
   <link rel="alternate" type="text/html" href="http://www.eleki-jack.com/mycom2/2010/06/canarduino1.html" />
   <id>tag:www.eleki-jack.com,2010:/mycom2//4.4372</id>
   
   <published>2010-06-10T01:48:30Z</published>
   <updated>2010-06-10T01:28:41Z</updated>
   
   <summary>　Arduinoには便利なライブラリが用意されていますが、今回は、筆者が製作した...</summary>
   <author>
      <name>nakao</name>
      <uri>http://www.wsnak.com/index2.html</uri>
   </author>
   
      <category term="Arduino入門" scheme="http://www.sixapart.com/ns/types#category" />
   
      <category term="動かして学ぶCAN通信" scheme="http://www.sixapart.com/ns/types#category" />
   
   <category term="263" label="AVR" scheme="http://www.sixapart.com/ns/types#tag" />
   <category term="3112" label="Arduino" scheme="http://www.sixapart.com/ns/types#tag" />
   <category term="1514" label="ライブラリ" scheme="http://www.sixapart.com/ns/types#tag" />
   
   <content type="html" xml:lang="ja" xml:base="http://www.eleki-jack.com/mycom2/">
      <![CDATA[　Arduinoには便利なライブラリが用意されていますが、今回は、筆者が製作した基板専用の自作ライブラリなどを紹介します。タイマやチャタリング・キャンセル付きのスイッチ入力など、そのまま、または若干の手直しで汎用的に使えるものも紹介しますので、通常のArduinoユーザにも役に立つと思います。<br />]]>
      <![CDATA[<p>　直接書籍の掲載内容とは関わりがないものもありますが、最終的には、CANドライバのライブラリ化を行うつもりなので、その練習もかねて、有用と思われるライブラリを作ってみました。</p>
<p>　なお、TIMER/COUNTERなどAVRの限られたリソースを使うため、組み合わせによってはほかのライブラリが使えなくなる場合もありますので、留意してください。</p>
<p>&nbsp;</p>
<p><font style="font-size: 1.25em;"><strong>●ライブラリ化について</strong></font></p>
<p>　Arduinoのスケッチには一般的なコンパイラがもつプロジェクト管理用ファイルに相当するものがなく、プロジェクトはフォルダの中身によって管理されています。つまり、スケッチ用フォルダに入っているスケッチ（ソース・ファイル）やヘッダ・ファイルがプロジェクトを構成するすべての要素ということです。</p>
<p>　したがって、ほかのフォルダにある共通関数みたいな共用ソースを参照することはできないようです。そういう使い方はArduinoの使い方に反するということでしょう。</p>
<p>　しかし、共通関数的なものがあると便利ですので、これまでは、同じファイルをスケッチ・フォルダにコピーして使っていました。この方法は一見簡単ですが、バグなどで修正が必要な時など、ファイルが分散するため管理が大変です。そこで登場するのがライブラリです。</p>
<p>　通常のユーザはライブラリを作るよりは、これを利用するだけでこと足りますので、自作する必要がない人は利用法だけ読んでもらってもかまいません。</p>
<p><font style="font-size: 1.25em;"><strong>●ライブラリの構造</strong></font></p>
<p>　資料を調べればちゃんと作り方がわかるのでしょうが、面倒なので、見よう見まねで作ってみました。</p>
<p>　ダウンロードしたライブラリのフォルダを調べて、スケッチと同様、ライブラリのフォルダに適切に作ったライブラリ・フォルダを置くだけで使えるのではないか、という推測の元で、まず簡単なものを作り、使えることを確認しました。</p>
<p>　構造はライブラリ用のフォルダを作成し、その中にソース・ファイルと、同名のヘッダ・ファイルを置きます。スケッチブックを起動し直せば、ファイルメニュー"Sketch"-"Import Library..."のリストにオブジェクトが追加されます（図参照）。</p>
<p>　具体的には、#258基板用のライブラリ "WSN258"というライブラリ・オブジェクトを作るとすると、"WSN258"というフォルダに"WSN25.cpp"、"WSN258.h"を置きます。"*.cpp"がライブラリ・オブジェクトの本体のソース・ファイルです。</p>
<p>　フォルダ名、ファイル名、オブジェクト名は同じでなくてもよいようですが、本家のライブラリはすべて同じにしてありますので、あわせたほうがよいでしょう。</p>
<p>　そのほか、本家ライブラリのフォルダ内を見ると、"keyword.txt"というファイルがありますが、このファイルの用途は不明です。おそらく、検索などのツールで使えるドキュメント管理用のものと思いますが、なくても支障がないようですので、とりあえずは気にしないことにします。</p>
<p>　次の図は、名称は少し違いますが、自作のライブラリ・オブジェクトが追加された状態のスケッチブックのキャプチャ画面です。こんな感じになります。</p>
<p>
</p><p>
</p><p>
</p><span style="display: inline;" class="mt-enclosure mt-enclosure-image"></span>
<p>
</p><span style="display: inline;" class="mt-enclosure mt-enclosure-image"><a onclick="window.open('http://www.eleki-jack.com/mycom2/nakao/book7-2/pic1-1.html','popup','width=503,height=603,scrollbars=no,resizable=no,toolbar=no,directories=no,location=no,menubar=no,status=no,left=0,top=0'); return false" href="http://www.eleki-jack.com/mycom2/nakao/book7-2/pic1-1.html"><img style="text-align: center; margin: 0px auto 20px; display: block;" class="mt-image-center" alt="pic1-1.jpg" src="http://www.eleki-jack.com/mycom2/nakao/book7-2/pic1-1-thumb-400x479.jpg" width="400" height="479" /></a></span><font style="font-size: 1.25em;"><strong></strong></font>
<p><font style="font-size: 1.25em;"><strong></strong></font>&nbsp;</p>
<p><font style="font-size: 1.25em;"><strong>●作成したライブラリ</strong></font></p>
<p>　すでに作成して動作確認が終わり、このブログで紹介する予定のものを挙げます。この他、CAN用のライブラリも追加する予定です。</p>
<p>　後にメソッドを追加するなど機能拡張する可能性もあります。また、フォルダ名、オブジェクト名などを変える可能性もあります。ただ、もし名称が変わったとしても、インスタンスを作成する部分を変更するだけなので、わずかな修正で済みます。</p>
<p>&nbsp;</p>
<p>(1) <strong>WSN258</strong></p>
<p>　このオブジェクトには現在、二つの機能があります。一つは同基板上のシフトレジスタ制御の8個のLEDの点消灯、もう一つは同基板上の2個のスイッチの入力です。スイッチ入力はチャタリング・キャンセラ付きです。</p>
<p>　スイッチ入力は、二つ独立して判別できますので、たとえば、SW1を押したままで、SW2を押してもSW2の押下状態を認識できます。なお、チャタリング・キャンセルを使う場合は、"wCtcTimer1A"や"wCtcTimer2A"など、数10ms程度のタイミングが発生できるものが必要です（詳細は後述）。"wCtcTimer1A/2A"はそのために作成しました。</p>
<p>　スイッチ入力ポートは#258に合わせて固定ですが、少し手直しすれば汎用的に使えると思います。なお、Arduinoのアナログ入力ポートA2、A3にスイッチがつながりますので、そのポートはアナログ入力としては使えません。</p>
<p>　のちにCAN制御を取り入れますが、これは別クラスに分けます。</p>
<p><strong></strong>&nbsp;</p>
<p><strong>(2) wCtcTimer1A</strong></p>
<p>　AVRのTIMER/COUNTER1(16bit)とコンペア・レジスタOCR1Aを使った16ビット・タイマです。CTCモードで作動します。100msなど正確なタイミングが得られます。時計などを製作するときに使用できます。ただし、"Servo"オブジェクトが同タイマを使用するため、同時使用はできません。割り込みは使用していません。</p>
<p><strong></strong>&nbsp;</p>
<p><strong>(3) wCtcTimer2A</strong></p>
<p>　AVRのTIMER・COUNTER2（8ビット）とコンペア・レジスタOCR2Aを使った8ビット・タイマです。CTCモードで作動します。8ms、16msなどのタイミングが得られます。ArduinonのD3とD11ポートのPWM制御との同時使用はできません（通常のI/Oポートとしては使用可能）。割り込みは使用していません。</p>
<p><br /><font style="font-size: 1.25em;"><strong>●クラスについて</strong></font></p>
<p>　クラスとは、オブジェクトを定義する枠組みのようなもので、平たくいうとC言語の構造体の中に関数や変数を定義して一つの"もの"（オブジェクト）としてまとめたようなものです。</p>
<p>　その中にある関数や変数をメンバといいます。オブジェクト指向言語では関数はメソッド、変数はフィールドという場合があります。</p>
<p>　このクラスは構造を定義しただけのものなので、実際に使うためには実体化させる必要があります。この実体のことをインスタンスといいます。</p>
<p>　オブジェクトにアクセスする（関数や変数を使う）場合は、このインスタンスを操作することになります。</p>
<p><font style="font-size: 1.25em;"><strong>●多態性（オーバロード）</strong></font></p>
<p>　オブジェクト指向言語では、同じ名称で引数の数や型が異なる複数のメソッドをもつことができます。これを多態性またはオーバロードといいます。</p>
<p>　一見、一つの関数で、引数の違うオプションがあるように見えますが、実際は、同じ名前の別の関数が定義されています。</p>
<p>　C言語ではこのようなことはできませんが、Arduinoのライブラリでは多用されていて、見かけることも多いと思いますので、スケッチのコードを見る場合は注意してください。</p>
<p><br /><font style="font-size: 1.25em;"><strong>●メンバのスコープ</strong></font></p>
<p>　クラスのメンバには"public"と"private"の二つの属性があります。察しが付くと思いますが、"public"は公開されたメンバで、外部から参照可能なもの、"private"は非公開でクラス内だけで参照可能で、外部からは見えないものです。</p>
<p>　オブジェクト内で使用するだけで、外部からアクセスする必要がないメソッドや変数は"private"で定義します。</p>
<p><font style="font-size: 1.25em;"><strong>●コンストラクタ</strong></font></p>
<p>　クラス名と同じ名称のメソッドで、クラスがインスタンス化されたときに最初に一度だけ実行される初期化関数です。</p>
<p>　変数の初期化や入出力ポートの初期化など、そのオブジェクトが動作に必要な初期化の処理を記述します。</p>
<p>&nbsp;</p>
<p>　次回からオブジェクトの使い方、コードの説明などを行いますが、最初はタイマ・オブジェクトから説明します。</p>
<p></p>
<hr>
参考文献など<br />CQ出版社刊 「動かして学ぶCAN通信」： <a href="http://shop.cqpub.co.jp/hanbai/books/42/42141.html" target="_blank">書籍案内ページ </a><br />WSN258基板のページ（筆者WEBサイト）： <a href="http://www.wsnak.com/kit/258/" target="_blank">http://www.wsnak.com/kit/258/</a> 
<p align="right"><a href="http://www.wsnak.com/index2.html" target="_blank">nakao</a><br /></p>]]>
   </content>
</entry>

<entry>
   <title>拡張PIC16Fマイコン 16F1827のPWMを試す(4)</title>
   <link rel="alternate" type="text/html" href="http://www.eleki-jack.com/mycom2/2010/06/pic16f_16f1827pwm4.html" />
   <id>tag:www.eleki-jack.com,2010:/mycom2//4.4355</id>
   
   <published>2010-06-09T04:37:56Z</published>
   <updated>2010-06-09T01:15:21Z</updated>
   
   <summary>　引き続き拡張PIC16マイコン（PIC16F1827）とその評価基板でアセンブ...</summary>
   <author>
      <name>goda</name>
      
   </author>
   
      <category term="PIC" scheme="http://www.sixapart.com/ns/types#category" />
   
      <category term="PICkit-3" scheme="http://www.sixapart.com/ns/types#category" />
   
      <category term="拡張PIC16マイコン" scheme="http://www.sixapart.com/ns/types#category" />
   
   <category term="5664" label="16F1827" scheme="http://www.sixapart.com/ns/types#tag" />
   <category term="680" label="PWM" scheme="http://www.sixapart.com/ns/types#tag" />
   
   <content type="html" xml:lang="ja" xml:base="http://www.eleki-jack.com/mycom2/">
      <![CDATA[<p>　引き続き拡張PIC16マイコン（PIC16F1827）とその評価基板でアセンブリ言語を使ったプログラムを作成し、PWM機能でLEDの調光実験の第2回目を行ってみます。<br />　今回はLED輝度テスト・プログラムtest13.asmよりもう少しテーブルを大きくしたり、実際に周期割り込みを発生させ、その割り込みルーチン内でデータ変更を行ってみます。<br />　記事内容は16F1827データシートがREV.Bそして、MPLABがV8.50をそれぞれ使った執筆時点のものです。</p>
]]>
      <![CDATA[<p>　今回のプログラムは大きいテーブルと割り込みルーチンの変更を行ったもので、次のとおりです。</p>
<p>　　　割り込みルーチンで動かす　　　<a href="http://www.eleki-jack.com/mycom2/goda/J80test14.txt">テスト・プログラムtest14.asm</a></p>
<p>　このプログラムは、<br />　・256バイトを超えるような大きなテーブル<br />　・周期割り込みルーチンで輝度データを入れ替える<br />を、行っています。<br />　大きなテーブルは同じ輝度データを結合して大きくしました。点灯1回目と2回目がわかるように、2回目の点灯では後にピカピカと点灯するデータを追加してあります。<br />　今回も気がついたところをレポートします。</p>
<p>●<b>割り込みルーチン内ではFSRレジスタのインクリメント機能が使えない</b><br />　すでに述べたようにFSRnにテーブル開始アドレスを入れておけば、データ・フェッチするごとにFSRnの内容をインクリメントしてポインタを更新できます。</p>
<pre>&nbsp;　moviw　　　INDF0++&nbsp;　　；テーブルよりデータ・フェッチしポインタ・アップ<br />&nbsp;　banksel&nbsp;　CCPR1L&nbsp;　　　;bank 5<br />&nbsp;　movwf &nbsp;　　CCPR1L &nbsp;　　; Duty データセット</pre>
<p>　しかし、割り込みルーチン内ではMOVIW命令でFSR0レジスタにテーブル・インデックス(tblx)値を加えてフェッチする必要があります。これは拡張PIC16マイコンの新機能により、割り込みルーチンから出るときに割り込み入り口で保存したFSRｎの内容に戻してしまうためです。<br />　つまり、割り込みルーチンで「MOVIW INDF0++」のようにインクリメントしても、そのアドレス値は次回の割り込み処理時に反映されません。<br /><br />　このため毎回16ビット長のテーブル・インデックス値をテーブルの開始アドレスがあるFSR0レジスタに加算処理を行いテーブル・フェッチの間接アドレスを計算します。その後にMOVFW命令の間接アドレス処理「MOVFW　INDF0」でプログラム・エリアのテーブルから輝度データをWレジに入れます。そして16ビット長のテーブル・インデックス値をインクリメント処理します。</p>
<p>●<b>16ビット演算とテーブル・フェッチについて</b><br />　割り込みルーチン内では下記のコーディングのように、テーブルのポインタ演算が必要になります。取り出そうとする値のある位置はテーブルの先頭を示すポインタにインデックス値を加算します。</p>
<p>　1) FSR0にtblxを加える16ビット長（tblxH、tblxL）の演算を行います。<br />　2) 次に、そこのテーブル・ポインタからデータをフェッチしWレジスタに入れます。<br />　3) 最終的に取り出した輝度データをCCPR1Lレジスタにストアします。</p>
<pre>&nbsp;　movfw&nbsp;　　tblxL<br />&nbsp;　addwf&nbsp;　　FSR0L,f<br />&nbsp;　movfw&nbsp;　　tblxH<br />&nbsp;　addwfc&nbsp;　　FSR0H,f&nbsp;&nbsp;　;2バイト長の加算(FSR0+tblx)<br />&nbsp;　movfw&nbsp;　　INDF0&nbsp;&nbsp;　　　;プログラム・エリアのTableから輝度データをもってくる<br />&nbsp;　banksel&nbsp;　CCPR1L&nbsp;&nbsp;　;bank 5<br />&nbsp;　movwf &nbsp;　　CCPR1L &nbsp;&nbsp;; Duty データセット</pre>
<p>　ここで使ったADDWFC命令は拡張PIC16マイコンで新しく追加された命令で、下位バイトの演算した結果、桁上がりが出たときに、上位バイトに加えるものです。また、減算命令にはSUBWFBという新しい命令があります。これで複数バイト長の加減算が簡単にできます。<br />　従来PIC16では、STATUSレジスタのキャリー・ビットを見て1を加算する/しないかの処理が必要でした。このキャリー・ビット処理のあるADDWFC/SUBWFB命令は2バイト長以外でも、4バイト長の演算などのコーディング・ステップを減らすことができます。</p>
<p>　ただ、困ったことに拡張PIC16マイコンでも比較命令がないので、テーブル・エンドをチェックする方法に工夫が必要です。テーブル・サイズが256を超えると、比較するデータは16ビット演算が必要となります。今回は大小チェックでなく、一致チェックでテーブル・エンドの確認を行っています。</p>
<p><br />●<b>指定したパルス幅データは次サイクルで反映される</b><br />　知られていることですが、PWM機能で指定されるパルス幅はプログラムでCCPRxLレジスタにセットしても、CCPRｘHレジスタの値で動作します。CCPRｘLに設定したパルス幅データはセットした周期の終わり、「タイマｘとPRｘレジスタが一致した割り込みセット」のタイミングでCCPRｘHレジスタに移動されます。<br />　つまり、最初にタイマ動かしても、最初のパルス幅は「設定できないCCPRｘHの値」で動作しますので、1発目のパルス幅は不定になります。1発目のパルスが終わった周期割り込みで、最初にCCPRｘLセットしたパルス幅の値がCCPRｘHレジスタに入ります。つまり、指定したパルス幅のパルスは２発目に出ることになります。ただ、この仕様でも、今回の例となるLEDの明かりや音などでは問題になりません。</p>
<p>
</p><span class="mt-enclosure mt-enclosure-image" style="display: inline;"><img class="mt-image-center" style="display: block; margin: 0px auto 20px; text-align: center;" alt="J81pwmzu.JPG" src="http://www.eleki-jack.com/mycom2/goda/J81pwmzu.JPG" width="489" height="239" /></span>　　　　　　　　　　タイミング図<br /><br />
<p>　このように仕様どおりに動くため、データシートに記載されている「22.0 DATA SIGNAL MODULATOR」に示すような用途においては注意が必要です。何度もタイマON/OFFしてデータ生成し、1発目の波形も使いたいときにはなんらかの工夫が必要のようです。</p>
<p>●（おまけ）<b>PICkit2黒ボタンでの書込実験OK</b><br />　PICkit2アダプタはMPLABにおいて、PIC16F1827のデバッグどころか書き込みもサポートしていません。しかし、先のレポートのように、PICkit2専用の書き込みプログラムでは、このマイコンへの書込をサポートしています。<br />　そこで、退役した初期の黒ボタンPICkit2アダプタ（MPLABでデバッグ・サポートに難あり）でも試してみました。</p>
<p>&nbsp;　写真は旧バージョンPICkit2（通称黒ボタン）に自作ZIFソケット接続、それにPIC16F1827を載せ書込み、LEDを接続して動かしたもの。</p>
<p>&nbsp;</p>
<p>
</p><span class="mt-enclosure mt-enclosure-image" style="display: inline;"><img class="mt-image-center" style="display: block; margin: 0px auto 20px; text-align: center;" alt="J82IMG_0777.jpg" src="http://www.eleki-jack.com/mycom2/goda/J82IMG_0777.jpg" width="459" height="266" /></span>
<p>&nbsp;</p>
<p>　次回の最終回では、プログラム・エリアの輝度データをRAMエリアに移してから動かす実験をします。</p>
<p>&nbsp;</p>
<p>過去のPWM実験記事</p>
<p>１．PWMでLEDをON/OFF（点滅）実験<br />　拡張PIC16Fマイコン 16F1827のPWMを試す(1)<br />&nbsp; 　<a href="http://www.eleki-jack.com/mycom2/2010/05/pic16f_16f1827pwm1.html">http://www.eleki-jack.com/mycom2/2010/05/pic16f_16f1827pwm1.html</a><br />　拡張PIC16Fマイコン 16F1827のPWMを試す(2)<br />　　<a href="http://www.eleki-jack.com/mycom2/2010/05/pic16f_16f1827pwm2.html">http://www.eleki-jack.com/mycom2/2010/05/pic16f_16f1827pwm2.html</a></p>
<p>２．PWMでLEDの明るさ変化実験<br />　拡張PIC16Fマイコン 16F1827のPWMを試す(3)<br />&nbsp;&nbsp; <a href="http://www.eleki-jack.com/mycom2/2010/06/pic16f_16f1827pwm3.html">http://www.eleki-jack.com/mycom2/2010/06/pic16f_16f1827pwm3.html</a></p>
<p align="right"><br />後田　敏</p>]]>
   </content>
</entry>

<entry>
   <title>HC08マイコンの使い方QY4A編 -《85》 自動ウェイクアップ（AWU）（2）</title>
   <link rel="alternate" type="text/html" href="http://www.eleki-jack.com/mycom2/2010/06/hc08qy4a_85_awu2.html" />
   <id>tag:www.eleki-jack.com,2010:/mycom2//4.4357</id>
   
   <published>2010-06-06T22:28:03Z</published>
   <updated>2010-06-07T02:21:25Z</updated>
   
   <summary>　自動ウェイクアップ・モジュール（AWU）を使ったテスト・プログラムを動かしてみ...</summary>
   <author>
      <name>kawano</name>
      <uri>http://www.cts-net.ne.jp/~kawano-r/</uri>
   </author>
   
      <category term="HC08マイコンの使い方QY4A編" scheme="http://www.sixapart.com/ns/types#category" />
   
   <category term="5543" label="AWU" scheme="http://www.sixapart.com/ns/types#tag" />
   <category term="5773" label="アナログ・テスタ" scheme="http://www.sixapart.com/ns/types#tag" />
   <category term="2598" label="キーボード割り込み" scheme="http://www.sixapart.com/ns/types#tag" />
   <category term="5774" label="スリープ状態" scheme="http://www.sixapart.com/ns/types#tag" />
   <category term="2603" label="自動ウェイクアップ" scheme="http://www.sixapart.com/ns/types#tag" />
   
   <content type="html" xml:lang="ja" xml:base="http://www.eleki-jack.com/mycom2/">
      <![CDATA[<p>　自動ウェイクアップ・モジュール（AWU）を使ったテスト・プログラムを動かしてみます。 非常に短いサイクルで間欠的に変化する回路電流を安定に読み取るため、アナログ・テスタを用いました。<br />　</p>
<p></p>
<span class="mt-enclosure mt-enclosure-image" style="DISPLAY: inline"><a onclick="window.open('http://www.eleki-jack.com/mycom2/hc08_tester01.html','popup','width=800,height=524,scrollbars=no,resizable=no,toolbar=no,directories=no,location=no,menubar=no,status=no,left=0,top=0'); return false" href="http://www.eleki-jack.com/mycom2/hc08_tester01.html"><img class="mt-image-center" style="DISPLAY: block; MARGIN: 0px auto 20px; TEXT-ALIGN: center" height="262" alt="hc08_tester01.jpg" src="http://www.eleki-jack.com/mycom2/hc08_tester01-thumb-400x262.jpg" width="400" /></a></span>]]>
      <![CDATA[<p align="center">手持ちのアナログ・テスタが久しぶりに活躍した<br />三和電気計器（株） T-50BZ（製造終了）</p>
<p>　<br /><strong><font color="#0000cc">◆ 自動ウェイクアップ（AWU） を使ったプログラムの動作仕様</font></strong><br />　下図に示す動作仕様で実験を行います。 本当は専用のテスト・ボードを用意したほうが測定結果が正確に出るのですが、実験を簡単にするためいつもの HC08スタータ・ボード・キットを使用します。<br />　</p>
<p></p>
<span class="mt-enclosure mt-enclosure-image" style="DISPLAY: inline"><a onclick="window.open('http://www.eleki-jack.com/mycom2/flow_chart_awu011.html','popup','width=550,height=584,scrollbars=no,resizable=no,toolbar=no,directories=no,location=no,menubar=no,status=no,left=0,top=0'); return false" href="http://www.eleki-jack.com/mycom2/flow_chart_awu011.html"></a></span>
<span class="mt-enclosure mt-enclosure-image" style="DISPLAY: inline"><a onclick="window.open('http://www.eleki-jack.com/mycom2/flow_chart_awu012.html','popup','width=548,height=584,scrollbars=no,resizable=no,toolbar=no,directories=no,location=no,menubar=no,status=no,left=0,top=0'); return false" href="http://www.eleki-jack.com/mycom2/flow_chart_awu012.html"><img class="mt-image-center" style="DISPLAY: block; MARGIN: 0px auto 20px; TEXT-ALIGN: center" height="426" alt="flow_chart_awu01.gif" src="http://www.eleki-jack.com/mycom2/flow_chart_awu01-thumb-400x426.gif" width="400" /></a></span>
<p>　<br />　このフローチャートに沿って作られたプログラムは、次のような動きになります。</p>
<blockquote>　<font color="#00a000">【 プログラムの動き 】</font><br />&nbsp;・ リセットが解除されてプログラムが動き始めたら、最初に初期設定を<br />　　行います（AWU 有効、キーボード割り込み許可）。<br />&nbsp;・ 動きを確認しやすいように、テスト用の出力ポート（PTA5） を反転します。<br />&nbsp;・ A-D変換待ちのループを利用して、待つ間に WDT クリアを行います。<br />&nbsp;・ 変換結果が VDD の 5分の 1 より小さいとき、スリープ状態にします。<br />&nbsp;・ CPUをストップ・モードにすると、AWU モジュールが動作開始します。<br />&nbsp;・ AWU タイマ時間が経過すると、キーボード割り込みが発生して CPU <br />　　ストップ・モードから抜け出します（*1）。<br />&nbsp;・ キーボード割り込み処理で ACKK = 1 を行い、AWU ラッチをクリアします。<br />　 （KBI ラッチはキーボード割り込みが開始された時点でクリア）<br />&nbsp;・ VR1 ツマミを左に回した状態ではスリープ状態が続き、AWU によって<br />　　間欠的に CPUストップ・モードから抜け出してメイン・ループを回り続けます。<br />&nbsp;・ VR1 ツマミを右に回して、変換結果が VDD の 5分の 1 以上になると <br />　　LED を点灯し、通常状態となります。 このときは CPU ストップ・モードに<br />　　なりません。<br />&nbsp;・ VR1 ツマミを左に回して、変換結果が VDD の 5分の 1 より小さくなると<br />　　再びスリープ状態になります。</blockquote>
<p>　<br /><strong><font color="#0000cc">◆ ユーザ・モード・モニタ入りマイコン用 C言語プログラムを動かしてみる</font></strong><br />　ユーザ・モード・モニタ入りマイコンのためのプログラムをプロジェクトごと圧縮して <a href="http://micon.arrow.jp/uploads/files/hc08_awu01u.zip" target="_blank">hc08_awu01u.zip</a> に保存しました。 ご利用ください。 main.c の主要部分を書き出します。</p>
<blockquote>
<p>//*************************<br />// マクロの定義<br />//*************************</p>
<p>#define DISABLE&nbsp;&nbsp;&nbsp;&nbsp; ( 0 )<br />#define ENABLE&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ( 1 )</p>
<p>#define PORT_CHECK&nbsp; ( PTA_PTA5 )</p>
<p>#define ADCH_VR&nbsp;&nbsp;&nbsp;&nbsp; ( 2 )&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // AD2(PTA4)<br />#define <font color="#00a000">VR_LOW&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ( 255 / 5 )</font></p>
<p>#define PORT_LED&nbsp;&nbsp;&nbsp; ( PTA_PTA1 )<br />#define LED_ON&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ( 0 )<br />#define LED_OFF&nbsp;&nbsp;&nbsp;&nbsp; ( 1 )</p>
<p>//*************************<br />// メイン処理<br />//*************************</p>
<p>void main( void ) {<br />&nbsp;&nbsp;&nbsp; init_hardware( );<br />&nbsp;&nbsp;&nbsp; init_PORT( );<br />&nbsp;&nbsp;&nbsp; init_ADC( ); <br />&nbsp;&nbsp;&nbsp; init_KBD( ENABLE ); <br />&nbsp;&nbsp;&nbsp; <br />&nbsp;&nbsp;&nbsp; EnableInterrupts;<br />&nbsp;&nbsp;&nbsp; <br />&nbsp;&nbsp;&nbsp; for ( ; ; ){<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; PORT_CHECK = ~PORT_CHECK;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ADSCR_ADCH = ADCH_VR;&nbsp;&nbsp; // A-D開始<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <font color="#00a000">do {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __RESET_WATCHDOG( );<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } while ( !ADSCR_COCO );</font>&nbsp; // A-D完了待ち</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if ( ADRL &lt; VR_LOW ){<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; PORT_LED = LED_OFF;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; asm( "STOP" );<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } else {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <font color="#ff8000">PORT_LED = LED_ON;</font><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />&nbsp;&nbsp;&nbsp; }<br />}</p>
<p>//*************************<br />// リセット後の初期化処理<br />//*************************</p>
<p>void init_hardware( void ) {<br />&nbsp;&nbsp;&nbsp; CONFIG2 = 0x00;&nbsp;&nbsp;&nbsp;&nbsp; // IRQピン無効<br />&nbsp;&nbsp;&nbsp; <font color="#ff8000">CONFIG1 = 0x82;&nbsp;&nbsp;&nbsp;&nbsp; // COPRS=1、SSREC=0、STOP有効、COP有効<br />//&nbsp; CONFIG1 = 0x02;&nbsp;&nbsp;&nbsp;&nbsp; // COPRS=0、SSREC=0、STOP有効、COP有効<br />//&nbsp; CONFIG1 = 0x86;&nbsp;&nbsp;&nbsp;&nbsp; // COPRS=1、SSREC=1、STOP有効、COP有効</font><br />&nbsp;&nbsp;&nbsp; OSCTRIM = Optional; <br />}</p>
<p>void init_ADC( void ) {<br />&nbsp;&nbsp;&nbsp; ADCLK = 0x32;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 3.2÷2=1.6MHz、8ビット、長期<br />&nbsp;&nbsp;&nbsp; ADSCR = 0x1F;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 単独変換、停止中<br />}</p>
<p>void init_KBD( U1 use ) {<br />&nbsp;&nbsp;&nbsp; KBSCR_IMASKK = 1;&nbsp;&nbsp; // KBI割り込み禁止<br />&nbsp;&nbsp;&nbsp; KBIPR = 0x00;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 極性は全てL（立下り）有効<br />&nbsp;&nbsp;&nbsp; KBIER = 0x40;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // AWU 使用<br />&nbsp;&nbsp;&nbsp; KBSCR_ACKK = 1;&nbsp;&nbsp;&nbsp;&nbsp; // KBIラッチクリア<br />&nbsp;&nbsp;&nbsp; if ( use ){<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; KBSCR_IMASKK = 0;&nbsp;&nbsp; // KBI割り込み許可<br />&nbsp;&nbsp;&nbsp; }<br />}</p>
<p>//*************************<br />// 割り込み処理<br />//*************************</p>
<p>// Keyboard Wakeup<br />#pragma TRAP_PROC<br />void _KBD_Interrupt( void ) {<br />&nbsp;&nbsp;&nbsp; <font color="#00a000">KBSCR_ACKK = 1;</font>&nbsp;&nbsp;&nbsp;&nbsp; // AWUラッチとKBIラッチをクリア<br />}<br /></p></blockquote>
<p>　「A-D変換待ちのループを利用して、待つ間に WDT クリア」 の部分ですが、必ず1回は WDT クリアを実行する必要があるため、 while 文ではなく do ～ while 文を使っています。</p>
<p><br />　テスト・プログラムが完成したので、さっそく動かしてみましょう。<br />　HC08スタータ・ボードを使って ユーザ・モード・モニタ入り QY4Aマイコン（KMC908QY4A）に書き込んだら、デバッガ画面を終了して HC08スタータ・ボードの POWERスイッチをオフにします。 ジャンパ類をユーザ・モード・モニタ入りマイコンのスタンド・アロンの設定にしてください。 JP1ショート（電流測定時はジャンパ・リンクなし）、JP2ショート、JP3は1-2間ショートまたはなし（今回は 1-2間ショート）、JP4は 1-2間ショート、VR1任意（実験時は左いっぱいまたは右いっぱい）、JP5～JP7ショート、<font color="#ff8000">JP8ジャンパ・リンクなし</font>。</p>
<p>　今回は動かす前に、二つほど注意点があります。 <font color="#00a000"><strong>JP8 を外す</strong></font> こと、そしてパソコンにつなぐ <font color="#00a000"><strong>D-Sub9 ピンのコネクタを外す</strong></font> ことを忘れないようにしてください。 これは電流を測定中に余計な電流を流さないためです。 それから、今回の実験は電源電圧 5V を使いました。 準備ができたら POWERスイッチをオンします。</p>
<p>　ツマミを左に回すと LED が消灯、右に回すと LED が点灯したでしょうか？　どうということのないテスト・プログラムですが、LED が消灯しているときはスリープ状態になっていて、消費電流がぐっと抑えられています。 そして、<font color="#ff8000">CPUストップ・モードを利用しているにも関わらず、ツマミを右に回すときちんと反応してウェイクアップできる</font>というのがポイントなのです。</p>
<p>　<br /><strong><font color="#0000cc">◆ テスト・プログラムを動かして測定を行う</font></strong><br />　動くところまで確認が済んだら、次はいよいよ消費電流を測定します。 また同時に、テスト出力ポートのようすをオシロスコープで観察してみましょう。</p>
<p>　電流の測定は <a href="http://www.eleki-jack.com/mycom2/2010/04/hc08qy4a_79_1.html" target="_blank">第79回</a> の要領で行います。 ただし今回はプッシュ・スイッチは関係ありません。 また、筆者が所有している安価な DMM（ディジタル・マルチ・メータ）には電流測定時に実効値または平均値を表示する機能がなかったため、アナログ・テスタを使用して電流測定を行っています。 オシロスコープに関しては <a href="http://www.eleki-jack.com/mycom2/2010/05/hc08qy4a_82_brkmon1.html" target="_blank">第82回</a> で説明したとおりです。</p>
<p>　測定の結果からお見せします。 いずれも JP8 と D-Sub9 ピン・コネクタを外しています。</p>
<p>&nbsp; </p>
<span class="mt-enclosure mt-enclosure-image" style="DISPLAY: inline"><a onclick="window.open('http://www.eleki-jack.com/mycom2/hc08_table_awu01.html','popup','width=605,height=211,scrollbars=no,resizable=no,toolbar=no,directories=no,location=no,menubar=no,status=no,left=0,top=0'); return false" href="http://www.eleki-jack.com/mycom2/hc08_table_awu01.html"><img class="mt-image-center" style="DISPLAY: block; MARGIN: 0px auto 20px; TEXT-ALIGN: center" height="167" alt="hc08_table_awu01.gif" src="http://www.eleki-jack.com/mycom2/hc08_table_awu01-thumb-480x167.gif" width="480" /></a></span>
<p>　いずれも LVI を使用する設定になっています（<a href="http://www.eleki-jack.com/mycom2/2010/04/hc08qy4a_79_1.html" target="_blank">第79回</a> の表を参照）。</p>
<p><br />　No．1 はマイコンをソケットから抜き取った状態で電源電流を計っています。</p>
<p></p>
<span class="mt-enclosure mt-enclosure-image" style="DISPLAY: inline"><a onclick="window.open('http://www.eleki-jack.com/mycom2/hc08_awu_no1.html','popup','width=800,height=602,scrollbars=no,resizable=no,toolbar=no,directories=no,location=no,menubar=no,status=no,left=0,top=0'); return false" href="http://www.eleki-jack.com/mycom2/hc08_awu_no1.html"><img class="mt-image-center" style="DISPLAY: block; MARGIN: 0px auto 20px; TEXT-ALIGN: center" height="240" alt="hc08_awu_no1.jpg" src="http://www.eleki-jack.com/mycom2/hc08_awu_no1-thumb-320x240.jpg" width="320" /></a></span>
<p>　すべて 直流30mAレンジ で計ったので、右端に 300 と書かれたスケールを見ます。 つまりメータの針が 300 を指したとき 30mA というわけです。 この写真では 11．2mA と読み取れます。 <font color="#00a000">アナログ式の計器類を読むときは <strong>「最小目盛の 10分の 1 まで読む」</strong> というのが原則です。</font> これがボード上のマイコン以外の回路に流れている電流です。</p>
<p>　<br />　No．2 は、マイコンをソケットに挿してツマミを左に回した状態です。 このときはスリープ状態で、LED は消灯しています。 写真から 11．3mA と読み取れます。 つまり、<font color="#00a000">スリープ状態のときはマイコンに 0．1mA が流れている</font>ことになります。</p>
<p></p>
<span class="mt-enclosure mt-enclosure-image" style="DISPLAY: inline"><a onclick="window.open('http://www.eleki-jack.com/mycom2/hc08_awu_no2.html','popup','width=800,height=602,scrollbars=no,resizable=no,toolbar=no,directories=no,location=no,menubar=no,status=no,left=0,top=0'); return false" href="http://www.eleki-jack.com/mycom2/hc08_awu_no2.html"><img class="mt-image-center" style="DISPLAY: block; MARGIN: 0px auto 20px; TEXT-ALIGN: center" height="240" alt="hc08_awu_no2.jpg" src="http://www.eleki-jack.com/mycom2/hc08_awu_no2-thumb-320x240.jpg" width="320" /></a></span>
<p>　<br />　No．3 は、ツマミを右に回してウェイクアップさせたところです。 LED は点灯しています。 写真から 24．6mA と読み取れます。 このときマイコンには 13．4mA 流れていることになります。 ただし、このときは LED が点灯しているのでその分の電流も含まれています。</p>
<p></p>
<span class="mt-enclosure mt-enclosure-image" style="DISPLAY: inline"><a onclick="window.open('http://www.eleki-jack.com/mycom2/hc08_awu_no3.html','popup','width=800,height=602,scrollbars=no,resizable=no,toolbar=no,directories=no,location=no,menubar=no,status=no,left=0,top=0'); return false" href="http://www.eleki-jack.com/mycom2/hc08_awu_no3.html"><img class="mt-image-center" style="DISPLAY: block; MARGIN: 0px auto 20px; TEXT-ALIGN: center" height="240" alt="hc08_awu_no3.jpg" src="http://www.eleki-jack.com/mycom2/hc08_awu_no3-thumb-320x240.jpg" width="320" /></a></span>
<p>　<br />　No．4 は、通常モードでも LED が点灯しないようにテスト・プログラムを少し変更したものです。 上のプログラム・リストの</p>
<p>　　　　<font color="#ff8000">PORT_LED = LED_ON;</font></p>
<p>という部分をコメント化して、マイコンに書き込んで実験を行いました。</p>
<p></p>
<span class="mt-enclosure mt-enclosure-image" style="DISPLAY: inline"><a onclick="window.open('http://www.eleki-jack.com/mycom2/hc08_awu_no4.html','popup','width=800,height=602,scrollbars=no,resizable=no,toolbar=no,directories=no,location=no,menubar=no,status=no,left=0,top=0'); return false" href="http://www.eleki-jack.com/mycom2/hc08_awu_no4.html"><img class="mt-image-center" style="DISPLAY: block; MARGIN: 0px auto 20px; TEXT-ALIGN: center" height="240" alt="hc08_awu_no4.jpg" src="http://www.eleki-jack.com/mycom2/hc08_awu_no4-thumb-320x240.jpg" width="320" /></a></span>
<p>　結果は 16．2mA で、No．1 と比較すると<font color="#00a000">スリープしない場合のマイコンの電流は 5．0mA</font> でした。 <a href="http://www.eleki-jack.com/mycom2/2010/04/hc08qy4a_79_1.html" target="_blank">第79回</a> の表を見ると標準値で 6．0mA となっているので、妥当な値と言えるでしょう。</p>
<p>　<br />　No．5 は、LED が点灯できるように先ほどの変更個所を元に戻し、さらに CONFIG1 の設定値を $02 に変更したプログラムをマイコンに書き込んで測定を行いました。 これは COPRS = 0 としたことで、自動ウェイクアップの期間を長く設定したものです。</p>
<p></p>
<span class="mt-enclosure mt-enclosure-image" style="DISPLAY: inline"><a onclick="window.open('http://www.eleki-jack.com/mycom2/hc08_awu_no5.html','popup','width=800,height=602,scrollbars=no,resizable=no,toolbar=no,directories=no,location=no,menubar=no,status=no,left=0,top=0'); return false" href="http://www.eleki-jack.com/mycom2/hc08_awu_no5.html"><img class="mt-image-center" style="DISPLAY: block; MARGIN: 0px auto 20px; TEXT-ALIGN: center" height="240" alt="hc08_awu_no5.jpg" src="http://www.eleki-jack.com/mycom2/hc08_awu_no5-thumb-320x240.jpg" width="320" /></a></span>
<p>　写真から 11．3mA と読み取れます。 CPU がウェイクアップして A-D を行う周期が長くなったので、わずかに電流が減るかと思ったのですが全体に影響はなかったようです。<br />　ちなみに、それぞれの実験では電流だけでなくテスト出力ポートが反転する時間も観測しています。 表に書き込んでいますので参照してください。 この No．5 に関しては、反転の時間が 602．2ms となっています。 約0．6 秒ということは、ツマミをクルックルッと回したときに反応が遅すぎて違和感がある場合があります。 自然光の明るさセンサなどの応用にはよいかもしれませんが、人が操作する場合にはちょっと反応が鈍すぎるでしょう。</p>
<p>　<br />　No．6 は、CONFIG1 を $86 にしてマイコンに書き込み、測定を行いました。 これは COPRS = 1 に戻し、SSREC = 1 としたことで、CPUストップ・モードからの復帰にかかる待機時間を短く設定したものです。</p>
<p></p>
<span class="mt-enclosure mt-enclosure-image" style="DISPLAY: inline"><a onclick="window.open('http://www.eleki-jack.com/mycom2/hc08_awu_no6.html','popup','width=800,height=602,scrollbars=no,resizable=no,toolbar=no,directories=no,location=no,menubar=no,status=no,left=0,top=0'); return false" href="http://www.eleki-jack.com/mycom2/hc08_awu_no6.html"><img class="mt-image-center" style="DISPLAY: block; MARGIN: 0px auto 20px; TEXT-ALIGN: center" height="240" alt="hc08_awu_no6.jpg" src="http://www.eleki-jack.com/mycom2/hc08_awu_no6-thumb-320x240.jpg" width="320" /></a></span>
<p>　結果は、11．3mA と読み取れます。 電流は変わりありませんが、表を見ると No．1 と比べてテスト出力の反転する時間が少し短くなっています。 <font color="#00a000">その差 0．32ms</font> となりました。</p>
<p>　たかだか 320μs の短縮で、何か良いことがあるのでしょうか？　あります。 ちゃ～んとあるんです。 たとえば、 CPU ストップ・モードから、通信ラインに信号が来たことによってウェイクアップさせる場合など、少しでも速く復帰できた方が有利です。 もっとも、そういったシステムの場合には 「通信相手の CPU をウェイクアップさせる信号を送信するときには、同じ内容のフレームを続けて 2回送信する」 など、エラーに強い構成をとるのが普通です。</p>
<p><br />　上記と同様の実験ができるように、ユーザ・モード・モニタ入りではない QY4A のためのプログラムを <a href="http://micon.arrow.jp/uploads/files/hc08_awu01.zip" target="_blank">hc08_awu01.zip</a> に保存しましたのでご利用ください。 電流を測定するときは、ジャンパ類の設定をユーザ・モード・モニタ入りマイコンで説明したのと同一にして条件をそろえてください。</p>
<p>　<br />　次回は、キー・マトリクス・スイッチを使ってみる予定です。</p>
<p><br />（*1）　この時点では CPU がストップ・モードから 「ウェイクアップ」 していますが、アプリケーションとして見ると 「スリープ状態」 のままである、と見ることができます。 アプリケーションとして見た場合は、ツマミを右に回して LED が点灯したときに 「ウェイクアップ」 したと考えられます。</p>
<p>&nbsp;</p>
<p>　『参考文献』<br /><font color="#00008b"><a href="http://shop.cqpub.co.jp/hanbai/books/46/46051.html" target="_blank"><font color="#00008b">「試しながら学ぶHC08マイコン入門」</font></a>&nbsp;</font>（CQ出版）<br />　　第9章　USB-HC08デバッグ・ツールを自作する<br />　　第10章　統合開発環境CodeWarriorを使ってみる<br />　　Appendix F　KMC908QY4Aユーザ・モード・モニタ入りマイコンの知識<br />筆者のホームページ　<a href="http://www.cts-net.ne.jp/~kawano-r/" target="_blank"><font color="#00008b">『マイコン工作の実験室』</font></a> </p>
<p align="right">組み込みエンジニア　KAWANO<br /></p>]]>
   </content>
</entry>

<entry>
   <title>拡張PIC16Fマイコン 16F1827のPWMを試す(3)</title>
   <link rel="alternate" type="text/html" href="http://www.eleki-jack.com/mycom2/2010/06/pic16f_16f1827pwm3.html" />
   <id>tag:www.eleki-jack.com,2010:/mycom2//4.4354</id>
   
   <published>2010-06-04T06:24:40Z</published>
   <updated>2010-06-04T05:49:18Z</updated>
   
   <summary>　拡張PIC16マイコン（PIC16F1827）とその評価基板でアセンブリ言語を...</summary>
   <author>
      <name>goda</name>
      
   </author>
   
      <category term="MPLAB" scheme="http://www.sixapart.com/ns/types#category" />
   
      <category term="PIC" scheme="http://www.sixapart.com/ns/types#category" />
   
      <category term="拡張PIC16マイコン" scheme="http://www.sixapart.com/ns/types#category" />
   
   
   <content type="html" xml:lang="ja" xml:base="http://www.eleki-jack.com/mycom2/">
      <![CDATA[<p>　拡張PIC16マイコン（PIC16F1827）とその評価基板でアセンブリ言語を使ったプログラムを作成し、PWM機能を確認してみます。第3回目以降はPWMによるLEDの輝度変化を行ってみます（合計3回あります）。<br />　記事内容はMPLABのV8.50、PIC16F1827のデータシート（REV.B)を使った執筆時点のもので、拡張PIC16マイコン関連で若干メーカの説明と異なるものがあります。</p>
<p>&nbsp;</p>]]>
      <![CDATA[<p>●<b>輝度変化させるには</b><br />　LEDの輝度変化（調光）はPWM動作のDUTY（パルス幅）を高速に変化させることで可能になります。調光動作において、DUTY可変となるパルス幅の指定値はPRｘレジスタで指定される周期割り込みごとにCCPRxLレジスタに入れ切り替えます。明かりは一定時間内の切り替え数を多くすることで滑らかに切り替わります。</p>
<p>　PIC16F1827で動作するテスト・プログラム13は蛍のような感じで、じわ～とLEDを点灯させるものです。これを実現させるために、<br />　　１）多くのパルス幅データをテーブルから取り出す<br />　　２）タイミングにあわせてパルス幅データを指定レジスタに設定する<br />などを行います。</p>
<p>参考資料　PIC16F1827のデータシート（REV.B)<br />　<a href="http://ww1.microchip.com/downloads/en/DeviceDoc/41391B.pdf">http://ww1.microchip.com/downloads/en/DeviceDoc/41391B.pdf</a></p>
<p><br />　このプログラムはPWM波形をCCP1へ出力、タイマがTMR2をそれぞれ使用しています。輝度データはプログラムエリアより持ってきています。<br />　ここでtblxはテーブルのn番目を示すインデックス変数、tableはテーブルの先頭アドレス・ポインタです。</p>
<p>　動作とTEST13のコーディングは、<br />　１）初期設定　FSR0にテーブル・アドレス設定<br /><br />&nbsp;　clrf&nbsp;　　　tblx<br />　&nbsp;movlw&nbsp;　HIGH table+80h&nbsp;　;テーブル先頭アドレス上位バイト（＊＊＊）<br />&nbsp;　movwf&nbsp;　FSR0H<br />&nbsp;　movlw&nbsp;　LOW table<br />&nbsp;　movwf&nbsp;　FSR0L&nbsp;&nbsp;　;FSRをテーブルの先頭へ</p>
<p>　２）CCP1+TMR2でPWM動作するよう設定<br />　　　　(省略）</p>
<p>　３）TMR2スタートさせる<br /><br />&nbsp;　bsf &nbsp;T2CON,TMR2ON</p>
<p>　４）周期ごとの割り込みフラグがセットするのを待つ。セットしたら５）へ</p>
<p>pwmloop<br />&nbsp;　btfss&nbsp;　PIR1,TMR2IF&nbsp;　;PWM周期割り込み？<br />&nbsp;　 bra&nbsp;　　pwmloop&nbsp;&nbsp;　　　;NO</p>
<p><br />　５）プログラム・エリアのテーブルよりパルス幅値を取り出しCCPR1Lレジスタに設定、</p>
<p>&nbsp;　bcf&nbsp;　　　PIR1,TMR2IF&nbsp;　　;YES, 周期割り込みフラグをリセット<br />　&nbsp;moviw&nbsp;　INDF0++&nbsp;&nbsp;　　　　;Tableから輝度データ　＆アドレス・アップ<br />&nbsp;　banksel&nbsp;CCPR1L&nbsp;&nbsp;　　　　;bank 5<br />&nbsp;　movwf &nbsp;　CCPR1L &nbsp;&nbsp;　　　; パルス幅値をセットする&nbsp;<br />&nbsp;　movlb&nbsp;　0&nbsp;&nbsp;　　　　　　　　　;bank0<br />　&nbsp;incfsz&nbsp;　tblx,f&nbsp;&nbsp;　　　　　　;Tableエンド?<br />&nbsp; 　bra&nbsp;　　pwmloop&nbsp;&nbsp;　　　　;NO</p>
<p>　６）テーブル超えたら先頭に戻し４）へ<br /><br />&nbsp;　clrf&nbsp;　　　tblx<br />&nbsp;　movlw&nbsp;　HIGH table+80h&nbsp;　;テーブル先頭アドレスセット　上位バイト<br />&nbsp;　movwf&nbsp;　FSR0H<br />&nbsp;　movlw&nbsp;　LOW table<br />&nbsp;　movwf&nbsp;　FSR0L&nbsp;&nbsp;　　　　　　;FSRをテーブルの先頭へ　下位バイト<br />&nbsp;　bra&nbsp;　　　pwmloop</p>
<p><br />実際の輝度テスト・プログラムtest13.asmは下記にあります。</p>
<p>　　輝度テスト 
</p><span class="mt-enclosure mt-enclosure-file" style="display: inline;"><a href="http://www.eleki-jack.com/mycom2/goda/J70_test13.txt">プログラムtest13.asm</a></span>
<p>&nbsp;</p>
<p>●<b>テーブル・フェッチの基本</b><br />　ここでテーブルからデータを取り出す方法（テーブル・フェッチ）の違いを確認しましょう。拡張PIC16マイコンでは、あらかじめ定義したプログラム・エリア内のテーブルより順番に取り出す方法が便利になりました。</p>
<p>１）従来マイコンはPCLレジスタにWレジスタのIndex値を加え、その位置の値を取り出す方法です。</p>
<p>;テーブル・インデックスはWレジ<br />&nbsp;&nbsp; addwf 　PCL,f<br />Table<br />&nbsp;&nbsp; retlw 　data1<br />&nbsp;&nbsp; retlw 　data2<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;：<br />&nbsp;&nbsp;&nbsp;&nbsp; ：</p>
<p>　この方法はテーブルの位置が256番地境界を越えることができません。</p>
<p>２）拡張PICマイコンは新命令BRWを使う<br />　新しいBRW命令を使うことで、この256番地境界を意識しなくてもよくなりました。この方法はテーブル・サイズが1バイトで指定できる256個の範囲なら使えます。</p>
<p><br />;テーブル・インデックスはWレジ<br />&nbsp;&nbsp; brw<br />Table<br />&nbsp;&nbsp; retlw 　data1<br />&nbsp;&nbsp; retlw 　data2<br />&nbsp;&nbsp;&nbsp;&nbsp;：<br />　　：</p>
<p>３）新命令のMOVIW命令なら番地境界もサイズの制限もない<br />　拡張PICマイコンは、16ビット長FSRレジスタの間接アドレス機能を使用した新命令MOVIW命令が追加されました。このFSRレジスタにより、アクセス・アドレスはデータRAMエリアからプログラムエリアまで全メモリ・アドレスをアクセスできるようになりました。<br />　これにより、拡張PICマイコンでは256番地境界の制限もなくなり、実質テーブル・サイズの制限もなくなっています。</p>
<p>&nbsp;&nbsp; movlw　HIGH Table+80h&nbsp; ;＊＊注意＊＊<br />&nbsp;&nbsp; movwf　FSR0H<br />&nbsp;&nbsp; movlw　LOW table<br />&nbsp;&nbsp; movwf　FSR0L　　&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ;FSR0をテーブルの先頭へ<br />　　　：<br />　　　：<br />　MOVIW　INDF0++　　　 ;実行するとテーブル先頭の値がWレジへ<br />　　　　　　　　　　　　;その後FSR0のテーブル・アドレスをカウント・アップ<br />　　　　　：<br />　　　　　：<br />Table<br />&nbsp;&nbsp; retlw 　data1<br />&nbsp;&nbsp; retlw 　data2<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;：<br />&nbsp;&nbsp;&nbsp;&nbsp;：</p>
<p>●<b>拡張PIC16マイコンでのテーブル・フェッチ</b><br />１）プログラム・メモリにあるテーブルのアドレス指定<br />　FSRnレジスタを使用するとデータRAMエリアの変数を読み出すだけでなく、プログラム・エリアのデータも読み出せます。拡張PICマイコンのプログラム・メモリ・エリア（定数テーブル）は、8000h番地（プログラムの番地は0番地）以降に割り当てられています。</p>
<p>　 
</p><span class="mt-enclosure mt-enclosure-image" style="display: inline;"><img class="mt-image-center" style="display: block; margin: 0px auto 20px; text-align: center;" alt="J71progMap.JPG" src="http://www.eleki-jack.com/mycom2/goda/J71progMap.JPG" width="459" height="542" /></span>　　　　　　　　プログラム・メモリの図　
<p>&nbsp;</p>
<p>　FSRレジスタにプログラム・エリアにあるテーブル・アドレスを設定するには、オペランドにHIGHとLOW指示子にて2バイト長のアドレス・ポインタをFSR0HとFSRxLレジスタに分けます。これにより、二つを結合した16ビット長FSRレジスタを使うことで、プログラム・エリアまで参照できます。</p>
<p>　ただし、上記リストの「＊注意＊」に示すところでは、説明書(複数)のHIGH指示子を使ったコーディング例が正常に動作しないので、プログラム・エリアを示すように80hを加えています。</p>
<p><u>説明書記載内容</u><br />　　MOVLW　HIGH　Table　　　;テーブルの先頭番地の上位バイトを<br />　　MOVWF　FSR0H　　　　　　;FSRレジスタの上位バイトへ</p>
<p><u>修正後</u><br />　　MOVLW　HIGH　Table+80h　;テーブルの先頭番地の上位バイトを<br />　　MOVWF　FSR0H　　　　　　;FSRレジスタの上位バイトへ</p>
<p>　プログラム開始は「0000番地から」スタートするため、アセンブラで指定するラベル・アドレスも「0000番地から」となります。しかし、これではアドレスの上位バイト値が00なので、FSRnでの読み出すアドレスの「8000番地から」になりません。<br />　仮にテーブルのアドレスが0123番地とすると、FSRxLは下位バイトなので、LOW指示子で「23」を入れれば問題ありません。しかし、FSRxHの上位バイトはHIGH指示子で「01」となり、プログラム・エリアにならず、データRAMエリアのアドレスとなってしまいます。そのため、現在は説明書どおりではなく、プログラム・テーブルをアクセスするために「80」を加え、FSRｘHを「81」とする必要があります。</p>
<p><strong>＊注意＊<br /></strong>　今後アセンブラMPASMが修正されるか、それともドキュメントが修正されるのかマイクロチップ社から回答ありません。執筆時点では、このコーディングになるか不明です。</p>
<p>２）新しいMOVIW命令で読み出す<br />　新しいしいMOVIW命令は16ビット長FSRレジスタの間接アドレス機能を使用し、輝度データのあるプログラム・エリアのテーブルからWレジスタに読み出します。</p>
<p>　このMOVIW命令は次のような仕様です。<br />　・FSRnはn=0ならFSR0HとFSR0L結合した16ビット・アドレスFSR0、n=1ならFSR1HとFSR1Lを結合した16ビット・アドレスFSR1を意味します。<br />　・INDFnはN=0ならFSR0で示す間接アドレスを、N=1ならFSR1で示す間接アドレスを示します。<br />　・MOVIWは間接アドレスからデータをWレジに入れる命令です。<br />　・MOVWI命令は逆のWレジより間接アドレス・エリアにストアします<br />　・使用できる間接アドレスのレジスタは二つのFSR0、FSR1があります(n=0,1)</p>
<p><br />　データシート(REV.B)では、MOVIW命令のオペランドに「FSRｎ」を指定するように書いてあります。これは「INFDn」の間違いです。MPLABデバッガの逆アセンブルでも同様に表示されます(n=0,1)。</p>
<p>　　MOVIW　FSRn++　　正しくは　MOVIW　INDFn++ です。</p>
<p>C言語のような＋＋や－－のある命令は、<br />・INDFnより先にある場合はFSRnレジスタに入っているアドレス値を命令実行前に一つカウント・アップまたはカウント・ダウンしてからWレジスタにデータを持ってきます。<br />・INDFnの後に＋＋や－－がある場合はWレジスタにデータを持ってきてから、FSRnレジスタのアドレス値をカウント・アップまたはカウント・ダウンします。</p>
<p>　MOVIW ++INDFn　　FSRnをカウント・アップしたアドレスからデータをWへ<br />　MOVIW --INDFn　　FSRnをカウント・ダウンしたアドレスからデータをWへ<br />　MOVIW INDFn++　　データをWへ入れた後にFSRnをカウント・アップ<br />　MOVIW INDFn--　　データをWへ入れた後にFSRnをカウント・ダウン</p>
<p>　実行で、FSRnレジスタを変更しない場合は、次のようにテーブルのk番目という指定になります。</p>
<p>　MOVIW k[INDFn]　FSRnアドレスのK番目データをWへ</p>
<p>　直接MOVIW命令で間接アドレスを使用するものは、アセンブラでエラーになりました。</p>
<p>　　MOVIW INDFn　　（執筆時点、これは使えない）</p>
<p>　どうしても使いたい人は、次のコーディングがあります。</p>
<p>　　MOVIW　0[INDFn]</p>
<p>　FSRnレジスタ使用は、ほかの命令でも使用可能で、下記のように行うこともできます。</p>
<p>　MOVFW　INDF0　　FSR0アドレスのデータをWへ</p>
<p>　このように拡張PICマイコンではプログラムメモリ・エリアに作成したテーブルから256境界やサイズ制限なしでデータを取り出すことができるようになりました。Wレジスタに読み出されるデータは命令語の0～7ビットの1バイト分です（13～8ビットは無視）。</p>
<p>●<b>輝度データの切り替えタイミング</b><br />　パルス幅データを変更するタイミングは1サイクル分が終了した後、周期の終わりに入れ替えます。周期の終わりでは「タイマｘとPRｘレジスタが一致すると割り込みフラグがセット」で周期割り込みTMRxIFがセットしますので、これを使います。<br />　データシートの周期割り込みは、ちょっと離れた「21.0 TIMER2/4/6 MODULES」のほうに書いてあります。TMR2IFのビット説明は16F88のデータシートにあったような「match」の単語が記述から抜けていますので、ちょっとわかりにくいかもしれません。</p>
<p>　ちなみに16F88では下記のように記述あります。<br />「1 = A TMR2 to PR2 match occurred (must be cleared in software)」</p>
<p>　輝度データ（パルス幅データ)切り替えタイミングは、このTMR2IFフラグがセットしたときに（割り込みを使用していない）プログラム・エリアにあるテーブルから読み出し、CCPRｘLレジスタにセットします。</p>
<p><br />　次回はデータ・テーブルをもう少し大きくしたり、またデータ変更を割り込みルーチン内で行うことにします。</p>
<p>&nbsp;</p>
<p>過去のPWM実験記事</p>
<p>１．PWMでLEDをON/OFF（点滅）実験<br />・拡張PIC16Fマイコン 16F1827のPWMを試す(1)<br />&nbsp; 　<a href="http://www.eleki-jack.com/mycom2/2010/05/pic16f_16f1827pwm1.html">http://www.eleki-jack.com/mycom2/2010/05/pic16f_16f1827pwm1.html</a><br />・拡張PIC16Fマイコン 16F1827のPWMを試す(2)<br />　　<a href="http://www.eleki-jack.com/mycom2/2010/05/pic16f_16f1827pwm2.html">http://www.eleki-jack.com/mycom2/2010/05/pic16f_16f1827pwm2.html</a></p>
<p align="right">後田　敏</p>]]>
   </content>
</entry>

</feed>
