PICの学習をCCS−Cではじめよう!   
                                           前章のTOPへ
【動かしましょう−4】
ここでは PIC16F1619 を動かしてみます。PIC演習用基板(4) を使用します。この PIC16F1619 は、MPLAB-IDE のメニュー Project - Project Wizard... の Step One :Select a device の中には出てきません。比較的新しいデバイスですので、MPLAB-IDE ではサポートされていません。それで、このプロジェクトは MPLAB-X-IDE で制作することにいたします。
この PICには、先に演習したものとは違った「新世代CIP(コアから独立した周辺モジュール)」が実装されており、PIN配置も、これまでの物とは異なっています。また、PPS( Peripheral Pin Select ) という機能が搭載されており、ファームウェア的にも周辺モジュールの取り扱いが従来とはかなり変わってきています。しかし、とても魅力的な新機能が利用できます。
[ COLUMN ]
MPLAB-IDE でプロジェクトを作成する時に、似たようなデバイスの名称(例えばPIC16F1527など) を使って行けば、プロジェクトを作成することはできます。main.c のトップで #include <16F1619.h> を入れているのでコンパイルそのものは 16F1619 としてできます。ただ、Pickit 3 からのダウンロードは MPLAB-IDE からはできません。それで、ダウンロード作業のみを MPLAB IPE を使って行えば、開発そのものは MPLAB-IDE ででもできます。

[ Contents ]
1. RS232Cとインターバルタイマーの構成
2. I2C による LCD(AQM0802A)への表示
3. A/Dを計測しバー(AQM1602Y)で表示する
. HEF (EEPROM代替え)に変数を記憶させる
. 温度を測定し LCDに表示する
6. SMT(信号計測タイマ)によるインターバルタイマー
7. ZCD(ゼロクロス検出)による電源周波数の測定
8. 超音波距離計(HC-SR04)による距離の測定
9. SMTにより周期・Duty可変の信号を発生させる
10. SMTによる信号の周期・デューティの測定


1. RS232Cとインターバルタイマーの構成
学習用のフォルダ「C:\PIC_Practice\chap4_1」を作成して下さい。これでは C:ドライブのルートに作成していますが、ご自分で管理できる所ならば、どこでも構いません。このフォルダ「chap4_1」の中に次の3つのファイルを入れて下さい。下のリストの main.c の範囲をドラッグして選択します、その状態で右クリックしてコピーします。それをメモ帳などのエディタに貼り付けて、名前を付けて保存で名前を main.c とします。同様に、 SciCommand.c の範囲をコピーして、 SciCommand.c とし、次に、HardProfile.h の範囲をコピーして HardProfile.h として保存して下さい。3つのファイルの境目の目印である・・・
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
・・・は、無視して良いです。これは、以降のサンプルでも同様です。LCDは使いませんが、接続したままでも問題ありません。
基板や Pickit 3 の接続は
この図 のようにしておき、電源を入れておいてください。
この章では、 初めて MPLAB-X-IDE を使いますので、プロジェクトの作成法について詳しく解説します。以降の章では述べませんので、ここでの記述を参考にしてください。


リスト chap4_1


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



最初の画面で、「Standalone Project」選択して Next をクリックします。次の画面で、デバイス(PIC16F1619)を選択して Next をクリックします。



Select Header では、そのまま Next で良いです。Select Tool では、Pickit 3 を選択して Next をクリックしてください。上記の接続をしておけば Pickit 3 の下に具体的な品番がでますので、その場合はその品番を選択してください。
Select Compiler では、 CCS-C とします。MPLAB-X Plug-in のインストールができていれば、下図の左のように、CCS-Cが選択できます。



Project Name and Folder では、まず Project Location の Browse... ボタンをクリックし、先に制作した chap4_1 ホルダーを選択します。次に、Project Name をchap4_1 とします。最後に、Finish をクリックするとウイザードは終了しプロジェクトが立ち上がります。

Project ウインドウ(左端)の Source Files を右クリックして、main.c を取り込んでください。次に「Important Files」を右クリックして SciCommand.c を取り込みます。この時 SciCommand.c を Source Files に入れるとコンパイルエラーとなります。これは、SciCommand.c が main.c の中で #include されているからです。SciCommand.c を Source Files に入れることも可能ですが、そうするためにはそのように記述する必要があります。
この一連の演習プロジェクトでは、main.c 以外のソースファイル(.c)は全て Important Files に入れます。次に、下図の右のように、メモリの使用状況を表示させるために、緑で囲っているビックリマークの部分をクリックすると、右図のようなウインドウが立ち上がりますから、赤丸印を付けているようにチェックを入れて OK としてください。そうすると Dashboard に使用メモリのゲージが追加されます。



ファイル名をダブルクリックすると、エディタ画面で編集できるようになります(下図)。



さあ、コンパイルしてターゲット基板の PIC に書き込みましょう。金槌マークをクリックしてコンパイルのみを実行することもできます。もう一つのやり方として、上の図の赤線で囲っている「Make and Program Device Main Project」をクリックすると、コンパイル作業と、その結果の Hexファイルをターゲット(基板のPIC) にダウンロードすることができます。右図のような Pickit 3 を選ぶウインドウが出ましたら、選択して OK とします。




ダウンロードが完了すると、上図のように Output 画面に 「Programming/verify complete」と出れば、書き込み完了で、既にターゲットは動作を開始しています。




まだ LCD をコントロールしてはいないので、LCD は動作していません。LED が一秒 ON、一秒 OFF を繰り返していれば、正常に動いています。

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



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



上図の右が、実際に通信している画面です。「? 次に Enter」で、メニューがでます。このサンプルコードでは、ほとんどコマンドは入れていませんが、'V + Enter' でバージョンを、'T2 + Enter' で、Timer 1 の割り込みによる SecNum のカウントの表示だけを入れています。色々なコマンドを自由に追加してテストをしてみてください。
C言語によるPICプログラミング入門」をマニュアルとして使いながら読んでみましょう。PIC に必要なC言語を、ここまでコンパクトにまとめてあるものは、他には知りません。ただ、この PIC16F1619 は、これまでのサンプルで使っている PIC とは、やや異なるデバイスです。このシリーズのデバイスには、PPS( Peripheral Pin Select ) という機能が搭載されています。この機能は、色んな周辺機能モジュール(Peripheral) のピン割当をかなり自由に変更(ただしデシタルのみ)できるようになっています。つまり、回路設計の自由度がとても高くなっているのです。逆に言うと、入門するにはその分ややハードルが高くなっているかも知れません。この PPSについての一般的な解説は ここに ありますので参考にしてみてください。ただ、CCS-C の拡張機能を利用すれば容易にそれらを適用できます。それに従って RS232C や I2C の使用開始に関するコードの書き方が従来とはやや変わってきますので、それだけは注意してください。つまり CCS-C では、PPS機能を持っている PICデバイスの場合、周辺機能モジュールを動作させる時には #pin_select によって、事前に入出力ピンを正しく割り当てる必要があります。どのピンをどこに割り当てられるかは、16F1619.h の PIN_SELECT の部分を参照すると分かります。

発振モードは、外部の 8MHz の水晶発振器(X1)を PLL を有効にして、高精度の 32MHz で動作させています。
#FUSES ECH, PLLEN, NOWDT, PUT, NOBROWNOUT, NOLVP
発振は・・・
ECL - External Clock Low-Power mode   (0 MHz to 0.5 MHz)
ECM - External Clock Medium-Power mode (0.5 MHz to 4 MHz)
ECH - External Clock High-Power mode   (4 MHz to 32 MHz)
LP - 32 kHz Low-Power Crystal mode
XT - Medium Gain Crystal or Ceramic Resonator (up to 4 MHz)
HS - High Gain Crystal or Ceramic Resonator (4 MHz to 20 MHz)
EXTRC - External Resistor-Capacitor
INTOSC - Internal oscillator       (31 kHz to 32 MHz)
・・・から選択しますが、その中から
ECH を選択し、PLLEN としています(16F1619.h :参照)。
main 関数のトップで setup_oscillator(OSC_32MHZ, OSC_PLL_READY); を実行しています。

