PIC18F14K50の基本動作から応用プログラムまでを学びます。

ホーム
16F18313
16F18325
16F18346
16F1619
Curiosity
---
---
    
12F1822
16F1455
16F1459
18F14K50
18F26J50
dsPIC
その他
リアルタイムクロック (RTCC)

RTCCは2000年~2099年まで対応するカレンダー時計です。時計の基準となるクロックは、外部に32.768KHzの水晶発振子を取り付けて使用すること基本ですが、内部のRC発振回路からのクロックを入力することもできます。基準クロックはモジュール内部のキャリブレーション回路を調整することで月差3秒にすることが可能です。実際の日時を保持している データ レジスターへの読み書きは他の多くのモジュールと異なり、どのデータレジスタにアクセスするかを RTCPTR ポインタにセットしてから、各レジスター共有の RTCVAL 入出力レジスタで読み書きします。さらに、簡単に時刻が書き変わらないように、書き込みを実施するためには、特別なシーケンスで書込みロックを解除する必要があります。

高低2レベルの優先度を使用するタイマー2に関連するレジスターを一覧で説明します。

レジスタ bit7 bit6 bit5 bit4 bit3 bit2 bit1 bit0
RCON IPEN CM RI TO PD POR BOR
INTCON GIEH GIEL TMR0IE INT0IE RBIE TMR0IF INT0IF RBIF
PIR3 SSP2IF BCL2IF RC2IF TX2IF TMR4IF CTMUIF TMR3GIF RTCCIF
PIE3 SSP2IE BCL2IE RC2IE TX2IE TMR4IE CTMUIE TMR3GIE RTCCIE
IPR3 SSP2IP BCL2IP RC2IP TX2IP TMR4IP CTMUIP TMR3GIP RTCCIP
RTCCFG RTCEN RTCWREN RTCSYNC HALFSEC RTCOE RTCPTR1 RTCPTR0
RTCCAL CAL7 CAL6 CAL5 CAL4 CAL3 CAL2 CAL1 CAL0
PADCFG1 RTSECSEL1 RTSECSEL0 PMPTTL
ALRMCFG ALRMEN CHIME AMASK3 AMASK2 AMASK1 AMASK0 ALRMPTR1 ALRMPTR0
ALRMRPT ARPT7 ARPT6 ARPT5 ARPT4 ARPT3 ARPT2 ARPT1 ARPT0
RTCVALH RTCC Value Register Window High Byte,
RTCVALL RTCC Value Register Window Low Byte,
ALRMVALH Alarm Value Register Window High Byte,
ALRMVALL Alarm Value Register Window Low Byte,
レジスタ BIT 説明 1 0
RCON 7 IPEN 2レベルのインタラプト優先度 使用
INTCON 7 GIEH 高優先度インタラプトを使用許可 許可
6 GIEL 低優先度インタラプトを使用許可 許可
PIR3 3 RTCCIF RTCC インタラプト発生フラグ 発生  
PIE3 3 RTCCIE RTCC インタラプトを使用許可 許可
IPR3 3 RTCCIP RTCC インタラプト優先度
RTCCFG 7 RTCEN RTCCの ON/OFF ON OFF
5 RTCWREN RTCVALH、RTCVALL の書込み許可 許可 禁止
4 RTCSYNC 桁上がりエラーの可能性 (Read Only) あり なし
3 HALFSEC 毎秒の前半または後半 (Read Only) 後半 前半
2 RTCOE RTCC出力ピンのイネーブル ON OFF
1 RTCPTR1 RTCVAL がアクセスするデータレジスタを指定するポインタ
データレジスタ・マップ参照   <初期値 00 >
0 RTCPTR0
RTCCAL CAL<7-0> 01111111(最大遅れ)- 00000000(無調整)- 10000000(最大進み)
PADCFG1 2 RTSECSEL1 RTCCピン選択 
10 : RTCC入力クロック 01 : 秒パルス 00 : アラームパルス
1 RTSECSEL0
0 PMPTTL NA
ALRMCFG 7 ALRMEN アラームの ON/OFF ON OFF
6 CHIME チャイムの ON/OFF ON OFF
5 AMASK3 アラーム・マスク
0000 : 1/2秒毎 (初期値)
0001 : 毎秒
0010 : 10秒毎
0011 : 毎分
0100 : 10分毎
0101 : 毎時
0110 : 毎日
0111 : 毎週
1000 : 毎月
1000 : 毎年
4 AMASK2
3 AMASK1
2 AMASK0
1 ALRMPTR1 ALRMVAL がアクセスするデータレジスタを指定するポインタ
データレジスタ・マップ参照   <初期値 00 >
0 ALRMPTR0
ALRMRPT ARPT<7-0> 00000000 : アラームは繰返さない  <初期値>
11111111 : アラームは255回繰り返す

RTCデータレジスタの読み書き

