//デジタル時計プログラム
//製作者　KK
/*
使用PICマイコン	PIC16F88
使用コンパイラ	CCS-C Compiler
*/

#include<16f88.h>
#use fast_io(a)
#fuses HS,PUT,NOWDT,NOPROTECT,NOLVP,NOCPD,MCLR,NOBROWNOUT
#use delay(clock=19660800)	//19.6608MHz

#define	Amode	0x00	//RA入出力
#define	Bmode	0x0f	//RB入出力
#byte	db = 6			//データバスRB

#define	rs		PIN_A0
#define	rw		PIN_A1
#define	stb		PIN_A2
#include"lcd_lib.c"

//ポート定義
#byte	RA=5
#byte 	RB=6
#bit	BL_SW=RB.2		//青色タクトスイッチ
#bit	RE_SW=RB.0		//赤色タクトスイッチ
#bit	WH_SW=RB.3		//白色タクトスイッチ

/*=====関数宣言=====*/
void main(void);
void lcd_disp(void);
void time_math(void);
void setting(void);
void sw_ch(void);

/*=====変数宣言=====*/
unsigned char cnt_10ms=0;	//10ms計測用カウンタ
unsigned char cnt_1s=0;		//1s計測用カウンタ
//スイッチ関連変数
unsigned char	bsw=0,rsw=0,wsw=0,long_sw=0;
unsigned char	cnt1=0,cnt2=0,cnt3=0,cnt4=0,cnt5=0,cnt6=0;
unsigned char	hour_select=1;
//時刻設定
unsigned char	mode=0,sig=0;
short			down=0,up=0;
signed char		data=0;
//時間記憶
short			uruu=0;
signed char		year=0;
signed char		month=1;
signed char		day=1;
signed char		youbi=0;
signed char		hour=0,hour2=0;
signed char		min=0;
signed char		sec=0;

/*=====メインプログラム=====*/
void main(void){
	//ポートすべて出力
	set_tris_a(Amode);
	set_tris_b(Bmode);
	lcd_init();
	//割り込み設定
	setup_timer_0(RTCC_INTERNAL | RTCC_DIV_256);
	set_timer0(64);
	enable_interrupts(INT_TIMER0);
	enable_interrupts(GLOBAL);
	//初期化
	RA=0x00;
	lcd_clear();
	lcd_disp();
		
	while(1){	
		if(long_sw){
			setting();
		}
			
		if(cnt_1s || (long_sw && cnt6)){
			cnt_1s=0;
			cnt6=0;
			time_math();
			lcd_disp();
		}
	}
}		

