 /**********************************************
* 作成日　2018年1月2日
* PIC24FV32KA302 family 
*
* DDS controller  DDS IC : AD9833 基準周波数25MHz
* Fosc 8MHz x 4 PLL (32MHz)
* 
*

***********************************************/
#include <xc.h>
#include <math.h>
#include <string.h>
#include <stdlib.h>
#define FCY 16000000UL// libpic30.hの前にFosc/2を定義　__delay関数用
#include <libpic30.h> 


// コンフィギュレーション設定　Fosc=32MHz 8x4PLL

#pragma config FNOSC = FRCPLL, SOSCSRC = DIG, LPRCSEL = HP, IESO = OFF
#pragma config POSCMOD = HS, OSCIOFNC = ON, FCKSM = CSDCMD
#pragma config FWDTEN = OFF, WINDIS = OFF, POSCFREQ = HS, BORV = V20
#pragma config LVRCFG = OFF, PWRTEN = ON, MCLRE = ON, ICS = PGx2



#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 LATBbits.LATB0	//CS: RB0
#define LCD_WR LATAbits.LATA1	//WR: RA1
#define LCD_DA LATAbits.LATA0	//DATA: RA0


#define RLED  LATBbits.LATB5  //RED LED
#define V01  PORTBbits.RB8  //Fast B L:CCW H:CW
#define V10  PORTBbits.RB7  //Slow B L:CCW H:CW




#define SPIFlg LATBbits.LATB15//SPI送信中L

unsigned char LCD_Tab[16];

unsigned char Segment[]={0xfa,0x0a,0xbc,0x9e,0x4e,0xd6,0xf6,0xca,0xfe,0xde,
                        0xfb,0x0b,0xbd,0x9f,0x4f,0xd7};
unsigned char Num[8];
double kd = 107.3741824; //kd = 10 x 2^28/25MHz

unsigned long int lastFREQ;
unsigned long int Freset = 100000; //1MHz RESET周波数 真周波数/10
unsigned long int FREQ = 710000; //7195KHz 初期設定周波数　真周波数/10
unsigned long int Fq[10];
unsigned int CNT;//エンコーダースピード

void initMain (void) {
    CLKDIV = 0x0000;//これが無いと32MHzにならない
	OSCCON = 0b0001000100000000; //Fosc 8MHz x4 PLL FRCPLL
	PORTB  = 0b0000000000000000; //全てL設定
 	TRISB  = 0b0101000110000000;  //ポートB　0-6:,9-11,13,15出力　7,8,12,14入力
 	PORTA  = 0b0000000000000000; //全てL出力
 	TRISA   =0b0000000000000000; //ポートA　0-15出力
 	ANSA = 0b000000000000000;//RA ANなし
 	ANSB = 0b000000000000000;//RB ANなし
    INTCON1 = 0b0000000000000000;//割込みネスト（多重割り込み）
    INTCON2 = 0b0000000000000110;//INT1,INT2立下りで割り込み	
    IPC5bits.INT1IP = 3;IPC7bits.INT2IP = 3;//外部割込み優先順位3
    IFS1bits.INT1IF = 0;IFS1bits.INT2IF = 0;//割込みフラグクリアー
    IEC1bits.INT1IE = 1;IEC1bits.INT2IE = 1;//外部割込み許可
    
	SPI1CON1 = 0b0000011101110010;//マスターモード プライマリ1/4、セカンダリ1/4、クロックactive_L
 	SPI1CON2 = 0b0000000000000000;//
 	SPI1STATbits.SPIROV = 0;
 	SPI1STATbits.SPIEN = 1;//SPI1有効化
    
    T1CON = 0b0000000000010000;//Timer1：プリスケーラー1/8 クロック：fosc/2  
    PR1 = 2000;//T1 カウントmax 1msごとに割り込み発生
    TMR1 = 0;//T1レジスタクリア
    IPC0bits.T1IP = 2;//t1 割込み優先度　２
    IFS0bits.T1IF = 0;//t1 割込みフラグクリア
    IEC0bits.T1IE = 1;//t1 割込み許可
    T1CONbits.TON = 1;// ti タイマースタート
}