実際の日時を保持している、どのデータレジスタにアクセスするかを RTCPTR ポインタにセットしてから、各レジスター共有の RTCVAL 入出力レジスタで読み書きします。 たとえば、RTC「月」のレジスタは、RTCPTRに、「10」をセットした後に、RTCVALH に読み書きを行います。 さらに、RTCPTRポインタの値は、RTCVALHにアクセスする毎に自動的に -1 ようになっているため、すべてのデータを読み書きするときは、RTCPTRポインタの値をユーザーが変更しなくても良いよう設計されています。アラームに関するデータレジスターも同様に、ALRMPTR ポインタにセットしてから、各レジスター共有の ALRMVAL 入出力レジスタで読み書きします。 なお、どちらのデータレジスタも、その内容は、2進数ではなく BCD (2進化10進数)で表記されています。

RTCPTR
<1:0>
RTCC Value Register Window
RTCVALH RTCVALL
十の位 一の位 十の位 一の位
<7654> <3210> <7654> <3210>
00
01
10
11
ALRMPTR
<1:0>
Alarm Value Register Window
ALRMVALH ALRMVALL
十の位 一の位 十の位 一の位
<7654> <3210> <7654> <3210>
00
01
10
11

書込み許可シーケンス

誤って時刻が書き変わらないように、RTCEN ビット や RTCVAL に書き込みを実施するためには、特別なシーケンスでロックを解除し、書き込み許可をする必要があります。 EECON2 に、0x55、0xAA と連続して書き込むと、次のワンサイクルだけ RTCWREN を「1」にすることができ、書込み許可をすることができます。

EECON2 = 0x55;
EECON2 = 0xAA;
RTCCFGbits.RTCWREN = 1;

プログラム例

32.768KHzの時計用水晶発振子を使用したカレンダー時計を作成しました。 RTCCの基本プログラムのために、現在時間の設定変更やアラーム機能は盛り込まれていません。 時刻表示は、I2C液晶上に行います。 さらに、PushSWで日時の設定を変更することができる応用プログラムを、RTCC リアルタイムカレンダーとして作成しました。

<プログラム> main.c

//*********************************************************
//  PIC18F26J50 RTCC Program//        :  MPLAB xc8
//  カレンダー時計の初期時間設定は、プログラムの最初にセットされる。
//  時間は、I2C接続のLCDに表示される。
//  外部 32.768KHz クリスタルを使用
//  Note:  4MHzシステムクロック
//         PORTB(5)pin26    :  SDA1
//         PORTB(4)pin25    :  SCL1
//*********************************************************

#include <xc.h>
#include <stdio.h>              // printfなどのライブラリ
#define _XTAL_FREQ 4000000      //delay_ms(x) のための定義

//*********************************************************************
//  調整用定数
//*********************************************************************
#define CONTRAST  0x28          // for 3.3V

//*********************************************************************
// もし、RTCC クロックがずれているようなら、
// RTCC キャリブレーションの値をセットし、毎分のクロック数を増減する。
//*********************************************************************
#define RTCCALIBRATION    0

//-------------- コンフィグレーション ----------------------
     #pragma config WDTEN = OFF, PLLDIV = 2, STVREN = ON, XINST = OFF
     #pragma config CPUDIV = OSC1, CP0 = OFF
     #pragma config OSC = INTOSC, T1DIG = OFF
     #pragma config LPT1OSC = OFF, FCMEN = OFF, IESO = OFF
     #pragma config WDTPS = 32768
     #pragma config DSWDTOSC = INTOSCREF, RTCOSC = T1OSCREF
     #pragma config DSBOREN = OFF, DSWDTEN = OFF, DSWDTPS = 8192
     #pragma config IOL1WAY = OFF, MSSP7B_EN = MSK7
     #pragma config WPFP = PAGE_1, WPEND = PAGE_0, WPCFG = OFF
     #pragma config WPDIS = OFF

//******************* プロトタイプ *******************************
void i2cByteWrite(char, char, char);
void i2cTxData(char);
void LCD_dat(char);
void LCD_cmd(char);
void LCD_clr(void);
void LCD_posyx(char,char);
void LCD_int(void);

//*********************************************************
// LCD で printf関数が使用できるようにするため putch を設定する
void putch(char data) {
        LCD_dat(data);      // LCD への一文字表示関数
}

