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(V3.50) を使用する。 はじめに、MPLAB-IDEに CCS-C を組み込んで使用します。CCS-IDE もありますが、日本語を入力できないのでMPLAB-IDEにします。MPLAB-X-IDEも使えますが、まずは軽快で使いこなれている MPLAB-IDE を通常は使うことにしました。MPLAB-IDEを軽快な日本語も入力できるエディターおよびダウンローダーとして使うわけです。 ![]() MPLAB-IDE で開発した CCS-C のコードは、容易にそのまま MPLAB-X-IDE に移行できるので問題はないです。開発のスムーズさと管理の容易さを優先しているだけで、使い分ければ良いと思います。 ・ デバッグは、RS232C を使います。 これを使って、デバイス内部の様々な情報を受け取ったり設定できますし、プロジェクトが完了して、そのままコードを残していても、また削除しても問題はないです。私個人は、Z80アセンブラのころから、専門のディバッグ装置は使ったことはなく、RS232C で内部の情報を取得したり設定したりしてきました。よほどの特殊な事をしない限りその必要もないと思っています。 ・ 対象のデバイスは、PIC16F1827 、 PIC16F1938 、PIC12F1822 、PIC16F1619、PIC12F1612 とします。 PIC16F1827は、PIC16F84A, PIC16F628A と、PIC16F1938は、PIC16F886 と全くPIN互換で、速度もメモリ容量も機能も格段と大きくなっています。また、PIC16F1シリーズは、従来のものよりCコンパイラが効率良いコードを生成できる機能を内蔵しており、逆に購入価格は従来の互換品よりも安くなっていますので、新たなプロジェクトは、これらで行くべきでしょう。 ;-------------- CCS-Cコンパイラについて、色々と苦言があることも承知いたしておりますが、これだけの長い間、プロに支持され続けているのには、それなりの理由があることだと思います。 それはさておき、学習の準備に入って行きましょう。 【環境の準備】 次の7項目の準備が必要です。エ〜ッと思うかもしれませんが、頑張ってやりましょう! 一度実行すれば良いのですから・・・。他の開発環境の準備では、これの数倍以上かかるものもあるので、それに比べれば楽なものですよ! 1. MPLAB-IDE(V8.92) および MPLAB-X-IDE(V3.50) のインストール まず、最初にマイクロチップ様のサイトのアーカイブのダウンロードから、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 も認識し表示すべきです。これはユーザーとして、要望いたします。 このページの学習のためには、MPLAB-IDE(V8.92)と MPLAB-X-IDE(V3.50)を MicroChip 様のアーカイブからダウンロード・インストールして下さい。この環境で PICkit3 は問題なく使用できます。 もし、MPLAB-X-IDEの最新版をインストールした場合は、MPLAB-IDE(V8.92)でコンパイルする事はOK(HEXファイルができる)ですが PICkit3 からの書き込みはできなくなるので、その場合の書き込みは MPLAB-X-IPEから、できている HEX ファイルを、最新の PICkit〇で書き込むことができます。要するに、この場合は MPLAB-IDE(V8.92)は、コンパイルする目的のためだけに使用することになります。 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-IDE と2の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、組込み写真3、PICkit 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:ドライブに移動すれば使えます。 |
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 では使いませんが、接続したままでも問題ありません。
![]() メニューの 「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, を入れて下さい。下のリストの各ファイル の範囲をドラッグして選択し、メモ帳などのエディタに貼り付けて、名前を付けて保存で各ファイルを作ってください。
![]() メニューの 「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は、秋月電子工房さんで取り扱っています。
![]() メニューの 「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は使いませんが付けたままで良いです。
![]() メニューの 「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 を接続してください。
![]() メニューの 「Project - Build All」を実行するとコンパイルが実行され、Output 画面に、BUILD SUCCEEDED が表示されれば、成功です。プロジェクトフォルダに、「main.hex」ファイルができているはずです。 先の例のように接続し、PICkit 3 の USBケーブルをパソコンに接続し、ターゲットの電源を入れて置き、書き込んでください。 ![]() 先の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 を接続してください。
![]() メニューの 「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 の組み込み関数の使い方を検討する時に見る必要がありますので便利です。 ![]() 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を下げて動かして下さい。
![]() メニューの 「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モードを持っています。 ![]() 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のカウンタをリセットして正確なパルス幅になるようにしています。 ![]() なお、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して下さい。下図のプロジェクトの画面の通りにしてください。 ![]() ![]() 距離計 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, を入れて下さい。下のリストの各ファイル の範囲をドラッグして選択し、メモ帳などのエディタに貼り付けて、名前を付けて保存で各ファイルを作ってください。
![]() メニューの 「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 では使いませんが、接続したままでも問題ありません。
![]() メニューの 「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 の範囲をコピーして、それぞれのファイルを作成します。ファイルの境目の目印である・・・ //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ・・・は、無視してください。あくまでも目印ですから。
![]() 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 ファイルができているはずです。 ![]() 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 で説明しましたので参照してください。そこでも書いておりますが、 このオルゴールは、「松田工作様」のコードを使わせていただいております。その方のサイトでは、「オルゴールの楽譜作成方法」も公開されていますので、色々と曲の変更などもできます。 ![]() 【動かしましょう−4】 ここでは PIC16F1619を動かしてみます。こちら にリンクします。 【 参考 】 XC8 から CCS-Cへの移植例 ラズパイ Zero によるインターネット・ラジオ |
;========================================================================================================= |
汎用製品通販のページへ USB-IOのページに戻 る |