//LCD表示用関数
void lcd_disp(void){
/*=====LCD表示（1行目）年：月：日：曜日=====*/
	lcd_cmd(0x80);
	//年
	if(year<10){
		if(long_sw && mode==3){
			if(cnt5<=30){
				printf(lcd_data,"200%1u ",year);
			}
			else if(cnt5<=60){
				printf(lcd_data,"     ");
			}
			else{
				cnt5=0;
				printf(lcd_data,"     ");
			}			
		}	
		else{
			printf(lcd_data,"200%1u ",year);
		}
	}	
	else if(year<100){
		if(long_sw && mode==3){
			if(cnt5<=30){
				printf(lcd_data,"20%2u ",year);
			}
			else if(cnt5<=60){
				printf(lcd_data,"     ");
			}
			else{
				cnt5=0;
				printf(lcd_data,"     ");
			}			
		}	
		else{
			printf(lcd_data,"20%2u ",year);
		}
	}	
	else{
		if(long_sw && mode==3){
			if(cnt5<=30){
				printf(lcd_data,"2%3u ",year);
			}
			else if(cnt5<=60){
				printf(lcd_data,"     ");
			}
			else{
				cnt5=0;
				printf(lcd_data,"     ");
			}			
		}	
		else{
			printf(lcd_data,"2%3u ",year);
		}
	}
	
	//月
	if(long_sw && mode==4){
		if(cnt5<=30){
			printf(lcd_data,"%2u ",month);
		}
		else if(cnt5<=60){
			printf(lcd_data,"   ");
		}
		else{
			cnt5=0;
			printf(lcd_data,"   ");
		}			
	}	
	else{
		printf(lcd_data,"%2u ",month);
	}
	
	//日
	if(long_sw && mode==5){
		if(cnt5<=30){
			printf(lcd_data,"%2u  ",day);
		}
		else if(cnt5<=60){
			printf(lcd_data,"    ");
		}
		else{
			cnt5=0;
			printf(lcd_data,"    ");
		}			
	}	
	else{
		printf(lcd_data,"%2u  ",day);
	}
	
	//曜日
	if(long_sw && mode==6){
		if(cnt5<=30){
			switch(youbi){	//日曜〜土曜まで
				case 0:printf(lcd_data,"Sun");break;
				case 1:printf(lcd_data,"Mon");break;
				case 2:printf(lcd_data,"Tue");break;
				case 3:printf(lcd_data,"Wed");break;
				case 4:printf(lcd_data,"Thu");break;
				case 5:printf(lcd_data,"Fri");break;
				case 6:printf(lcd_data,"Sat");break;
			}
		}
		else if(cnt5<=60){
			printf(lcd_data,"   ");
		}
		else{
			cnt5=0;
			printf(lcd_data,"   ");
		}			
	}	
	else{
		switch(youbi){	//日曜〜土曜まで
			case 0:printf(lcd_data,"Sun");break;
			case 1:printf(lcd_data,"Mon");break;
			case 2:printf(lcd_data,"Tue");break;
			case 3:printf(lcd_data,"Wed");break;
			case 4:printf(lcd_data,"Thu");break;
			case 5:printf(lcd_data,"Fri");break;
			case 6:printf(lcd_data,"Sat");break;
		}
	}
		
/*=====LCD表示（2桁目）時：分：秒=====*/
	lcd_cmd(0xc0);
	if(hour_select){	//24時間表示
		printf(lcd_data,"  ");
		hour2=hour;
	}
	else{				//12時間表示
		if(hour>11){
			hour2=hour - 12;
			printf(lcd_data,"PM");
		}
		else{
			hour2=hour;
			printf(lcd_data,"AM");
		}
	}			
	if(hour2<10){
		if(long_sw && mode==2){
			if(cnt5<=30){
				printf(lcd_data," 0%1u : ",hour2);
			}
			else if(cnt5<=60){
				printf(lcd_data,"    : ");
			}
			else{
				cnt5=0;
				printf(lcd_data,"    : ");
			}			
		}	
		else{
			printf(lcd_data," 0%1u : ",hour2);
		}
	}
	else{
		if(long_sw && mode==2){
			if(cnt5<=30){
				printf(lcd_data," %2u : ",hour2);
			}
			else if(cnt5<=60){
				printf(lcd_data,"    : ");
			}
			else{
				cnt5=0;
				printf(lcd_data,"    : ");
			}			
		}	
		else{
			printf(lcd_data," %2u : ",hour2);
		}
	}
	
	if(min<10){
		if(long_sw && mode==1){
			if(cnt5<=30){
				printf(lcd_data,"0%1u  ",min);
			}
			else if(cnt5<=60){
				printf(lcd_data,"    ");
			}
			else{
				cnt5=0;
				printf(lcd_data,"    ");
			}			
		}	
		else{
			printf(lcd_data,"0%1u  ",min);
		}
	}
	else{
		if(long_sw && mode==1){
			if(cnt5<=30){
				printf(lcd_data,"%2u  ",min);
			}
			else if(cnt5<=60){
				printf(lcd_data,"    ");
			}
			else{
				cnt5=0;
				printf(lcd_data,"    ");
			}			
		}	
		else{
			printf(lcd_data,"%2u  ",min);
		}
	}
	
	if(sec<10){
		if(long_sw && mode==0){
			if(cnt5<=30){
				printf(lcd_data,"0%1u",sec);
			}
			else if(cnt5<=60){
				printf(lcd_data,"  ");
			}
			else{
				cnt5=0;
				printf(lcd_data,"  ");
			}			
		}	
		else{
			printf(lcd_data,"0%1u",sec);
		}	
	}
	else{
		if(long_sw && mode==0){
			if(cnt5<=30){
				printf(lcd_data,"%2u",sec);
			}
			else if(cnt5<=60){
				printf(lcd_data,"  ");
			}
			else{
				cnt5=0;
				printf(lcd_data,"  ");
			}			
		}	
		else{
			printf(lcd_data,"%2u",sec);
		}
	}
	printf(lcd_data,"     ");	//カーソル枠外へ追いやる
}

