/****************************************************************** * PIC18F26J50 * カレンダー時計の初期時間設定は、プログラムの最初にセットされる。 * 時間は、I2C接続のLCDに表示される。外部に 32.768KHz クリスタルを使用 * * I/O Pins Used: * PORTB(7)pin28 : LED2 * PORTB(6)pin27 : LED1 * PORTB(5)pin26 : SDA1 * PORTB(4)pin25 : SCL1 * PORTB(3)pin24 : SW2 * PORTB(2)pin23 : SW1 * * ここまで、「はじめてのPIC」さんのオリジナルコメント *==================================================================== * PIC18F_RTCC_CLOCK_V1.c * * <オリジナルとの相違点> * @ 表示フォーマットの変更 *   曜日を追加した。 *   表題表示は省略し、年月日(曜日)+時刻表示のみとした。 * A @に伴い、時計合わせのソフトを変更した。 * * ※ オリジナルは、tabの文字数を4文字でエディトしているが、 *   私は習慣的に、8文字にしているので設定を変えて編集した。 * * 2016/9/20 * 作成:N.Ishii ********************************************************************/ #include #include #include #include #include "L_i2c1_LCD.h" // I2C接続LCD関数 #include // printfなどのライブラリ // もし、RTCC クロックがずれているようなら、 // RTCC キャリブレーションの値をセットし、毎分のクロック数を増減する。 #define RTCCALIBRATION 0 #define LED2 LATBbits.LATB7 // 毎秒間隔で点滅 #define LED1 LATBbits.LATB6 #define SW2 PORTBbits.RB3 // SW2で数値を+1 #define SW1 PORTBbits.RB2 // SW1で次の数 // コンフィグレーションの設定 #pragma config RTCOSC = T1OSCREF #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 #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 // プロトタイプの宣言 int _user_putc (char c); // ユーザー出力のプロトタイプ unsigned char getNum(unsigned char,char,char,char); char getDigit(char,char,char,char ); #pragma code // ++++++++++++++++ ユーザー出力の出力を定義 ++++++++++++++ int _user_putc (char c){ LCD_dat(c); // 一文字出力する命令を指定 } // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ void main(void){ // --------- 時計初期値 BCDで設定する --------- /* unsigned char year = 0x12; // 2012年 unsigned char month = 0x01; // 1月 unsigned char day = 0x01; // 1日 unsigned char week = 0x01; // 1日 */ unsigned char year = 0x16; // 2016年 unsigned char month = 0x09; // 9月 unsigned char day = 0x13; // 13日 unsigned char week = 0x01; // 火曜:追加 N.I unsigned char hour = 0x12; // 12時 unsigned char min = 0x00; // 0分 unsigned char sec = 0x00; // 0秒 char CntSW ; // SW状態・カウント char tens, ones ; // SW状態・カウント OSCCON = 0b01100011; // 内部クロック4Mhz LATB = 0; // TRISB = 0b00111111; // SCL1、SDA1(RB4)は入力に設定 INTCON2bits.RBPU = 0; // PortBを弱プルアップ ANCON0 = 0b11111110; // すべてデジタルに設定 ANCON1 = 0b00011111; OpenTimer1(TIMER_INT_OFF & // Secondary Oscを RTCC T1_SOURCE_PINOSC & // で利用するため T1_PS_1_1 & // OSC1を有効にする T1_OSC1EN_ON & T1_SYNC_EXT_OFF, 0); OpenI2C1(MASTER, SLEW_OFF); // I2Cマスターモード指定 SSP1ADD = 9; // Board Rate 100kHz LCD_int(); // LCDを初期化 // --------- 年月日設定画面 --------------- /* LCD_ROMstr("Set >"); fprintf(_H_USER, "20%02X/%02X/%02X", year, month, day); LCD_posyx(1,0); LCD_ROMstr("Date "); fprintf(_H_USER, "%02X:%02X:oo", hour, min); */ fprintf(_H_USER, "20%02X/%02X/%02X(%02X )", year, month, day, week); LCD_posyx(1,0); fprintf(_H_USER, "%02X:%02X:oo", hour, min); // --------- PushSWでの初期値設定 --------- /* year = getNum( year,99,0,8); // 年の設定 month = getNum(month,19,0,11); // 月の設定 day = getNum( day,39,0,14); // 日の設定 */ year = getNum( year,99,0,2); // 年の設定 month = getNum(month,19,0,5); // 月の設定 day = getNum( day,39,0,8); // 日の設定 // week = getNum( week,6,0,12); // 曜日の設定:追加 N.I week = getNum( week,6,0,11); // 曜日の設定:追加 N.I // --------- 時間設定画面 ----------------- /* LCD_posyx(0,5); LCD_dat(' '); LCD_posyx(1,0); LCD_ROMstr("Time >"); */ // --------- PushSWでの初期値設定 --------- /* hour = getNum(hour,29,1,8); // 時の設定 min = getNum( min,59,1,11); // 分の設定 */ hour = getNum(hour,29,1,0); // 時の設定 min = getNum( min,59,1,3); // 分の設定 //// ここまでの設定(SW1で最後の項目の分まで送って、SW2で合わせ(或いはそのままで))、SW1で送ると //// 日時表示に移行し、RTCCレジスタの設定を行い、00秒から時計が動き始める。 //// コメント追記:N.I /// --------- 日時表示画面 (設定終了直後)----------------- /* LCD_posyx(0,0); LCD_ROMstr("Date "); fprintf(_H_USER, "20%02X/%02X/%02X", year, month, day); LCD_posyx(1,5); LCD_ROMstr(" "); fprintf(_H_USER, "%02X:%02X:%02X", hour, min, sec); */ LCD_posyx(0,0); fprintf(_H_USER, "20%02X/%02X/%02X", year, month, day); // 年/月/日の後に、曜日を表示する。→ 例:(Mon) if (week == 0) LCD_ROMstr("(Sun)"); if (week == 1) LCD_ROMstr("(Mon)"); if (week == 2) LCD_ROMstr("(Tue)"); if (week == 3) LCD_ROMstr("(Wed)"); if (week == 4) LCD_ROMstr("(Thu)"); if (week == 5) LCD_ROMstr("(Fri)"); if (week == 6) LCD_ROMstr("(Sat)"); // 時刻表示 LCD_posyx(1,0); fprintf(_H_USER, "%02X:%02X:%02X", hour, min, sec); // --------- RTCC 日時の設定 (起動時のみ) --------- EECON2 = 0x55; // RTCC レジスタを EECON2 = 0xAA; // unlock しRTCCの RTCCFGbits.RTCWREN = 1; // 設定準備をする RTCCFGbits.RTCPTR1 = 1; // RTCVALHにアクセスする毎に RTCCFGbits.RTCPTR0 = 1; // RTCPTRは自動的に -1 する RTCVALL = year; // 年 RTCPTR<1:0>= 11(この部分追記:N.I) RTCVALH = 0xFF; // 未設定 RTCVALL = day; // 日 RTCPTR<1:0>= 10 RTCVALH = month; // 月 RTCVALL = hour; // 時 RTCPTR<1:0>= 01 // RTCVALH = 0x01; // 曜日(0:日、1:月、…) RTCVALH = week; RTCVALL = sec; // 秒 RTCPTR<1:0>= 00 RTCVALH = min; // 分 RTCCFGbits.RTCEN = 1; // RTCC を有効に RTCCAL = RTCCALIBRATION; // キャリブレーション値セット while(1){ RTCCFGbits.RTCPTR1 = 1; // RTCPTR のセット RTCCFGbits.RTCPTR0 = 1; // RTCPTR<1:0>= 11(0x03):年レジスタの位置にする 追記:N.I while(RTCCFGbits.RTCSYNC != 1); // RTCの位上げ中に、読み込ぬよう while(RTCCFGbits.RTCSYNC == 1); // SYCが「0」になるまで待つ LED2=!LED2; year = RTCVALL; day = RTCVALH; // RTCPTR を -1 するためのダミー読み込み // これで、RTCPTR<1:0>= 10(0x02):月/日レジスタの位置にするなる 追記:N.I day = RTCVALL; month = RTCVALH; // これを実行後、自動的に、RTCPTR は -1されRTCPTR<1:0>= 01(0x01):週/時レジスタの位置になる、 // hour = RTCVALH; // RTCPTR を -1 するためのダミー読み込み :オリジナルには何故かこれが無い。誤記? 追加 N.I // これは勘違いだった。 160921 hour = RTCVALL; week = RTCVALH; // 追加:N.I // これを実行後、自動的に、RTCPTR は -1されRTCPTR<1:0>= 00(0x00):分/秒レジスタの位置になる、 // sec = RTCVALH; // RTCPTR を -1 するためのダミー読み込み→ これは必要なくなる。 追記:N.I 160921 sec = RTCVALL; min = RTCVALH; // --------- RTCC 日時の表示 -----------------(ここは後でサブルーチン化して、設定終了後と共用する)) /* LCD_posyx(0,6); fprintf(_H_USER, "20%02X/%02X/%02X", year, month, day); LCD_posyx(1,8); fprintf(_H_USER, "%02X:%02X:%02X", hour, min, sec); */ LCD_posyx(0,0); fprintf(_H_USER, "20%02X/%02X/%02X", year, month, day); // 年/月/日の後に、曜日を表示する。→ 例:(Mon) if (week == 0) LCD_ROMstr("(Sun)"); if (week == 1) LCD_ROMstr("(Mon)"); if (week == 2) LCD_ROMstr("(Tue)"); if (week == 3) LCD_ROMstr("(Wed)"); if (week == 4) LCD_ROMstr("(Thu)"); if (week == 5) LCD_ROMstr("(Fri)"); if (week == 6) LCD_ROMstr("(Sat)"); // 時刻表示 LCD_posyx(1,0); fprintf(_H_USER, "%02X:%02X:%02X", hour, min, sec); } } //****** 2桁の初期値を入力する関数 ************************************************************ // num 入力される初期数 top 値の最大値 // y 十の位のLCD縦位置 x 十の位のLCD横位置 // (オリジナルは一の位のLCD横位置となっていたが誤記と判断) //**************************************************************************************** unsigned char getNum(unsigned 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位設定 if(x != 11) ones=getDigit(ones,9,y,x+1); // 1位設定: 週設定値以外の最大値は、9 else ones=getDigit(ones,6,y,x+1); // 週設定値の最大は、6 LCD_cmd(0x0C); // 表示点滅を解除 return ((tens << 4) + ones) ; // 値計算 } //****** 1桁の初期値を入力する関数 ***************************************************** // num 入力される初期数 top 値の最大値 // y 十の位のLCD縦位置 x 十の位のLCD横位置 // (オリジナルは一の位の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回確認 // →1mS周期でのセンスはチャッタと見なしているのだと思われる。追記:N.Ishii Delay1KTCYx(12); // 1mSec遅延 }while(OnSW); while(SW1 & SW2); // SWのPushを待つ // → 押されてない状態を確認してから初めてSW ON待ちを行っている。追記:N.Ishii if(!SW1)return num; // SW1で終了 if(!SW2){ // SW2で数値を+1 num++; num %= top; LCD_dat(num+0x30); // 数値表示 LCD_posyx(y,x); // カーソルを戻す } } }