PICの学習をCCS−Cではじめよう!

【はじめに】
 PIC の開発環境が近年大きく変わり、戸惑っている入門者の方々が多いようです。ネット上のコードや書籍のコードを入力しても動かない。ある種の混乱があり、PIC が登場した初期のころのシンプルな楽しさが容易には味わえないようになっていると感じています。
今回、若い方々( PICの理解もC言語も覚束ない)に、PICを動かすことを学んでもらいたいという機会があり、その時にやったことを、記事として上げることにしました。色々なやり方があるとは思いますが、方針として以下のことを掲げました。
;--------------
CCS-C(PCM) を使ってプログラミングの学習を進める。
幸いに、後閑哲也氏の「C言語によるPICプログラミング入門」という名著があります。CCS-C を使っておられて、PICとC言語の活用を、
良くぞここまでと、まとめ上げておられます。PIC用 の C言語 および デバイスの概要のマニュアルとして活用できると思っています。デバイス(PIC)の詳細の理解やアセンブラによるコーディングは、C言語を使って、入門の PIC を楽しく動かせるようになってからでも良いと思っています。Microchip様 のコンパイラ(XC8, XC16, XC32) を使う時でも、C言語の文法そのものは同じですので利用できます。なおここで使用しているCCS-Cのバージョンは、V5.076 です。上位のバージョンでも問題ないです。
MPLAB-X-IDE でも CCS-C は以前と同様に、
そのまま使えるところが良いところです。

・ IDE(統合開発環境)は、MPLAB-IDE(V8.92)MPLAB-X-IDE を使用する。
はじめに、MPLAB-IDEに CCS-C を組み込んで使用します。CCS-IDE もありますが、日本語を入力できないのでMPLAB-IDEにします。MPLAB-X-IDEも使えますが、まずは
軽快で使いこなれている MPLAB-IDE を通常は使うことにしました。MPLAB-IDEを軽快な日本語も入力できるエディターおよびダウンローダーとして使うわけです。CCS-Cと組み合わせればコンパイルはとても速く、動きが軽いのがベストであり、今後も使用にあたって問題はないです。また、右図のように、関連はないが関心のある様々なプロジェクトのショートカットを作成して整理でき、目的のプロジェクトを探しまわる手間がなく、ダイレクトに目的のプロジェクトをスタートできるので、この機能は意外とありがたいものです。MPLAB-IDE(V8.92)をメインで使いますが、最新のデバイスは MPLAB-X-IDE でしかサポートしていないものもあるので、この双方の IDE をインストールして使い分けます。Microchip のデバイスの種類は膨大な数になっていますが、ほとんどのデバイスは MPLAB-IDE で取り扱えるので通常の開発はこれで行い、これで対応できないものだけ MPLAB-X-IDE を使うことにします。
MPLAB-IDE で開発した
CCS-C のコードは、容易にそのまま MPLAB-X-IDE に移行できるので問題はないです。開発のスムーズさと管理の容易さを優先しているだけで、使い分ければ良いと思います。

・ デバッグは、RS232C を使います。
これを使って、デバイス内部の様々な情報を受け取ったり設定できますし、プロジェクトが完了して、そのままコードを残していても、また削除しても問題はないです。私個人は、Z80アセンブラのころから、専門のディバッグ装置は使ったことはなく、RS232C で内部の情報を取得したり設定したりしてきました。よほどの特殊な事をしない限りその必要もないと思っています。

・ 対象のデバイスは、PIC16F1827 PIC16F1938
PIC12F1822PIC16F1619PIC12F1612 とします。
PIC16F1827は、PIC16F84A, PIC16F628A と、PIC16F1938は、PIC16F886 と全くPIN互換で、速度もメモリ容量も機能も格段と大きくなっています。また、PIC16F1シリーズは、従来のものよりCコンパイラが効率良いコードを生成できる機能を内蔵しており、逆に購入価格は従来の互換品よりも安くなっていますので、新たなプロジェクトは、これらで行くべきでしょう。
;--------------
CCS-Cコンパイラについて、色々と苦言があることも承知いたしておりますが、これだけの
長い間、プロに支持され続けているのには、それなりの理由があることだと思います。
それはさておき、学習の準備に入って行きましょう。

【環境の準備】
 次の7項目の準備が必要です。エ〜ッと思うかもしれませんが、頑張ってやりましょう! 一度実行すれば良いのですから・・・。他の開発環境の準備では、これの数倍以上かかるものもあるので、それに比べれば楽なものですよ!

1. MPLAB-IDE(V8.92) および MPLAB-X-IDE のインストール
まず、最初にマイクロチップ様のサイト
アーカイブのダウンロードから、MPLAB_IDE の最終の MPLAB IDE v8.92 をダウンロードしてインストールしてください。こちらからも簡単にダウンロードできます。
次に、
MPLAB-X-IDE もインストールしましょう。ただこれは、JAVA 環境で開発されてい るので、JAVA のランタイム環境(JRE v6)を必要とします。したがって使用するバソコンに JAVA 環境がインス トールされていない場合は、先に JRE 6 をインストールする必要があります。もしインストールされているな らば、これはスキップです。JRE のインストールについては ここを ご参照ください。
MPLAB-X-IDE のインストール方法は WEB 上にたくさん紹介されています。例として
こちらを参照して最新版をインストールして下さい。MPLAB IPE も同時にインストールするようにチェックを確認して下さい。

 (注意! MPLAB-X-IDEのバージョンについて)
   2023年6月
 個人的な話ですが、 Windows を再インストールする必要が起こり、実行しました。アプリの再インストールも必要となったので、当時の最新版 MPLAB-X-IDE V6.10 をインストールしました。この後、PICに書き込みが必要となり MPLAB-X-IPE V6.10 を起動して Pickit 3 を接続しましたが、Tool のところに Pickit 3 が認識されません。これまでは問題なく認識されていたのに何度やり直しても認識されません。やむなく Pickit 4 を接続すると、これは問題なく認識され、書き込みはできました。あくまで推測ですが、最新版では、 Pickit 3 はサポートされなくなっているようです。その証拠に、 MPLAB-X-IDE V3.50 にダウングレードすると Pickit 3 は問題なく使えます。どのバージョンまでダウングレードすれば良いかはわかりませんが V5.50 くらいは良いとの報告もあります。結局、最新版 MPLAB-X-IPE を使うならば Pickit 4 が必要ということになります。どのバージョンの MPLAB-X-IDE (IPE) を使うかは、それぞれの判断で行ってください。幸い、アーカイブで初期からの全バージョンがダウンロードできるようです。
 一般的にデバイスは、採算が取れにくくなると、すぐに製造中止にするメーカーが多い中で、Microchip様の良いところは、少々価格を上げてでも古い品種を供給し続けるところだと思っております。その精神から言うと、MPLAB-X-IPE のデバイスを選択したら、それが Pickit 3 で開発したことが考えられるデバイスであれば、Tool では、当然 Pickit 3 も認識し表示すべきです。これはユーザーとして、要望いたします。


2. CCS-Cのインストール
CCS-C はデバイスに応じて色々の種類がありますが、まずはこちらから PCM を入手してください
有償ですが、それだけの価値はあると思います。期間限定のお試しフルセット(45日間)は、ここにあります。これはフルセットで、IDEを含めて全て入っています。ここで使用するPCMも含まれていますので、下記の MPLAB Plug-in や MPLAB-X-IDE Plug-in をインストールすれば、この演習には使えます。

3. MPLAB Plug-in および MPLAB-X-IDE Plug-in のインストール
ここから、MPLAB-IDE Plug-in を選択してダウンロードします (注: MPLAB-X-IDEの方ではない)。
(重要) 必ず、上の
1のMPLAB-IDE2のCコンパイラインストールしたにプラグインをインストールして下さい。これは MPLAB-X-IDE Plug-in も同様です。順番に実行して行けば問題はないです。
次に、
MPLAB-X-IDE Plug-in もインストールしましょう。MPLAB-X-IDE 上で CCS-C にてコンパイルする時に、インストールしておけばすぐに使えます。

4. PICkit 3 または PICkit 4 の準備
PICデバイスにコンパイルした結果(HEXファイル)を書き込むためのツールを入手してください。秋月電子通商さんからでしたら、ここにあります。PICkit 3 については、互換品ならば、ここにあり、他にも色々あります。PICkit 4 が発売されてから、PICkit 3 の正規品は、発売されなくなりました。しかし、ここで演習している PIC16F1 シリーズの学習には、PICkit 3 で全く問題はないです。私も互換品を購入して動作させましたが全く問題はありませんでした。なにしろ価格が 1/4 くらいで入手できます。PICkit 4 のコネクタは 8Pin、PICkit 3 は 6Pin ですが、今のところ増えている 2Pin は使われていないようです。したがって、1Pin を合わせて使用すれば、PICkit 3 と同様に使用できます。PICkit 4 を使う場合は、この後の記述で、PICkit 3 と記入しているものについては、
PICkit 4 に読み替えて、書き込みは MPLAB-X-IPE を使用してください。

5. HEXファイルを PICkit 3, 4で書き込む為の独立したツールをインストール
このツールの名称は [MPLAB IPE] (Integrated Programmming Environment)と言います。これは JAVA環境で開発されているので、
JAVAのランタイム環境もインストールすることが必要です。基本的に、1.で MPLAB-X-IDE をインストールする時に、IPE の同時インストールのチェックを付けていたら、同時にインストールされているはずです。新デバイスのPICkit 3 への対応は、このツールで実行されますので、インストールは必須です。もし、MPLAB-X-IDE のインストールの時に、IPE がインストールされていなければ ここに、ダウンロードとインストールの説明がされていますので参照してください。いきなり MPLAB-IDE から PICkit 3 を起動した時に、ターゲットと接続できない場合は、一度この IPE でターゲットにアクセスすると PICkit 3 に準備がなされ、以降はそのデバイスに関しては持続的に MPLAB-IDE からターゲットに直接ダウンロードできるようになります。
実際の 接続の例 をここに示します。

6. Tera Tarm の準備
ディバッグ用として使う Tera Tarm(フリーソフト)を入手してインストールしてください。
窓の社さんからでしたらここにあります。インストールして起動後、後で説明いたします設定をしてください。
パソコンにRS232Cのコネクタがある場合は9ピンの
ストレートケーブルが必要で、ない場合は、アダプタが必要ですが安価(例:秋月電子通商Amazon)です。Tera Tarm の提供者に感謝します。

7. ターゲット・その他の基板および電源の準備
ここでは、二種類の基板を使います。一つは PIC組み込みの
ターゲット基板で、もう一つは、ターゲットに PICkit の接続と RS232C(モニター) 機能を提供するミニサイズの書き込み・モニター基板です。この2枚の基板を組み合わせてディバッグしていきます。組込み写真をご参照ください。
組込み写真1組込み写真2
組込み写真3PICkit 4 の接続について
双方とも提供いたしております(ここで提供)。回路図は、提供先にあります。電源はDC5V、センタープラス(プラグ外径:5.5mm,プラグ内径:2.1mm)です。秋月電子通商さんでしたら、
ここにあります。
もし、ブレッドボードでユニットを作成される場合は、ここに便利な拡張基板があります。

[ COLUMN ]
ここで、MPLAB-X-IDE もインストールしました。ここの例題では、CCS-C コンパイラを使用しますが、Microchip様 のコンパイラである C18, C30, C32, XC8, XC16, XC32 も、この際インストールして置くことをお勧めしますが、大変なのでとりあえず C18 と XC8 だけでも良いです。MPLAB-IDE や MPLAB-X-IDE を使った書籍やWEB上のコードをテストする時に困らないからです。別のコンパイラのコードも CCS-C に移植することができます。その時に、元のコードの動作が確認できると、移植する場合にとても参考になります。
実際、[音楽(オルゴール)の演奏]のコードや「ZCD(ゼロクロス検出)による電源周波数の測定」のコードは、MPLAB-X-IDE 上で動かしてあった提供者様のコードを動作確認後、MPLAB-IDE や MPLAB-X-IDE 上の CCS-C に移植したものです。開発の容易さから CCS-C を使いますが、他のコンパイラでも自在に扱えるようにしておきたいものです。( XC8 から CCS-Cへの移植例 )

【 参考 】 私の Program Files の構成状況を示します。これは Windows 10 , 64bit の例です。
      その後、Windows 11 にそのまま移行しましたが、問題なく使えています。
      下図は、こうでなければならないということではありません。あくまでも参考としてください。

      上記の必要な分のインストールができていれば良いのです。MicrochipとCCS-Cの分のみです。


【動かしましょう−1】
ここでは PIC16F1827を動かしてみます。PIC演習用基板(1)を使用します。入門は、これまでは 'Lチカ(LEDを点滅)' ですが、ここでは、いきなり RS232Cを動かして、ターゲットとパソコンで通信します。
とにかく、
ターゲット(PIC)と実モードで対話ができる状態を作ることが、入門にはとても大切だと強く思っています。'Lチカ' は、その中でもできます。

[ Contents ]
1. RS232Cでパソコンと接続
2. インターバルタイマーを組み込む
3. LCD (I2C動作、AQM0802A、8桁 x 2行) に表示する
4. 内蔵EEPROMへのアクセスと変数の保管
5. A/Dを読み出し、それをLCDに疑似レベルバーで表示する
6. 外部EEPROM (I2C) へのアクセスと変数の保管
7. ステッピングモーター(28BYJ-48)を動かす

