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 }