/***********************************************************************/
/*                                                                     */
/*  FILE        :RTC_watch.c                                           */
/*  DATE        :2007/10/23    by T.AZAMI                              */
/*  DESCRIPTION :RTC-8564NB を使った時計                               */
/*               時間設定できるバージョン                              */
/*               割り込みを使ったものに改造 071024                     */
/*  CPU TYPE    :AKS8 (R8C/Tiny R5F2114)                               */
/*                                                                     */
/*  This file is generated by Renesas Project Generator (Ver.4.0).     */
/*                                                                     */
/***********************************************************************/
                  

#include <sfr_r811.h>
#define  CLOCK 20000
#include "LCD.h"
#include "RTC8564.h"

//  定数の定義
#define SW1		p0_7	// Function - SET
#define SW2		p0_6	// Function - UP
#define SW3		p0_5	// Function - DOWN
#define LED1	p0_4	// 時刻設定時に点灯
#define LED2	p0_3	// 秒表示
#define ON		0
#define OFF		1
#define LOW		0
#define HIGH	1
#define IN	    0
#define OUT     1

char Sw_state = 0;									//  スイッチ状態用変数

char MsgSpace[]    = "                \0";			//　表示メッセージバッファ
char Msg_opning1[] = "RTC8564 RTC TEST\0";
char Msg_opning2[] = "for R8C/OAKS8   \0";
char Msg_date[]    = "2000/00/00 Sun  \0";
char Msg_time[]    = "TIME 00:00:00   \0";
char Msg_set1[]    = "SET TIME MODE   \0";
char Msg_set2[]    = "00000= 00       \0";

char Sec, Min, Hour, Weekday, Year, Month, Day; 	// 時刻表示用変数

//--------------------------------------------------------------
//　　　クロックの切替 (20MHz)
//--------------------------------------------------------------
void main_ck(void) {
	asm("FCLR I");
	prcr = 1;
	cm13 = 1;
	cm15 = 1;
	cm05 = 0;
	cm16 = 0;
	cm17 = 0;
	cm06 = 0;
	asm("nop"); asm("nop"); asm("nop"); asm("nop");
	ocd2 = 0;
	prcr = 0;
}

//--------------------------------------------------------------
//  スイッチ入力処理（ディレイによるチャタリング除去）
//--------------------------------------------------------------
void Get_sw_data(void)
{
	if (SW1 == ON){
		Delay_ms(30);
		if (SW1 == ON){
			Sw_state = 1;
			Delay_ms(30);
		}
	} else if (SW2 == ON){
		Delay_ms(30);
		if (SW2 == ON){
			Sw_state = 2;
			Delay_ms(30);
		}
	} else if (SW3 == ON){
		Delay_ms(30);
		if (SW3 == ON){
			Sw_state = 3;
			Delay_ms(30);
		}
	} else {
			Sw_state = 0;
	}
}

//--------------------------------------------------------------
//   数値から文字列に変換(long型）
//--------------------------------------------------------------
void Itostring(int digit, unsigned long data, char *buffer)
{
	int i;
	buffer += digit;							//文字列の最後
	for(i=digit; i>0; i--)						//最下位桁から上位へ
	{	
		buffer--;								//ポインター１
		*buffer = (data % 10) + '0';			//その桁数値を文字にして格納
		data = data / 10;						//桁-1
	}
}

//--------------------------------------------------------------
//   数値から文字列に変換  ゼロサプレス処理済み
//--------------------------------------------------------------
void Itostring_zs(int digit, unsigned long data, char *buffer){
	char i;
	char f = 0;	
	Itostring( digit, data, buffer );

	for(i=1; i<digit; i++){					//最初からの桁がゼロの場合空白に置き換える
		if ((f == 0) && (*buffer == '0')){
			*buffer = ' ';
		}else{
			f = 1;							//ゼロ以外の数値に来たらフラグを立てて処理しない
		}
		buffer++;
	}
}

//--------------------------------------------------------------
//　曜日文字列を表示用バッファに書き込むサブルーチン
//--------------------------------------------------------------
void Wkd_string ( char *Wkd, char *buffer ){
	char i;
	buffer = buffer + 11;
	for(i=1; i<=3; i++){
		*buffer = *Wkd;
		buffer ++;
		Wkd ++;
	}
}

