// PIC16F1827
// PLL VFO 50MHz TC9256P 
// LCD TS174 付 
// 2018 JUL 28
// 

#include <xc.h>
#include <pic16f1827.h>
//#include <pic.h>
#pragma config CLKOUTEN = OFF, WDTE = OFF, PWRTE = OFF, CP = OFF, BOREN = ON
#pragma config FCMEN = ON, MCLRE = ON, CPD = OFF, IESO = ON, FOSC = HS, PLLEN = OFF 

__EEPROM_DATA(0xa2,0x62,0,0,0,0,0,0);//Freq初期設定25.250KHz(50.500KHz)

//__delay_us(), __delay_ms()へのクロック情報の設定
#define _XTAL_FREQ 7200000 //PICのクロックをHzで設定(7.2MHz)

#define BIAS   0x52           //0b1000 0101 0010  1/3duty 4com
#define SYSDIS 0X00           //0b1000 0000 0000
#define SYSEN  0X02           //0b1000 0000 0010
#define LCDOFF 0X04           //0b1000 0000 0100
#define LCDON  0X06           //0b1000 0000 0110
#define XTAL   0x28           //0b1000 0010 1000
#define RC256  0X30           //0b1000 0011 0000
#define TONEON  0X12           //0b1000 0001 0010
#define TONEOFF 0X10           //0b1000 0001 0000
#define WDTDIS  0X0A        //0b1000 0000 1010

#define LCD_CS LATAbits.LATA2	//CS: RA2
#define LCD_WR LATAbits.LATA1	//WR: RA1
#define LCD_DA LATAbits.LATA0	//DATA: RA0
#define GLED    LATBbits.LATB1  //GRN LED
#define PLL_PERIOD LATBbits.LATB5
#define PLL_CLOCK  LATBbits.LATB4
#define PLL_DATA  LATBbits.LATB3
#define RLED    LATBbits.LATB2  //RED LED

unsigned char LCD_Tab[]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00};

unsigned char Segment[]={0xfa,0x0a,0xbc,0x9e,0x4e,0xd6,0xf6,0xca,0xfe,0xde,
                        0xfb,0x0b,0xbd,0x9f,0x4f,0xd7};
unsigned char Num[8];
unsigned long int Freq;//LCD表示周波数
unsigned long int lastFreq;//ラストLCD表示周波数
unsigned int PLL_Freq;//実際の発振周波数
unsigned int lastPLL_Freq;//ラストのPLL_Freq
unsigned char PLL_read;// D3hのbit0からbit7までの読み込みデータ
unsigned char PLL_set;//D0hに書きこむ設定データ　1KHz,HF、7.2MHz
unsigned char UNLOCK;
unsigned char ENB;//ENABLE
unsigned char PE123;//PE3,PE2,PE1の順に並べ変えた位相誤差データ


/******************************************************
 * LCDへデータ書き込み
*******************************************************/

void LCD_Wr_Data(unsigned char Data,unsigned char cnt) {
  unsigned char i,d,B;
  d = Data;             //Dataを一度ローカル変数に置き換える
  for (i=0;i<cnt;i++) {  
    LCD_WR=0;
    B=d & 0x80;         //Dataと0x80とアンドを取った値を一度ローカル変数に置く
    B=B>>7;
    LCD_DA =B;          //LCD_DA=Data & 0x80 ではうまくいかない
    LCD_WR=1;
    d = d<<1; 
  }
}

/********************************************************
void LCD_WrCmd(uchar Cmd)
 * コマンド書き込み
********************************************************/

void LCD_WrCmd(unsigned char Cmd) {
  LCD_CS=0;
  LCD_Wr_Data(0x80,4);        //
  LCD_Wr_Data(Cmd,8);                //
  LCD_CS=1;
}

/********************************************************
void LCD_WrOneData(uchar Addr,uchar Data)
********************************************************/

void LCD_WrOneData(unsigned char Addr,unsigned char Data) {
  LCD_CS=0;
  LCD_Wr_Data(0xa0,3);                //
  LCD_Wr_Data(Addr<<2,6);        //
  LCD_Wr_Data(Data<<4,4);        //
  LCD_CS=1;  
}

/********************************************************
void LCD_WrAllData(uchar Addr,uchar *p,uchar cnt)
********************************************************/

void LCD_WrAllData(unsigned char Addr,unsigned char *p,unsigned char cnt) {
  unsigned char i;
  LCD_CS=0;
  LCD_Wr_Data(0xa0,3);        //
  LCD_Wr_Data(Addr<<2,6);        //
  for (i=0;i<cnt;i++) {
      LCD_Wr_Data(*p,8);        //
      p++;
      }
  LCD_CS=1;  
}

