//-----------------------------------------------------------------------------------------------------------
// PIC16F1823で7seg4桁LEDの表示
// 7SEG4D-20130817版の基板用
// 2013/08/11-2013/08/26-2013/10/25
//-----------------------------------------------------------------------------------------------------------
// <内容>
//   59分59秒までカウントアップする
// <操作方法>
//   SW1:カウントのスタート・ストップ
//   SW2:カウントのリセット
//   SW3:秒のカウントアップ(インクリメント)
//   SW4:分のカウントアップ(インクリメント)
//-----------------------------------------------------------------------------------------------------------

#include <htc.h>
#include <stdio.h>

__CONFIG (FOSC_INTOSC & WDTE_OFF & PWRTE_ON & MCLRE_OFF & CP_OFF &  CPD_OFF & BOREN_OFF & FCMEN_ON);
__CONFIG (LVP_OFF & WRT_OFF & PLLEN_OFF & STVREN_ON & BORV_HI);

unsigned const char s[15]={200,188,177,165,153,140,127,114,100,86,72,57,41,25,9};	// スイッチの閾値
unsigned const char seg[16]={	0b0111111,	// 7segLEDのビットデータ　"0"
							0b0000110,	//	"1"
							0b1011011,	//	"2"
							0b1001111,	//	"3"
							0b1100110,	//	"4"
							0b1101101,	//	"5"
							0b1111101,	//	"6"
							0b0100111,	//	"7"
							0b1111111,	//	"8"
							0b1101111,	//	"9"
							0b1110111,	//	"A"
							0b1111100,	//	"B"
							0b0111001,	//	"C"
							0b1011110,	//	"D"
							0b1111001,	//	"E"
							0b1110001};	//	"F"

unsigned char dat[4];		// 7segLEDの表示データ
unsigned char cnt;		// 7segLEDのダイナミック点灯の表示桁
unsigned char sw;			// スイッチの押されたデータ(下位4ビット)
unsigned int count;		// Timet1の割り込みでインクリメント

void interrupt xxx(void){
	unsigned char d;
	TMR1=65536-5000;	// 5msで割り込み(1us x 5000回)

	cnt = (++cnt & 0b00000011);

	d=dat[cnt];
	LATA&=0b111000; LATA|=(d & 0b000111);
	d/=8;
	LATC&=0b100000; LATC|=(d & 0b011111);

	if(cnt==0) { LATA&=0b011111; LATC&=0b011111; }
	if(cnt==2) { LATA&=0b011111; LATC|=0b100000; }
	if(cnt==1) { LATA|=0b100000; LATC&=0b011111; }
	if(cnt==3) { LATA|=0b100000; LATC|=0b100000; }

	count++;

	TMR1IF=0;
}

void wait1ms(int t){		// 1*nミリ秒の時間待ち
	PR2=125;
	T2CON=0b00000111;		// 8us
	TMR2=0;
	while(t){
		TMR2IF=0;
		while(!TMR2IF);
		t--;
	}
}

unsigned char eeread(unsigned char adr){					// EEPROMの読み込み
	EEADRL=adr;
	RD=1;
	while(RD);
	return EEDATL;
}

void eewrite(unsigned char adr,unsigned char dat){		// EEPROMの書き込み
	WREN=1;
	EEADRL=adr;
	EEDATL=dat;
	EECON2=0x55;
	EECON2=0xaa;
	WR=1;
	WREN=0;
	while(WR);
}

unsigned char readsw_(){
	unsigned char d,i;
	
	GO=1;
	while(GO) ;
	d=ADRESL;
	for(i=0; i<=14; i++){
		if(d>=s[i]) break;
	}
	return(i);
}

unsigned char readsw(){
	unsigned char t,d,dd;
	t=0; d=0xff;
	while(1){
	 	dd=readsw_();
		if(d==dd){
			if(++t>=5) break;
		}else{
			t=0; d=dd;
		}
		wait1ms(1);
	}
	return(dd);
}

