2016年1月10日日曜日

レジスタとかコンフィグとかPICのプログラムが分からなすぎて調べた

まず、PICの入門に古い本はやめたほうがいい。
私は回路や部品が秋月でセット販売されているという理由で「プリント基板で作るPIC応用装置」(amazonリンク)という本を入門用に買ったのですが、プログラムが古くて動かせない!

本が出版されたの2009年10月、現在は2016年1月。
この間に開発環境も変わって、ヘッダファイルも変わって、コンフィグの書き方とかも変わったようだ。
以前の記事「【PIC入門】MPLABとXC8をインストール、PICKIT3を接続など簡単な回路を動かすまでのまとめ」で書いた開発環境だと、本のサポートページからダウンロードできるソースコードがエラー出て動かんのですよ。。

PICプログラムと開発環境の基礎が解ってる人は、なんとか出来るんでしょうけど初心者には厳しい!一応、最後まで目は通してパーツは組み立てるけど苦労するぜ。。

それで、ネットでとりあえず最近の開発環境で動く単純なプログラムを調べてみることにした。
本のプログラムでエラー出たタイミングですぐやれよって今更思った(笑)

今回理解するための目標プログラム

ちょうど手元にあった PIC16F88 のプログラムを”xc8”でコンパイルするプログラムをグーグルで検索。このコンパイラ名を指定して検索するのがポイント!そうしないと、古いプログラムとかアセンブラとか沢山混ざってくる。

16F88 XC8開発例 - LEDを蛍のように点灯させる(CCPモジュールのPWM機能)」うむ、簡単そうだし、丁寧に説明してあるので、このページのプログラムを目標に設定。

順番に読んでいく。その前に、コンフィグについて寄り道。

PICプログラムの一般的な設定

PICはチップによってピン数や機能が違うので一様には説明できないが、基本的な考え方がある。
まずはこのページ「コンフィグレーション・ワードについて」を読んだ。

次のように説明がある。
プログラム領域・・・実行するプログラムを格納しておく領域
EEPROM領域・・・電源供給がなくてもデータを記憶しておく領域
コンフィグ領域・・・動作設定を格納

これ読んだら「なんでプログラムのmainで実行する設定の他に、プリプロセッサで指定する設定があるんだろ?」と思ってた疑問が解けた。
(自分的推測)
そもそも、プリプロセッサで指定している設定は、プログラム領域に焼いていない。
プログラム開始では間に合わない処理を予め「コンフィグ領域」に焼いている。
プログラム開始後に行う設定は、柔軟に対応出来るようプログラムで行っている。
(推測終わり)

詳細は参考サイト見て欲しいのですが、おおまかに次のことを設定すれば良いそう。
コードプロテクトを有効にする。(お遊びの場合は無効でOK)
低電圧書き込みを有効にする。(PIC書き込み専用ツール使うなら無効)
ブラウンアウト・リセットを有効にする。(お遊びの場合は無効でOK)
パワーアップ・タイマーを有効にする。
ウォッチドッグ・タイマーを有効にする。(お遊びの場合は無効でOK)
動作クロックを選択する。
基本はこれだけでいいと分かったら見通し良くなった。
ブラウンアウトリセット、パワーアップタイマ等を知らなかったが、サイトの説明がとても親切だった。

リセットに関しては「リセットの使い方」というページの説明が細かったが分かりやすかった。
4つの種類のリセットについて説明してある。
(1) パワーオンリセット
(2) MCLR端子によるリセット(外部リセット)
(3) ウォッチドッグタイマタイムアウトによるリセット
(4) ブラウンアウトリセット(BOR)

MCLRという単語はPICのコンフィグでも出てきて、利用するかどうか必要になる。


プログラムの設定を理解する(mainより前)

それでは、参考にしたサイトのプログラムの前半部分を読んでコメント入れてみた。
最近の書き方はpragmaでやるっぽい。古い書き方してると、__CONFIGとかになってる。
// picプログラムおきまりのヘッダファイル
#include <xc.h>

// _XTAL_FREQ を定義しないとコンパイル時にエラーになる
#define _XTAL_FREQ 8000000      // 8MHz

