12F1822覚書

〔PICの動かせ方入門に戻る〕


忘れないうちにメモします。
ここでの記載はMPLAB X V2.15
MPLAB(R) XC8 C Compiler Version 1.32を使用しての内容です。 *3)
データシートはこちらです。日本語だよ〜ん
16F1823はピン数(14ピン)が多いですが同じように参考になります。

内蔵発振回路
PICの内部に付いているクロック周波数回路は4MHz/8MHz/16MHz/32MHzを利用できる。
また、32MHZにする場合は、内部・外部クロックとも8MHzにして内蔵PLL回路を通す必要がある。

内部クロックを利用する場合
コンフィギュレーションを
#pragma config PLLEN = OFF , FOSC = INTOSC
にして
OSCCONレジスターにて使用する周波数を設定します。
OSCCON = 0b01111010 ;
緑の数字部分が内部クロックを使用する時の設定("10")です。
赤い数字部分を変更する事により周波数を変更できます。
それ以外の数字部分はそのまま使用する。
1111 16MHz
1110 8MHz
1101 4MHz
1100 2MHz
1011 1MHz
その他 500KHz/250KHz/125KHz 62.5KHz/31.25KHz/31KHz

内部クロック32MHzを利用する場合(4xPLLで動作)
コンフィギュレーションを PLLEN = ON , FOSC = INTOSC にして
OSCCON = 0b01110000 として 8MHz x 4倍 で動作させます。

コンフィギュレーション *3)
#pragma config キーワード1 = 設定値 , キーワード2 = 設定値   の様に記述する。
#pragma config BOREN = ON , BORV = HI , FOSC = INTOSC  // 記述の例

CONFIG1
 FOSC         :オシレータ選択ビット
                    HS       = 外部クロックで高い水晶振動子を使用する(HSモード)
                    INTOSC= 内部クロックを使用し、CLKINピン(RA5)はデジタルピンとする
 WDTE         :ウォッチドッグタイマの有無設定ビット
                    ON       = ウォッチドッグタイマを有効にする
                    OFF       = ウォッチドッグタイマを無効にする
                    NSLEEP = 動作時に有効、スリープ中に無効にする
                    SWDTEN= WDTCONレジスタのSWDTENビットで制御する
 PWRTE       :パワーアップタイマの有無設定ビット
                    ON = 電源ONから64ms後にプログラムを開始する
                    OFF= パワーアップタイマは無効とする
 MCLRE       :MCLR/VPP ピン機能選択ビット
                    ON = ピンはMCLR(外部リセットピン)として機能する
                    OFF= ピンはデジタル入力ピン(RA3)として機能する
                    LVP= ONの場合はこのビットは無視される。
 CP            :プログラムメモリー保護の有無設定ビット
                    ON = プログラムメモリーの保護を行う
                    OFF= プログラムメモリーの保護はしない
 CPD          :データメモリー保護の有無設定ビット
                    ON = データメモリーの保護を行う
                    OFF= データメモリーの保護はしない
 BOREN       :電源電圧がBORVより下がったらリセットを行うかの設定ビット
                    ON = 電源電圧降下常時監視機能は有効とする
                    OFF= 電源電圧降下常時監視機能は無効とする
                    NSLEEP = 動作時に有効、スリープ中に無効にする
                    SBODEN=BORCONレジスタのSBORENビットで制御する
 CLKOUTEN :クロック出力の有無設定ビット
                    ON = CLKOUTピンは有効とする
                    OFF= CLKOUTピンは無効、RA4ピンとして使用する
 IESO         :内部・外部クロック切り換えビット(2段階起動モード)
                    ON = 内部から外部クロックへの切替えで起動を行う
                    OFF= 内部から外部クロックへの切替えでの起動はしない
 FCMEN       :外部クロックの監視ビット
                    ON = 外部オシレータに障害が発生した場合に内部オシレータに切替えるか監視する
                    OFF= 外部クロックの監視はしない