//時間計算
void time_math(void){	
/*=====現在時刻計算=====*/	
	if(sec>59){	//５９秒を超えたら１分追加。時間設定時は分への加算しない
		sec=0;
		min++;
	}
	if(min>59){	//５９分５９秒を超えたら１時間追加
		min=0;
		hour++;
	}
	if(hour>23){//２３時５９分５９秒を超えたら０時０分０秒にする
		hour=0;
		day++;
		youbi++;
		if(youbi>6){
			youbi=0;
		}	
	}
	
	switch(month){
		case 2:	//２月
			//閏年算出
			if (((year%4 == 0) && (year%100 != 0)) || year%400 == 0){
				uruu=1;
			}
			else{
				uruu=0;
			}
			//閏年なら29日、平年なら28日で3月に移行
			if((!uruu && day>28) || (uruu && day>29)){
				day=1;
				month++;
			}		
			break;
		
		case 1:case 3:case 5:case 7:case 8:case 10:case 12:	//31日の月
			if(day>31){
				day=1;
				month++;
			}
			break;
		
		case 4:case 6:case 9:case 11:	//30日の月
			if(day>30){
				day=1;
				month++;
			}
			break;
	}				
	
	if(month>12){	//12月31日を過ぎたら1年追加
		month=1;
		year++;
		if(year>100){	//2100年以上いかないようにする
			year=0;
		}	
	}	
}