#define PR2_DATA 0xFF           // PR2 設定データ
#define T2_DIV_BY_1 0b00000000  // T2CON 設定データ
#define CCP_PWM 0b00001100      // CCP1CON 設定データ

// 16F88
// CONFIG1
#pragma config FOSC = INTOSCIO // 内部発振使用(昔は外部の発振を使ったりした)
#pragma config WDTE = OFF   // ウォッチドッグタイマ
#pragma config PWRTE = ON   //パワーアップタイマーON
#pragma config MCLRE = ON   //マスタークリアー機能
#pragma config BOREN = ON   // ブラウンアウトリセットON
#pragma config LVP = OFF    //低電圧プログラム書き込みOFF
#pragma config CPD = OFF    //データーコードプロテクションOFF
#pragma config WRT = OFF    // フラッシュ書き込みOFF
#pragma config CCPMX = RB3  // CCPのパルス出力ピン
#pragma config CP = OFF     //プログラムコードプロテクションOFF

// CONFIG2
#pragma config FCMEN = OFF  // Fail-Safe Clock Monitor
#pragma config IESO = OFF   // Two-Speed Start-up

config2の部分は「PIC18F2550を使う (2) コンフィギュレーションビットについて調べる」 というページの途中に説明が書いてあった。今回は使わなそう。

あと、xc8インストール時にハードディスクに保存されるコンフィグ説明も参考になるかもしれない。
私の場合、ファイルパスは C:\Program Files (x86)\Microchip\xc8\v1.35\docs\chips/16f88.html だった。

プログラムの設定を理解する(main以降)

個々の部分、どの手順でどれを設定すればOKか読み終わっても分かってない。
PICの仕組み(PIC16F84A編)」も読んだがもうちょっと調べないと駄目だな。

OSCCON = 0b01110000;    // 内蔵クロックの周波数を8MHzに設定

PORTA = 0x00;           // PORTAを初期化
PORTB = 0x00;           // PORTBを初期化

TRISA = 0x00;           // PORTAの入出力設定
TRISB = 0x00;           // PORTBの入出力設定

ANSEL = 0x00;           // A/D変換を無効化
ADCON0 = 0x00;
ADCON1 = 0x00;

mainの最初に上記の設定をしていた。この辺で、入出力に利用するピン等の指定をしているようだ。それぞれのピンの指定方法はここを参考にした。
http://www.xcprod.com/titan/XCSB-DOC/physical_io.html
http://www.xcprod.com/titan/XCSB-DOC/physical_io_16f88.html


中途半端だけど、ガンダムが始まるので今日はここまで!!


2016/1/11追記:

レジスタの初期設定について

ちょっと調べた。
PIC16F88のデータシートが最終的に見るべきものなのだが、これは英語だし長いしとっつきにくい。
PIC 16F88の構造(PIC16F88-I/F)」というレジスタ周りを日本語で説明してるページがあった!すげぇ。。


最小限やるなら次の6つを設定しておけば良いらしい。
1. OSCCON
2. ANSEL
3. TRISA
4. TRISB
5. PORTA
6. PORTB

OSCCONはOSCILLATOR CONTROL REGISTERの略で周波数設定。
ANSELはANALOG SELECT REGISTERの略でA/D変換の設定。
TRISはTRISTATE PORT REGISTERの略で、ピンの入出力設定。
PORTはそのままPORT REGISTERの略で、ピンの値設定。

データシートの53ページに次のような文がある。
PORTA is an 8-bit wide, bidirectional port. The corre-sponding data direction register is TRISA. Setting a TRISA bit (=1) will make the corresponding PORTA pin an input (i.e., put the corresponding output driver in a high-impedance mode). Clearing a TRISA bit (=0) will make the corresponding PORTA pin an output (i.e., put the contents of the output latch on the selected pin). 
要約すると、「PORTとTRISは対応してて一緒に使うんだよ。bitに0と1で入力出力切り替えできるからよろしく。」って感じかな。

ここまで分かれば、実際の回路に合わせてレジスタ初期化を書いてあげればよさそうだな。

追記終わり。