//*********************************************************
void main(void){
    unsigned char year, yearh, month, day, hour, min, sec;
    OSCCON = 0b01100011;       // 内部クロック4Mhz
    ANCON0 = 0b00011111;       // すべてのポートをデジタルに設定
    ANCON1 = 0b00011111;       //
    T1CON = 0b00001000;        // T1 Oscを有効にする
    
    // I2C設定 -----------------------------------------------
    TRISBbits.TRISB4 = 1;      // SCL1(RB4)を入力に設定
    TRISBbits.TRISB5 = 1;      // SDA1(RB5)を入力に設定
    INTCON2bits.RBPU = 0;      // 弱プルアップ ON
    SSP1STAT = 0b10000000;     // スルーレート制御はOff
    SSP1ADD  = 9;              // クロック設定 100k@4MHz
    SSP1CON1 = 0b00101000;     // I2C Master modeにする
    // LCD初期化 ---------------------------------------------
    LCD_int();
    // RTCC設定 ----------------------------------------------
    // RTCC レジスタを unlock し、RTCCの設定する
    EECON2 = 0x55;
    EECON2 = 0xAA;
    RTCCFGbits.RTCWREN = 1;
    // RTCC 日時の設定 (起動時のみ)
    RTCCFGbits.RTCPTR1 = 1;    // RTCVALHにアクセスする毎に
    RTCCFGbits.RTCPTR0 = 1;    // RTCPTRは自動的に -1 する
    RTCVALL = 0x09;            // 年
    RTCVALH = 0xFF;            // 未設定
    RTCVALL = 0x01;            // 日
    RTCVALH = 0x01;            // 月
    RTCVALL = 0x12;            // 時
    RTCVALH = 0x01;            // 曜日(0:日、1:月、…)
    RTCVALL = 0x00;            // 秒
    RTCVALH = 0x00;            // 分
    RTCCFGbits.RTCEN = 1;      // RTCC を有効に
    RTCCAL = RTCCALIBRATION;   // キャリブレーション値セット
    while(1){
        RTCCFGbits.RTCPTR1 = 1;         // RTCPTR のセット
        RTCCFGbits.RTCPTR0 = 1;
        while(RTCCFGbits.RTCSYNC != 1); // RTCの位上げ中に、読み込ぬよう
        while(RTCCFGbits.RTCSYNC == 1); // SYCが「0」になるまで待つ
        year  = RTCVALL;
        day   = RTCVALH;     // RTCPTR を -1 するためのダミー読み込み
        day   = RTCVALL;
        month = RTCVALH;
        hour  = RTCVALL;
        sec   = RTCVALH;     // RTCPTR を -1 するためのダミー読み込み
        sec   = RTCVALL;
        min   = RTCVALH;
        // --------- 上段にカーソル移動 ------------------
        LCD_posyx(0,0);
        printf("20%02X/%02X/%02X", year, month, day);
        // --------- 下段にカーソル移動 ------------------
        LCD_posyx(1,0);
        printf("%02X:%02X:%02X", hour, min, sec);
    }
}

//********************************************************************
// I2C 関連 
//********************************************************************
//-------- ByteI2C送信
void i2cByteWrite(char addr, char cont, char data){
    SSP1CON2bits.SEN = 1;      // Start condition 開始
    while(SSP1CON2bits.SEN);   // Start condition 確認
    i2cTxData(addr);           // アドレス送信
    i2cTxData(cont);           // 制御コード送信
    i2cTxData(data);           // データ送信
    SSP1CON2bits.PEN = 1;      // Stop condition 開始
    while(SSP1CON2bits.PEN);   // Stop condition 確認    
}
//-------- Data送信
void i2cTxData(char data){
    PIR1bits.SSP1IF = 0;       // 終了フラグクリア
    SSP1BUF = data;            // データセット
    while(!PIR1bits.SSP1IF);   // 送信終了待ち
}
//********************************************************************
// LCD 関連 
//********************************************************************
//-------- 1文字表示
void LCD_dat(char chr){
    i2cByteWrite(0x7C, 0x40, chr);
    __delay_us(50);            // 50μsec
}
//-------- コマンド出力
void LCD_cmd(char cmd){
    i2cByteWrite(0x7C, 0x00, cmd);
    if(cmd & 0xFC)             // 上位6ビットに1がある命令
        __delay_us(50);        // 50usec
    else
        __delay_ms(2);         // 2msec ClearおよびHomeコマンド
}
//-------- 全消去
void LCD_clr(void){
    LCD_cmd(0x01);             //Clearコマンド出力
}
//-------- カーソル位置指定
void LCD_posyx(char ypos, char xpos){
    unsigned char pcode;
    switch(ypos & 0x03){    
        case 0:    pcode=0x80;break;
        case 1:    pcode=0xC0;break;
    }
    LCD_cmd(pcode += xpos);
}
//-------- 初期化
void LCD_int(void){
    __delay_ms(100);
    LCD_cmd(0x38);             // 8bit 2行 表示命令モード
    LCD_cmd(0x39);             // 8bit 2行 拡張命令モード
    LCD_cmd(0x14);             // OSC  BIAS 設定1/5
                               // コントラスト設定 
    LCD_cmd(0x70 + (CONTRAST & 0x0F));
    LCD_cmd(0x5C + (CONTRAST >> 4));
    LCD_cmd(0x6B);             // Ffollwer
    __delay_ms(100);
    __delay_ms(100);
    LCD_cmd(0x38);             // 表示命令モード 
    LCD_cmd(0x0C);             // Display On 
    LCD_cmd(0x01);             // Clear Display 
}