16F1827覚書

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


忘れないうちにメモします。
ここでの記載はMPLAB X V2.15
MPLAB(R) XC8 C Compiler Version 1.32を使用しての内容です。 *3)
データシートはこちらです。英語だけどね
(こちらのデータシートは16F1938で少し異なりますが日本語なので何かと参考になり便利です。)
16F1826も同じ内容です。

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

内部クロックを利用する場合
コンフィギュレーションを
#pragma config PLLEN = OFF , FOSC = INTOSC
にして
OSCCONレジスターにて使用する周波数を設定します。
OSCCON = 0b01111010 ;赤い数字部分を変更する事により周波数を変更できます。
緑の数字部分が内部クロックを使用する時の設定です。
赤い数字部分を変更する事により周波数を変更できます。
それ以外の数字部分はそのまま使用する。
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倍 で動作させます。

外部クロック(プライマリ外部オシレータ)を利用する場合
コンフィギュレーションを FOSC = HS にして
OSCCON = 0b00000000 として動作させます。

また、プライマリとは別にセカンダリ外部オシレータとして、 外付けの32.768 kHz 水晶振動子を駆動出来ます、って事はRTC(リアルタイムクロック)が実現出来そうですね。

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

CONFIG1
 FOSC         :オシレータ選択ビット
                    HS = 外部発振器で高い振動子を使用する
                    INTOSC= 内部クロックを使用し、CLKINピン(RA7)はデジタルピンとする
                    ほかにRCオシレータや外部クロック利用等有るが詳しくはデータシート参照。
 WDTE         :ウォッチドッグタイマの有無設定ビット
                    ON = ウォッチドッグタイマを有効にする
                    OFF= ウォッチドッグタイマを無効にする
                    NSLEEP = 動作時に有効、スリープ中に無効にする
                    SWDTEN= WDTCONレジスタのSWDTENビットで制御する
 PWRTE       :パワーアップタイマの有無設定ビット
                    ON = 電源ONから64ms後にプログラムを開始する
                    OFF= パワーアップタイマは無効とする
 MCLRE       :MCLR/VPP ピン機能選択ビット
                    ON = ピンはMCLR(外部リセットピン)として機能する
                    OFF= ピンはデジタル入力ピン(RA5)として機能する
                    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          :4KWのフラッシュメモリ自己書き込み保護ビット
                    OFF= 保護しない
                    BOOT= 000h-1FFhを書込み保護にし、200h-FFFhをEECON制御によって変更可能
                    HALF= 000h-7FFhを書込み保護にし、800h-FFFhをEECON制御によって変更可能
                    ALL= 000h-FFFhを書込み保護にし、EECON制御によるアドレス変更を不可にする
 PLLEN       :4xPLLを動作させるかの有無設定ビット
                    ON = 動作させない
                    OFF= 動作させる(クロックを32MHzで動作させる場合に使用)
 STVREN     :スタックがオーバフローやアンダーフローしたらリセットを行うかの有無設定ビット
                    ON = リセットを行う
                    ON = リセットを行なわない
 BORV         :電源電圧降下常時監視の電圧設定ビット
                    HI = リセット電圧(VBOR)のトリップポイントを高(2.5V)に設定する
                    LO = リセット電圧(VBOR)のトリップポイントを低(1.9V)に設定する
 LVP          :低電圧プログラミング機能の有無設定ビット
                    ON = 低電圧プログラミングを行う
                    OFF= 低電圧プログラミングは行わない

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

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

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

クロック 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接続)でリセットが掛かります。
 リセットスイッチを付けない場合は、内部でプルアップされているので端子はオープンでも構わない。

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

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

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

キャプチャモード
 キャプチャモードの周波数発生源はTimer1です。
 キャプチャ機能の話は、PIC16F1829での記事ですがこちらを参考にして下さい。
 PIC16F1829と16F1827のCCPピン割当てが異なります、16F1827ではCCP4ピンは"RA4"となります。
 因みに、16F1829ではCCP4ピンは"RC6"となります。

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

CCP3/4(PWM)機能[標準CCP機能]
PIC16F1827はCCP3とCCP4の2個からPWMを出力できます。
CCP3とCCP4にはそれぞれTimer2/4/6の何れかを使用する様にします。
次の順番で使用します。 (CCP3を利用しTimer2を使用する例での記載です)
@ CCP3でどのタイマーを使用するのかを設定します。
   CCPTMRS = 0b00000000 ;
   赤数字部分がCCP4用設定で緑数字部分がCCP3用設定の場所です。
   Timer2=00 , Timer4=01 , Timer6=10 この設定でCCP3はTimer2を使用です。
A PWM機能(PWMモード)を使用する事の宣言を行います。
   CCP3CON = 0b00001100 ;
B TMR2プリスケーラ値の設定を行います。
   T2CON = 0b00000010 ; この設定は16倍に設定
   赤い数字部分にて設定します、1倍=00 4倍=01 16倍=10 64倍=11
C PWMの周期を設定します。
   PR2 = 124 ; この設定はPWM周波数1000Hz(1KHz)で設定
D カウンターなどのレジスターを初期化します
   CCPR3L = 0 ; // デューティ値は0で初期化
   CCPR3H = 0 ;
   TMR2 = 0 ; // タイマー2カウンターを初期化
E TMR2(PWM機能)のスタート要求を行います。
   TMR2ON = 1 ;