1. RS232Cでパソコンと接続
学習用のフォルダ「C:\PIC_Practice\chap_1」を作成して下さい。これでは C:ドライブのルートに作成していますが、ご自分で管理できる所ならば、どこでも構いません。このフォルダ「chap_1」の中に次の2つのファイルを入れて下さい。下のリストの main.c の範囲をドラッグして選択します、その状態で右クリックしてコピーします。それをメモ帳などのエディタに貼り付けて、名前を付けて保存で名前を main.c とします。同様に、 SciCommand.c の範囲をコピーして、 SciCommand.c とします。2つのファイルの境目の目印である・・・
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
・・・は、無視して良いです。これは、以降のサンプルでも同様です。LCDは使いませんが、接続したままでも問題ありません。
上記のように、ソースファイルを構築していきますが、参考として、当方で構築している「C:\PIC_Practice」の中身一式を便利のために掲載しておきます。参考にしてください。 ソースファイル一式 (PIC_Practice.zip)

「PIC_Practice」フォルダができますので、これを C:ドライブに移動すれば使えます。

リスト chap_1


次に、MPLABを起動して下さい。立ち上がりましたら、メニューの「Project - Project Wizard...」をクリックします。



Step1でDevice をPIC16F1827に設定し、Step2 で
Language Toolsuite を CCS-C とします。
MPLAB Plug-in のインストールができていれば、上記のように、CCS-Cが選択できます。



Step3で、Project File を Browse してchap_1.mcp 作成し、Step4で、
main関数のある main.c のみを Add します。以上で新プロジェクトの設定は完了です。「次へ」をクリックして行ってください。

新プロジェクトが立ち上がります。メニュー「View」のProject と Output にチェックを入れ、またMemory Usage Gauge を見れるようにします。また、図のように、「Build Configration」を
必ず Debug から Release にしてください。



「Other Files」 を右クリックして SciCommand.c を取り込みます。この時 SciCommand.c を Source Files に入れるとコンパイルエラーとなります。これは、SciCommand.c が main.c の中で #include されているからです。SciCommand.c を Source Files に入れることも可能ですが、そうするためにはそのように記述する必要があります。
この一連の演習プロジェクトでは、main.c 以外のソースファイル(.c)は全てOther Files に入れます。ファイル名をダブルクリックすると、エディタ画面で編集できるようになります(下図)。



メニューの 「Project - Build All」を実行するとコンパイルが実行され、Output 画面に、BUILD SUCCEEDED が表示されれば、成功です。プロジェクトフォルダに、「main.hex」ファイルができているはずです。
ターゲットに書き込むために、下図のように接続してください。PICkit 3 の USBケーブルをパソコンに接続し、そして
ターゲットの電源を入れて置きます