CONFIG2
 WRT          :2KWのフラッシュメモリ自己書き込み保護ビット
                    OFF   = 保護しない
                    BOOT= 000h-1FFhを書込み保護にし、200h-7FFhをEECON制御によって変更可能
                    HALF = 000h-3FFhを書込み保護にし、400h-7FFhをEECON制御によって変更可能
                    ALL   = 000h-7FFhを書込み保護にし、EECON制御によるアドレス変更を不可にする
 PLLEN       :4xPLLを動作させるかの有無設定ビット
                    OFF= 動作させない
                    ON  = 動作させる(クロックを32MHzで動作させる場合に使用)
 STVREN      :スタックがオーバフローやアンダーフローしたらリセットを行うかの有無設定ビット
                    ON = リセットを行う
                    OFF= リセットを行なわない
 BORV         :電源電圧降下常時監視の電圧設定ビット
                    HI = リセット電圧(VBOR)のトリップポイントを高(2.5V)に設定する
                    LO = リセット電圧(VBOR)のトリップポイントを低(1.9V)に設定する
 LVP          :低電圧プログラミング機能の有無設定ビット
                    ON = 低電圧プログラミングを行う(RA3のI/Oピンは使用不可)
                    OFF= 低電圧プログラミングは行わない

DEBUGはCONFIGで指定しない、IDEやデバッガから自動的にON/OFFされるらしい。

delay *3)
delay関数を使用する場合は、
#define _XTAL_FREQ 4000000の行を追加するただしこれはクロックが4MHzの場合

__delay_us(50462464) __delay_ms(50462) クロック4MHzならこの値まで設定可能
ただし、( )の中は変数使用不可です、直接数値を入力、うんん...ちょっとぉいまいち!
例えば、50秒以上待たせたいなら、
for (i=0 ; i < 5000 ; i++) __delay_ms(10) ; // 50秒待つ
という感じにします。

クロック 4MHz __delay_us(50462464) __delay_ms(50462)
クロック 8MHz __delay_us(25231232) __delay_ms(25231)
クロック16MHz __delay_us(12615616) __delay_ms(12615)
クロック32MHz __delay_us(6307808) __delay_ms(6307)

4番ピンの使い方(MCLR) *2)
Vpp
 PICチップにプログラムを書込む時の、書込み電圧を負荷するピンという意味なので、
 動作時には気にしなくて良い。

MCLR
 外部リセット信号を入力する場合のピンとして使用。
 リセット信号はLOW(0V:GND接続)でリセットが掛かります。
 リセットスイッチを付けない場合は、内部でプルアップされているので端子はオープンでも構わない。

RA3
 MCLRをDisable(禁止)にしI/OのRA3の入力端子とした方が良いでしょう。
 #pragma config MCLRE = OFF,LVP = OFF
 を記述すればDisableに出来ます。
 但し、プルアップが無効になるので利用する場合は別途プルアップをONさせる必要が有ります。

CCP機能(CAPTURE/COMPARE/PWM MODULES) *4)
CCP機能は、キャプチャ/コンペア/PWMを行うモジュールです。
キャプチャモードでは、外部イベントの発生時間を計測する事が出来ます。
コンペアモードでは、予め設定した時間が経過した時点で外部イベントをトリガする事が出来ます。
PWMモードでは、各種周波数とデューティサイクルのパルス幅変調信号を生成出来ます。
CCP機能は、CCP1で利用出来ます。

PWMモード
 PWM機能に付いては下記の方に記載しています。

キャプチャモード
 キャプチャモードの周波数発生源はTimer1です。
 キャプチャ機能の話は、PIC16F1829での記事ですがこちらを参考にして下さい。
 12F1822ではCCP1ピンのみ使用出来まが、"RA2/RA5"の何方かをAPFCON.CCP1SELレジスタで
 割り当てます。

コンペアモード
 コンペアモードの周波数発生源はTimer1です。
 コンペア機能の話は、PIC16F18313での記事ですがこちらを参考にして下さい。
 12F1822には、CCPxCONレジスタのCCPxMビットに”比較一致時に出力をトグルし、
 タイマ−カウンターもクリアする”モードが有りません、自分で割り込み処理内でクリアさせる必要が
 有ります。
 16F18313では”PPSでRA4ピンをCCP1出力に割当てる”ですが、12F1822のCCP1ピンは”RA2/RA5”の
 何方かをAPFCON.CCP1SELレジスタで割り当てます。