さて、RS232Cを送受信に使えるようにするには、次の記述をします。
#use delay(clock=32000000, internal)
#pin_select U1TX = PIN_B7      // Use this, to be hardware UART
#pin_select U1RX = PIN_B5      // Use this, to be hardware UART
#use rs232(baud=19200, parity=N, bits=8, UART1)
ここでの記述では、TX と RX にディフォールト(PPS) のピンを割り当てています。これで、送受共にできますが、受信割り込みを設定するには main()関数の初めに・・・
enable_interrupts(INT_RDA);   // RS232C(USART)受信割込みを許可
enable_interrupts(GLOBAL);    // 割込み全体を許可する
・・・記述が必要です。

「C言語」は比較的易しいです。それでも、実際に自分が書いたコードをコンパイルしてターゲットに書き込み、通信しながら動作を確認していかないと、書籍だけを読んでいても行き詰まってしまいます。 上記の書籍 (C言語によるPICプログラミング入門) を手元に置いて「C言語の文法」を、常に参照してください。

「main.c」「SciCommand.c」は、それぞれ今のところ最小限の記述をしています。今後、これに必要なものを次々に追加していきます。自分で追加した場合、コンパイル可能なブロックを入力した時に
すぐにコンパイルしてみることを強く勧めます。多くを入力してエラーが出た場合は、エラー文が続々と出て、何が悪いのか判断するのが困難になります(これはどのコンパイラでも同じです)。