void Int2Num(unsigned long int digi) {
    unsigned long int x;
    unsigned char i,k;
    x=digi;
    k=0;
    Num[0]=0;
    Num[1]=x/1000000;x=x%1000000;
    Num[2]=x/100000;x=x%100000;
    Num[3]=x/10000;x=x%10000;
    Num[4]=x/1000;x=x%1000;
    Num[5]=x/100;x=x%100;
    Num[6]=x/10;x=x%10;
    Num[7]=x;
    
    for (i=1;i<8;i++){
        LCD_Tab[i]=Segment[Num[i]];
        if ((Num[i]==0) && (k==0)) {
            LCD_Tab[i]=0;
            } else {k=1;}
        }
    if (RA3 == 1) {//受信時LCD左側に*マークを表示
        LCD_Tab[5]=LCD_Tab[5] | 0x01;
        GLED = 1;
    } else {
        LCD_Tab[5]=LCD_Tab[5] & 0xFE;
        GLED = 0;
    }
    LCD_Tab[7] = LCD_Tab[7] | 0x01;
}

/********************************************************
void LCD__Init(void)
********************************************************/

void LCD__Init(void) {
  LCD_CS=1;
  LCD_WR=1;
  LCD_DA=1;
 __delay_ms(100);
  LCD_WrCmd(BIAS);
  LCD_WrCmd(RC256);            //
  LCD_WrCmd(SYSDIS);
  LCD_WrCmd(WDTDIS);
  LCD_WrCmd(SYSEN);
  LCD_WrCmd(LCDON);
}
void LCD_disp() {
    	Int2Num(Freq);
    LCD_WrAllData(0,LCD_Tab,16); 
}
void PLL_Wr_Data(unsigned char Data,unsigned char cnt) {
  unsigned char i,d,B;
  d = Data;             //Dataを一度ローカル変数に置き換える
  for (i=0;i<cnt;i++) {  
    PLL_CLOCK=0;
    B=d & 0x01;         //Dataと0x80とアンドを取った値を一度ローカル変数に置く
    PLL_DATA =B;          //LCD_DA=Data & 0x80 ではうまくいかない
     __delay_us(2);
    PLL_CLOCK=1;
    d = d>>1; 
  }
}
void PLL_Read_Data() {
    unsigned char i,d,B;
    PLL_read = 0;
    TRISBbits.TRISB3 = 1;
    for (i=0;i<8;i++) {
        PLL_read = PLL_read << 1;
        PLL_CLOCK = 0;
        d=0;
        __delay_us(2);
        PLL_CLOCK = 1;
        d = RB3;
        B = d | PLL_read;
        PLL_read = B;
       }
    for (i=0;i<16;i++) {
        PLL_CLOCK = 0;
        __delay_us(2);
        PLL_CLOCK = 1;
    }
}
void Set_Freq(unsigned int PF){//プログラムカウンタデータとICの基本セット書き込み
    unsigned char pgc;
    PLL_PERIOD=0;
    PLL_Wr_Data(0xD0,8);
    PLL_PERIOD=1;
    pgc=PF;
    PLL_Wr_Data(pgc,8);//プログラムカウンター下位8bit書き込み
    pgc=PF>>8;
    PLL_Wr_Data(pgc,8);//プログラムカウンター上位8bit書き込み
    PLL_Wr_Data(PLL_set,8);//基本セット書き込み
    PLL_PERIOD=0;
    __delay_us(2);
    PLL_PERIOD=1;
   
}
void Reset_UNLOCK () {//ENBとUNLOCK　FFをリセット　PLL LOCKが解除される
    PLL_PERIOD=0;
    PLL_Wr_Data(0xD2,8);
    PLL_PERIOD=1;
    PLL_Wr_Data(0x80,8);
    PLL_Wr_Data(0,8);
    PLL_Wr_Data(0,8);
    PLL_PERIOD=0;
    __delay_us(2);
    PLL_PERIOD=1;
    
}
void Read_PLL() {// PLLの情報を読み取る
    unsigned char pgc;
    PLL_PERIOD=0;
    PLL_Wr_Data(0xD3,8);
    PLL_PERIOD=1;
//    pgc=Freq;
    PLL_Read_Data();//レジスタアドレスD3hを先頭から8bit読み込みPLL_readに格納
    PLL_PERIOD=0;
    __delay_us(2);
    PLL_PERIOD=1;
    TRISBbits.TRISB3 = 0;
    ENB = (PLL_read & 0x80) >> 7;
    UNLOCK = (PLL_read & 0x40) >> 6;
    PE123 = (PLL_read & 0x38) >> 3;
 
   if (UNLOCK == 0) {RLED=1;} else {RLED=0;}
}
void Freq_Chenge() {
    unsigned int realFRQ;//実際のPLL発振周波数
    if (RA3 == 1) {//受信時周波数を200KHzずらす
        realFRQ = PLL_Freq;
    } else {
        realFRQ = PLL_Freq + 100;
    }
    Set_Freq(realFRQ);

PLL01:
    __delay_us(100);
    Reset_UNLOCK ();//UNLOCK FFリセット　PLLロック解除
PLL02:
    __delay_us(1200);//基準周波数1KHz（1msec）以上待つ
    Read_PLL();//     ENB,UNLOCK,PE1-PE3取得
	if (ENB == 0) { goto PLL02;}
PLL03:
    Read_PLL();//ENB,UNLOCK,PE1-PE3取得
	if (UNLOCK == 1) { goto PLL01;}//UNLOCKならPLL01へ
	if (PE123 > 0) { goto PLL03;} //PE1-PE3判定 +/-0.55uS以下ならOK
    LCD_Tab[0]=Segment[PE123];
   lastPLL_Freq = PLL_Freq; 

}
unsigned int takelastFreq() {
	unsigned char f;
	PLL_Freq = eeprom_read(1); 
	PLL_Freq = PLL_Freq << 8;
	f = eeprom_read(0);
	PLL_Freq = PLL_Freq | f;
	return PLL_Freq;	
}
unsigned long int PLL2Freq(unsigned int PF) {
    unsigned long int LF;
    LF = PF;
//    LF =10*LF/2;
    LF =20*LF;
    return LF;
}
void interrupt R_encorder(void) {//ロータリーエンコーダー
		if (INTF == 1) {
		INTE =0;
		INTF = 0;

		if (RA4 == 1) {
			if (PLL_Freq < 27000) {PLL_Freq=PLL_Freq+1;}
		}
		if (RA4 ==0) {
			if (PLL_Freq > 25000) {PLL_Freq=PLL_Freq-1;}
		}
	__delay_ms(1);
	
   
	INTE = 1;
	}
	
}