//--------------------------------------------------------------
//　キー入力による日時設定処理用サブルーチン(Set_timeより呼ばれる)
//--------------------------------------------------------------
void Set_value( char *Display_string, char *Number, char Min, char Max )
{
	int i;
	char *Msg_pointer;
	Msg_pointer = Msg_set2;
	for ( i=1; i<=5; i++ ){					// 表示用文字列バッファにDisplay_stringで
		*Msg_pointer = *Display_string;		// 与えられた文字列を書き込む
		Msg_pointer++;
		Display_string++;
	}
	Itostring( 2, *Number, Msg_set2+7 );	// 各々現在の数値をセットし表示
	LCD_lineprint( 1, 2, Msg_set2 );
	do{
		Get_sw_data();						// スイッチ入力
		if ( Sw_state == 2 ){				// SW2ならアップカウント
			if ( *Number == Max ){			// 各々最低数値と最大数値が異なる
					*Number = Min;
			} else {
				*Number = *Number + 1;
			}
			Itostring( 2, *Number, Msg_set2+7 );
			Sw_state = 0;
		}
		if ( Sw_state == 3 ){				// SW3ならダウンカウント
			if ( *Number == Min ){			// 各々最低数値と最大数値が異なる
					*Number = Max;
			} else {
				*Number = *Number - 1;
			}
			Itostring( 2, *Number, Msg_set2+7 );
			Sw_state = 0;
		}
		LCD_lineprint( 1, 2, Msg_set2 );	
		Delay_ms(100);
	} while	( Sw_state != 1 );				// SW1ならこのサブルーチンを出る
}

//--------------------------------------------------------------
//　日時設定処理
//--------------------------------------------------------------
void Set_time(void){
	unsigned char Temp = 0;
	LCD_lineprint( 1, 1, Msg_set1 );
	Set_value ( "Year ", &Year,  0, 99);	// 設定サブルーチン  引数：設定時表示文字列、設定値ポインタ、最低値、最高値
		Temp = ( Year / 10 ) << 4;			// BCDに分解
		Temp = Temp | (Year % 10);
		I2C_write( 0x08 , Temp );			// 設定値をRTCのレジスタに書き込む
	Set_value ( "Month", &Month, 1, 12);
		Temp = ( Month / 10 ) << 4;
		Temp = Temp | (Month % 10);
		I2C_write( 0x07 , Temp );
	Set_value ( "Day  ", &Day,   1, 31);
		Temp = ( Day / 10 ) << 4;
		Temp = Temp | (Day % 10);
		I2C_write( 0x05 , Temp );
	Set_value ( "Hour ", &Hour,  0, 23);
		Temp = ( Hour / 10 ) << 4;
		Temp = Temp | (Hour % 10);
		I2C_write( 0x04 , Temp );
	Set_value ( "Sec  ", &Sec,   0, 59);
		Temp = ( Sec / 10 ) << 4;
		Temp = Temp | (Sec % 10);
		I2C_write( 0x03 , Temp );
	Set_value ( "Min  ", &Min,   0, 59);
		Temp = ( Min / 10 ) << 4;
		Temp = Temp | (Min % 10);
		I2C_write( 0x02 , Temp );
}


//--------------------------------------------------------------
//   メインルーチン
//--------------------------------------------------------------
void main(void){

	main_ck();								// メインクロック切替
	asm( "FCLR I" );						// 割り込み禁止

	// 出力ポートの設定
	pd1_0 = 1;			// LCD
	pd1_1 = 1;			// LCD
	pd1_2 = 1;			// LCD
	pd1_3 = 1;			// LCD
	pd1_6 = 1;			// LCD
	pd1_7 = 1;			// LCD
	prc2  = 1;			// ※R8C/11の場合は、P0の設定時毎に必要
	pd0_3 = 1;			// LED
	prc2  = 1;			// ※R8C/11の場合は、P0の設定時毎に必要
	pd0_4 = 1;			// LED
	
	LED1 = OFF;
	LED2 = OFF;
	
	// I2Cイニシャライズ、ポート設定 
	SCL_DIRECTION = HIGH;
	SDA_DIRECTION = HIGH;
	SCL = 1;
	SDA = 1;

	// INT2 割り込み設定
	pd3_2 = 0;								// RTCのINT出力をP32に入力する
	r1edg = 1;								// INT2立ち下がりエッジ検出
	ilvl0_int2ic = 1;						// INT2割り込み優先レベル１
	ir_int2ic = 0;							// 割り込み要求フラグクリア

	// RTC8564の定周期タイマの設定
	I2C_write( 0x0F, 0b00000001 );			// ダウンカウンタ値設定 -> 1秒毎
	I2C_write( 0x01, 0b00010001 );			// 繰り返しモード、割り込み信号発生
	I2C_write( 0x0E, 0b10000010 );			// 定周期タイマ開始

	LCD_init();								// LCD初期化
	LCD_lineprint( 1, 1, Msg_opning1);		// オープニングメッセージ
	LCD_lineprint( 1, 2, Msg_opning2);
	Delay_ms(3000);
	LCD_clear();							// 表示全消去

	asm( "FSET I" );						// 割り込み許可

	while(1){
		Get_sw_data();						// SW1で時刻設定へ
		if ( Sw_state == 1 ){
			Sw_state = 0;
			I2C_write( 0x0E, 0b00000010 );	// 割り込み出力停止
			LED1 = ON;
			Delay_ms(100);
			Set_time();
			I2C_write( 0x0E, 0b10000010 );	// 定周期タイマ開始
			LED1 = OFF;
		}
		Delay_ms(100);
	}
}