ここでは、RS232Cの受信に割り込みを使っています。パソコンから一文字一文字送られて来るたびに、割り込み関数 void isr_rcv() が起動されます。受信バッファーとして、char Rbuf[22]; があり、その一文字をこのバッファーに入れて行きます。もし受信した一文字が CR(Enter) か LF の場合は、文字列のターミネータである \0(Null) をバッファーに入れて、 コマンド受信フラグ(Rcmflg)を true にします。一方、void main()は・・・
  while(TRUE)
  {
   if (SecNum != SecNumS) {
      SecNumS = SecNum;
      output_toggle(PIN_C2);   // LEDを1秒ごとに点滅させる
    }

    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':  ・
              ・
          break;
         case '1':   ・
         ・
         ・
・・・受信バッファー(Rbuf)の先頭からの文字を見て(switch文)、該当するコマンドが有るかを case文で処理します。処理後は・・・
 Rnum = 0;      // 受信文字数をクリアする
 Rcmflg = FALSE;   // コマンド受信フラグをクリアする
・・・として、初期状態にします。
受信文字は小文字であっても、標準文字処理関数の toupper で全て大文字にして処理しています。コマンド追加予備としての、T3, T4, T5 を使って色々な作業を追加してテストしてください。


次に、インターバル・タイマーの設定値の算出法について見て見ましょう。タイマー割り込み処理関数の上にレム文として書き込んでおり、必要な定数を #define していますので、それについて説明します。
;-------------------
///// TIMER Constants
#define T1PS 15536
  // 65536(0x10000) - 15536 = 50000          C
  // Fosc(32MHz)/4 -> 8MHz (Timer1 IN)        @
  // DIV:1/8 -> 1.0MHz(T:1.0uS)            A
  // 50000 x 1.0us = 50ms               B
#define T2PR  100   // Period:0~255
#define T2PO  4    // Postsscale:1~16 for INT times of OV
  // Fosc(32MHz)/4 -> 8MHz (Timer2 IN)       D
  // DIV:1/2 -> 4.0MHz(T:0.25uS) DIV=Prescaler     E
  // 0.25us x 100 x 4 = 100us               F
;-------------------
上の #define T1PS 15536 が
Timer1 のための #define です。
65536でオーバーフローして割り込みが掛かるので、割り込みルーチンの中で定数:T1PSをセットすれば、(65536 - T1PS)のカウント後に割り込みが掛かります、そのT1PSの算出は次の通りです。@のクロックが入ります。プリスケーラを1/8とするとクロックはAとなります。目的の50msにするにはBの計算で 50000でなります。その 50000をカウントさせるためには、割り込みの中で、Cの計算で出た 15536を設定すれば良い事になります。 Foscを変える時には、プリスケーラを調整するなどして合うようにします。ここで定義した T1PS は、
割り込みの中で set_timer1(T1PS); として設定します。
次の #define T2PR 100 と #define T2PO  4 が
Timer2 のための #define です。
タイマ2は、プリスケーラ(DIV)と、2つの定数:T2PR, T2PO で割り込み周期を決めます。T2PR の範囲は 0〜255であり、T2PO の範囲は 1〜16です。Dのクロックが入り、プリスケーラを1/2とするとクロックはEとなります。目的の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(50ms)の設定
setup_timer_2(T2_DIV_BY_2, T2PR, T2PO);     // Timer2(100us)の設定
enable_interrupts(INT_TIMER1);            // Timer1の割り込みを許可
enable_interrupts(INT_TIMER2);            // Timer2の割り込みを許可
enable_interrupts(INT_RDA);             // RS232C(USART)受信割込みを許可
enable_interrupts(GLOBAL);              // 割込み全体を許可する
・・・の記述が必要です。


. I2C による LCD(AQM0802A) への表示
学習用のフォルダ「C:\PIC_Practice\chap4_2」を作成して下さい。これでは C:ドライブのルートに作成していますが、ご自分で管理できる所ならば、どこでも構いません。このフォルダ「chap4_2」の中に次の5つのファイルを入れて下さい。下のリストの main.c の範囲をドラッグして選択します、その状態で右クリックしてコピーします。それをメモ帳などのエディタに貼り付けて、名前を付けて保存で名前を main.c とします。同様に、 SciCommand.c、HardProfile.h、ST7032i_lib.c、ST7032i_lib.h のそれぞれの範囲をコピーして、それぞれの名前で保存して下さい。ファイルの境目の目印である・・・
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
・・・は、無視して良いです。これは、以降のサンプルでも同様です。基板や Pickit 3 の接続は
この図 のようにしておき、電源を入れておいてください。


リスト chap4_2


さて、MPLAB-X-IDE から、前章のプロジェクトの制作を参照しながら、下図のプロジェクト画面となるようにしてください。



パソコンと基板を Pickit 3 と RS232C ケーブルで接続し、基板の電源を入れておいてください。「Make and Program Device Main Project」(下矢印)をクリックし、ファームウェアをダウンロードします。



ダウンロードが完了すると既に動作を開始しています。LCD の一行目に表示されている SN は、Timer1 の割り込み(#int_timer1) でカウントアップされている SecNum の値です。

さて、LCD の制御に使う I2C を使えるようにするには、次の記述をします。PPS機能を #pin_select を使って PIN 割当をしています。

// I2C のハードウェア動作を指示
#pin_select SCL1OUT = PIN_B6
#pin_select SCL1IN  = PIN_B6
#pin_select SDA1OUT = PIN_B4
#pin_select SDA1IN = PIN_B4
#use i2c( MASTER, FAST, I2C1, FORCE_HW )

この記述は、SCL と SDA にディフォールト(PPS) のピンを割り当ています。どの PINにどの機能を割り当てる事ができるかは、16F1619.h の PIN_SELECT の項目を参照してください。また、 LCD(I2C) の制御コードを使うようにするためにこの後に #include "ST7032i_lib.c" を実行しています。

main 関数の無限ループでは・・・
while(TRUE)
{
  if (SecNum != SecNumS) {
    stiLCD_SetCursor(0, 0);
    printf(stiLCD_Putc, "SN:%lu", SecNum);
    SecNumS = SecNum;
    output_toggle(PIN_C2);
  }

  exe_command();   // Execute RS232C Command
}
・・・と記述し、前章と同様に LED を一秒ごとに点滅させており、同時に SecNum を LCD の一行目に表示しています。同時に exe_command(); を実行し、RS232C のモニターが常時アクティブになっています。LCD のコントラスト調整は、ソフトで行います。AQM0802A と AQM1602Y では、最適値が異なっています。ST7032i_lib.h の中に次の記述があります。
// コントラスト調整用定数
#define CONTRAST 0x18    // for 3.3V(AQM0802A)
//#define CONTRAST 0x28   // for 3.3V(AQM1602Y)
現在は、AQM0802A が生きており、AQM1602Y はレムにされていますので AQM1602Y を使用されている場合は、レムを入れ替えてください。別に、モニターから 'T5xx' (xxは十進数:0~63) コマンドで変更することができます。

[ COLUMN ]
プロジェクト・ウインドウに、複数のプロジェクトがでています。ここでは、chap4_1 とchap4_2 というようになっています。今、有効なプロジェクトは、プロジェクト名が太字( chap4_2 )になっています。これを変更したい場合は、マウスのポインタを有効にしたいプロジェクト名( たとえば chap4_1 )の上に持っていって右クリックをします。そうするとコンテキストメニューが開き、その中に「Set as Main Project」という項目が有りますので、それをクリックすると chap4_1 を有効なプロジェクトに切り替えることができます。



3. A/Dを計測しバー(AQM1602Y)で表示する
学習用のフォルダ「C:\PIC_Practice\chap4_3」を作成して下さい。これでは C:ドライブのルートに作成していますが、ご自分で管理できる所ならば、どこでも構いません。このフォルダ「chap4_3」の中に次の5つのファイルを入れて下さい。下のリストの main.c の範囲をドラッグして選択します、その状態で右クリックしてコピーします。それをメモ帳などのエディタに貼り付けて、名前を付けて保存で名前を main.c とします。同様に、 SciCommand.c、HardProfile.h、ST7032i_lib.c、ST7032i_lib.h のそれぞれの範囲をコピーして、それぞれの名前で保存して下さい。LCD は前章の AQM0802A から AQM1602Y に差し替えてください。そして、ターゲット基板と「書込み&ディバッグ基板」を接続し、パソコンとの間を RS232C通信ケーブルと Pickit 3 USBケーブルで接続してください。ターゲットの電源を入れておいてください。


リスト chap4_3


さて、MPLAB-X-IDE から、前章のプロジェクトの制作を参照しながら、下図のプロジェクト画面となるようにしてください。



パソコンと基板を Pickit 3 と RS232C ケーブルで接続し、基板の電源を入れておいてください。「Make and Program Device Main Project」(下矢印)をクリックし、ファームウェアをダウンロードします。



ダウンロードが完了すると既に動作を開始しています。LCD の1行目には A/D-CH7(温度センサの出力) の値を、2行目には A/D-CH8( VR1の出力) の値を、それぞれ電圧(V) で表示し、その右側に擬似レベルバーで表示しています。

さて、LCD の制御に使う I2C の設定は、前章と全く同じです。
ただ、今回使用する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 <16F1619.h> ) のすぐ下に ・・・
#device ADC = 10
・・・ と記入し、コンパイラに A/Dの使用を宣言します。
次に main()関数の始めに ・・・
   setup_adc_ports(sAN7 | sAN8 | VSS_VDD);   // RC3,RC6がアナログ入力
   setup_adc(ADC_CLOCK_INTERNAL);      // FRC(内蔵発振)
   set_tris_c(0b01001001);             // Port_C Mode Set
・・・ とします。これで A/Dの7チャンネルと8チャンネルは使えるようになります。
読み込みは ・・・
   set_adc_channel(7);              //チャネル選択、引数にチャンネル番号を指定
   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 の仕様書を参照してください。


. HEF (EEPROM代替え)に変数を記憶させる
学習用のフォルダ「C:\PIC_Practice\chap4_4」を作成して下さい。これでは C:ドライブのルートに作成していますが、ご自分で管理できる所ならば、どこでも構いません。このフォルダ「chap4_4」の中に次の6つのファイルを入れて下さい。下のリストの main.c の範囲をドラッグして選択します、その状態で右クリックしてコピーします。それをメモ帳などのエディタに貼り付けて、名前を付けて保存で名前を main.c とします。同様に、 SciCommand.c、HardProfile.h、ST7032i_lib.c、ST7032i_lib.h、HEF_Access.c のそれぞれの範囲をコピーして、それぞれの名前で保存して下さい。前の章と同名であっても、内容が変わっている場合もありますので、このリストから取得してください。そして、ターゲット基板と「書込み&ディバッグ基板」を接続し、パソコンとの間を RS232C通信ケーブルと Pickit 3 USBケーブルで接続してください。ターゲットの電源を入れておいてください。LCD は AQM1602Y を使います


リスト chap4_4


さて、MPLAB-X-IDE から、chap4_1のプロジェクトの制作を参照しながら、下図のプロジェクト画面となるようにしてください。



パソコンと基板 を Pickit 3 と RS232C ケーブルで接続し、基板の電源を入れておいてください。「Make and Program Device Main Project」(下矢印)をクリックし、ファームウェアをダウンロードします。



ダウンロードが完了すると既に動作を開始しています。LCD に HEF (High-Endurance Flash) から読み込んだ 8個のデータが、2行に渡って表示されています。

さて、PIC16F1619 には、EEPROMがありません。私も始めは、困ったものだと思ったのですが、どうやらプログラムフラッシュの一部をその代替に使用することにしているようです。一般的に、メモリの書き換え上限はEEPROMで10万回以上、プログラムフラッシュでは1万回程度となっています。ところがブログラムフラッシュの末端128バイトは HEF と呼ばれる特殊なフラッシュになって、HEF は High-Endurance Flash を意味し、EEPROMと同等の10万回以上の書き換え耐性を持たせているようです。末端の128バイトとは言え、ここはプログラムメモリの一部であることは間違いありませんのでプログラム容量が若干減ることになりますが普通はここまで使うことは無いでしょう。上の表は、 PIC16F1619 のデータシートの一部です。先に、128 バイトと言いましたが、データ 1つは 14bit で構成されているので、128word と言うべきかも知れません。しかし、14bit には2バイトを入れることができませんので、この 14bit を1 バイトとして扱います。この HEF の書き込み・読み出しのテストをモニター(RS232C) を使って実行します。

それでは実際にコマンドを使って HEF にデータを書き込み、そしてそれを読み出して見ましょう。
テラタームを起動してください。 コマンド '?+Enter' でメニューが表示されます。

TD |Read HEF
T1 |Write HEF-1
T2 |Write HEF-2
T3 |Write HEF-3
---------------
TS |Valuable -> HEF
TX |Change Valuable
TL |HEF -> Valuable
V |Version
?  |Help

これらのコマンドを実行する前に、LCDの表示について先に説明しておきます。ソフトが起動された時に、main()関数のループの前で HEF の読み込みを行い、その結果を LCD に表示しています(コードを参照)。それ以外に、LCD に表示を実行するのは、モニターコマンドの '
TD' のみです。

読み書きは、1ブロック単位で行われます。ここでは 1ブロックを8ワードとしています。上の写真の LCD の1行目のデータは左から Index が 7,6,5,4 、2行目のデータは、3, 2,1,0 の値を 16進数で示しています。上のモニター図の右下に、読み書き用バッファ(buf[8]) の位置と Index との関係を示しています。

【コマンド】
'TD' : HEF 読出し・
表示(LCD)コマンドで、指定された HEFの場所から 8word読み出して出力します。
'T1' : コードに記入しているデータを 8word書き込みます。何を書いたかをテラタームに出力します。
'T2' : コードに記入している違うデータを 8word書き込みます。何を書いたかをテラタームに出力します。
'T3' : コードに記入している全て '00'を 8word書き込みます。何を書いたかをテラタームに出力します。
以上は、基本的な読み書き確認のテスト用です。コードを読んでいただければ了解できると思います。
'TS' : 変数 TIMS, CALIB, TESの値を HEFに書き込みます。書いたものをテラタームに出力します。
'TX' : 変数 TIMS, CALIB, TESのRAM上の値を初期値とは違う値にし、それをテラタームに出力します。
'TL' : 変数 TIMS, CALIB, TESの値を、HEF に保存されているものを読み出してRAM に上書きします。
    そしてそれをテラタームに出力します。

上のモニター図に、詳細なコメントを付けています。左側が基本的な読み書き確認テスト、右側が実際の変数を使った読み書きテストです。モニターコマンドの実行関数である exe_command()関数のコードと、上図の実行結果を照らし合わせながら解読してください。
CCS-C のヘッダーファイル(16F1619.h) の中に次の定義があります。
void read_program_memory(__ADDRESS__ address, unsigned int8* dataptr, unsigned int16 count);
void write_program_memory(__ADDRESS__ address, unsigned int8* dataptr, unsigned int16 count);
これらを利用すれば容易にプログラム・メモリにアクセスできます。自分でこれらを書くとなれば、本当はもっと複雑な手順を記述しなければなりません。書き込みには、前もって必要な消去も含まれているようです。

HES_Access.c の始めに、上の2つの関数の引数として使うものを次のように定義しています。
//======== HEF Buffer & etc ========
int16  buf[8];          // HEF Buffer(8 word))
#define TopAdr  0x1FF8     // Access HEF top address(0x1F80-0x1FFF)
#define buff   (int8*)buf      // as int8 pointer
#define dnum   16       // 8 word
上の関数の「引数の
」に合わせる必要があります。つまり、バイトとしてデータを処理しています。今回は、1ブロック・8word ですが、もっと多く(128以内)を使う場合は、ここの記述を修正します。ただし、メモリマップを強く意識しながら行ってください。

変数の保存と復活に関しては、HEF_Access.c の中に記述しています。
//======== Target Variable ========
int16 TIMS = 1000;      // TimerS
float CALIB = -18.5;     // Calibration
int8 TES = 15;         // TES

//======== HEF programming Adrs ========
//         Index(BUF[])     Byte
const int16 eTIMS = 0;   //TimerS    2
const int16 eCALIB = 2;    //CALIB    4
const int16 eTES   = 6;   //TES    1

「 Target Variable」は、対象の変数の宣言と初期値を定義しています。ここに、自分が使う HEF に保存したい変数を定義します。ただし、今回は1ブロック・8バイトの HEFアクセスですので、それを超えないように注意しなければなりません。「HEF programming Adrs」の Indexの数値は、その変数が buf[ ] のどの位置から始まるかを
自分で指定します。レムの Byte の数値は、その変数の所用メモリサイズを byte で書いています。TIMS を、0,1 を使うようにすると、CALIB は 2,3,4,5 を使い、 TES は 6 を使うというように自分でマップしてください。buf[7] は、今回は使用していません。いずれにしても、お互いの変数のマップ領域が重ならないように注意しましょう。

void SaveField(int16 index, char *pa, int8 sn);         // SAVE of domain(RAM->HEF)
void LoadField(int16 index, char *pa, int8 sn);         // LOAD of domain(HEF->RAM)
上の2つの関数は、1つの変数の値を buf[ ] に代入したり、buf[ ] から引用したりを実行しています。
void SaveHEF(void);           // Write necessary variable to HEF
void LoadHEF(void);           // Read necessary variable from HEF
この2つの関数は、いくつかの変数をまとめて HEF に書き込んだり、読み出したりを実行しています。

EEPROM が実装されてなくとも、HEF (High-Endurance Flash) が実装されていれば、困らないことが分かります。今回は 1ブロック 8ワードで3つの変数を格納しました。基板の電源を切って再度、電源を入れた時に、前に保存した値が残っていることを確認(コマンド:'TL')してください。この機能は PIC16F1619 では 128バイトまで使えますので、余程のことが無い限り不足することはないと思います。


. 温度を測定し LCDに表示する
学習用のフォルダ「C:\PIC_Practice\chap4_5」を作成して下さい。これでは C:ドライブのルートに作成していますが、ご自分で管理できる所ならば、どこでも構いません。このフォルダ「chap4_5」の中に次の6つのファイルを入れて下さい。下のリストの main.c の範囲をドラッグして選択します、その状態で右クリックしてコピーします。それをメモ帳などのエディタに貼り付けて、名前を付けて保存で名前を main.c とします。同様に、 SciCommand.c、HardProfile.h、ST7032i_lib.c、ST7032i_lib.h、HEF_Access.c のそれぞれの範囲をコピーして、それぞれの名前で保存して下さい。前の章と同名であっても、内容が変わっている場合もありますので、このリストから取得してください。そして、ターゲット基板と「書込み&ディバッグ基板」を接続し、パソコンとの間を RS232C通信ケーブルと Pickit 3 USBケーブルで接続してください。ターゲットの電源を入れておいてください。LCD は AQM1602Y を使います


リスト chap4_5


さて、MPLAB-X-IDE から、chap4_1のプロジェクトの制作を参照しながら、下図のプロジェクト画面となるようにしてください。



パソコンと基板 を Pickit 3 と RS232C ケーブルで接続し、基板の電源を入れておいてください。「Make and Program Device Main Project」(下矢印)をクリックし、ファームウェアをダウンロードします。



ダウンロードが完了すると既に動作を開始しています。LCD の2行目に、計測した温度を表示しています。

使用している温度センサーの名称は LM61BIZ です。その仕様書を
ここに 置いておきます。センサーの基板上の名称は「S1」です。基板の左上 (VR1の上) にあります。

【 A/Dの設定と読み込み 】
A/Dを使用する設定については、
前章を参照してください。main 関数での無限ループは次のようになっています。
while(TRUE)
{
  int i;

  // A/D チャンネル7 計測 LCD表示
  fdata = 0;
  for(i=0; i<20; i++)  // 20回連続で読み込み、平均を取る
  {
    set_adc_channel(7);     //チャネル7選択(温度センサー設置チャンネル)
    delay_us(15);        //アクイジション待ち
    fdata += read_adc();     //A/D変換データ10ビット読込み(加算していく)
    delay_ms(1);
  }
  fdata = fdata / 20;       //平均値を出す

  fdata = (fdata * 3300) / 1024 + 0.005;      //電圧(mV)へスケール変換
  fdata = (fdata / 10) - 60 + CALIB;       //温度へ変換(CALIB:補正)

  stiLCD_SetCursor(0, 0);     //LCD1行目の先頭へ
  printf(stiLCD_Putc, "Environmental");
  stiLCD_SetCursor(0, 1);
  printf(stiLCD_Putc, " Temp.: %2.1f",fdata);
  stiLCD_Putc(0x08); printf(stiLCD_Putc, "C ");   // '°C'の表示

  delay_ms(100);

  exe_command();    // Execute RS232C Command
}

20回の読み込みの平均値を出し、それを一旦 mV 単位の電圧値に変換しています。次に、その電圧値を温度へ変換しています。仕様書では、センサーの出力電圧(Vo)は、 Vo(mV) = 10 x T(℃) + 600 と提示されています。Vo が分かれば、温度(T) は、T = (Vo / 10) - 60 で計算できることになります。計算した後、その値を LCD に表示しています(CALIB は補正)。
'°' の文字を・・・
sti_one_set_cgram(cgram_degdt);   // '°'の登録

・・・で登録し stiLCD_Putc(0x08); で表示しています。

この温度センサー (LM61BIZ) は、とてもレンジ( -30 〜 85 ℃ ) が広いです。その代り、かなり誤差が大きいです(±2℃、最大±3℃)。しかし仕様書に書かれているように、出力電圧は摂氏温度にリニアに比例(+10mV/℃ )するように、工場で較正されています。それで、今の温度で測定値を較正すれば、誤差をかなり低減させることができると思います。その較正をモニターからのコマンド入力で以下のように行います。

コマンドとして 'TL' と 'Cxx' を追加しています。HEF に登録する変数は、 TIMS, CALIB, TES, IFL ですが、実際に使っているのは、CALIB, IFL の2つです。HEF に変数を登録する詳細については、前章を参照してください。コマンド:TL で HEF に登録しているこれらの変数の値を確認できます。コマンド:Cxx で較正するための補正値を指定し HEF に登録します。'xx' は、左の図の入力例のように実数(-1.8) の数値を入力します。この数値は小さいので、入力値の絶対値が5以下でなければ無視します。
また、main() 関数のループの前に・・・
LoadHEF();    // HEFの値の Load
if (IFL != 0) {
  // 初めて電源ONの時に補正値を初期化する
  IFL = 0; CALIB = 0; SaveHEF();
}
・・・というように変数の初期化が入っています。
初めての起動かどうかを IFL で判断しています。プログラムを書き込んだときは、フラッシュメモリは初期化されており、プログラムが書かれていない領域は、すべて 'FF' が書き込まれているので、IFL の値が 0かそれ以外かで、初回かどうかを判断し、初回であれば、補正値(CALIB) を 0とし IFL も 0として、HEF に保存します。したがって電源を落としても、次回以降は、保存されている補正値を使用することになります。
なお念のため、補正なし(CALIB=0) の場合の LCD表示温度が基準となる温度計よりも +1.8℃であった場合は、コマンドは 'C-1.8' として較正値を登録します。



6. SMT(信号計測タイマ)によるインターバルタイマー
学習用のフォルダ「C:\PIC_Practice\chap4_6」を作成して下さい。このフォルダ「chap4_6」の中に次の5つのファイルを入れて下さい。下のリストの main.c の範囲をドラッグして選択します、その状態で右クリックしてコピーします。それをメモ帳などのエディタに貼り付けて、名前を付けて保存で名前を main.c とします。同様に、 SciCommand.c、HardProfile.h、ST7032i_lib.c、ST7032i_lib.h のそれぞれの範囲をコピーして、それぞれの名前で保存して下さい。前の章と同名であっても、内容が変わっている場合もありますので、このリストから取得してください。そして、ターゲット基板と「書込み&ディバッグ基板」を接続し、パソコンとの間を RS232C通信ケーブルと Pickit 3 USBケーブルで接続してください。ターゲットの電源を入れておいてください。LCD は AQM1602Y を使います


リスト chap4_6


さて、MPLAB-X-IDE から、chap4_1のプロジェクトの制作を参照しながら、下図のプロジェクト画面となるようにしてください。



パソコンと基板 を Pickit 3 と RS232C ケーブルで接続し、基板の電源を入れておいてください。「Make and Program Device Main Project」(下矢印)をクリックし、ファームウェアをダウンロードします。



ダウンロードが完了すると既に動作を開始しています。インターバルタイマの割り込みでカウントしている SecNum を LCD に表示しています。
SMTの24ビットタイマでカウントしています。フルカウント(0xFFFFFF)は、16,777,215です。しかし、1秒のインターバルを得るのにカウントクロックを32MHzにすると、さすがに 24bitでもオーバーフローするので Fosc を16MHzにして動作させています。もちろん Fosc=32MHzの場合でも、Fosc/4を選択すれば、最長約2秒という長時間のインターバルを生成することもできます。

SMT については「SMT (信号計測タイマ) の使い方」としてリンク先に詳細に解説されています、ありがとうございます。
SMT には、
11のモードがあることにご留意ください。これはその内の一番単純な「タイマーモード」になります。
ヘッダーファイル(16F1619.h) の「SMT」という項目を見ると・・・
#define SMT_MODE_WINDOWED_COUNTER        0x0A00
#define SMT_MODE_GATED_COUNTER           0x0900
#define SMT_MODE_COUNTER              0x0800
#define SMT_MODE_CAPTURE              0x0700
#define SMT_MODE_TIME_OF_FLIGHT          0x0600
#define SMT_MODE_GATED_WINDOWED_MEASURE   0x0500
#define SMT_MODE_WINDOWED_MEASURE       0x0400
#define SMT_MODE_HIGH_LOW_TIME_MEASUREMENT  0x0300
#define SMT_MODE_PERIOD_DUTY_CYCLE_ACQ     0x0200
#define SMT_MODE_GATED_TIMER             0x0100
#define SMT_MODE_TIMER                 0
・・・という、11のモードが記述されていますので、setup_smt1 にてそのモードを指定します。CCS-C では、このように拡張関数が提供されているのでそれらを利用することで比較的楽に設定できます。リンク先(SMTの使い方) の内容とヘッダーファイルを見比べていると大方の拡張関数の使い方は分かると思います。

// タイマモード、クロック:Fosc、1周期のカウント数を指定(16,000,000 - 1:#define SMT_PERIOD参照)
setup_smt1(SMT_ENABLED | SMT_MODE_TIMER | SMT_CLK_FOSC, SMT_PERIOD);
smt1_start();   //start SMT1
これで、SMT のモードを設定し動作を開始しています。

while(TRUE)
{
  if (SecNum != SecNumS) {
  stiLCD_SetCursor(0, 1);
  printf(stiLCD_Putc, "SecNum:%lu", SecNum);
  SecNumS = SecNum;
}
  exe_command(); // Execute RS232C Command
}
main()ではこの無限ループで、 SecNum が変化した時のみ LCDの表示を更新しています。



7. ZCD(ゼロクロス検出)による電源周波数の測定
学習用のフォルダ「C:\PIC_Practice\chap4_7」を作成して下さい。このフォルダ「chap4_7」の中に次の5つのファイルを入れて下さい。下のリストの main.c の範囲をドラッグして選択します、その状態で右クリックしてコピーします。それをメモ帳などのエディタに貼り付けて、名前を付けて保存で名前を main.c とします。同様に、 SciCommand.c、HardProfile.h、ST7032i_lib.c、ST7032i_lib.h のそれぞれの範囲をコピーして、それぞれの名前で保存して下さい。前の章と同名であっても、内容が変わっている場合もありますので、このリストから取得してください。そして、ターゲット基板と「書込み&ディバッグ基板」を接続し、パソコンとの間を RS232C通信ケーブルと Pickit 3 USBケーブルで接続してください。ターゲットの電源を入れておいてください。LCD は AQM1602Y を使います


リスト chap4_7


さて、MPLAB-X-IDE から、chap4_1のプロジェクトの制作を参照しながら、下図のプロジェクト画面となるようにしてください。



商用AC電源の周波数を計測するテストです。これは、PIC fun様へのリンク「ZCD(ゼロクロス検出)の使い方」に詳しく解説されています、ありがとうございます。それをここでは CCS-C 版に移植したものです。
CN-ACPOW の 1-4 Pin 間に商用AC電源を加えます。参考先では、AC100Vを 330kΩの抵抗を経由して直接PICのピンに接続されています。抵抗値の計算方法などについてはこのリンクでの説明を良く読んでください。

ここのテストでは、
トランスを介してAC 8V を加えました。写真の R2 は、AC100Vを加えて良いように参考先と同じ 330KΩを取り付けていますが、それにパラに 30KΩを付けて 27.5KΩとしました。どの電圧を加えてテストするかは、ご自分で決めてくだい。AC100Vを接続した場合は、感電にご注意ください。いずれにしろこの配線をしてAC電源を接続して置かないとテストは始まりません(CN-ACPOW 紫-青の配線)。制限電流を超える低い抵抗を取り付けると PIC を壊しますのでご注意ください。

パソコンと基板 を Pickit 3 と RS232C ケーブルで接続し、基板の電源を入れておいてください。「Make and Program Device Main Project」(下矢印)をクリックし、ファームウェアをダウンロードします。



ダウンロードが完了すると既に動作を開始しています。表示の仕方は、参考のリンク先と同じで、上の行は、約0.5秒間隔の測定値、下の行は、20回測定の平均値です。main() の無限ループ内で表示しています。計測値が表示されない、LED が点滅 (電源周波数での点滅ですから、やや薄い点灯に見える) していない場合は、ACの電圧と抵抗(R2) の値の関係が合っていませんのでチェックしてください。

設定について説明いたします。
#FUSES ECH, PLLEN, NOWDT, PUT, NOBROWNOUT, NOLVP, NOZCDDIS   //ZCDを生かす
・・・で ZCD機能を生かしています。
測定には必要ないのですがモニターのために・・・
#pin_select ZCD1OUT = PIN_C2   // LEDにZCD信号を出力する(モニタ用))
・・・を設定して、ZCD信号で LEDを参考のために点滅させています。

main() の初期設定で・・・
// 窓周期計測モード、クロック:Fosc、ZCD1、1回のみの測定モードを設定
setup_smt1(SMT_ENABLED | SMT_MODE_WINDOWED_MEASURE | SMT_CLK_FOSC
               | SMT_WIN_INPUT_ZCD1 | SMT_SINGLE_DATA_ACQ_MODE);
setup_zcd(ZCD_ENABLE);
・・・とし、SMTと ZCD のセットアップをしています。

SMT_window信号は、ZCDとしており、ZCDは電源波形の半周期ごとにトグルになっているので、ZCDの1周期は電源の1周期と同じとなります。1秒のカウント数は 32,000,000(32MHz)であるので、それを計測信号の1周期のカウント数(temp)で割ればAC電源の周波数が出ることになります。

Freq = 32000000.0 / (float)temp;     // 周波数に変換

これをテストしている地域は九州ですので 60Hzです。関東でしたら 50Hz になります。
1回のみの測定モードを設定しているので smt1_start(); を実行してループのトップに戻ります。

いずれにしろ CCS-C では、設定と表示のコードが、かなりシンプルにできることが良く分かると思います。



8. SMT(信号計測タイマ)による距離の測定
学習用のフォルダ「C:\PIC_Practice\chap4_8」を作成して下さい。このフォルダ「chap4_8」の中に次の5つのファイルを入れて下さい。下のリストの main.c の範囲をドラッグして選択します、その状態で右クリックしてコピーします。それをメモ帳などのエディタに貼り付けて、名前を付けて保存で名前を main.c とします。同様に、 SciCommand.c、HardProfile.h、ST7032i_lib.c、ST7032i_lib.h のそれぞれの範囲をコピーして、それぞれの名前で保存して下さい。前の章と同名であっても、内容が変わっている場合もありますので、このリストから取得してください。そして、ターゲット基板と「書込み&ディバッグ基板」を接続し、パソコンとの間を RS232C通信ケーブルと Pickit 3 USBケーブルで接続してください。ターゲットの電源を入れておいてください。LCD は AQM1602Y を使います


リスト chap4_8


さて、MPLAB-X-IDE から、chap4_1のプロジェクトの制作を参照しながら、下図のプロジェクト画面となるようにしてください。



超音波距離計(HC-SR04) を下図の写真のように取り付けてください。パソコンと基板 を Pickit 3 と RS232C ケーブルで接続し、基板の電源を入れておいて、「Make and Program Device Main Project」(下矢印)をクリックし、ファームウェアをダウンロードします。



ダウンロードが完了すると既に動作を開始しています。距離計(HC-SR04) をターゲットに向けると、そこまでの距離をセンチ(cm)で表示します。RS232C で計測している値を表示しています。

設定について説明いたします。
//ゲート付きタイマモード、クロック:Fosc、SMT1SIG、繰り返しモードを設定
setup_smt1(SMT_ENABLED | SMT_MODE_GATED_TIMER | SMT_CLK_FOSC
               | SMT_SIG_INPUT_SMTSIGx | SMT_REPEAT_DATA_ACQ_MODE);

モードは、ゲート付きタイマモードです。クロックは Fosc とし、SMT_sugnal の入力を SMTSIGx に設定、さらにスタートすると 繰り返しの測定をするモードにしています。また、下の設定で SMT1PWA の割り込みを許可します。

enable_interrupts(INT_SMT1PWA);     //SMT1PWA の割り込み
enable_interrupts(INT_RDA);
enable_interrupts(GLOBAL);

割り込みルーチンは・・・
#int_smt1pwa
void pwa_isr(void)
{
  temp = smt1_read(SMT_CAPTURED_PULSE_WIDTH_REG);
  Fint = TRUE;
}
・・・としており、割り込みがかかる度にカウントしているレジスタ値を temp に読み込み Fintフラグを TRUEにします。Fint は、メインループで割り込みがあったことを検知するためのフラグになっています。

この超音波距離計(HC-SR04) のマニュアルを
ここに示しますので見て下さい。Trig端子に 10us のトリガパルスを加えると Echo 端子にターゲットまでの往復時間が HIGH であるパルスが返ってきます。
この Echo の時間を計測することで、ターゲットまでの距離を測定します。
この距離計(HC-SR04) の最大測定可能距離は、400cm となっています。余裕を見て往復 1,000cm を計測するとすれば、音速を340m/sとして・・・
10(m) / 340(m/s) = 29,412us の時間まで計測できれば良いこととなります。

クロックは Fosc(32MHz) で、SMT のカウンタは 24bitですから、最大カウント時間は・・・
(1 / 32)us × 0xFFFFFF(16,777,215) = 524,287 us 
・・・です。したがって可能な連続計測積算回数は・・・
524,287 ÷ 29,412 = 17.82 となり、17回まではオーバーフローしないで積算できることになります。SMT の無い PICの 16bit のカウンタを使う事で苦労したことを思えばウソみたいですね。そこでここでは、繰り返し積算回数を 10回と定義します。
const int RN = 10;     //距離測定繰り返し回数
main() のループで・・・
 smt1_start();

 for(i=0; i<RN; i++) {      //繰り返しモードなのでRN回のSMT1SIGのHIを積算
   output_high(TRIG);  // Triger On
   delay_us(11);
   output_low(TRIG);   // Triger Off
   while(Fint == FALSE) exe_command();    //割り込み実行待ち
   Fint = FALSE;
   delay_ms(60);
 }
 temp /= RN;   //平均値
・・・として、10回の計測をして平均値を出しています。

片道の距離(cm) = T(Echo:us) × 1/2 × 340(m/s) × 100(cm/m) × 1/1000000(us/s)
上の式をまとめると 片道の距離(cm) = 往復の時間T(Echo:us) × 0.017(cm/us)
----------------
すなわち
往復の時間(us)が分かれば、上記の式によって片道の距離(cm)が出ることになります。

temp は Fosc をカウントしており、その周期は (1000000/32000000) = 0.03125(us) です。
したがって 0.03125 × temp により往復の時間(us)が出るので・・・
Distance = (0.03125 * (float)temp) * 0.017;    //対象迄の距離(cm)
・・・の式により、対象までの距離がセンチ単位で算出できます。

次の計測に入る前に、レジスタの積算値をクリアしなければならないので・・・
smt1_reset_timer();    // カウンタクリア
・・・を実行し無限ループのトップに戻ります。

ここでは簡略的に音速は、約 340 m/s としましたが、常用されている速度としては、1気圧の乾燥空気中では 331.5 + 0.61t ( t は摂氏温度)が使われています。先に演習した「5. 温度を測定し LCDに表示する」で実行した温度を利用して式を立てれば、もう少し精度の高い測定になるでしょう。

それにしても前の PIC16F1938 の演習で、16bit のカウンタを使って苦労して距離を測定していましたが、SMT の 24bitカウンタを使えば楽に高精度の計測が可能なことがわかります。


9. SMTにより周期・Duty可変の信号を発生させる
学習用のフォルダ「C:\PIC_Practice\chap4_9」を作成して下さい。このフォルダ「chap4_9」の中に次の5つのファイルを入れて下さい。下のリストの main.c の範囲をドラッグして選択します、その状態で右クリックしてコピーします。それをメモ帳などのエディタに貼り付けて、名前を付けて保存で名前を main.c とします。同様に、 SciCommand.c、HardProfile.h、ST7032i_lib.c、ST7032i_lib.h のそれぞれの範囲をコピーして、それぞれの名前で保存して下さい。前の章と同名であっても、内容が変わっている場合もありますので、このリストから取得してください。そして、ターゲット基板と「書込み&ディバッグ基板」を接続し、パソコンとの間を RS232C通信ケーブルと Pickit 3 USBケーブルで接続してください。ターゲットの電源を入れておいてください。LCD は AQM1602Y を使います


リスト chap4_9


さて、MPLAB-X-IDE から、chap4_1のプロジェクトの制作を参照しながら、下図のプロジェクト画面となるようにしてください。



このプロジェクトは、SMT1 と SMT2 のタイマー機能を使って、1HZ から 12KHz の矩形波信号を発生させて、さらにそのデューティを 0.1% から 99.9% まで可変にするものです。
パソコンと基板 を Pickit 3 と RS232C ケーブルで接続し、基板の電源を入れておいてください。「Make and Program Device Main Project」(下矢印)をクリックし、ファームウェアをダウンロードします。



ダウンロードが完了すると既に動作を開始しています。現在発生している信号の情報として、LCDの上の行に周波数を、下の行にデューティを表示しています。コネクタ CN-SENSER の 3 - 4(GND) 間に出力しています。ディフォールトは 1000HZ, Duty:50% です。オシロスコープで観察すると上図の右の一番上のようになっています。

周波数やデューティを変更するには、モニター(RS232C) を使って実行します。左図は、モニターを起動して操作している画面です。コマンド’?’ で使用できるコマンドの一覧を示します。

コマンド’P’で、現在の設定の確認をしています。左の例では 周波数 10Hz,Duty:50.0% が返っています。
次にコマンド’D35.5’ で、デューティ35.5%に変更しています。周波数はそのままです。
次にコマンド 'F10K' で、周波数を 10,000Hzに変更した上で、コマンド’P’で、現在の設定を再度確認しています。
次にコマンド 'F300' で周波数を 300Hzに変更し、コマンド’P’で、設定されている内容の確認をしています。
まずは、具体的に各コマンドを発行して動かして見てください。

コマンド 'D', 'F' は、入力のヘルプです。

Fxxx 1 =< xxx =< 12K
'xxx' must be upper range!

Dxxx 0.1 =< xxx =< 99.9
'xxx' must be upper range!

・・・のように表示されます。レンジの範囲外の数値を入力したときも同じメッセージが出ます。
実際に出力されている波形はオシロスコープが無いと分かりませんが、次の演習(「SMTによる信号の周期・デューティの測定」)で、確認ができます。

main.c のはじめに、次の記述があります。
;----------
#define CLOCKA 16000000
#use delay(clock=CLOCKA, internal)

// グローバル変数・プロトタイプ宣言
float   Freq = 1000;
float   Duty = 50;
int32 SMT_PERIOD = (CLOCKA / Freq) - 1;
int32 SMT_DUTY = (CLOCKA / Freq) * (Duty / 100);
;----------
ここに、このファームウェアで使う主要な共通変数を定義しています。クロックは 16MHz で動作させます。モニターのコマンドで周波数・デューティを変更できますが、それはコマンドでこの変数の値を書き換えて、さらに SMT1 と SMT2 を再設定することで実現しています。

main() 関数の始めに・・・
;----------
SMT_Setup();   // SMT1, 2 のセットアップ

enable_interrupts(INT_SMT1);   //enabled SMT1 interrupt
enable_interrupts(INT_SMT2);   //enabled SMT2 interrupt
enable_interrupts(INT_RDA);
enable_interrupts(GLOBAL);
;----------
・・・として、SMT1, 2 のセットアップをして、SMT1, SMT2 の割り込みを許可しています。
上で呼び出している「SMT1, 2 のセットアップ」は・・・
void SMT_Setup(void)
{
  smt1_stop();
  smt2_stop();
  output_low(PIN_A4);
  // タイマモード、クロック:Fosc、1周期のカウント数を指定(int32 SMT_PERIOD 参照)
  setup_smt1(SMT_ENABLED | SMT_MODE_TIMER | SMT_CLK_FOSC, SMT_DUTY);
  setup_smt2(SMT_ENABLED | SMT_MODE_TIMER | SMT_CLK_FOSC, SMT_PERIOD);
  output_high(PIN_A4);
  smt1_start();   //start SMT1 割り込みで自身を停止
  smt2_start();   //start SMT2 連続、割り込みで SMT1_startを実行
}
・・・となっており、SMT2 が全体の周期を決める単純タイマーモードで動作します、これは LEDの点滅で確認できます。SMT1 も単純タイマーモードですが、 SMT_DUTY の時間後の割り込みで、自身で、smt1_stop(); を実行して動作を停止し、One Shot 動作をするようにしています、これは信号として PIN_A4 に出力されます。以下の割り込みをご参照ください。

割り込みの記述は・・・
#int_smt1
void smt1_isr(void)
{
  output_low(PIN_A4);
  smt1_stop();    //自分自身でstop こうすれば One Shot なる
}

#int_smt2
void smt2_isr(void)
{
  output_high(PIN_A4);
  smt1_start();
  output_toggle(PIN_C2);    //LED点滅
}
・・・となっています。PIN_A4 が信号の出力(CN-SENSER 3pin) になります。回路図をご参照ください。

C言語の学習としては、SciCommand.c 内で記述しているコマンドの受付などは良い教材になると思います。ここでは、Tstf = strtod(p, &tp); などの標準関数を使っていますが、これらの標準関数を使い慣れてまいりましょう。また、 CalculateFreq() 関数内で使っている Count = sprintf(str, "%0.2f ", FreqS); などの sprintf 関数の使い方に慣れておくことも良いと思います。


10. SMTによる信号の周期・デューティの測定
学習用のフォルダ「C:\PIC_Practice\chap4_10」を作成して下さい。このフォルダ「chap4_10」の中に次の3つのファイルを入れて下さい。下のリストの main.c の範囲をドラッグして選択します、その状態で右クリックしてコピーします。それをメモ帳などのエディタに貼り付けて、名前を付けて保存で名前を main.c とします。同様に、ST7032i_lib.c、ST7032i_lib.h のそれぞれの範囲をコピーして、それぞれの名前で保存して下さい。前の章と同名であっても、内容が変わっている場合もありますので、このリストから取得してください。そして、ターゲット基板と「書込み&ディバッグ基板」を接続し、パソコンとの間を RS232C通信ケーブルと Pickit 3 USBケーブルで接続してください。ターゲットの電源を入れておいてください。LCD は AQM1602Y を使います


リスト chap4_10


さて、MPLAB-X-IDE から、chap4_1のプロジェクトの制作を参照しながら、下図のプロジェクト画面となるようにしてください。



このプロジェクトは、CCS, Inc. から提供されている「 ex_smt_period_duty.c 」を流用しています。指定端子に入力されている信号の周期とデューティを同時に測定するものです。

下の写真では、左の基板が、前章の「SMTにより周期・Duty可変の信号を発生させる」による信号発生で、右の基板が今回の「SMTによる信号の周期・デューティの測定」です。この2枚の基板の間をそれぞれの CN-SENSERの Pin 3-4(GND) で接続しています(赤・茶の配線)。この2枚を用意できない場合は、右の基板(現動作基板)のコネクタ(CN-SENSER)の Pin 3-4(GND) 間に測定したい信号を入力して下さい。また写真では、書き込み・モニター基板からの 8PINコネクタが左の基板にささっていますが、右の、今回動かす基板の方に挿してください。
パソコンと基板 を Pickit 3 と RS232C ケーブルで接続し、基板の電源を入れておいてください。「Make and Program Device Main Project」(下矢印)をクリックし、ファームウェアをダウンロードします。



ダウンロードが完了すると既に動作を開始していますが、信号が入力されていないと測定できません。現在入力されている信号の情報として、LCDの上の行に周期を、下の行にデューティを表示しています。コネクタ CN-SENSER の 3 - 4(GND) 間から信号を入れてください。


書き込み・モニター基板からの 8PINコネクタを、今回動かす基板(右)にさして RS232Cケーブルをパソコンに接続し Tera Term を起動すると、左図のモニターの画面のように、現在測定している数値を約 0.5秒間隔で送信してきています。

SMT の設定は次の通りです。
setup_smt1(SMT_ENABLED | SMT_MODE_PERIOD_DUTY_CYCLE_ACQ | SMT_CLK_FOSC | SMT_SIG_INPUT_SMTSIGx);

つまり、モードは、周期_デューティ同時測定モードで、クロックは Fosc(16MHz)、入力は SMTSIG1 です。
enable_interrupts(INT_SMT1PRA);
enable_interrupts(INT_SMT1PWA);
enable_interrupts(GLOBAL);

・・・で、2つの割り込みを許可します。

それぞれの割り込みの中で、周期とデューティの数値をレジスタから読み取っています。
割り込みが掛かって数値の読み取りが完了すると、フラグ(NewCapture)を TRUE とします。main()関数の無限ループの中ではそのフラグをチェックしていて、それが TRUE になるとRS232C に送信し、LCD に表示しています。表示が終わると・・・
NewCapture = FALSE;
smt1_start();   //re-start SMT1
・・・とし、次の測定を開始します。これらのモードについては「SMT (信号計測タイマ) の使い方」でお調べください。日本語で解説されているのでありがたいです。この文書での、11個のモードの中の「@ 周期とデューティサイクルモード」にあたります。

【割り込み】
#INT_SMT1PRA
void period_isr(void)
{
SignalPeriod = smt1_read(SMT_CAPTURED_PERIOD_REG);   //read captured period
NewCapture = TRUE;
}

#INT_SMT1PWA
void duty_isr(void)
{
SignalDuty = smt1_read(SMT_CAPTURED_PULSE_WIDTH_REG);   //read captured duty
}

各レジスタの読み込みも、このようにシンプルに行えます。先のリンクの「(1) 周期とデューティモードの動作」の項目に描いてある図と説明をご参照下さい。
いずれにしろ、CCS-C用 に用意された関数を使えば、比較的容易にデバイスの設定および読み取りが行えることが分かると思います。逆に言うと、コードを解釈するときに「何をしているのか?」という意図が分かりやすいという所が良いと思います。



【動かしましょう−5】
ここでは PIC12F1612 を動かしてみます。PIC演習用基板(5) を使用します。この PIC12F1612 は、比較的新しいデバイスですので、MPLAB-IDE ではサポートされていません。それで、このプロジェクトも MPLAB-X-IDE で制作することにいたします。
この PICは、前章で動かした、PIC16F1619 と同様に「新世代CIP(コアから独立した周辺モジュール)」が実装されています。ただし、PPS機能は搭載されていません。
[ COLUMN ]
MPLAB-IDE でプロジェクトを作成する時に、似たようなデバイスの名称(例えばPIC12F1501など) を使って行けば、プロジェクトを作成することはできます。main.c のトップで #include <12F1612.h> を入れているのでコンパイルそのものは 12F1612 としてできます。ただ、Pickit 3 からのダウンロードは MPLAB-IDE からはできません。それで、ダウンロード作業のみを MPLAB IPE を使って行えば、開発そのものは MPLAB-IDE ででもできます。

[ Contents ]
1. 超音波距離計(HC-SR04)のテスト
2. 信号の周期・デューティの測定


1. 超音波距離計(HC-SR04)のテスト
学習用のフォルダ「C:\PIC_Practice\chap5_1」を作成して下さい。これでは C:ドライブのルートに作成していますが、ご自分で管理できる所ならば、どこでも構いません。このフォルダ「chap5_1」の中に次の3つのファイルを入れて下さい。下のリストの main.c の範囲をドラッグして選択します、その状態で右クリックしてコピーします。それをメモ帳などのエディタに貼り付けて、名前を付けて保存で名前を main.c とします。同様に、 ST7032i_lib.c の範囲をコピーして、 ST7032i_lib.c とし、次に、ST7032i_lib.h の範囲をコピーして ST7032i_lib.h として保存して下さい。3つのファイルの境目の目印である・・・
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
・・・は、無視して良いです。これは、以降のサンプルでも同様です。
ターゲット基板に距離計(HC-SR04)を取り付け、更に書き込みディバック基板に Pickit 3 を接続し、PROGコネクタでターゲットに
接続して電源を入れておいてください。
この章では、 MPLAB-X-IDE でプロジェクトを作成しますが、作成法については前章(chap4_1)をご参照ください。


リスト chap5_1


プロジェクト作成の結果が下図のようになるようにしてください。次に金槌マークのコンパイルを実行し、「BUILD SUCCESSFUL」が出ればOKです。



次に、下矢印マークのダウンロードを実行してください。ダウンロードが完了しましたら、PICkit 3 をモニター・デバッグ基板から外してください(下図参照)。そして、ターゲット基板の左端にある RESET スイッチを押してください。そうすると動作を開始し、LCD にターゲットまでの距離をセンチ単位で表示します。テラタームを起動し、19200bpsで開くと、下図の右図のように測定値を表示します。



この PIC は8Pinであるため、端子の余裕がありません、それでファームウェアの書き込みに必要な端子(PGD,PGC,MCLR)と実動作に必要な端子を共用しています。したがって書き込み後の PICkit 3 の切り離しと RESET 操作が必要になります。PIKkit 3 の PGD,PGC,MCLRに接続される外部回路は OUT になっていると書き込みはできません(OUTがぶつかる) ので、ターゲット基板を設計する場合は、共用する端子に接続する外部回路は IN (もしくはOpen)にする必要があります。この様な工夫は必要ですが、ディバッグで書き込みが必要なときに、その都度 PIC を抜き差しする必要がないのでとても重宝します。

このPIC12F1612 には、USARTとI2Cのモジュールがありません。したがって RS232C通信と LCDを表示するための I2C通信は、ソフトウェアで実装する必要がありますが、CCS-C ではその機能を持っています。

#use delay(clock=32000000)
#use rs232(baud=19200,xmit=PIN_A2)   //送信のみ
#use i2c(MASTER, SDA=PIN_A0, SCL=PIN_A1, ADDRESS=0xa0)

・・・を記述することで、RS232C と I2C は使えるようになります。これはとてもありがたいです。

この、「距離測定」のソフトの内容は、全く前章(
chap4_8)と同じですので、フローの解説はそちらをご参照ください。


2. 信号の周期・デューティの測定
学習用のフォルダ「C:\PIC_Practice\chap5_2」を作成して下さい。これでは C:ドライブのルートに作成していますが、ご自分で管理できる所ならば、どこでも構いません。このフォルダ「chap5_2」の中に次の3つのファイルを入れて下さい。下のリストの main.c の範囲をドラッグして選択します、その状態で右クリックしてコピーします。それをメモ帳などのエディタに貼り付けて、名前を付けて保存で名前を main.c とします。同様に、 ST7032i_lib.c の範囲をコピーして、 ST7032i_lib.c とし、次に、ST7032i_lib.h の範囲をコピーして ST7032i_lib.h として保存して下さい。3つのファイルの境目の目印である・・・
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
・・・は、無視して良いです。
基板および Pickit 3 の接続を
しておき、電源を入れておいてください。
この章では、 MPLAB-X-IDE でプロジェクトを作成しますが、作成法については前章(chap4_1)をご参照ください。


リスト chap5_2


プロジェクト作成の結果が下図のようになるようにしてください。次に金槌マークのコンパイルを実行し、「BUILD SUCCESSFUL」が出ればOKです。




計測する信号をターゲット基板の CN-SENSORコネクタの 3 - 4(GND)ピンに入力しておいてください。前章の chap4_9 で発生している信号でも良いです。その方が信号の周期とデューティが分かっていて良いかもしれません。次に、下矢印マークのダウンロードを実行してください。ダウンロードが完了しましたら、PICkit 3 をモニター・デバッグ基板から外してください(下図参照)。そして、ターゲット基板の左端にある RESET スイッチを押してください。そうすると動作を開始し、LCD の上の行に周期を、下の行にデューティを表示します。



この PIC は8Pinであるため、端子の余裕がありません、それでファームウェアの書き込みに必要な端子(PGD,PGC,MCLR)と実動作に必要な端子を共用しています。したがって書き込み後の PICkit 3 の切り離しと RESET 操作が必要になります。PIKkit 3 の PGD,PGC,MCLRに接続される外部回路は OUT になっていると書き込みはできません(OUTがぶつかる)ので、ターゲット基板を設計する場合は、共用する端子に接続する外部回路は IN(もしくはOpen) にする必要があります。この様な工夫は必要ですが、ディバッグで書き込みが必要なときに、その都度 PIC を抜き差しする必要がないのでとても重宝します。

このPIC12F1612 には、USARTとI2Cのモジュールがありません。したがって RS232C通信と LCDを表示するための I2C通信は、ソフトウェアで実装する必要がありますが、CCS-C ではその機能を持っています。これでは、 I2Cのみを下記の記述で実装します。

#define CLOCKA 16000000
#use delay(clock=CLOCKA, internal)
#use i2c(MASTER, SDA=PIN_A0, SCL=PIN_A1, ADDRESS=0xa0)

・・・これで I2C を使えるようになります。これはとてもありがたいです。
この小さな PICに LCDの表示まで実装しているので、ROM の使用率は 91%になっていますが問題なく動作しています。

この、「信号の周期・デューティの測定」のソフトの内容は、全く前章(
chap4_10)と同じですので、フローの解説はそちらをご参照ください。


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

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

(4) PIC16F1619 のテスト基板


(5) PIC12F1612 のテスト基板



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


Reported by TokioYamada@ADK

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