void main()

{
	PORTA = 0x00;
	PORTB = 0b00111000;
	ANSELA = 0x00;	//AD OFF
	ANSELB = 0x00;	//AD OFF
    TRISA = 0b10011000;	//RA0-2:OUT RA3-4:IN RA5:MCLR RA6:OSC2 RA7:OSC1
	TRISB = 0b01000001;	//RB0:IN RB1-5:OUT RB6:IN RB7:OUT

	INTEDG = 0; //RB0 立ち下がりで割り込み 
	GIE=1; //全割り込み許可
	INTE=1;	//INT(RB0)割り込み許可

    
  unsigned char fl,fh;
  unsigned int bkuptime = 0;
  unsigned char bkupflg = 1;//0:バックアップする。1:バックアップしない
  unsigned char lastMode;//送信か受信状態フラグ　H:送信
  Freq=0;
  PLL_Freq=25000;//ダミー
  lastPLL_Freq=25000;//ダミー
  PLL_set=0b10100001;//7.2MHz　基準周波数1KHz　HFパルススワロー方式（AMin）
	
  LCD__Init();     //LCDイニシャライズ

  __delay_ms(100);
  if (RA3 == 1) {lastMode = 1;} else {lastMode = 0;}

  Set_Freq(PLL_Freq);//PLL IC レジスター不定の為、252500KHzとPLL_setを書き込む

  PLL_Freq=takelastFreq();//ラスト周波数の読み込み
  Freq = PLL2Freq(PLL_Freq);
  Int2Num(Freq);
  LCD_WrAllData(0,LCD_Tab,16);//ラスト周波数のLCD表示
  Freq_Chenge();
  
  while(1) {
        Freq = PLL2Freq(PLL_Freq);
    	LCD_disp();//周波数表示
        if (lastMode != RA3) {Freq_Chenge();lastMode = RA3;}
    	if (lastPLL_Freq != PLL_Freq) {
            Freq_Chenge();//周波数が変更されたらPLL書き換え
            bkuptime = 0;bkupflg = 0;//周波数が変更されたらタイマとフラグをリセット
        }

	bkuptime ++;

	if ((bkupflg == 0) && (bkuptime > 200)) {//周波数が変更されて2秒以上経過したらEEPROMに周波数をセーブ
	
        fl= PLL_Freq;
		 eeprom_write(0, fl);  
		fh = PLL_Freq >> 8;
		eeprom_write(1, fh); 
		bkupflg = 1;
  
		}
    __delay_ms(1);
 
    }
}