void main(){
	unsigned int d;			// 7segの表示数値
	unsigned char sw1,sw2;		// sw1:今回のスイッチデータ、sw2:前回のスイッチデータ
	unsigned char flag;		// 0:カウント停止中、1:カウント動作中

	OSCCONbits.SPLLEN = 1;
	OSCCONbits.SCS = 0;		
	OSCCONbits.IRCF = 0b1110;	// 000x = 31 kHz LF
							// 0010 = 31.25 kHz MF
							// 0011 = 31.25 kHz HF(1)
							// 0100 = 62.5 kHz MF
							// 0101 = 125 kHz MF
							// 0110 = 250 kHz MF
							// 0111 = 500 kHz MF ( リセット時の既定値)
							// 1000 = 125 kHz HF(1)
							// 1001 = 250 kHz HF(1)
							// 1010 = 500 kHz HF(1)
							// 1011 = 1MHz HF
							// 1100 = 2MHz HF
							// 1101 = 4MHz HF
							// 1110 = 8MHz または32 MHz HF( セクション5.2.2.1「HFINTOSC」参照)
							// 1111 = 16 MHz HF

	OSCTUNEbits.TUN=0b00000;	// 内部クロックの微調整

	nWPUEN = 0;				// 弱プルアップON
	WPUA=0b11101111;
	WPUC=0b11111111;

	TRISA=0b00011000;			// PORTA入出力設定(0:出力 1:入力)
	ANSELA=0b00010000;		// PORTAデジアナ設定(0:デジタル 1:アナログ) RA4(AN3)をアナログ入力
	ADCON1bits.ADPREF=0;
	ADCON1bits.ADCS=0b010;
	ADCON0bits.CHS=3;
	ADFM=1;
	ADON=1;
	GO=1;

	TRISC=0b00000000;			// PORTC入出力設定(0:出力 1:入力)
	ANSELC=0;				// PORTCをデジタルI/O設定

	//=============================== Timer1設定					
	T1CONbits.TMR1CS = 0;			// 内部クロック選択 FOSC/4
	T1CONbits.T1CKPS = 3;			// プリスケーラ 1:8
	T1CONbits.nT1SYNC=1;			// 同期しない
	TMR1ON=1;
	TMR1IE=1;

	PEIE=1;
	GIE=1;

	while(1){							// メインループ
		sw2=sw1;							// 前回のスイッチデータ
		sw1=readsw();						// 今回のスイッチデータ
 		if((sw1==1)&&(sw2==0)){			// SW1が押された場合
			if(flag==0){					//   カウント停止中の場合
				flag=1;					//     フラグをセット
				GIE=0; count=0; GIE=1;		//     カウンタをリセット
			}else{						//   カウント動作中の場合
				flag=0;					//     フラグをクリア
	  		}
		}

		if((flag==1)&&(count>=200)) { d++; GIE=0; count-=200; GIE=1; }	// 1秒経てばインクリメント
 		if((sw1==2)&&(sw2==0)&&(flag==0)) { d=0; }					// SW2が押されればカウントリセット
 		if((sw1==0)&&(sw2==4)&&(flag==0)) { d+=1; }					// SW3が押されれば秒インクリメント
 		if((sw1==0)&&(sw2==8)&&(flag==0)) { d+=100; }				// SW4が押されれば分インクリメント
		if(flag==0) { GIE=0; count=0; GIE=1; }
		if((d%100)>=60) d+=40;							// 60秒で分に繰り上げ
		if(d>=6000) d=0;								// 60分でクリア
	
		dat[3] = ~seg[d % 10];	
		dat[2] = ~seg[(d/10) % 10];
		dat[1] = ~seg[(d/100) % 10] & ((count<100)?0b01111111:0b11111111);	// 分のドットを点滅
		dat[0] = ~seg[(d/1000) % 10];	
	}  
}