---
---
18F26J50のRTCC機能と時計用クリスタルを使用し、PushSWで電源ON時に日時の初期設定が行えるカレンダー時計です。
![]() |
SW1で カーソル移動 ⇒⇒⇒ |
![]() |
SW2で 数値設定 ⇒⇒⇒ |
![]() |
この回路は、基本回路のリアルタイムクロック RTCCに、PushSWによる時刻合わせを追加して、少し実用的にしました。SWによる入力回ををうまく使えば、アラーム等も実装することが可能です。
電源ONで日時の設定画面になります。SW1,SW2を使い現在時刻に合わせます。
設定が終了すると、毎秒LEDが点滅し、画面も更新されます。
<プログラム>
main.c
//*********************************************************
// PIC18F26J50 RTCC Program// : MPLAB xc8
// カレンダー時計の初期時間設定は、プログラムの最初にセットされる。
// 時刻は、I2C接続のLCDに表示される。
// 外部 32.768KHz クリスタルを使用
// Note: 4MHzシステムクロック
// PORTB(7)pin28 : LED
// PORTB(5)pin26 : SDA1
// PORTB(4)pin25 : SCL1
// PORTB(3)pin24 : SW2
// PORTB(2)pin23 : SW1
//*********************************************************
#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
#define LED PORTBbits.RB7 // 毎秒間隔で点滅
#define SW2 PORTBbits.RB3 // SW2で数値を+1
#define SW1 PORTBbits.RB2 // SW1で次の数
//-------------- コンフィグレーション ----------------------
#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);
unsigned char getNum(unsigned char,char,char,char);
char getDigit(char,char,char,char );
//*********************************************************
// LCD で printf関数が使用できるようにするため putch を設定する
void putch(char data) {
LCD_dat(data); // LCD への一文字表示関数
}
//*********************************************************
void main(void){
// --------- 時計初期値 BCDで設定する ---------
char year = 0x12; // 2012年
char month = 0x01; // 1月
char day = 0x01; // 1日
char hour = 0x12; // 12時
char min = 0x00; // 0分
char sec = 0x00; // 0秒
OSCCON = 0b01100011; // 内部クロック4Mhz
ANCON0 = 0b00011111; // すべてのポートをデジタルに設定
ANCON1 = 0b00011111; //
T1CON = 0b00001000; // T1 Oscを有効にする
TRISBbits.TRISB7 = 0; // LED用に出力設定
// 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();
// --------- 年月日設定画面 ---------------
printf("Set >20%02X/%02X/%02X", year, month, day);
LCD_posyx(1,0);
printf("Date %02X:%02X:oo", hour, min);
// --------- PushSWでの初期値設定 ---------
year = getNum( year,99,0,8); // 年の設定
month = getNum(month,19,0,11); // 月の設定
day = getNum( day,39,0,14); // 日の設定
// --------- 時間設定画面 -----------------
LCD_posyx(0,5);
LCD_dat(' ');
LCD_posyx(1,0);
printf("Time >");
// --------- PushSWでの初期値設定 ---------
hour = getNum(hour,29,1,8); // 時の設定
min = getNum( min,59,1,11); // 分の設定
// --------- 日時表示画面 -----------------
LCD_posyx(0,0);
printf("Date 20%02X/%02X/%02X", year, month, day);
LCD_posyx(1,5);
printf(" %02X:%02X:%02X", hour, min, sec);
// --------- RTCC 日時の設定 (起動時のみ) ---------
// RTCC レジスタを unlock し、RTCCの設定する
EECON2 = 0x55;
EECON2 = 0xAA;
RTCCFGbits.RTCWREN = 1;
RTCCFGbits.RTCPTR1 = 1; // RTCVALHにアクセスする毎に
RTCCFGbits.RTCPTR0 = 1; // RTCPTRは自動的に -1 する
RTCVALL = year; // 年
RTCVALH = 0xFF; // 未設定
RTCVALL = day; // 日
RTCVALH = month; // 月
RTCVALL = hour; // 時
RTCVALH = 0x01; // 曜日(0:日、1:月、…)
RTCVALL = sec; // 秒
RTCVALH = min; // 分
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」になるまで待つ
LED = !LED;
year = RTCVALL;
day = RTCVALH; // RTCPTR を -1 するためのダミー読み込み
day = RTCVALL;
month = RTCVALH;
hour = RTCVALL;
sec = RTCVALH; // RTCPTR を -1 するためのダミー読み込み
sec = RTCVALL;
min = RTCVALH;
// --------- 上段にカーソル移動 ------------------
LCD_posyx(0,6);
printf("20%02X/%02X/%02X", year, month, day);
// --------- 下段にカーソル移動 ------------------
LCD_posyx(1,8);
printf("%02X:%02X:%02X", hour, min, sec);
}
}
//****** 2桁の初期値を入力する関数 *************************
// num 入力される初期数 top 値の最大値
// y 十の位のLCD縦位置 x 十の位のLCD横位置
//*******************************************************
char getNum(char num,char top,char y,char x){
char tens, ones;
LCD_cmd(0x0D); // 表示点滅
top = top/10;
tens = num >> 4;
ones = num & 0xF;
tens=getDigit(tens,top,y,x); // 10位設定
ones=getDigit(ones,9,y,x+1); // 1位設定
LCD_cmd(0x0C); // 表示点滅を解除
return ((tens << 4) + ones) ; // 値計算
}
//****** 1桁の初期値を入力する関数 ************************
// num 入力される初期数 top 値の最大値
// y 入力のLCD縦位置 x 入力のLCD横位置
//*******************************************************
char getDigit(char num,char top,char y,char x){
char OnSW;
top++;
LCD_posyx(y,x); // 表示位置
while(1){
OnSW = 5; // SWがOnでないことを確認する
do{
if(SW1 & SW2)OnSW--;
else OnSW = 5; // 1mSecおきに5回確認
__delay_ms(1); // 1mS遅延
}while(OnSW);
while(SW1 & SW2); // SWのPushを待つ
if(!SW1)return num; // SW1で終了
if(!SW2){ // SW2で数値を+1
num++;
num %= top;
LCD_dat(num+0x30); // 数値表示
LCD_posyx(y,x); // カーソルを戻す
}
}
}
//********************************************************************
// 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
}