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 | アラーム・マスク
|
||||||
| 4 | AMASK2 | |||||||
| 3 | AMASK1 | |||||||
| 2 | AMASK0 | |||||||
| 1 | ALRMPTR1 | ALRMVAL がアクセスするデータレジスタを指定するポインタ データレジスタ・マップ参照 <初期値 00 > |
||||||
| 0 | ALRMPTR0 | |||||||
| ALRMRPT | ARPT<7-0> | 00000000 : アラームは繰返さない <初期値> 11111111 : アラームは255回繰り返す |
||||||
実際の日時を保持している、どのデータレジスタにアクセスするかを 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
}