CCP1(PWM)機能
CCP1にはコンペア/キャプチャ機能も有ります。
又、PWM機能にはエンハンスモードとしてハーフブリッジ(18F1822)・フルブリッジ(16F1823)機能が
有り、ステアリング制御も可能です。
尚、ステアリング制御の話に付いてはこちらの記事を参考にして下さい。

次の順番で使用します。
@ PWM機能(シングルモード)を使用する事の宣言を行います。
   CCP1CON = 0b00001100 ;
A TMR2プリスケーラ値の設定を行います。
   T2CON = 0b00000010 ; この設定は16倍に設定
   赤い数字部分にて設定します、1倍=00 4倍=01 16倍=10 64倍=11
B PWMの周期を設定します。
   PR2 = 124 ; この設定はPWM周波数1000Hz(1KHz)で設定
C カウンターなどのレジスターを初期化します
   CCPR1L = 0 ; // デューティ値は0で初期化
   CCPR1H = 0 ;
   TMR2 = 0 ; // タイマー2カウンターを初期化
D TMR2(PWM機能)のスタート要求を行います。
   TMR2ON = 1 ;
E あとはデューティ値を(CCPR1L/CCP1CON)に設定します。
   (PR2が255設定でないので、デューティ値解像度は10ビットの内8ビットのみ使用される)

PR2の値を計算する(PWM周波数=1KHz)

 PR2 = ( クロック周波数 / (PWM周波数 × 4 × TMR2プリスケール値) ) - 1

 ・PICのクロック周波数が8MHzとします。
  PR2 = ( 8,000,000 / (PWM周波数 × 4 × TMR2プリスケール値) ) - 1
 ・PWM周波数を1000Hz(1KHz)にしたい場合です。
  PR2 = ( 8,000,000 / (1000 × 4 × TMR2プリスケール値) ) - 1
 ・TMR2プリスケール値を1倍・4倍・16倍・64倍で計算します。
  PR2 = 1999 = ( 8,000,000 / (1000 × 4 × 1) ) - 1
  PR2 = 499 = ( 8,000,000 / (1000 × 4 × 4) ) - 1
  PR2 = 124 = ( 8,000,000 / (1000 × 4 × 16) ) - 1
  PR2 = 30.25 = ( 8,000,000 / (1000 × 4 × 64) ) - 1

 結果PR2の最大値は255までですので、16倍での124を選択します。
 TMR2プリスケール値を16倍にしてPR2を124に設定します。

デューティ値の設定方法

memo1

 デューティ値は10ビット(0-1023)で
 指定します。

 CCPR1Lレジスターは8ビットなので、
 CCPR1Lを上位8ビットとして、
 下位2ビットをCCP1CONレジスター
 の4-5ビット目を使用しセットします。

この様にセットするのは面倒なので、CCP1CONレジスターの4-5ビット目は0でセットして置き、
設定したいデューティ値を4で割り、その値をCCPR1Lレジスターにセットします。

PWM周波数(1KHz)とデューティ値のPWM波形概要

memo2
但し、デューティ値10ビット(0-1023)はPR2が255の場合で、それ以外は10ビット以下になります。
(PWM制御についてのもう少し詳しい話はこちらのページを参考にして下さい。)

CCP1のサンプルプログラムは「可変抵抗のツマミを回してLEDの明るさを可変します」を参照して下さい。

TIMER0とTIMER1
Timer0 モジュールは 8 ビットのタイマ/カウンタです。
Timer1 モジュールは 16 ビットのタイマ/カウンタで、タイマー動作の他に、
CCPモジュールのキャプチャ/コンペア機能と容量検知オシレータ機能でも使用されます。

TIMER0/TIMER1のサンプルプログラムは「タイマー割込みを使ってLEDを点滅させます」を参照して下さい。

TIMER2 *1)
Timer2 モジュールは 8 ビットのタイマ/カウンタで、タイマー動作の他に、CCPモジュールの、PWMモード時の動作のタイム ベースとして使用されます。
タイマー動作機能は設定した時間毎に割込み処理を行うものです。