//--------------------------------------------------------------
//   定周期タイマ割り込み処理ルーチン
// 　1秒毎のRTCからの割込み信号でRTCデータを読み込み表示する
//--------------------------------------------------------------
#pragma interrupt int2_int (vect=21)
void int2_int(void)
{
	LED2 = ON;							// LED点灯

	I2C_read( 0x02 );					// 秒のアドレスをセットしデータを読み込む
	Min = I2C_rxdata;
	Min = Min & 0b01111111;				// 不要ビットのマスク処理
	Min = Min / 16 * 10 + Min % 16;		// 秒のBCD形式から10進変換
	Itostring( 2, Min,  Msg_time+11);	// 秒数を表示文字列バッファに記入

	I2C_read( 0x03 );					// 分のアドレスをセットしデータを読み込む
	Sec = I2C_rxdata;
	Sec = Sec & 0b01111111;		
	Sec = Sec / 16 * 10 + Sec % 16;
	Itostring( 2, Sec,  Msg_time+8 );	// 分の数値を表示文字列バッファに記入
		
	I2C_read( 0x04 );					// 時のアドレスをセットしデータを読み込む
	Hour = I2C_rxdata;
	Hour = Hour & 0b00111111;
	Hour = Hour / 16 * 10 + Hour % 16;
	Itostring( 2, Hour, Msg_time+5 );	// 時の数値を表示文字列バッファに記入

	I2C_read( 0x05 );					// 日のアドレスをセットしデータを読み込む
	Day = I2C_rxdata;
	Day = Day & 0b00111111;
	Day = Day / 16 * 10 + Day % 16;
	Itostring( 2, Day,   Msg_date+8 );	// 日の数値を表示文字列バッファに記入
	
	I2C_read( 0x07 );					// 月のアドレスをセットしデータを読み込む
	Month = I2C_rxdata;
	Month = Month & 0b00011111;
	Month = Month / 16 * 10 + Month % 16;
	Itostring( 2, Month, Msg_date+5 );	// 月の数値を表示文字列バッファに記入
	
	I2C_read( 0x08 );					// 年のアドレスをセットしデータを読み込む
	Year = I2C_rxdata;
	Year = Year / 16 * 10 + Year % 16;
	Itostring( 2, Year, Msg_date+2 );	// 月の数値を表示文字列バッファに記入

	I2C_read( 0x06 );					// 曜日のアドレスをセットしデータを読み込む
	Weekday = I2C_rxdata;
	Weekday = Weekday & 0b00000111;
	switch ( Weekday ){
		case 0:							// 読み込んだ数値によって文字列を入れ替える
			Wkd_string ( "Sun", Msg_date );
			break;
		case 1:
			Wkd_string ( "Mon", Msg_date );
			break;
		case 2:
			Wkd_string ( "Tue", Msg_date );
			break;
		case 3:
			Wkd_string ( "Wed", Msg_date );
			break;
		case 4:
			Wkd_string ( "Thu", Msg_date );
			break;
		case 5:
			Wkd_string ( "Fri", Msg_date );
			break;
		case 6:
			Wkd_string ( "Sat", Msg_date );
			break;
		default:
			Wkd_string ( "   ", Msg_date );
	}

	LCD_lineprint( 1, 1, Msg_date );		// 日付けを表示
	LCD_lineprint( 1, 2, Msg_time );		// 時間を表示
	ir_int2ic = 0;							// 割り込み要求フラグクリア
	LED2 = OFF;								// LED消灯

}
