---
---
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 }