割込みとは?
 たとえば、Aさんと電話していて、Bさんから割込みキャッチホンがはいれば、
 Bさんと話して終わったらAさんと続きを話しますよね、これと同じ事です。
 プログラムのmain()を処理中にTIMER0割込みがはいれば、main()を一時中断後
 interrupt InterTimer()を処理して再びmain()を再開します。
 (InterTimerの関数名は変更できます)

割込み発生タイミング
 TIMER2 はTMR2(8ビット)のレジスターを0からカウントアップして行きます、
 PR2 のレジスター値と比較して一致したら、次のカウントでTMR2 のレジスター値は
 0に戻り、ポストスケーラを駆動させます。
 ポストスケーラは指定した回数(1〜16)だけカウントしたら割込みを発生させます。
 例えば、ポストスケーラの設定値が1:1であれば、レジスター値を比較して一致したその都度割込み
 が発生し、1:10 なら、レジスター値を比較して一致した回数が10 回したら割込みを発生させます。

ワンカウントの時間は?
 PICのクロック周波数とプリスケーラ設定値できまります。
 ・ 例えばクロック周波数4MHzでプリスケーラ設定値が 16 なら
  ((1/システムクロック周波数) x 4) x プリスケーラ設定値
  ((1 / 4MHz) x 4) x 16 = 16μs → これがワンカウントの時間です。
  これを256回カウントアップさせると 16x256=4096us(4.096ms)が、プリスケーラ値64 での
  最大割込み時間ですが、ポストスケーラが1:16倍なら16x4096us=65536usで割込みが発生する。
  なら1秒は1000000/65536us=15.258回割り込みを数えればよさそう。
 ・ 1秒ピッタリは?
  クロック周波数4MHz プリスケーラ 1:16 ポストスケーラ 1:10 カウントアップは250回
  にして割込みを25回数える、PR2の周期レジスター設定値は250-1=249をセットする。
 ・プリスケーラ設定方法
  T2CON = 0b00000010 ; この設定はプリスケーラ値16です。
  赤数字文字の部分を変更します、 1 = 00 4 = 01 16 = 10 64 = 11 となります。

使い方は次の順番で行います

@ タイマー制御レジスターの設定を行う
  プリスケーラ設定は上記載を参照して下さい。
  T2CON = 0b00000111 ;
  緑数字部分 1:TIMER2を動作させる 0:TIMER2を動作させない
  赤数字部分でポストスケーラの設定を行います。
1:1 1:2 1:3 1:4 1:5 1:6 1:7 1:8 1:9 1:10 1:11 1:12 1:13 1:14 1:15 1:16
0000 0001 0010 0011 0100 0101 0110 0111 1000 1001 1010 1011 1100 1101 1110 1111

A 周期レジスター(PR2)の設定を行う
  TMR2を何カウントアップさせるかの設定です、
  PR2=249 とした場合は、TMR2は0から249までカウントアップし250カウントめで割込み発生です

B TMR2カウントアップレジスターの初期化を行う
  TMR2 = 0 ;

C TMR2IFのタイマー2割込みフラグを初期化します
  TMR2IF = 0 ;

D 割込み機能を許可します
  TMR2IE = 1 ;      // TIMER2の割込みを許可する
  PEIE = 1 ;      // 周辺装置割り込み有効
  GIE = 1 ;      // 全体の割込み処理を許可する

 割込み関数の書き方
void interrupt 割込み関数名( void )
{
     if (TMR2IF == 1) {  // タイマー0の割込み発生か?
          TMR2IF = 0 ;   // タイマー0割込フラグをリセット(再カウントアップ開始)
     }
}
TIMER2のサンプルプログラムはこちらからダウンロードして下さい。

その他



CCP機能で一部追記(*4) 2018/04/13
MPLAB X用に記事変更(*3) 2015/10/01
記事変更(*2) 2015/06/30
追記(*1) 2013/03/06


【きむ茶工房ガレージハウス】
Copyright (C) 2006-2020 Shigehiro Kimura All Rights Reserved.