//時刻設定
void setting(void){
	if(sec>59){
		sec=0;
	}
		
	if(up){		//赤スイッチが押されたら+1
		up=0;
		data=1;
		cnt5=0;
	}
	if(down){	//青スイッチが押されたら-1
		down=0;
		data=-1;
		cnt5=0;
	}
			
	switch(mode){
		case 0:	//秒設定
			if(data!=0){	//赤か青スイッチが押されたら0秒に戻す
				sec=0;
				cnt_10ms=0;
			}
			break;
				
		case 1:	//分設定
			min+=data;
			if(min>59){
				min=0;
			}
			if(min<0){
				min=59;
			}
			break;
			
		case 2:	//時設定
			hour+=data;
			if(hour>23){
				hour=0;
			}
			if(hour<0){
				hour=23;
			}		
			break;	
		
		case 3:	//年設定
			year+=data;
			if(year>100){
				year=0;
			}
			if(year<0){
				year=100;
			}
			break;
		
		case 4:	//月設定
			month+=data;
			if(month>12){
				month=1;
			}
			if(month<1){
				month=12;
			}
			break;
		
		case 5:	//日設定
			day+=data;
			
			switch(month){
				case 2:	//２月
					//閏年算出
					if (((year%4 == 0) && (year%100 != 0)) || year%400 == 0){
						uruu=1;
					}
					else{
						uruu=0;
					}
					//閏年なら29日、平年なら28日で3月に移行
					if((!uruu && day>28) || (uruu && day>29)){
						day=1;
					}		
					if(day<1){
						if(uruu){
							day=29;
						}
						else{
							day=28;
						}
					}			
					break;
				
				case 1:case 3:case 5:case 7:case 8:case 10:case 12:	//31日の月
					if(day>31){
						day=1;	
					}
					if(day<1){
						day=31;
					}	
					break;
			
				case 4:case 6:case 9:case 11:	//30日の月
					if(day>30){
						day=1;
					}
					if(day<1){
						day=30;
					}	
					break;
			}		
			break;
							
		case 6:	//曜日設定
			youbi+=data;
			if(youbi>6){
				youbi=0;
			}
			if(youbi<0){
				youbi=6;
			}
			break;
		
		default:	//時計へ戻る
			long_sw=0;
			sig=0;
			mode=0;
			up=0;
			down=0;
			lcd_disp();
			break;
	}
	data=0;
}			
			
			
//スイッチ状態確認用関数
void sw_ch(void){
/*=====タクトスイッチ（赤）状態確認=====*/
	switch(rsw){
		case 0:		//押していない状態
			if(!RE_SW)rsw=1;
			cnt1=0;
			break;
		
		case 1:		//ﾁｬﾀﾘﾝｸﾞ対策
			if(cnt1<=1 && RE_SW)rsw=0;
			else if(cnt1>1 && !RE_SW)rsw=2;
			break;

		case 2:		//押している状態
			if(RE_SW)rsw=3;
			cnt1=0;
			break;
	
		case 3:		//ﾁｬﾀﾘﾝｸﾞ対策
			if(cnt1<=1 && !RE_SW)rsw=2;
			else if(cnt1>1 && RE_SW)rsw=4;
			break;
	
		case 4:		//押した後の動作
			rsw=0;
			if(long_sw){
				up=1;
			}	
			else{
				hour_select=1;	//24時間：12時間表示変更
				lcd_disp();
			}	
			break;		
	}	
	
/*=====タクトスイッチ（青）状態確認=====*/
	switch(bsw){
		case 0:		//押していない状態
			if(!BL_SW)bsw=1;
			cnt2=0;
			break;
		
		case 1:		//ﾁｬﾀﾘﾝｸﾞ対策
			if(cnt2<=1 && BL_SW)bsw=0;
			else if(cnt2>1 && !BL_SW)bsw=2;
			break;

		case 2:		//押している状態
			if(BL_SW)bsw=3;
			cnt2=0;
			break;
	
		case 3:		//ﾁｬﾀﾘﾝｸﾞ対策
			if(cnt2<=1 && !BL_SW)bsw=2;
			else if(cnt2>1 && BL_SW)bsw=4;
			break;
	
		case 4:		//押した後の動作
			bsw=0;
			if(long_sw){
				down=1;
			}	
			else{
				hour_select=0;	//24時間：12時間表示変更
				lcd_disp();
			}	
			break;		
	}

/*=====タクトスイッチ（白）状態確認=====*/
	switch(wsw){
		case 0:		//押していない状態
			if(!WH_SW)wsw=1;
			cnt3=0;
			break;
		
		case 1:		//ﾁｬﾀﾘﾝｸﾞ対策
			if(cnt3<=1 && WH_SW)wsw=0;
			else if(cnt3>1 && !WH_SW)wsw=2;
			cnt4=0;
			break;

		case 2:		//押している状態
			if(WH_SW)wsw=3;
			cnt3=0;
			if(cnt4>50){	//50msの長押しで時刻設定⇔時計の変更
				if(!sig){
					long_sw=1;
					mode=0;
					data=0;
					up=0;
					down=0;
				}
				else{
					long_sw=0;
				}		
				
			}	
			break;
	
		case 3:		//ﾁｬﾀﾘﾝｸﾞ対策
			if(cnt3<=1 && !WH_SW)wsw=2;
			else if(cnt3>1 && WH_SW)wsw=4;
			break;
	
		case 4:		//押した後の動作
			wsw=0;
			if(sig){
				if(long_sw){
					mode++;
				}
				else{
					sig=0;
				}		
			}	
			if(long_sw && !sig){
				sig=1;
			}	
			break;		
	}
}
		
/*=====割り込み処理=====*/
#INT_TIMER0
void timer(void){
	set_timer0(64);	//10ms割り込み
	cnt_10ms++;		//10msカウンタカウント
	
	/*1sカウンタ*/
	if(cnt_10ms == 100){
		cnt_10ms=0;
		cnt_1s++;
		sec++;
	}
	
	sw_ch();	//スイッチ状態確認関数
	
	//カウント
	cnt1++;
	cnt2++;
	cnt3++;
	cnt4++;
	cnt5++;
	cnt6++;
}