/******************************************************
 * 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;  
// RLED=1;
}

void Int2Num(unsigned long int digi) {//INTデータを8ケタの数値に分解（LCD表示用）
    unsigned long int x;
    unsigned char i,k,gate;
    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;}
        }
    gate = 2;
	switch(gate){
       case 2: {
            LCD_Tab[6]=LCD_Tab[6] | 0x01;//KHzの位置に小数点表示
            break;
            }
        case 4: {
            LCD_Tab[7]=LCD_Tab[7] | 0x01;//KHzの位置に小数点表示
            break;
            }
        case 24: {
            LCD_Tab[7]=LCD_Tab[7] | 0x01;//KHzの位置に小数点表示
            break;
            }
    }
    
 	if (FREQ == 0) {LCD_Tab[7] = 0xFA;}//周波数がゼロの場合、100Hzの位置にゼロを表示
}

/********************************************************
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); 
}

//データEEPROMへの読み書き
unsigned int eeRead(unsigned int address) {
    while(NVMCONbits.WR);      // wait for any last write to complete
    TBLPAG = 0x7f;            // eprom is a t 0x7ffe00
     return __builtin_tblrdl(0xFE00+address);
 }

 void eeWrite(unsigned int address, unsigned int data) {
      while(NVMCONbits.WR);      // wait for last write to complete
     NVMCON = 0x4058;        // Set up NVMCON to erase one word of data EEPROM
    TBLPAG = 0x7f;            // eprom is a t 0x7ffe00
    __builtin_tblwtl(0xFE00+address, 0xffff);
    asm volatile ("disi #5");
     __builtin_write_NVM();       // Issue Unlock Sequence & Start Write Cycle
    while(NVMCONbits.WR);      // wait for errase to complete
    NVMCON = 0x4004;        // Set up NVMCON to write one word of data EEPROM
    __builtin_tblwtl(0xFE00+address, data);   // Write EEPROM data to write latch
    asm volatile ("disi #5");
    __builtin_write_NVM();
 }

// DDS 書き込み
void DDSwrite(unsigned int data) {
	SPIFlg = 0; //DDS FSYNC 0(CEをL)    
	SPI1BUF = data;
	while(SPI1STATbits.SPITBF);
    __delay_us(20);
	SPIFlg = 1; // CEをH
}

void Freqwrite(unsigned long int FQ, unsigned char ML) {
	unsigned long int Freg;
	unsigned int MLset,MFreg,LFreg;
	double DFreg;
	if (ML == 0) {MLset = 0x4000;} else {MLset = 0x8000;}
    DFreg = FQ;
	Freg = (double) (DFreg * kd); //Freg = DFreg;
	MFreg = (Freg >> 14) + MLset;
	LFreg = (Freg & 0x00003FFF) + MLset;
	DDSwrite(LFreg);
    __delay_us(20);
	DDSwrite(MFreg);
}

void initDDS() {
	DDSwrite(0x2100);//DDS reset
	DDSwrite(0xC000);//PHASE0 0
	DDSwrite(0xE000);//PHASE1 0
	DDSwrite(0x2000);//16bit連続2回送信にて周波数確定
	Freqwrite(Freset,0);//reg0に1MHz書き込み
	Freqwrite(Freset,1);//reg1に1MHz書き込み
}	



void __attribute__((__interrupt__,__no_auto_psv__)) _INT1Interrupt(void){
 
 IFS1bits.INT1IF = 0;
 IEC1bits.INT1IE = 0;
       if (V01 == 1) {          
           if (FREQ < 720000) {
               if (CNT > 80) {FREQ = FREQ + 1;} else {
               		if (CNT > 40) {FREQ = FREQ + 10;} else {FREQ = FREQ + 100;}
               		}
                }
       		}	
 		if (V01 == 0) {
            if (FREQ > 700000) {
                if (CNT > 80) {FREQ = FREQ - 1;} else {
               		if (CNT > 40) {FREQ = FREQ - 10;} else {FREQ = FREQ - 100;}
               		}
                }
       		}
	__delay_us(100);  
    CNT = 0;
 IEC1bits.INT1IE = 1;
}
void __attribute__((__interrupt__,__no_auto_psv__)) _INT2Interrupt(void){
 IFS1bits.INT2IF = 0;
 IEC1bits.INT2IE = 0;
        if (V10 == 1) {
			if (FREQ < 720000) {FREQ = FREQ +100;}	
		}
		if (V10 == 0) {
			if (FREQ > 700000) {FREQ = FREQ -100;}
		}
	__delay_us(200); 
 IEC1bits.INT2IE = 1;
}
void __attribute__((__interrupt__,__no_auto_psv__)) _T1Interrupt(void){
    
 IFS0bits.T1IF = 0;
 IEC0bits.T1IE = 0;
 RLED = ~RLED;
 if (CNT < 1000) {CNT++;}
 TMR1 = 0;
 IEC0bits.T1IE = 1;
}


int main()  {

initMain();
initDDS();//DDSイニシャライズ

//	__delay_ms(1000);
RLED =0;
LCD__Init();     //LCDイニシャライズ
__delay_ms(100);

Int2Num(FREQ);
LCD_WrAllData(0,LCD_Tab,16);//
Freqwrite(FREQ,0);//reg0にFREQを書き込み
lastFREQ = FREQ;
while(1){
	//if (lastFREQ != FREQ) {
		Freqwrite(FREQ,0);//reg0にFREQを書き込み
		LCD_disp();//周波数表示
	//	}
//    RLED=~RLED;
	__delay_ms(10);
     }
 }