下図の左のように、メニュー「Programmer」をクリックし、Select Programmer から、PICkit 3 を選択します。PICkit 3 を接続していなければアクティブにならず選択できないのでご注意ください。PICkit 4 を使用する方は、
MPLAB IPE を使用しての書き込みになりますので、以降の PICkit 3 を PICkit 4 による書き込みに、読み替えてください。(PICkit 3, 4 の接続比較図
選択すると接続が始まり、「Voltage Caution」が出ますが「OK」を押して左下の表示となれば接続が完了したことになります。同時に「Program, Read, Verify ・・・」などのメニューバーが使えるようになります。
 もし接続できない場合は、Select Programmer から一旦 None を選択し、つぎに先にインストールしている [ MPLAB IPE ] を起動して
接続してください。以降はこのデバイスに関しては、持続的に MPLAB から認識できます。IPE を終了して再度、Select Programmer から PICkit 3 を選択して接続して下さい。
次に書き込みです。下図の右のように「Program」(または、Programmer - Program)をクリックすると現プロジェクトの HEXファイルが書き込まれて、完了するとターゲットは動作を開始(RUN)します。



さて、いよいよ
ターゲットとの対話です。上の写真の接続では、USBシリアルケーブル(パソコンにポートがあればストレートケーブル)を接続していますのでターゲットと通信できます。テラタームを起動して 下図の設定をしてください。左図は「編集 - シリアルポート」、右図は「設定 - 端末」で行い、記入されているように設定します。ポート番号は、「デバイス マネージャ」の「ポート(COMとLPT) 」を参照すると分かりますからそれに合わせます。「デバイス マネージャ」の開き方はOSにより違いがあります。ネットで「デバイスマネージャーの開き方」を検索してください。



メニュー「設定 - ウインドウ」で下図の左の画面となり、ディフォルトの黒画面から白に変更できます。これらの一連の設定が終了したら、
「設定 - 設定の保存」を実行します。



上図の右が、実際に通信している画面です。「? 次に Enter」で、メニューがでます。このサンプルコードでは、T0, T1, T2 のテストコマンドを入れています。画面に青字でコメントしているように動作します。コマンド T2 は、ターゲット基板のSWを実際に操作しながら結果を見ています。ポート(RA)の第7, 6 ビットが操作に応じて変わっていることが確認できます。回路図を参照して下さい。
演習のスタートですので、最小限のコードです。「
C言語によるPICプログラミング入門」をマニュアルとして使いながら読んでみましょう。PIC に必要なC言語を、ここまでコンパクトにまとめてあるものは、他には知りません。

RS232Cを送受信に使えるようにするには、下の一行の記入で済みます。
#use rs232(baud=19200,parity=N,xmit=PIN_B5,rcv=PIN_B2,bits=8,stream=PORT1)
この記入で、送受共にできますが、受信割り込みを設定するには main()関数の初めに・・・
enable_interrupts(INT_RDA);   // RS232C(USART)受信割込みを許可
enable_interrupts(GLOBAL);    // 割込み全体を許可する
・・・記述が必要です。

「C言語」は比較的易しいです。それでも、実際に自分が書いたコードをコンパイルしてターゲットに書き込み、通信しながら動作を確認していかないと、書籍だけを読んでいても行き詰まってしまいます。コーディングを始めたばかりの方が良く陥ることは、自分で
新しい「C言語の文法」を作っていることです(笑い)。コンパイラは書き手の思いまでは受け止めてくれませんので、上記の書籍を手元に置いて常に参照してください。書籍が手垢でかなり汚れてきたら、まずまず自分のものになってきていると思います。

「main.c」「SciCommand.c」は、それぞれ今のところ最小限の記述をしています。今後、これに必要なものを次々に追加していきます。自分で追加した場合、コンパイル可能なブロックを入力した時に
すぐにコンパイルしてみることを強く勧めます。多くを入力してエラーが出た場合は、エラー文が続々と出て、何が悪いのか判断するのが困難になります(これはどの言語のどのコンパイラでも同じ)。「MPLAB + CCS-C」のコンパイルに要する時間はとても短いので、とことん繰り返して良いと思います(これが、この組み合わせを選択した一つの理由です)。コードにはできるだけ日本語でコメントを入れていますので、それを参考にして解読してください。

ここでは、RS232Cの受信に割り込みを使っています。パソコンから一文字一文字送られて来るたびに、割り込み関数 void isr_rcv() が起動されます。受信バッファーとして、char Rbuf[22]; があり、その一文字をこのバッファーに入れて行きます。もし受信した一文字が CR(Enter) か LF の場合は、文字列のターミネータである \0(Null) をバッファーに入れて、 コマンド受信フラグ(Rcmflg)を true にします。一方、void main()は・・・
  while(true)
  {
    exe_command();   // RS232Cのコマンドが有れば実行する
  }
・・・となっており、常時 exe_command() を実行しています。その void exe_command() のトップで、Rcmflg が false ならば直に戻ります。true の場合は・・・
 p = Rbuf;
 switch(c = toupper(*p++)) {   // 最初の一文字を取り出す(c)
   case 'T':  // for Test
     switch(c = toupper(*p++)) {
       case '0': output_a(0x00); output_low(LED_4);   // LED1~LED3, LED4 の消灯
       puts("LED1~4 OFF");
       break;
       ・
       ・
・・・受信バッファー(Rbuf)の先頭からの文字を見て(switch文)、該当するコマンドが有るかを case文で処理します。処理後は・・・
 Rnum = 0;     // 受信文字数をクリアする
 Rcmflg = False;   // コマンド受信フラグをクリアする
・・・として、初期状態にします。
受信文字は小文字であっても、標準文字処理関数の toupper で全て大文字にして処理しています。コマンド追加予備としての、T3, T4, T5 を使って色々な作業を追加してテストしてください。
いわゆる遊んでみることが大切です。

ここでは、RS232Cの受信の処理に、いきなりポインタを使っていますが、もし分からない場合は構いませんから、そのままオマジナイとして使ってください (使える物は使って、後で解釈すれば良い)。ただ言えることは、ここでの p は char のポインタ(アドレス)であり、あるアドレスを指しているのでポインタといい、*p は、そのアドレスにある中身(実体)を表しています。ポインタをインクリメント(++)すると、この場合は次の文字を指します。また、
配列( Rbuf[22])の名前(Rbuf)は、その配列のトップアドレスを表しています。ですので、p = Rbuf; とすることで、配列のトップアドレスをポインタに代入していることになります。


2. インターバルタイマーを組み込む
前と同様に学習用のフォルダ「C:\PIC_Practice\chap_2」を作成して下さい。このフォルダ「chap_2」の中に次の2つのファイルを入れて下さい。 main.c と SciCommand.c の作成方法は、前述の通りです。ファイルの名称は、chap_1 と同じですが、中身は違いますので注意してください。LCDは使いませんが、接続したままでも問題ありません。

リスト chap_2


前のプロジェクト chap_1.mcp を立ち上げて置いて、メニュー Project - New で chap_2 のプロジェクトを作ります。設定は、前回と同様です。
main.c は、プロジェクト画面の Source Files 上で右クリックして Addし、 SciCommand.c は、Other Files上で右クリックして Add します。



前のプロジェクトと同様のやり方で、コンパイルして、PICに書き込んでください。RS232Cでの確認の様子を下図に示します。


それぞれの周期を確認するため、割り込みごとに、LEDを点滅させています。タイマ1は LED_5 を、タイマ2は LED_4 を点滅させます。そのLED制御のポートの端子にオシロスコープを接続して測定した波形が下図です。LED_5は、1秒に5回の点滅ですから、目で点滅が見えますが、LED_4は点灯しきりに見えます(実際は1秒に5000回点滅している)。この点灯しきりに見えるタイマ2を10,000回カウントすると1秒になりますが、ソフトの練習として、タイマ1のやり方を参考にしてLED_4を点滅させてストップウォッチで計測すると、オシロスコープが無くともタイマーの時間の確認ができますので、挑戦して見て下さい。



100ms と 100us の正確なインターバルタイマーは、あらゆる場面に使うことが多いです。カウンタとして int32 を使っていますから、4,294,967,295回までカウントできます。100msなら119,304.6時間(4,971日)ですから、長時間の監視ができます。100us(0.1ms)は、例えば
スイッチが5秒間押され続けた時にモードを変えるとか、20ms未満の押しは無視するとかを実現する時に利用できるので、ユーザーインターフェイスを作る時にとても重宝します。他の目的にタイマ1・タイマ2を使用しない限りは、このインターバルタイマーは常に搭載して利用することが多いです。搭載しておいても、それほど多くのROMは食わないですから・・・。それぞれのタイマーの設定値の算出法については、それぞれの割り込み処理関数の上にレム文として書き込んでおり、必要な定数を #define していますので、それについて説明します。
;-------------------
【タイマ1】
#define  T1PS  15536
// 65536(0x10000)-15536 = 50000    C
// Fosc(16MHz)/4 -> 4MHz (Timer1 IN)  @
// DIV:1/8 -> 0.5MHz(T:2.0uS)      A
// 50000 x 2.0us = 100ms        B
65536でオーバーフローして割り込みが掛かるので、割り込みルーチンの中で定数:T1PSをセットすれば、(65536 - T1PS)のカウント後に割り込みが掛かります、そのT1PSの算出は次の通りです。@のクロックが入ります。プリスケーラを1/8とするとクロックはAとなります。目的の100msにするにはBの計算で 50000でなります。その 50000をカウントさせるためには、割り込みの中で、Cの計算で出た 15536を設定すれば良い事になります。 Foscを変える時には、プリスケーラを調整するなどして合うようにします。ここで定義した T1PS は、割り込みの中で set_timer1(T1PS); として設定します。
;-------------------
【タイマ2】
#define  T2PR  100      // Period:0~255
#define  T2PO  4       // Postsscale:1~16   for INT times of OV
// Fosc(16MHz)/4 -> 4MHz (Timer2 IN) @       
// DIV:1/1 -> 4.0MHz(T:0.25uS)      A
// 0.25us x 100 x 4 = 100us        B
タイマ2は、プリスケーラ(DIV)と、2つの定数:T2PR, T2PO で割り込み周期を決めます。T2PR の範囲は 0〜255であり、T2PO の範囲は 1〜16です。@のクロックが入り、プリスケーラを1/1とするとクロックはAとなります。目的の100usとするには、(クロック周期 x T2PR x T2PO) = 100usとなるように T2PR, T2PO を調整します。
ここで出た DIV, T2PR, T2PO は、main() の初期設定で setup_timer_2(T2_DIV_BY_1, T2PR, T2PO); とします。

RS232Cの受信割り込みとTIMER1, TIMER2 の割り込みを実現するため、main() 関数の初めに・・・
setup_timer_1(T1_INTERNAL|T1_DIV_BY_8);   // Timer1(100ms)の設定
setup_timer_2(T2_DIV_BY_1,T2PR,T2PO);     // Timer2(100us)の設定
enable_interrupts(INT_TIMER1);          // Timer1の割り込みを許可
enable_interrupts(INT_TIMER2);          // Timer2の割り込みを許可
enable_interrupts(INT_RDA);           // RS232C(USART)受信割込みを許可
enable_interrupts(GLOBAL);            // 割込み全体を許可する
・・・の記述が必要です。


3. LCD (I2C動作、AQM0802A、8桁 x 2行) に表示する

前と同様に学習用のフォルダ「C:\PIC_Practice\chap_3」を作成して下さい。このフォルダ「chap_3」の中に次の4つのファイルを入れて下さい。 main.c 、 SciCommand.c 、ST7032i_lib.c、ST7032i_lib.h の4つです。作成方法は、前述した通りです。ファイルの境目に・・・
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
・・・がありますので、この行は無視してください。以前のプロジェクトと同名のファイルがありますが中身は違いますので注意してください。このプロジェクトでLCDは、AQM0802A を使います。バックライト無しの「-RN-GBW」でも、バックライト有りの「-FLW-GBW」のどちらでも良いです。
リスト chap_3


前の chap_2.mcp を立ち上げて置いて、メニューの 「Project - New」 で chap_3 のプロジェクトを作ります。前のやり方と同様に進めてください。 main.c は、プロジェクト画面の Source Files 上で右クリックして Add し、 SciCommand.c と ST7032i_lib.c は、Other Files 上で右クリックして Add し、 ヘッダーファイルの ST7032i_lib.h は、Header Files 上で右クリックして Addして下さい。下図のプロジェクトの画面の通りになります。



コンパイルして、PICに書き込んでください。LCD画面の下の行に、タイマー1でカウントアップしている SecNum を表示しています。RS232Cで、LCDのコントラストを変更できます。この AQM0802A-RN-GBWのコントラストは、外付けのボリュームではなく、ソフトウェアのコマンドで設定します。このように、atoi() という標準文字処理関数を使って、入力文字列を数字に変換することができます。コントラストは、あらかじめ標準的な値をソフトの中に書き込んでいますが、このようにモニターで調整・確認した上で、ソフト内の定数を変更すると良いと思います。(AQM0802A-RN-GBWの仕様書)



このように、モニターからソフト内部の変数を書き換えたり、また参照したり、デバイスのI/Oの状況・その他を変更したり参照することができますので、ディバッグするのにとてもこのモニターは有用です。
LCDの制御ライブラリ(ST7032i_lib.c, ST7032i_lib.h)は、
「ST7032i」というコントロールデバイスを使用しているLCDに共通に使えます。この後に出てくる AQM1602Yでも使用しますし、ストロベリー・リナックス[SB1602B][SB1602BW]などにも利用できます。もちろん、CCS-C で使う仕様になっています。

この LCD のインターフェイスは I2C ですが、それを利用するためには、以下の一行の記述が必要です。
#use i2c(MASTER, SDA=PIN_B1, SCL=PIN_B4, ADDRESS=0xa0, FORCE_HW)
さらに main()関数のポート設定に・・・
output_float(PIN_B1);     // SDA(I2C用・設定)
output_float(PIN_B4);     // SCL(I2C用・設定)
・・・の記述も必要ですので注意してください。I2Cが使えるようになれば、その他の I2C インターフェイスのデバイスが全て利用可能になるので大変便利になります。

main()関数の無限ループ内に・・・
 if (SecNum != SecNumS) {  // 前回の表示値と異なる場合のみ実行
   stiLCD_SetCursor(0, 1);    // LCDの2行目の先頭にカーソルを設定
   printf(stiLCD_Putc, "SN:%lu", SecNum);
   SecNumS = SecNum;
 }
・・・という記述があります。
CCS-C には、printf 関数の拡張があり、LCDに容易に printf の書式付を利用することができます。これはとても有用です。従来は、float値などを表示するために sprintf, strcat などを使って苦労していましたから・・・
上記の if 文で「前回の表示値と異なる場合のみ実行」という箇所がありますが、これが無いと無限ループの毎回にLCDの書き込みを実行することになります。このように「変わった時だけ」実行する一つのサンプルとして、変数の控え(SecNumS)を使うことを銘記しておいて下さい。

また参考として、if文の書き方の例として・・・
if (A)
{
  puts("True");
}
else
{
  puts("False");
}
・・・とある場合、変数Aが 0の場合は「false」、
0以外の場合は「true」です。0以外とは正であれ負であれです。また、true や false のブロックが1文の場合は、その1文そのものが1ブロックとなりますからブロック指定の { } を省いて・・・
if (A) puts("True"); else puts("False");
・・・と1行で書くことができます。とてもシンプルとなり、冗長でなく逆に分かりやすくなると思いますので、場合によって使い分けると良いと思います。


4. 内蔵EEPROMへのアクセスと変数の保管

これまでと同様に学習用のフォルダ「C:\PIC_Practice\chap_4」を作成して下さい。このフォルダ「chap_4」の中に次の6個のファイルを入れて下さい。 main.c 、 SciCommand.c 、ST7032i_lib.c、ST7032i_lib.h、EEPROM.c EEPROM.h です。作成方法は、これまで通りです。以前のプロジェクトと同名のファイルがありますが中身が違うものもありますので注意してください。LCDは、前の分(AQM0802A)を流用しています。
リスト chap_4


これまでと同様に chap_3.mcp を立ち上げて置いて、メニューの 「Project - New」 で chap_4 のプロジェクトを前と同様の作業で新たに作ってください。 main.c は、プロジェクト画面の Source Files 上で右クリックして Add し、 SciCommand.c 、ST7032i_lib.c、EEPROM.c は、Other Files 上で右クリックして Add し、 ヘッダーファイルの ST7032i_lib.h、EEPROM.h は、Header Files 上で右クリックして Addして下さい。下図のプロジェクトの画面の通りにしてください。


コンパイルして、PICに書き込んで走らせてください。LCDは前と同じ動作をしています。モニターを立ち上げて、下図の左のように、内蔵EEPROMに対しての個別のバイトの書き込み(W)・読み出し(R)テストをしています。内蔵EEPROMは256バイトですので、Rコマンドで全バイトの読み出し表示をしています。
下図の右の画面では、内蔵EEPROMに floatの変数(Testfloat)をコマンド'T6'で、その値をEEPROMに
保管した後に強制的に 123.4 と書換えています。次に'T7'で、今の値を表示した後、保管してあるEEPROMから読み出して元の変数(Testfloat)に戻し、その値を表示します。次に、Rコマンドで、その保管がどのように格納されているのを見ています。コマンド'T6', 'T7'のコードを読んで納得してください。


内蔵EEPROMのアクセスは、CCS-Cでは組み込み関数があり、read_eeprom、 write_eeprom で簡単にアクセスできます。コードを読む上での補足をします。コマンド 'W015A'で、アドレス:01にデータ:5A を書き込んでいますが、そのアドレスおよびデータはそれぞれ2桁のHEX表記で入力します。そのRS232C受信データを exe_command() 関数側で数値に変換する関数:xhexstonum(char *p, int n) は、exe_command.c ファイルの下の方に定義しています。引数の pは、その文字の始まりの位置(Rbuf上)を指定し、nは、そこから何文字を16進文字列として受け取るかを指定します、そしてそれを数値に変換して返します。
ここでは使っていませんが、同様な動作の10進数版が、その下にある xdecitonum(char *p, int8 n) です。

次に、変数をEEPROMに格納し、逆にEEPRMから変数に復帰させる関数を EEPROM.c に定義しています・・・
int   iSaveField(long adrs, char *pa, int sn)         // 領域の一括SAVE(RAM->E2ROM)
void  iLoadField(long adrs, char *pa, int sn)         // 領域の一括LOAD(E2ROM->RAM)
・・・の形式です。
変数の種類(例:int, float・・)によって必要なバイト数が異なりますので、それを sn で指定します。その変数の記憶場所(RAM上)を pa で指定し、さらに EEPROM のどの位置から格納するかを adrs で指定します。その上で iSaveField と iLoadField を実行すると char のイメージで sn バイト数を読み書きします。

先に、ポインタの説明のときに 「配列の名前は、その配列のトップアドレスを表します」 と確認しましたが、それでは、配列でない変数のアドレスはどのように表すのでしょうか。そのためには、変数名の先頭に '
&' を付けます。
float Testfloat; と宣言している変数の格納位置(トップアドレス)は、&Testfloat と表現します。もう一つ、キャスト演算子についても確認しておきましょう。これはデータの前に「
(変換したい型)」を付けて、型変換を明示的に指定するものです。思い出してください、ポインタにも型がありました。char のポインタならインクリメント(++)でアドレスは +1 されますが float のポインタなら +4 されます。したがって、上のように「char のイメージで」動作するポインタに float の変数のポインタ(トップアドレス)を渡す時には明示的に char のポインタに型変換して置かなければなりません。この例では、(char *)&Testfloat としています。つまり、アドレス:&Testfloatを char のポインタとして渡すということです。この辺りさえシッカリ押さえておけば、ポインタに関しては卒業できると思いますよ!

EEPROM のどの位置から格納するかを
検討するために EEPROM.h の始めに・・・
// 内蔵EEPROM の使用位置
// ここでは、変数をどこに格納するかを指定する。その変数の
使用する領域が他と重ならないように注意する。
//      変数名    EEPROM 位置          サイズ
#define ieTestInt        0x10      // Test int   1
#define ieTestLong       0x11      // Test long   2
#define ieTestInt32      0x13      // Test int32   4
#define ieTestfloat       0x17      // Test long   4
・・・として書いています。ここでは、コマンド'T6', 'T7' で、float(Testfloat) だけを実際の対象としてテストしています。コマンドを追加して、long や int などについてもテストしてみて下さい。


5. A/Dを読み出し、それをLCDに疑似レベルバーで表示する

これまでと同様に学習用のフォルダ「C:\PIC_Practice\chap_5」を作成して下さい。このフォルダ「chap_5」の中に次の4個のファイルを入れて下さい。 main.c 、 SciCommand.c 、ST7032i_lib.c、ST7032i_lib.h です。作成方法は、これまで通りです。以前のプロジェクトと同名のファイルがありますが内容は変わっていますので注意してください。このプロジェクトでLCDは、
AQM1602Y-RN-GBW(16桁、2行) を使います。9ピンのコネクタで、先の AQM0802A と差し替えられるようにしていますので、交換して下さい。
リスト chap_5


これまでと同様に以前のこのシリーズのプロジェクトを立ち上げて置いて、メニューの 「Project - New」 で chap_5 のプロジェクトを以前と同様の作業で新たに作ってください。 main.c は、プロジェクト画面の Source Files 上で右クリックして Add し、 SciCommand.c 、ST7032i_lib.c は、Other Files 上で右クリックして Add し、 ヘッダーファイルの ST7032i_lib.h は、Header Files 上で右クリックして Addして下さい。下図のプロジェクトの画面の通りにしてください。


コンパイルして、PICに書き込んで走らせてください。



上図の左は、モニター画面で、コマンドとしては LCDのコントラストの確認・調整だけを入れています。右は LCD画面です。A/Dのチャンネル0を1行目に、チャンネル1を2行目に表示しています。
今回使用するLCDは、16桁・2行(AQM1602Y) のものです。先のプロジェクトで使った LCD(AQM0802A) を挿したままでも壊れることはありませんが、レベルバーは表示外となりますし、コントラスト設定値の違いでコントラストがまともではないでしょう。双方とも基本的に同じライブラリで動作します。ただ、下記のCONTRASTの定義値だけが違います。どちらの LCDもコントラストは、コマンドで設定しますが、その最適値にかなりの違いがあります。
ST7032i_lib.h の始めに、その2種の LCDのデフォルト値を記述しています ・・・
// コントラスト調整用定数
//#define CONTRAST 0x18     // for 3.3V(AQM0802A)
#define CONTRAST 0x28      // for 3.3V(AQM1602Y)
・・・ これでは、上の行はレム文にされていて、下の行が生きています。今回のLCDは AQM1602Y であるので下の行を使います。

【 A/Dの設定と読み込み 】
main.c のトップの、デバイスファイル( #include <16F1827.h> ) のすぐ下に ・・・
#device ADC = 10      // A/D変換 10bitモード
・・・ と記入し、コンパイラに A/Dの使用を宣言します。
次に main()関数の始めに ・・・
   setup_adc_ports(sAN0 | sAN1 | VSS_VDD);      // RA0,RA1がアナログ入力
   setup_adc(ADC_CLOCK_INTERNAL);          // FRC(内蔵発振)
   set_tris_a(0b11100011);               // Port_A モード設定
・・・ とします。これで A/Dの0チャンネルと1チャンネルは使えるようになります。
読み込みは ・・・
   set_adc_channel(0);              //チャネル選択、引数にチャンネル番号を指定
   delay_us(15);                  //アクイジション待ち
   fdata = read_adc();               //A/D変換データ10ビット読込み
・・・ とすればできます。

【 A/D値のレベルバー表示 】
   sti_all_set_cgram(cgram_levHdt[0]);          // 一括登録する(8文字分)
・・・ を実行することにより、LCD の CGRAM領域に、ST7032i_lib.h ファイルに定義している 64バイト(8キャラクタ分)のデータ( cgram_levHdt[] ) を連続して書き込んでいます。実際に使用しているのは「 |, ||, |||, ||||, |||||」の5つです。後の3つはスペースと同じになっています。この登録している5つのキャラクタを使用してレベルバーを表示しています。フルスケールは 3.3V (黒ベタ8文字) です。使用できるユーザー定義のキャラクタを書き込む CGRAMの領域は、LCDによって異なりますので、仕様書を確かめなければなりません。 AQM1602Y では、8キャラクタが使用できます。ちなみに AQM0802A では、6キャラクタが使用できます。
この定義したキャラクタを使い、表示位置(X,Y)およびA/D値を引数で受け取り、実際にLCDに表示するのは ・・・
   void DspLevelHorizontal(int x, int y, float Data)     // 水平方向表示の疑似レベルメーター
・・・ という関数です。レベルバーの表示幅は8文字分固定としています。このLCDでは、CGRAMアドレス00〜07に定義している文字は、アドレス08〜0Fでも重複して読み込める事に注意してください。詳細は AQM1602Y の仕様書を参照してください。


6. 外部EEPROM (I2C) へのアクセスと変数の保管

これまでと同様に学習用のフォルダ「C:\PIC_Practice\chap_6」を作成して下さい。このフォルダ「chap_6」の中に次の4個のファイルを入れて下さい。 main.c 、 SciCommand.c 、EEPROM.c、EEPROM.h です。作成方法は、これまで通りです。以前のプロジェクトと同名のファイルがありますが内容は変わっていますので注意してください。LCDは使いませんが、接続したままでも問題ありません。基板か回路図を見ていただければ分かりますが、J3(ジャンパ)は ON(接続)で開始してください。ON で 外付けEEPROMの chipアドレスは 0(000)で OFFで 1(001) となります。初期状態は 0 で開始します。
リスト chap_6


これまでと同様に以前のこのシリーズのプロジェクトを立ち上げて置いて、メニューの 「Project - New」 で chap_6 のプロジェクトを以前と同様の作業で新たに作ってください。 main.c は、プロジェクト画面の Source Files 上で右クリックして Add し、 SciCommand.c 、EEPROM.c は、Other Files 上で右クリックして Add し、 ヘッダーファイルの EEPROM.h は、Header Files 上で右クリックして Addして下さい。下図のプロジェクトの画面の通りにしてください。


コンパイルして、PICに書き込んで走らせてください。



上図の左は、モニター画面で、コマンドで、外付けEEPROMにフルアドレスを指定してデータを1バイト書き込んでいます。コマンドは、Waaaadd の形で、aaaa は4桁の16進数(HEX)のアドレス、dd は、2桁の16進数(HEX)のデータです。この基板には、24LC64 という EEPROM を搭載しています。容量は 64Kbit です。アドレスで言えば、0x0000 〜 0x1FFF のバイトがアクセスの範囲になります。コマンド Raa の aa は、アドレスの上位2桁(最後のページなら'1F')を指定して 256 バイトを一度に表示します。つまり、R05 と入力すれば 0x0500 〜 0x05FF の256 バイトを読み出して表示します。先に書き込んだデータが指定位置に書き込まれていることが確認できます。
上図の右は、各種変数の保管と復活のテストです。モニター画面上に書いているコメントの通りに動作しています。

変数を外付けEEPROMに格納し、逆に変数に復帰させる関数を EEPROM.c に定義しています。先の内蔵EEPROMとは別に定義しています ・・・
int   SaveField(long adrs, char *pa, int sn)         // 領域の一括SAVE(RAM->E2ROM)
void  LoadField(long adrs, char *pa, int sn)         // 領域の一括LOAD(E2ROM->RAM)
・・・の形式です。動作的には、内蔵EEPROMと同じですが、読み書きのための関数が異なります。

また、外付けEPROM のどの位置から格納するかを
検討するために EEPROM.h の始めに・・・
// 外付けEEPROM の使用位置のテスト
// ここでは、変数をどこに格納するかを指定する。その変数の使用する領域が他と重ならないように注意する。
//        変数名      位置              サイズ
#define    eTstInt       0x1010      // Test int   1
#define    eTstLong      0x1011      // Test long   2
#define    eTstfloat       0x1013      // Test long  4
・・・ として書いています。

なお、exe_command.c ファイルの始めに、int chip = 0; として、chipアドレスを 0に定義しています。この章のトップに書いていますように、これは J3(ジャンパ)が ON(接続)の時の状態です。J3 を OFF (chipアドレス 1)でテストする場合は、下記の 'T1' コマンドで変更する必要があります。変更しなければ、Waaaadd コマンドは、NG になります。
コマンド T0, T1, T2 の内容
T0  :  外付けEEPROMのアクセスのための chipアドレスを 0 に書き換える
T1  :  外付けEEPROMのアクセスのための chipアドレスを 1 に書き換える
T2  :  外付けEEPROMのアクセスのための現在の chipアドレスを確認する

exe_command.c、EEPROM.c ファイルを読んで、どの様にコントロールしているかを確認の上、'Tコマンド'などにご自分で色々なテストを追加して納得を深めてください。


7. ステッピングモーター(28BYJ-48)を動かす

学習用のフォルダ「C:\PIC_Practice\chap_7」を作成して下さい。このフォルダ「chap_7」の中に次の4個のファイルを入れて下さい。 main.c 、 SciCommand.c 、ST7032i_lib.c、ST7032i_lib.h です。作成方法は、これまで通りです。以前のプロジェクトと同名のファイルがありますが内容は変わっていますので注意してください。LCDは、AQM0802Aを使います。また、基板の CN-MTR に付属のコネクタ付ケーブルを使ってモーターを接続しておいて下さい(下の写真を参照)。
リスト chap_7


メニューの 「Project - New」 で chap_7 のプロジェクトを以前と同様の作業で新たに作ってください。 main.c は、プロジェクト画面の Source Files 上で右クリックして Add し、 SciCommand.c 、ST7032i_lib.c は、Other Files 上で右クリックして Add し、 ヘッダーファイルの ST7032i_lib.h は、Header Files 上で右クリックして Addして下さい。下図のプロジェクトの画面の通りにしてください。



コンパイルして、PICに書き込んで走らせてください。
この状態で、初期値の設定でモーターは回転しています。このモーターの仕様を確かめましょう。下図を参照してください。


ステッピング・モーターは、パルスに
同期して動作するモーターであり、パルスモーター(Pulse motor)とも言われるものです。正確な位置決め制御を実現できるので、装置の位置決めを行なう時に使います。上の回路図は、このモーターに付属しているドライバーのもので、PIC からは、IN1, IN2, IN3, IN4 を出力ポートでコントロールします。上記のシーケンス図の 1->2->3・・・->8->1->2・・・の順に制御すると正転(時計方向:ClockWise)し、その逆方向に制御すると逆転(反時計方向: Counter ClockWise)します。 1->2->3・・ と移動する段をステップと呼び、そのステップの移動が速ければ回転速度は上がり、遅ければ、下がります。止まれば、その位置に停止し、位置保持します。モーター設計の電気的および機械的要因によって、ある限度以上は速くはなりませんし、停止してしまいます。これを脱調(Out-of-step)と言っています。また、負荷がかかりすぎても脱調が起こりますから、脱調を起こさない範囲で使用する必要があります。このため、何の目的に使うかによってモーターを選定しなければなりません。このテストでは、上の写真の接続のように、LED1〜4 の出力ポートにモーターの IN1, IN2, IN3, IN4 を接続していますので、モーターが回転していると上図のシーケンスのように LED の点滅が移動します。このモーターのステップ角と減速ギアと出力軸の関係については、上の「モーターとギアの仕様を参照してください。



上図の左は、モーターを回転させている時の IN1, IN2, IN3, IN4 をオシロスコープで観察している状況です。@ABCDEFGは、「スイッチングシーケンス」のHigh・Low通りになっていることが分かります。またこの場合のステップ周期(T)は、1.1msであることも分かります。
上図の右は、モニターから、モーターの動作をコントロールしている状況です。コマンドとして「MSxxx」「MDx」「MBx」の3種類を実装しています。頭の2文字(例:MD + Enter)を入力すると現在の状況の表示だけをします。画面にコメントで書き入れているように制御できます。状況の表示で表示されている「mtr_timn」「mdir」「mstp」は、このプロジェクトの中で使用している変数名です。それぞれについて説明します。

mtr_timn : ステップ周期は 0.1ms x mtr_timn となっている。変数・mtr_timnを変更することでステップ周期を変更することができる。例えば、mtr_timn を 11(10進)とするとステップ周期は、1.1ms となり、上図・左の波形図のようになる。
mdir : モーターの回転方向で、0 が正転(CW)で 1 が逆転(CCW)を表し、この変数を書き換えることで回転方向を変更できる。
mstp : モーターの回転・停止で、0 が回転で 1 が停止を表し、この変数を書き換えることで回転・停止を制御できる。
このようにモニターからモーターの動作を変更することが確認できます。つまり、実用のソフトでの制御で、これらの変数を書き換えることで、モーターを自由にコントロールすることができます。

LCD には、これらの状況を表示しています。
1行目 :「 MTR- xxxx」 、正転の場合 xxxx は CW 、逆転の場合は CCW 、停止の場合は STOP と表示されます。
2行目 : 「Peri:xxx」 、Peri はPeriodの略で、ステップ周期を表しており、mtr_timnをそのまま表示しています。LCDの関係で3桁表示にしていますので、モニターコマンドで 'ms2000' などとすると確かに動作は、ステップ周期が 200ms(2000x0.1)に変わりますが、ここの表示は 'Peri: 0' となります。

基板上の SW1, SW2 から、ステップ周期と回転方向の変更ができます。SW1 を押すごとにステップ周期がインクリメント(+1)され、 SW2 を押すごとにデクリメント(-1)されます。また SW1とSW2 を同時に押すと、回転方向が入れ替わります。この変化の状況は、LCD に表示されます。

タイマー2の100us(0.1ms)割り込みが、このモーターコントロールのメインになっています。
void isr2() // 100us Interrupt OK
{
  ++Cnt100us;    // 100us counter
  ++Cnt100usA;   // used in ChkInputPin

  if(cnt_mtr-- == 0) {  // mtr_timn x 100us に1回、ここに入ってくる
    cnt_mtr = mtr_timn;     // カウンター設定値を元に戻す
    if(mstp == 0) {          // 停止であれば何もしない
      MTR_OUT(MTR_DT[i]);     // 現在の i のdataをポートに出力する
      if (mdir == 0) {
        if(++i > 7) i = 0;    // 正転(CW)
      }
      else {
        if(--i < 0) i = 7;      // 逆転(CCW)
      }
    }
  }
}
この中に、モーター制御の3つの変数(mtr_timn、mdir、mstp)が全て登場していますので、この短いルーチンを読めばモーター制御に関しては分かると思います。ここに出てくる 配列:MTR_DT[] は main.c の始めに定義しています・・・
// モーター回転データの配列 MTR_DT[0]〜MTR_DT[7] を使っている  正転 ->
int MTR_DT[9] = {0b1000, 0b1100, 0b0100, 0b0110, 0b0010, 0b0011, 0b0001, 0b1001, 0b0000};
・・・ 上に示した「スイッチングシーケンス」の通りになっています。最後の '0b0000' は使用していません。
関数:MTR_OUT(MTR_DT[i]); では、モータードライバーの IN1,IN2,IN3,IN4 に上のスイッチングデータを出力しています。

main()関数の無限ループの中は ・・・
while(true)
{
  LCD_Disp_MTR();    // LCDにモーターの状態を表示する
  MTR_SW_Cont();     // モーターの速度と回転方向をSW操作によって変える
  exe_command();     // Execute RS232C Command
}
・・・ となっています。例えば、LCD_Disp_MTR(); と MTR_SW_Cont(); の行をレム(//)にすれば、LCD 表示と SW 操作はできなくなりますが、モニターからの操作はできます。

初心者の方が、C言語で良く間違って、てこづっているケースの典型を取り上げてみます。
それは、'=', '==' と '&', '&&' また '|', '||' の使い方についてです。それぞれの前者は、「代入や演算」であり、後者は「
論理」であることを強く意識しないといけないです。間違って使っていても、コンパイルエラーは出ないケースが多いので、間違いに気付くのにさんざん時間がかかっているのです。例えば if (A = B) とした場合は、B を A に代入し、代入した結果の A の論理(true, false) によって if 文は動作します、BASIC言語などとは違うことに気をつけましょう。



【動かしましょう−2】
ここでは PIC16F1938を動かしてみます。PIC演習用基板(2)を使用します。前章の【動かしましょう-1】とダブル所もありますが、できるだけ重複してでも説明するつもりですが、長くなる場合は、前の記述を参照(リンク)していただきます。まず、RS232Cを動かして、ターゲットとパソコンで通信します。また同時に、このデバイスがもっている全てのタイマーをインターバルタイマーとして動かしてみます。
ターゲット(PIC)と実モードで対話ができる状態を作ることが、入門にはとても大切です。例えば、C言語の演算子を実際にRS232Cのモニターのコマンドで動かしてみて結果をモニターに表示することで、手応えのある理解が進みます。動作の基本となるクロックの発振モードは、内部オシレータが従来のPICに比較すると、とても高精度になっており、このPIC16F1938でも 工場にて±1% (標準)に較正されているので、外部発振子は特別な理由がない限り使わないでも済むようになってきています。この演習基板は、セラロックを実装できるようにしてはいますが、ここでは 8MHz ・16MHz ・ 32MHz の内部オシレータ設定で動作させていきます。


[ Contents ]
1. RS232Cモニター/タイマー割り込み
2. ロータリーSWの読み込みとLEDへの出力
3. LCD(ACM1602NI)への表示(I2C)
4. 内蔵EEPROMと外部EEPROM の読み書き
5. A/Dを読み出し、LCDに疑似レベルバーで表示する
6. コンパレータの動作テスト
7. DCモーターの回転と速度変更
8. RCサーボ Motorの動作テスト
9. Stepping Motorの回転
10. 超音波距離計(HC-SR04)を動かす
11. スピーカーへの単音出力
12. 音楽(オルゴール)の演奏


1. RS232Cモニター/タイマー割り込み
学習用のフォルダ「C:\PIC_Practice\chap2_1」を作成して下さい。これでは C:ドライブのルートに作成していますが、ご自分で管理できる所ならば、どこでも構いません。このフォルダ「chap2_1」の中に次の2つのファイルを入れて下さい。下のリストの main.c の範囲をドラッグして選択します、その状態で右クリックしてコピーします。それをメモ帳などのエディタに貼り付けて、名前を付けて保存で名前を main.c とします。同様に、 SciCommand.c の範囲をコピーして、 SciCommand.c とします。2つのファイルの境目の目印である・・・
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
・・・は、無視して良いです。これは以降も同様です。LCDは chap2_1 では使いませんが、接続したままでも問題ありません。


リスト chap2_1


MPLAB を起動して、プロジェクトを作成します。作成法は、「動かしましょう-1」のはじめに詳しく説明いたしましたので参照してください。ただし、Project Wizard のDevice は「PIC16F1938」を選択しなければいけません、他は同様に進めてください。Project Wizard が終了すると新プロジェクトが立ち上がります。その画面のメニュー「View」のProject と Output にチェックを入れ、またMemory Usage Gauge を見れるようにします。また、図のように、「Build Configration」を必ず Debug から Release にしてください。
「Other Files」 を右クリックして SciCommand.c を取り込みます。この時 SciCommand.c を Source Files に入れるとコンパイルエラーとなります。これは前にも説明しましたが、SciCommand.c が main.c の中で #include されているからです。SciCommand.c を Source Files に入れることも可能ですが、そうするためにはそのように記述する必要があります。この一連の演習プロジェクトでは、main.c 以外のソースファイル(.c)は全てOther Files に入れます。ファイル名をダブルクリックすると、エディタ画面で編集できるようになります(下図)。




メニューの 「Project - Build All」を実行するとコンパイルが実行され、Output 画面に、BUILD SUCCEEDED が表示されれば、成功です。プロジェクトフォルダに、「main.hex」ファイルができているはずです。
ターゲットに書き込むために、下図のように接続してください。PICkit 3 の USBケーブルをパソコンに接続し、そして
ターゲットの電源を入れて置きます



メニュー「Programmer」をクリックし、Select Programmer から、PICkit 3 を選択します。PICkit 3 を接続していなければアクティブにならず選択できないのでご注意ください。
選択すると接続が始まり、「Voltage Caution」が出ますが「OK」を押して
ここの左下の表示となれば接続が完了したことになります(ただしDevice ID Revision = 00000003 となる)。 同時に「Program, Read, Verify ・・・」などのメニューバーが使えるようになります。
 もし接続できない場合は、Select Programmer から一旦 None を選択し、つぎに先にインストールしている [ MPLAB IPE ] を起動して
接続してください。以降はこのデバイスに関しては、持続的に MPLAB から認識できます。IPE を終了して再度、Select Programmer から PICkit 3 を選択して接続して下さい。
次に書き込みです。接続でアクティブになった「Program」(または、Programmer - Program)をクリックすると現プロジェクトの HEXファイルが書き込まれて、完了するとターゲットは動作を開始(RUN)します。

次に、ターゲットとの対話です。上の写真の接続では、ストレートケーブルを接続していますが、USBシリアルケーブルでも勿論OKです。テラタームを起動して 前章で説明した設定(赤の囲み)をしてください。


2. ロータリーSWの読み込みとLEDへの出力
学習用のフォルダ「C:\PIC_Practice\chap2_2」を作成し、その中に main.c, SciCommand.c, を入れて下さい。下のリストの各ファイル の範囲をドラッグして選択し、メモ帳などのエディタに貼り付けて、名前を付けて保存で各ファイルを作ってください。


リスト chap2_2


MPLAB を起動して、プロジェクトを作成します。作成法は、先に紹介した通りです。
下図のように構成してください。




メニューの 「Project - Build All」を実行するとコンパイルが実行され、Output 画面に、BUILD SUCCEEDED が表示されれば、成功です。プロジェクトフォルダに、「main.hex」ファイルができているはずです。
先の例のように接続し、PICkit 3 の USBケーブルをパソコンに接続し、ターゲットの電源を入れて置き、書き込んでください

このサンプルは、非常に単純です。タイマ1、タイマ2、RS232C も「chap2_1」と同じ設定で入れていますが具体的には使っていません。ですが、特にこれらが特別な他の用途がない限り、これらを入れておくと大変に便利です。
main関数の・・・

   while(true)
   {
      DSW_DT = ~input_b();       // ロータリーSWの読み込み
      output_a(DSW_DT << 2);     // PORTA のLEDに出力する

      exe_command();    // Execute RS232C Command
   }

・・・の部分によって、ロータリーSWの数値が LEDに BCD (Binary Coded Decimal)で表示されていることが分かります。このような単純なプロジェクトの時に、「ビット演算子」や「シフト演算子」のテストを十分にされることをお勧めします
例えば、RS232Cのコマンド "T1"を入力するとテラタームの画面では・・・
T1
SW_DT: 09
SW_DT: F6
・・・と表示され、ロータリーSWの数値の状況を、そのまま読んだ値とリバース(1の補数)した値を比較して納得することができます(ロータリーSWの数値は、下の1桁)。
このように、RS232Cのモニタに自分のテスト用の短いプログラムを組み込んで様々なテストをして見てください。


3. LCD(ACM1602NI)への表示(I2C)
学習用のフォルダ「C:\PIC_Practice\chap2_2」を作成し、その中に main.c, SciCommand.c, ACM1602_lib.c, ACM1602_lib.h を入れて下さい。下のリストの各ファイル の範囲をドラッグして選択し、メモ帳などのエディタに貼り付けて、名前を付けて保存で各ファイルを作ってください。もちろん、LCD(ACM1602NI)を取り付けておいてください。このLCDは、秋月電子工房さんで取り扱っています。


リスト chap2_3


MPLAB を起動して、プロジェクトを作成します。作成法は、先に紹介した通りです。
下図のように構成してください。




メニューの 「Project - Build All」を実行するとコンパイルが実行され、Output 画面に、BUILD SUCCEEDED が表示されれば、成功です。プロジェクトフォルダに、「main.hex」ファイルができているはずです。
先の例のように接続し、PICkit 3 の USBケーブルをパソコンに接続し、ターゲットの電源を入れて置き、書き込んでください


動作を開始すると左図のように一秒ごとに経過した秒数を表示していきます。左の表示はすでに10時間半くらい経過していますが・・・

プログラムを書く上では、まず I2Cの設定をします。最初に下の行で I2C使用宣言をします。これは、RS232Cの使用宣言と同様にプログラムの最初に記述します。

#use i2c(MASTER, SDA=PIN_C4,
    SCL=PIN_C3, ADDRESS=0xa0,
            FORCE_HW)


次に、main 関数の始めで、次のような I2Cの初期化をします。
   // Set for I2C
   output_float(PIN_C3); // SCL
   output_float(PIN_C4); // SDA

これは、
必ず必要です。以上の記述で I2Cは使用できるようになります。外付けEEPROM などのような他の I2Cデバイスと混在する場合でも全く同じです。

この後は、個々のデバイスの I2Cの初期化をします。この場合 ACM1602NI というLCDです。
   acmLCD_init();
   acmLCD_Clear();
これで、LCDの初期化は完了しました。いつでもLCDを使用できる状態になりました。レム文にも書いていますが、acmLCD_Init(); を実行する時に、LCDのデバイスを取り付けていないと、この関数から戻ってこないので注意してください。
   acmLCD_SetCursor(0, 1);
   acmLCD_Puts(TstStr);
上の行で、LCDに書き込む際のカーソルの位置を設定しています。桁も行も、0数えです。
この場合、LCDの2行目の先頭にカーソルが来ます。次の行で TstStr ("ACM1602NI-DspTst") がLCDの2行目に表示されます。
この後、無限ループに入ります。
   while(true)
   {   
      if (SecNum != SecNumS) {
         acmLCD_SetCursor(0, 0);
         printf(acmLCD_Putc, "SecNum : %lu", SecNum);
         SecNumS = SecNum;
      }

      exe_command(); // Execute RS232C Command
   }
無限ループの毎回にLCD表示を行うのではなく、SecNum が変わった時だけ1行目に表示するようにしています。SecNum はタイマ1で一秒ごとに更新されています。exe_command(); は、RS232Cに受信コマンドがあった時のみ実行されます。
ACM1602_lib.c の中にこのLCDに使える様々な関数が記入されていますから、色々と研究してみて下さい。


4. 内蔵EEPROMと外部EEPROM の読み書き
学習用のフォルダ「C:\PIC_Practice\chap2_4」を作成し、その中に main.c, SciCommand.c, を入れて下さい。下のリストの各ファイル の範囲をドラッグして選択し、メモ帳などのエディタに貼り付けて、名前を付けて保存で各ファイルを作ってください。今回は、LCDは使いませんが付けたままで良いです。


リスト chap2_4


MPLAB を起動して、プロジェクトを作成します。作成法は、先に紹介した通りです。
下図のように構成してください。




メニューの 「Project - Build All」を実行するとコンパイルが実行され、Output 画面に、BUILD SUCCEEDED が表示されれば、成功です。プロジェクトフォルダに、「main.hex」ファイルができているはずです。
先の例のように接続し、PICkit 3 の USBケーブルをパソコンに接続し、ターゲットの電源を入れて置き、書き込んでください

このサンプルでは、RS232C のコマンドだけですべてのテストを行います。
main関数は・・・
   while(true)
   {

      exe_command();    // Execute RS232C Command
   }
・・・で、RS232Cのコマンドのみを実行します。I2C の設定は先に説明した通りです。この外付けEEPRONのアクセスでは、特にデバイスの初期化の必要はありません。
それでは、コマンドを実行して見ます。



上図の左側で、コマンド '?' を実行するとメニューが出ています。内蔵EEPROMのアドレス '10' に、データ '1C' を書き込むコマンド 'W101C' を実行します。コマンド 'R' で内蔵EEPROMのすべてを読み出します(256バイト)。そうすると確かにアドレス '10' に、データ '1C' が書き込まれていることが確認できます。

次に上図の右側で、外付けEEPROMにアクセスします。アドレス '1000' に、データ 'BC' を書き込むコマンド 'W1000BC' を実行します。
次に、アドレス '1000' のデータを 256バイト読み出すコマンド 'R10' を実行します。確かにアドレス '1000' に、データ 'BC' が書き込まれていることが確認できます。

内蔵・外付けEEPROMのアクセスに関しては、exe_command()内のサンプルを見ますと了解できると思います。ちなみに外付けEEPROMの I2Cアドレスは '1' としています。この場合、ハードウェア的には JP3 の接続を外しておかなくては、このサンプルでは動作しません。JP3 を接続すると、外付けEEPROMの I2Cアドレスは '0' となります。
exe_command()内の外付けEEPROMにアクセスする部分に次のような行が2箇所あります。
   adr = 0xA2;     //chip select アドレスは 001 に固定している(JP3->OFF)
アドレス '0' にアクセスする場合は、この 0xA2 を 0xA0 に変更しなければいけません。この説明は、関数 main()の下側に記述している、「外付けEEPROMの1バイト単位の書き込みと読み出し」の中に書いております。さまざまにアクセスして納得してください。


5. A/Dを読み出し、LCDに疑似レベルバーで表示する
学習用のフォルダ「C:\PIC_Practice\chap2_5」を作成し、その中に main.c, SciCommand.c, ACM1602_lib.c, ACM1602_lib.h を入れて下さい。下のリストの各ファイル の範囲をドラッグして選択し、メモ帳などのエディタに貼り付けて、名前を付けて保存で各ファイルを作ってください。もちろん、LCD(ACM1602NI)を取り付けておき、アナログの内部入力を取り込むための JP1, JP2 を接続してください。


リスト chap2_5


MPLAB を起動して、プロジェクトを作成します。作成法は、先に紹介した通りです。
下図のように構成してください。




メニューの 「Project - Build All」を実行するとコンパイルが実行され、Output 画面に、BUILD SUCCEEDED が表示されれば、成功です。プロジェクトフォルダに、「main.hex」ファイルができているはずです。
先の例のように接続し、PICkit 3 の USBケーブルをパソコンに接続し、ターゲットの電源を入れて置き、書き込んでください

 このプロジェクトは、先の PIC16F1827の chap5 と動作的には全く同じです。ただ大きく異なるのはLCDの仕様がかなり違っていることです。

先のLCDは、AQM0802A であり、そのライブラリファイルは、ST7032i_lib.c、ST7032i_lib.h で、コマンドの先頭に stiLCD_・・・という接頭文字がついていました。
今回は、
ACM1602NI で、ライブラリファイルは、ACM1602_lib.c, ACM1602_lib.h であり、コマンドの先頭に acmLCD・・・という接頭文字を持っています。

接頭文字以降のコマンド名は、まったく同じになっていますから、同類のものの接頭文字を入れ替えればそのまま動作させることができます。

まったく違っているのがコントラスト調整です。先のAQM0802Aがコマンドでコントラストを変更したのに対して、これで使っている ACM1602NI は、外付けボリュームで行います。図のオレンジで囲っているボリームです。

動作は、図の上の方にある VR1 を廻すと LCD の一行目の CH0 の数値とレベルバーが変化します。
数値は 0.00 〜 3.30 の間をボリュームの調節にしたがって変わります。 同様に、その右隣りにある VR2 を廻すと LCDの二行目 の CH1 の数値とレベルバーが変化します。

動きは chap5 とまったく同じですので、ソフトウェアの解説については、そちらをご参照ください。


6. コンパレータの動作テスト
学習用のフォルダ「C:\PIC_Practice\chap2_6」を作成し、その中に main.c, SciCommand.c, ACM1602_lib.c, ACM1602_lib.h を入れて下さい。下のリストの各ファイル の範囲をドラッグして選択し、メモ帳などのエディタに貼り付けて、名前を付けて保存で各ファイルを作ってください。もちろん、LCD(ACM1602NI)を取り付けておき、アナログの内部入力を取り込むための JP1, JP2 を接続してください。


リスト chap2_6


MPLAB を起動して、プロジェクトを作成します。作成法は、先に紹介した通りです。
下図のように構成してください。




メニューの 「Project - Build All」を実行するとコンパイルが実行され、Output 画面に、BUILD SUCCEEDED が表示されれば、成功です。プロジェクトフォルダに、「main.hex」ファイルができているはずです。
先の例のように接続し、PICkit 3 の USBケーブルをパソコンに接続し、ターゲットの電源を入れて置き、書き込んでください

PIC16F1938 のコンパレータは、 「改訂版・C言語によるPICプログラミング入門」のサンプルで使っている PIC16F88xシリーズとは、コンパレータの構成がかなり変わっています。ですので、この書籍は、コンパレータに関してはリファレンスとしては使えません。幸い PIC16F193xシリーズには、日本語のデータシート があり、143〜144ページにコンパレータの概要が分かりやすく書いてあります。それを見ると、内容的には逆にシンプルになり分かりやすくなっていると思います。また、上のプロジェクト図には、「Header Files」の中に「16F1938.hを取り込んでいます。これは、コンパレータやその他の周辺回路をセットアップするための CCS-C の定数が載っており、これと日本語データシートの説明を合わせて読めば、
どのような定数を選んでセットアップすれば良いかがおおよそ見当が付きます。この「16F1938.h」の在り場所は CCS-C が組み込んである「C:\Program Files\PICC\Devices」(64bitの場合はProgram Files (x86)) ですので、上のようにプロジェクトに取り込んで置けば、すぐに参照することができます。
もちろんプログラム本体で #include <16F1938.h> としていますから、ここに取り込まなくてもコンパイルはできますが、CCS-C の組み込み関数の使い方を検討する時に見る必要がありますので便利です。

とにかく、まず動かして見ましょう。コンパレータのリファレンス入力は DAC による設定にしています。その DAC の出力電圧は 1.65V にしています。
CH0 は 1.64V を指していますのでリファレンス電圧の 1.65V より小さいのでコンパレータは ON していません。 CH1 は 1.84V であり、コンパレータは ON しています。
コンパレータの出力をそれぞれ LED3 と LED4 に出力していますので、 LED3 は OFF、LED4 は ON しています。VR1, VR2 を回してみて 1.65V 前後で ON/OFF することを確認してください。

main関数のコンパレータのセットアップ部を下記に示します。
// ***** コンパレータの FVRによる設定 *****
//setup_comparator(CP1_A0_FVR | CP2_A1_FVR
//    | CP1_OUT_ON_A4 | CP2_OUT_ON_A5 | CP1_INVERT | CP2_INVERT);
//setup_vref(VREF_COMP_DAC_2v048);    // FVR設定 2.048V

// ***** コンパレータの DACによる設定 *****
setup_comparator(CP1_A0_DAC | CP2_A1_DAC
    | CP1_OUT_ON_A4 | CP2_OUT_ON_A5 | CP1_INVERT | CP2_INVERT);
setup_dac(DAC_VSS_VDD);  // DAC設定
dac_write(16);      // DAC値書き込み(0〜31) VDDx(値/32), 16->1.65V

現在、上のコンパレータの FVRによる設定の3行は、コメントアウトされています。下の「コンパレータの DACによる設定」で動いています。 リファリンス電圧は、(3.3V / 32) x 16 = 1.65V の設定です。dac_write(16); の数値を 0〜31 の間に変えることによって ON/OFF する電圧を変更できます。
上の「コンパレータの FVRによる設定」のコメントを解除して、下の「コンパレータの DACによる設定」の部分をコメントアウトすることで、FVR(固定電圧リファレンス)を使う動作になります。「16F1938.h」を参照すると・・・
#define  VREF_COMP_DAC_OFF    0
#define  VREF_COMP_DAC_1v024   0x84
#define  VREF_COMP_DAC_2v048   0x88
#define  VREF_COMP_DAC_4v096   0x8C
・・・となっており、現在の設定の 2.048V以外に、1.024V と 4.096V を選択することができます。
まずは基本的な動作のテストをしました。必要に応じて、マニュアルの「コンパレータ モジュールの概略ブロック図」を参照しながら、割り込みなども使うことができます。


7. DCモーターの回転と速度変更
学習用のフォルダ「C:\PIC_Practice\chap2_7」を作成し、その中に main.c, SciCommand.c, ACM1602_lib.c, ACM1602_lib.h を入れて下さい。下のリストの各ファイル の範囲をドラッグして選択し、メモ帳などのエディタに貼り付けて、名前を付けて保存で各ファイルを作ってください。もちろん、LCD(ACM1602NI)を取り付けておき、アナログの内部入力を取り込むための JP1 を接続してください。DCモーターの制御入力(PWM)は、PIC の 13番ピン(CCP1)です。ここにはスピーカーアンプの入力も接続されています。サーボ制御は 20kHz となり、スピーカーの再生範囲を超えており聞こえませんがノイズが出ますので VR3を下げて動かして下さい。


リスト chap2_7


MPLAB を起動して、プロジェクトを作成します。作成法は、先に紹介した通りです。
下図のように構成してください。




メニューの 「Project - Build All」を実行するとコンパイルが実行され、Output 画面に、BUILD SUCCEEDED が表示されれば、成功です。プロジェクトフォルダに、「main.hex」ファイルができているはずです。
先の例のように接続し、PICkit 3 の USBケーブルをパソコンに接続し、ターゲットの電源を入れて置き、書き込んでください

このDCモーターの速度コントロールは、まったく単純PWMの応用です。 setup_ccp1(CCP_PWM); でCCP1をPWMモードにして、一緒に関連して動く Timer2 を setup_timer_2(T2_DIV_BY_1, FULL, 1); の文で 20kHz(周期 50us) で動作するように設定します。タイマ2の割り込みを記述していますが、これは動作的には全く使用していません、単に周期を確認するモニターとしての使用です。

このモーターの品番は RS-385PH で定格電圧は 6Vですが、左図で分かりますように、コネクタ CN-STP_MTR (基板上部の中央)の 5番ピンの 5V(赤の線)で動作させています。モーターのマイナス側は、コネクタ CN-DC_MTR (基板左側)の 3番ピン(茶色の線、TR2を通ったCCP1の出力) に接続します。JP7を接続しておく必要があります。 
回路図 を参照してください。

動作としては、ADC-CH0を読み込みます。その読み値は 10ビットですから、0〜1023 になります。
setup_timer_2(T2_DIV_BY_1, FULL, 1); の設定で FULL(200)の値をタイマ2の比較設定値にしていますから、デューティ設定値を FULL(200)とするとデューティは、100%となります。ADCの電圧でデューティを設定する関数は次の通りです。
void SetDuty(void)
{
   if (adata != adatas) {
      DUTY = (long)(Ritu * adata);
      CCPR1L = DUTY;
      adatas = adata;   //前回値を更新
   }
   delay_ms(100);
}
ADC の読み込み値が 1023(VR1を右いっぱい)の時に、変数DUTYを 200にするための定数(Ritu = 0.1956)を掛けて、ADC値をデューティに変換した DUTY を CCPR1L (デューティ設定レジスタ) に設定する様にしています。モーターの電源は、基板から取るよりも別電源を使った方が良いです。テストでは上図のように基板からとっていますので、ADCの読み込み値にノイズが入っています。上図の ADC CH0 の読み値の一桁目がかなり動いているのが分かります。VR1 を動かすとデューティが変わり、モーターのスピードが変化します。このモーターでは、デューティを 60% 以下にするとモーターは停止してしまいます。このコントロールの仕方は、光源の明るさを変えたりするなどの応用にも使われています。 「改訂版・C言語によるPICプログラミング入門」の340ページには、DCモーターの正転・逆転をコントロールする例が書かれています。しかし、かなり複雑な外付け回路が必要です。
実際のところ、正転・逆転・停止・ブレーキができるパラレルインターフェイスや I2Cのシリアルインターフェイスを持った組み込み用ドライバー基板が比較的安価で色々と供給されていますので、DCモーターの制御には、これらを使うのが実際的かなとも思われます。



8. RCサーボ Motorの動作テスト
学習用のフォルダ「C:\PIC_Practice\chap2_8」を作成し、その中に main.c, SciCommand.c, ACM1602_lib.c, ACM1602_lib.h を入れて下さい。下のリストの各ファイル の範囲をドラッグして選択し、メモ帳などのエディタに貼り付けて、名前を付けて保存で各ファイルを作ってください。もちろん、LCD(ACM1602NI)を取り付けておき、アナログの内部入力を取り込むための JP1 を接続してください。また、RCサーボモータ(SG90)の接続は、赤色の線は コネクタ CN-STO_MTR の 5番(+5V)へ、茶色の線は同じコネクタの 6番(GND)へ、オレンジの線は、コネクタ CN-SENSEの 3番(CCP1)に接続してください。サーボの制御入力(PWM)は、PIC の 13番ピン(CCP1)です。ここにはスピーカーアンプの入力も接続されています。サーボ制御は 50Hz となり、スピーカーの再生範囲ではないので 50Hz としては聞こえませんがノイズが出ますので VR3を下げて動作させて下さい。このモーターも秋月電子通商さんで取り扱っています。

リスト chap2_8


MPLAB を起動して、プロジェクトを作成します。作成法は、先に紹介した通りです。
下図のように構成してください。



メニューの 「Project - Build All」を実行するとコンパイルが実行され、Output 画面に、BUILD SUCCEEDED が表示されれば、成功です。プロジェクトフォルダに、「main.hex」ファイルができているはずです。
先の例のように接続し、PICkit 3 の USBケーブルをパソコンに接続し、ターゲットの電源を入れて置き、書き込んでください
ここで使っているRCサーボモーターの型番は、SG90 です。その仕様書を参照してください。

リモコンの自動車のハンドルを切ったり、飛行機の補助翼を操作したりする様な時に使います。
この仕様によれば、20ms 間隔で送るパルスの幅が 0.5ms の時には -90°となり、2.4ms の時には +90°となり、1.45msで中央の 0°となります。例えば、0.5ms のパルスを送り続けていれば -90°の位置を保持し続ける(サーボ)動作をします。

結論から言えば、どのような方法でも構わないので、20ms 間隔で、保持したい位置のパルス幅(0.5〜2.4ms)を送り続ければ指定した角度の位置に停止するのです。

まずは動かして見ましょう。走らせ始める(初期状態) と、-90°からある角度(2.368°)づつ一定間隔で +90°に向かって動いて行き、+90°に達すると一気に -90°に戻ります。これを無限に繰り返します。これは、「改訂版・C言語によるPICプログラミング入門」の 336〜338ページにあるサンプルソフトと同じ動作です。
この電源投入時の動作を「AUTO」モードと言っています。このソフトでは、これとは別に2モードを持っています。
「MANUAL」モードと「MONITOR」モードです。左図を参照して、コマンド 'M1'を入力すると「MANUAL」モードに切り変わります。このモードでは、基板上部の VR1 を使ってサーボモーターを制御します。
VR1 を左回し一杯とすると -90°(0.5ms) となります。右回し一杯とすると +90°(2.4ms)になり、VR1 の回転に応じてサーボの位置が自在に変更できるのが分かります。

次に、コマンド 'M2'を入力すると「MONITOR」モードに切り替わり、RS232C のコマンドでサーボをコントロールできるようになります。
ただ、この時に入力する 'wxxxx' の xxxx は、ソフトの変数 Width1 に代入されるので、その範囲が決まっています。main関数内のレム文を見ると分かりますが 1000〜4800 が取りうる範囲になっています。
1000 で -90°(0.5ms)、4800で +90°(2.4ms) です。2900 で 0°(1.45ms) の中央になります。

コンペアモードでは、上の本の 326ページに記述されているように、
CCP1 は TIMER1と密接な関係があります。つまり、ワンショットのパルス幅を決定することができる訳です。また、このソフトでは、20ms のベースのタイマーとしては TIMER2 を使っています。上記の本では TIMER0を使っています。
理由は、このソフトのクロックが16MHzなので、TIMER0では、うまく 20ms が作れないので TIMER2 に変更しています。
のソフトの構成で
一番大切な働きは TIMER2 の割り込み内の処理が担っています。


   #int_timer2
   void isr2(void) {       // 50Hzで入ってくる(周期20ms)
     setup_ccp1(CCP_OFF);                 //CCP1出力オフ(Low)
     setup_ccp1(CCP_COMPARE_CLR_ON_MATCH);     //コンペアモード再セット
     CCP_1 = Width1;                   //コンペア値再セット
     set_timer1(0);                     //タイマ1リセット

    ++Cnt20ms;           // タイマーカウンタ
     output_toggle(MONI);       // 確認用モニター(周期20ms)-OK
   }
どのモードからも簡単にサーボモーターをコントロールできましたが、それはこの割り込みの中で、パルス幅を決める
Width1 (Global変数)を各モードの中で変更しているからです。Timer2 の割り込み処理内の説明は、次の通りです。
タイマ2の 20ms ごとの割り込み処理では、まずいったん CCP1 をオフにして出力を Low としています。その後 CCP をコンペアモードに再設定し、ワンショットパルスとして
Width1 をパルス幅データとして設定し、タイマ1のカウンタをリセットして正確なパルス幅になるようにしています。

先に述べましたように、このプログラムでは、3つのMODEを持っています。上の例では、モニター(RS232C)でMODEを切り替えました。それ以外に基板上の2つの押し釦SW(1と2)でも切り替えることができます。SW1 のみを 1秒以上押すと MANUAL(A/D)に切り替わります。また SW2 のみを 1秒以上押すと MONITOR(SCI)に切り替わります。また、SW1 と SW2 を同時に 1秒以上押すと初期の AUTO に切り替わります。

なお、LCD に '°'を表示するために、LCD の CGRAM に '°'を一文字登録し、LCD_Disp(void)の中で、acmLCD_Putc(0x08); にて表示しています。
これでは、SW の操作やモニターを活用しました。SciCommand.c 内の各ルーチンは、'C言語'の学習に役に立つと思います。このファイルの先頭で #include <stdlib.h> を実行しています。これは標準関数 atol(p); を使用するためにインクルードすることが必要です(先の本の 208 〜 209 ページを参照:ライブラリ)。


9. Stepping Motorの回転

学習用のフォルダ「C:\PIC_Practice\chap2_9」を作成して下さい。このフォルダの中に次の4個のファイルを入れて下さい。 main.c 、 SciCommand.c 、ACM1602_lib.c、ACM1602_lib.h です。作成方法は、これまで通りです。もちろん、LCD(ACM1602NI)を取り付けてください。また、基板の CN-STP_MTR に付属のコネクタ付ケーブルを使ってモーターを接続しておいて下さい(下の写真を参照)。
この chap2_9 は、前の 16F1827 で行った chap_7 と全く同じ動作です。したがって説明も、ほぼそのまま引用します。
リスト chap2_9


メニューの 「Project - New」 で chap2_9 のプロジェクトを以前と同様の作業で新たに作ってください。 main.c は、プロジェクト画面の Source Files 上で右クリックして Add し、 SciCommand.c 、ACM1602_lib.c は、Other Files 上で右クリックして Add し、 ヘッダーファイルの ACM1602_lib.h は、Header Files 上で右クリックして Addして下さい。下図のプロジェクトの画面の通りにしてください。



コンパイルして、PICに書き込んで走らせてください。
この状態で、初期値の設定でモーターは回転しています。このモーターの仕様を確かめましょう。下図を参照してください。


ステッピング・モーターは、パルスに
同期して動作するモーターであり、パルスモーター(Pulse motor)とも言われるものです。正確な位置決め制御を実現できるので、装置の位置決めを行なう時に使います。上の回路図は、このモーターに付属しているドライバーのもので、PIC からは、IN1, IN2, IN3, IN4 を出力ポートでコントロールします。上記のシーケンス図の 1->2->3・・・->8->1->2・・・の順に制御すると正転(時計方向:ClockWise)し、その逆方向に制御すると逆転(反時計方向: Counter ClockWise)します。 1->2->3・・ と移動する段をステップと呼び、そのステップの移動が速ければ回転速度は上がり、遅ければ、下がります。止まれば、その位置に停止し、位置保持します。モーター設計の電気的および機械的要因によって、ある限度以上は速くはなりませんし、停止してしまいます。これを脱調(Out-of-step)と言っています。また、負荷がかかりすぎても脱調が起こりますから、脱調を起こさない範囲で使用する必要があります。このため、何の目的に使うかによってモーターを選定しなければなりません。このテストでは、上の写真の接続のように、LED1〜4 の出力ポートにモーターの IN1, IN2, IN3, IN4 を接続していますので、モーターが回転していると上図のシーケンスのように LED の点滅が移動します。このモーターのステップ角と減速ギアと出力軸の関係については、上の「モーターとギアの仕様を参照してください。



上図の左は、モーターを回転させている時の IN1, IN2, IN3, IN4 をオシロスコープで観察している状況です。@ABCDEFGは、「スイッチングシーケンス」のHigh・Low通りになっていることが分かります。またこの場合のステップ周期(T)は、1.1msであることも分かります。
上図の右は、モニターから、モーターの動作をコントロールしている状況です。コマンドとして「MSxxx」「MDx」「MBx」の3種類を実装しています。頭の2文字(例:MD + Enter)を入力すると現在の状況の表示だけをします。画面にコメントで書き入れているように制御できます。状況の表示で表示されている「mtr_timn」「mdir」「mstp」は、このプロジェクトの中で使用している変数名です。それぞれについて説明します。

mtr_timn : ステップ周期は 0.1ms x mtr_timn となっている。変数・mtr_timnを変更することでステップ周期を変更することができる。例えば、mtr_timn を 11(10進)とするとステップ周期は、1.1ms となり、上図・左の波形図のようになる。
mdir : モーターの回転方向で、0 が正転(CW)で 1 が逆転(CCW)を表し、この変数を書き換えることで回転方向を変更できる。
mstp : モーターの回転・停止で、0 が回転で 1 が停止を表し、この変数を書き換えることで回転・停止を制御できる。
このようにモニターからモーターの動作を変更することが確認できます。つまり、実用のソフトでの制御で、これらの変数を書き換えることで、モーターを自由にコントロールすることができます。

LCD には、これらの状況を表示しています。
1行目 :「 Mortor DIR - xxxx」 、正転の場合 xxxx は CW 、逆転の場合は CCW 、停止の場合は STOP と表示されます。
2行目 : 「Period :  xxxx」 、Period は、ステップ周期を表しており、mtr_timnをそのまま表示しています。つまり、モニターコマンドで 'ms2000' などとする、ステップ周期が 200ms(2000x0.1)に変わります。

基板上の SW1, SW2 から、ステップ周期と回転方向の変更ができます。SW1 を押すごとにステップ周期がインクリメント(+1)され、 SW2 を押すごとにデクリメント(-1)されます。また SW1とSW2 を同時に押すと、回転方向が入れ替わります。この変化の状況は、LCD に表示されます。

タイマー2の100us(0.1ms)割り込みが、このモーターコントロールのメインになっています。
void isr2() // 100us Interrupt OK
{
  ++Cnt100us;    // 100us counter

  if(cnt_mtr-- == 0) {  // mtr_timn x 100us に1回、ここに入ってくる
    cnt_mtr = mtr_timn;     // カウンター設定値を元に戻す
    if(mstp == 0) {          // 停止であれば何もしない
      MTR_OUT(MTR_DT[i]);     // 現在の i のdataをポートに出力する
      if (mdir == 0) {
        if(++i > 7) i = 0;    // 正転(CW)
      }
      else {
        if(--i < 0) i = 7;      // 逆転(CCW)
      }
    }
  }
}
この中に、モーター制御の3つの変数(mtr_timn、mdir、mstp)が全て登場していますので、この短いルーチンを読めばモーター制御に関しては分かると思います。ここに出てくる 配列:MTR_DT[] は main.c の始めに定義しています・・・
// モーター回転データの配列 MTR_DT[0]〜MTR_DT[7] を使っている  正転 ->
int MTR_DT[9] = {0b1000, 0b1100, 0b0100, 0b0110, 0b0010, 0b0011, 0b0001, 0b1001, 0b0000};
・・・ 上に示した「スイッチングシーケンス」の通りになっています。最後の '0b0000' は使用していません。
関数:MTR_OUT(MTR_DT[i]); では、モータードライバーの IN1,IN2,IN3,IN4 に上のスイッチングデータを出力しています。

ステッピング・モーターにも、色々なタイプのものが有ります。基本的には、そのモーター合ったドライバー用のICや、それを搭載した基板を使うことになると思います。しかし考え方は全く同じですが、そのシーケンスの構成は仕様書に合わせて構成してください。このテストに使用したモーターのスピードやトルクはとても小さいですが、それらが大きいものも沢山あります(例えばコピー機の紙の移動など)。


10. 超音波距離計(HC-SR04)を動かす

学習用のフォルダ「C:\PIC_Practice\chap2_10」を作成して下さい。このフォルダの中に次の4個のファイルを入れて下さい。 main.c 、 SciCommand.c 、ACM1602_lib.c、ACM1602_lib.h です。作成方法は、これまで通りです。もちろん、LCD(ACM1602NI)を取り付けてください。また、距離計の
HC-SR04 を コネクタ CN-SENSE に付属のコネクタ付ケーブルを使って接続しておいて下さい(下の写真を参照)。さらにもう一つ、下の写真のように RC1 と RC2 をあらかじめジャンパーしておく必要があります。これを接続しておかないと動作しません。

リスト chap2_10


メニューの 「Project - New」 で chap2_10 のプロジェクトを以前と同様の作業で新たに作ってください。 main.c は、プロジェクト画面の Source Files 上で右クリックして Add し、 SciCommand.c 、ACM1602_lib.c は、Other Files 上で右クリックして Add し、 ヘッダーファイルの ACM1602_lib.h は、Header Files 上で右クリックして Addして下さい。下図のプロジェクトの画面の通りにしてください。



コンパイルして、PICに書き込んで走らせてください。
距離計 HC-SR04 を対象物に向けてください。 0.5秒おきに、距離の計測をして LCDの2行目に表示いたします。

HC-SR04 の仕様によれば、10us のトリガを掛けると、その後に対象物までの往復にかかった時間が High である Echo パルスで返ってきます。
この Echo パルスの長さは、往復にかかった時間を示しています。(左のオシロ図を参照)
したがって、この往復にかかった時間を得ることによって、計算によって片道の距離が分かるわけです。音速は温度によって変化( 331.5 + 0.61 x 摂氏温度 )します。おおかた気温15°で 340m/s の速度になります。A/Dに温度計を付ければ校正することもできますが、今回はそれはなしで進めます。

また、パルス幅を測るやり方も、Timer1のゲート信号による方式や、PIC16F1シリーズで新たに追加された 24bit のカウンタによる本格的な SMT (Signal Mesurement Timer)機能などがあります。しかし、今回のハードウェアでは、前者は、T1CKIを他の目的に使っているため使えませんし、後者は、16F1938には搭載されていないので使えません。

それで、「改訂版・C言語によるPICプログラミング入門」の 334 〜 336ページに記載されている2つの CCP を使ったやり方を使います。このためには、写真のように RC1 と RC2 をあらかじめピンを使ってジャンパーしておく必要があります。これは、CCP1 と CCP2 に同じ信号を入れて、Echo の立ち上がりを CCP2 でキャプチャし、立ち下がり時点で CCP1 でキャプチャするようにするわけです。

このソフトを制作する前に、上記の本に記載されている「USARTのボーレートの測定」を実行し、動作確認をしました。そこに記述されている内容は、今回の計測にも、ズバリ参考になると思います。

Echo の立ち上がりを CCP2 でキャプチャし、立ち下がりを CCP1 でキャプチャしたあと、CCP1 の割り込みが入りますから、ここで両者のキャプチャ値の差をとれば、Echo の幅が PIC のサイクルタイムの単位で分かることになります。

対象物までの距離を出す計算は、main.c の void CalcDistDspLcd(void) の中にレム文でも書いています。

【 対象物までの距離の計算 (音速を340m/sとして計算する) 】
  (1) 片道の距離(cm)=T(Echo:us)×1/2×340(m/s)×100(cm/m)×1/1000000(us/s)
  (2) 上の式をまとめると 片道の距離(cm)=往復の時間T(Echo:us) × 0.017(cm/us)
  ----------------
  
対象物までの往復の時間(us)が分かれば、上記の式によって片道の距離(cm)が出る
  pulse は (Freq/4)をカウントしている、その周期は(4000000/Freq)(us)である
  したがって (4000000/Freq) × pulse により往復の時間(us)が出る

これに従って、void CalcDistDspLcd(void)の中で・・・
  Distance = ((4000000/(float)Freq) * pulse) * 0.017;    //対象迄の距離(cm)
・・・という計算式で、対象までの距離をセンチ単位でだしています。

実際に動作している波形図は、上のオシロの図の通りです。対象物を移動して計測結果と実距離を比較してみましたが、思ったよりは正確な測定ができていると思いました。ネット上では、詳細な誤差まで出している方もいるので、参考にされると良いかもしれません。

【 注意 】 HC-SR04 の測定可能距離は仕様書上では、2cm-400cm となっています。しかし、クロック16MHz で今の設定では、使っているカウンタが 16bit であるので、270cmくらいまでしか計測できないです。分解能は下がるけれども、setup_timer_1()のプリスケーラを T1_DIV_BY_2 にすると HC-SR04の測定可能距離(2cm-400cm)を十分カバーできます。もちろん距離の計算式も、それに合わせることが必要ですが・・・。使用目的に応じて使い分けると良いと思います。しかし、この様なことを考慮すると、PIC16F1シリーズで新たに追加された 24bit のカウンタによる本格的な SMT (Signal Mesurement Timer)機能を使うのは魅力的ですね。16F161x、16F188xx、12F161x などに搭載され、同時に Zero-Cross Detect 機能もあるので計測にはうってつけです。
ここに、PIC16F1619 の SMT を使った「同じ距離計の例、および SMT, ZCD を使った「電源周波数測定の例を掲載しています。カウンタのビット数が 24bitということは 16bitよりも 256倍の数をカウントできるので、メチャクチャな余裕があります。

;------------------------- USARTのボーレートの測定 ( おまけ ) ----------------------------
このソフトを作成する前に、「USARTのボーレートの測定」を実行したと書きました。そのコードの main.c のみを掲載して置きます。SciCommand.c, ACM1602_lib.c, ACM1602_lib.h は、そのまま使用して main.c のみを入れ替えたプロジェクトを別に作ります。HC-SR04 は取り外して
CN-PROG の 6番ピン(TX) と、CN-SENSE の 3番ピン(RC2) を接続してください(下の写真を参照)。RS232C の TX 信号を計測ピンにつなぐわけです。このコードは上記の本の 335 〜 336ページと同じ構成です。ただ、サンプルではクロックが 10MHz でしたが、これでは 16MHz ですので、これに関連する項目の変更しています。また、LCD も I2C を使うものに変えていますので、その部分の変更もしています。



実行している写真とオシロ観測波形を下に示します。測定したのは、USART のボーレート設定が 19200bps ですので、ほぼ近い値がでています。




11. スピーカーへの単音出力
学習用のフォルダ「C:\PIC_Practice\chap2_11」を作成し、その中に main.c, SciCommand.c, を入れて下さい。下のリストの各ファイル の範囲をドラッグして選択し、メモ帳などのエディタに貼り付けて、名前を付けて保存で各ファイルを作ってください。


リスト chap2_11


MPLAB を起動して、プロジェクトを作成します。作成法は、先に紹介した通りです。
下図のように構成してください。




メニューの 「Project - Build All」を実行するとコンパイルが実行され、Output 画面に、BUILD SUCCEEDED が表示されれば、成功です。プロジェクトフォルダに、「main.hex」ファイルができているはずです。
先の例のように接続し、PICkit 3 の USBケーブルをパソコンに接続し、ターゲットの電源を入れて置き、書き込んでください

このサンプルは、「改訂版・C言語によるPICプログラミング入門」の 339ページにある、「単純PWMモードの使用例」のコードです。サンプルとはクロックが違いますが動作は分かります。スタートは、SW1の押し下げで一連の音階を出力します。


12. 音楽(オルゴール)の演奏
学習用のフォルダ「C:\PIC_Practice\chap2_12」を作成して下さい。フォルダ「chap2_12」の中に main.c, SciCommand.c, gakufu.h, sound.h, Hw_profile.h, を入れて下さい。下のリストの各ファイル の範囲をドラッグして選択し、メモ帳などのエディタに貼り付けて、名前を付けて保存で各ファイルの名前を付けてください。LCDは chap2_12 では使いませんが、接続したままでも問題ありません。


リスト chap2_12


MPLAB を起動して、プロジェクトを作成します。作成法は、先に紹介した通りです。ただし、Project Wizard のDevice は「PIC16F1938」を選択しなければいけません、他は同様に進めてください。Project Wizard が終了すると新プロジェクトが立ち上がります。その画面のメニュー「View」のProject と Output にチェックを入れ、またMemory Usage Gauge を見れるようにします。また、図のように、「Build Configration」を必ず Debug から Release にしてください。
下図のように構成してください。




メニューの 「Project - Build All」を実行するとコンパイルが実行され、Output 画面に、BUILD SUCCEEDED が表示されれば、成功です。プロジェクトフォルダに、「main.hex」ファイルができているはずです。
先の例のように接続し、PICkit 3 の USBケーブルをパソコンに接続し、ターゲットの電源を入れて置き
、書き込んでください(Device ID Revision = 00000003)
このサンプルでは、4曲しか入っていません。曲の選択にロータリーの10進SWを使っていますが、下の2Bitしか使っていませんので、0〜3が選択できます。例えば 2を選んで スタートSW (SW1) を押すと、「古時計」の曲が流れるはずです。

このプロジェクトは、クロックを 32MHzで動作させ、オルゴール制御用に、基本的に CCPモジュールの「単純PWMモード」で動作させます。PWMモードの時間の制御は、タイマ2に依存していますが、タイマ2の割り込み周期を16us(62.5KHz)にして、その割り込みルーチン内で 音符(周波数)とFade(減衰)のコントロールをしています。
main関数の中の・・・
   for(i=0; i<play_time; i++){    // 1音符の再生(長さとFadeのコントロール)
      timer100us(288);
      pwm_dc = (pwm_dc << 4) - pwm_dc;
      pwm_dc >>= 4;
      amp = pwm_dc >> 4;

      if(!SW_PLAY) {   // 再度のSW1押し下げで演奏終了
         icode = iend;
         break;
      }
   } // end for(play_time)
・・・の部分とタイマ2の割り込みとが協力しあって、1つの音符の発音とテンポおよびFade(減衰)を実現しているようです。

このオルゴールは、「松田工作様」の Hi-Tech-C のコードのオルゴール演奏の部分のみを CCS-C でそのまま移植させていただきました。大枠の動作解析はしましたが、個々の変数の動作やアルゴリズムについては解析していません。これは、元は PIC12F1822 の8ピンのPICで動かされていたものです。
発音は基板取付の表面実装のスピーカーを使っていますが、大きめのスピーカー(5cm程度)に付け替えれば結構いい音が出ています。レベルの変更は、LCDの左にある VR3 で行います。
 古時計

オルゴールの楽譜作成方法」も公開されています(Excelファイルと取扱説明)。新しい曲を追加してみてください。今は、ロータリーの10進SWの 0〜3 しか使っていませんが、コードを少し改変すれば 10曲にできますので挑戦してみてください。




【動かしましょう−3】
ここでは
PIC12F1822を動かしてみます。PIC演習用基板(3)を使用します。これは、オルゴールを鳴らすことに特化した基板です。
学習用のフォルダ「C:\PIC_Practice\chap3_1」を作成して下さい。これでは C:ドライブのルートに作成していますが、ご自分で管理できる所ならば、どこでも構いません。このフォルダ「chap3_1」の中に次の4つのファイルを入れて下さい。下のリストの main.c の範囲をドラッグして選択します、その状態で右クリックしてコピーします。それをメモ帳などのエディタに貼り付けて、名前を付けて保存で名前を main.c とします。同様に、それぞれ gakufu.h, Hw_profile.h, sound.h の範囲をコピーして、それぞれのファイルを作成します。ファイルの境目の目印である・・・
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
・・・は、無視してください。あくまでも目印ですから。


リスト chap3_1


次に、MPLABを起動して下さい。立ち上がりましたら、メニューの「Project - Project Wizard...」をクリックします。



Step1でDevice をPIC12F1822に設定し、Step2 で Language Toolsuite を CCS-C とします。
MPLAB Plug-in のインストールができていれば、下記のように、CCS-Cが選択できます。Location は 32bit の場合は、Program Files (x86) の ' (x86)' が有りません。




Step3で、Project File を Browse してホルダ「chap3_1」の中にchap3_1.mcp 作成し、Step4で、main関数である main.c のみを Add します。以上で新プロジェクトの設定は完了です。「次へ」をクリックして行ってください。



「完了」をクリックすると、新プロジェクトが立ち上がります。メニュー「View」のProject と Output にチェックを入れます。また、下図のように、「Build Configration」を
必ず Debug から Release にしてください。



main.c は
Project Wizardで既に追加しています。3個のヘッダーファイル(gakufu.h, Hw_profile.h, sound.h)は main.c 内で #include されているのでコンパイルはできますが、上図の「Header Files」のように、それらを取り込んで置くと参照・編集ができます。「Project - Build All」 を実行して Output に 'Build Successful.' が出れば成功です。フォルダ「chap3_1」の中に、main.hex ファイルができているはずです。

その main.hex を書き込んで走らせて見たいと思います。左の写真のように接続してください。USART は使っていないのではずして良いです。
PIC12F1822 は、ピン数が少ないので書き込みピンはデジタルSWの入力と共用していますので、書き込む時はデジタルSWを必ず「0」にしてください。もし、デジタルSWを「0」にしないままですと、デバイスが認識されません。

PICkit3を接続し、基板の電源を入れてメニューの「Programmer - Select Programmer - 6.PICkit3」にチェックを入れて下さい。上の図の Output のように「Device ID Revision = 00000009」と出れば接続・認識完了となります。

この時、デバイスが認識できない時は、メニューの 「Select Programmer」で、「None」を選択し、一旦 MPLAB-IDE からPICkit3 を切り離します。そして、最初に説明しインストールしている [MPLAB IPE]を起動して、これを使ってこのターゲットに接続し認識させれば、これ以降はMPLAB-IDEから、上のやり方で書き込めるようになります。もちろんこのMPLAB-IPEから、書き込むファイル(main.hex)を指定してそのまま書き込むこともできます。MPLAB-IDEで、今までに使ったことのないデバイスを書き込む場合は、このMPLAB-IPEで一度アクセスする必要があります。

さて、MPLAB-IDEから上記の操作を実行して「Device ID Revision = 00000009」が出てターゲットが認識されると、上図のように Programmer に関するメニューが追加されますので、メニューの中の「Program (書き込みと赤枠で囲っている)」を実行します。Outputウィンドウに「Programming/Verify complete」が表示されれば書き込み完了です。CN-PRGのコネクタからケーブルを抜いて基板から PICkit3 を切り離します。書き込みピンとI/Oピンを共用しているので、書き込み完了後は、このケーブルを抜いてください。

これで基板はすでに動作しています。 SW-ST の押し釦SWを押すと、デジタルSW(Select Melody)で選択されている曲のメロディが演奏されます。ボリューム(VR)で音量を調整してください。演奏の途中に、もう一度 SW-ST を押すと、演奏を中断し待機に入ります。デジタルSW(Select Melody)の切り替えで 10曲の選択ができます。

回路図を参照していただければ分かりますように、デジタルSWを「0」とすれば、コネクタ(CN-EXT) から、この基板をコントロールすることができます。すなわち、選曲とスタートSWの操作が外部からできます。また、スライドSWを「EXT SP」側に切り換えると CN-EXTの「+ , -」端子から外部スピーカーを駆動することができます。外部スピーカー(例えば直径5cm程度)を使えば、かなり良い音が出ていることが分かると思います。

このプログラムの簡単な説明は、前章の chap2-12 で説明しましたので参照してください。そこでも書いておりますが、 このオルゴールは、「松田工作様」のコードを使わせていただいております。その方のサイトでは、オルゴールの楽譜作成方法」も公開されていますので、色々と曲の変更などもできます。

green green




【動かしましょう−4】
   ここでは PIC16F1619を動かしてみます。こちら にリンクします。

【 参考 】     XC8 から CCS-Cへの移植例     ラズパイ Zero によるインターネット・ラジオ


;=========================================================================================================

テストに使用した回路


(1) PIC16F1827 のテスト基板


(2) PIC16F1938 のテスト基板


(3) PIC12F1822 のテスト基板


(4) PIC16F1619 のテスト基板


(5) PIC12F1612 のテスト基板



(6) PIC書き込みとRS232Cモニター通信基板


Reported by TokioYamada@ADK


汎用製品通販のページへ              USB-IOのページに戻 る