F あとはデューティ値を(CCPR3L/CCP3CON)に設定します。
   (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に設定します。

デューティ値の設定方法
図のCCPR1L/CCP1CONはCCPR3L/CCP3CONと読み替えて下さい。
memo1  デューティ値は10ビット(0-1023)で
 指定します。

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

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

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

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

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

ECCP1/2機能[拡張型CCP機能]
PWMモード・シングルPWM機能
 この機能についての説明とサンプルプログラムは
 「可変抵抗のツマミを回してLEDの明るさを可変します(2/2)」を参照して下さい。
PWMモード・ハーフブリッジPWM機能

PWMモード・フルブリッジPWM機能

TIMER0
Timer0 モジュールは 8 ビットのタイマ/カウンタです。

TIMER0のサンプルプログラムはこちらからダウンロードして下さい。
また、概要は12F675での記事ですが、こちらを参考にして下さい。

TIMER1
Timer1 モジュールは 16 ビットのタイマ/カウンタで、タイマー動作の他に、 CCPモジュールのキャプチャ/コンペア機能と容量検知オシレータ機能でも使用されます。
また、Timer0からのオーバフロー・外部ピン・コンパレータ出力からの信号によるゲート制御機能が追加されています、 これによりパルスカウントやサイクル時間の測定が可能と思われますが、ここではこの機能には触れません。

TIMER1のサンプルプログラムはこちらからダウンロードして下さい。
また、概要は12F675での記事ですが、こちらを参考にして下さい。
ただ、T1CONの設定とワンカウントの時間計算が少し異なります。

T1CONの設定
 T1CON = 0b00000001 ;
 青数字部分でTimer1のクロックソースを選択します。
  00 = Fosc/4  01 = Fosc  10 = 外部入力  11 = 内蔵の容量検知オシレータ (CAPOSC)
 緑数字部分でプリスケーラの設定を行います。
  00 = 1:1  01 = 1:2  10 = 1:4  11 = 1:8
 赤数字部分 1=TIMER1を動作させる 0=TIMER1を動作させない

ワンカウントの時間計算
システムクロックが4MHzとする場合での計算
・クロックソースが 00 = Fosc/4 でプリスケーラの設定が 11 = 1:8 なら
  ((1/4MHz)x 4)x8 = 8us
・クロックソースが 01 = Fosc でプリスケーラの設定が 11 = 1:8 なら
  (1/4MHz)x 8 = 2us

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

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

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

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

使い方は次の順番で行います(TIMER2での例です)

@ タイマー制御レジスターの設定を行う
  プリスケーラ設定は上記載を参照して下さい。
  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のサンプルプログラムは「タイマー割込みを使ってLEDを点滅させます」を参照して下さい。

 1秒がしりたい場合は?(ポストスケーラが1:1の場合です)
 はっきり言って1秒ピッタリは無理ですが、出来るだけ1秒に近づける場合算出方法
 ((1秒 / TMR2)/(プリスケーラ設定値 x(4 x 1000000 /クロック周波数)))
 ・クロック8MHzで1秒なら
 ((1000000/ TMR2)/(プリスケーラ設定値 x(4 x 1000000 /8000000)))
 ・TMR2=256カウントアップ プリスケーラ設定値=64
 ((1000000/256)/(64*(4*1000000/8000000)))=122.0703 割込み回数を122回数えれば約1秒
 ・TMR2=250カウントアップ プリスケーラ設定値=64
 ((1000000/250)/(64*(4*1000000/8000000)))=125 割込み回数を125回数えれば約1秒

 この場合は下を採用した方が誤差なくてピッタリそうで、よさそうですね。
 プリスケーラ値64 で、TMR2:250-1=249 をセットして、割込み回数を125回数えれば約1秒です。
 って事で、TMR2とプリスケーラ設定値を適度に入れてみて計算して下さい。

SPI(MSSP)
SPIについては、12F1822での記事ですが同じ様に利用出来ます、こちらを参考にして下さい。

16F1827のSPI1(SSP1)ピンは以下の様に利用します。
 SCK1:10番ピン(RB4) SDI1:7番ピン(RB1) 
 SDO1:15番ピン(RA6)と8番ピン(RB2)のどちらかで SDO1SELレジスターで選択します。
 SS1 :11番ピン(RB5)と4番ピン(RA5)のどちらかで SS1SELレジスターで選択します。
 SDO1SEL 0=RB2 1=RA6   SS1SEL 0=RB5 1=RA5
 SDIはデジタル入力に設定して、スレーブならSCKも入力に設定します。

16F1827にはMSSP機能が2個あります、2個目のSPI2(SSP2)ピンは以下の様に利用します。
 SCK2:11番ピン(RB5) SDI2:8番ピン(RB2) SDO2:17番ピン(RA0) SS2:18番ピン(RA1)

また、2個目のSPI2(SSP2)を利用する場合はレジスター名をSSP1からSSP2に変更します。

USART(EUSART)(非同期モード)
USARTについては、12F1822/16F628Aでの記事ですが同じ様に利用出来ます、こちらを参考にして下さい。

16F1827のUSARTピンは以下の様に利用します。
 TX:11番ピン(RB5)と8番ピン(RB2)のどちらかで TXCKSELレジスターで選択します。
 RX:7番ピン(RB1)と8番ピン(RB2)のどちらかで RXDTSELレジスターで選択します。
 TXCKSEL 0=RB2 1=RB5   RXDTSEL 0=RB1 1=RB2
 RXはデジタル入力に設定します。

SPBRGレジスタの設定値とボーレートの関係はデータシートを参照して下さい。
16F1827のデータシートはこちらの301-302ページを見て下さい。

その他



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


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