 /**********************************************
* 作成日　2018年9月8日
* PIC24FV32KA302 family 
* Multi Freq VFO Ver 0.8
*
* DDS controller  DDS IC : AD9833 基準周波数25MHz
* Fosc 8MHz x 4 PLL (32MHz)
* LCD  16x2 ACM1602K
* PLL逓倍回路内蔵

***********************************************/
#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 = NONE, OSCIOFNC = OFF, FCKSM = CSDCMD
#pragma config FWDTEN = OFF, WINDIS = OFF, POSCFREQ = HS, BORV = V20
#pragma config LVRCFG = OFF, PWRTEN = ON, MCLRE = ON, ICS = PGx2




#define LCD_PORT LATB	/* set LCD port */

#define LCD_E LATBbits.LATB2		/* set E bit of I/O port */
#define LCD_RS LATBbits.LATB1		/* set RS bit of I/O port */
#define LCD_CMD 0
#define LCD_DAT 1

//#define RLED  LATBbits.LATB3  //RED LED
#define RE1A  PORTBbits.RB14  //Low Step A L:CCW H:CW
#define RE1B  PORTBbits.RB9  //Low Step B L:CCW H:CW
#define RE2A  PORTBbits.RB12  //Low Step A L:CCW H:CW
#define RE2B  PORTBbits.RB8  //Low Step B L:CCW H:CW
#define RE3A  PORTAbits.RA7  //Low Step A L:CCW H:CW
#define RE3B  PORTAbits.RA2  //Low Step B L:CCW H:CW

#define CALsw PORTAbits.RA4 //CAL Stand-by SW H:ON

#define SPIFlg LATBbits.LATB15//SPI送信中L
#define PLLOE LATBbits.LATB10 //PLL OE & RED H:PLL ON L:direct
#define PLLS0 LATBbits.LATB3 // PLL S0
#define PLLS1 LATAbits.LATA3 // PLL S1
#define ioS1 TRISAbits.TRISA3
#define ioS0 TRISBbits.TRISB3

unsigned char lcd_data[16];
unsigned char BandMsg[16];
unsigned char lastCALsw;

double kd = 1.073741824; //kd = 10 x 2^28/25MHz

unsigned long int tempFREQ;
unsigned long int Freset = 20000000; //1MHz RESET周波数 真周波数/10
unsigned long int FREQ = 71951200; //7195KHz 初期設定周波数　真周波数/10
unsigned long int Fq[10];
//unsigned int CNT,iCNT;//エンコダーパルス間隔、i:割込み直後の間隔（msec）
static char RE_table[] = {0,-1,1,0,1,0,0,-1,-1,0,0,1,0,1,-1,0};
static char lastRE = 0; 
unsigned char saveGO;//前モード
unsigned long int lastFREQ;//現在の周波数
unsigned long int MinFreq;//最低周波数
unsigned long int MaxFreq;//最高周波数
unsigned int UpDownSpan;//最小スパン    
unsigned long int UpDownSpanEX;//拡張スパン
unsigned char Div_ratio;//目的周波数とDDS周波数の分周比
unsigned int savecnt;//自動セーブカウンタ
unsigned int Band,lastBand;

void initMain (void) {
    CLKDIV = 0x0000;//RESETでRCDIVが1/2になるので、これが無いと32MHzにならない
//	OSCCON = 0b0001000100000000; //Fosc 8MHz x4 PLL FRCPLL Configで設定済み

	PORTB  = 0b1000100000000010; //
 	TRISB  = 0b0101001100000001;  //ポートB　1-6:,9-11,13,15出力　0,8,12,14入力
 	PORTA  = 0b0000000000100000; //全てL出力
 	TRISA   =0b0000000010010111; //ポートA　0,1,2,4,7 入力
 	ANSA = 0b000000000000000;//RA ANなし
 	ANSB = 0b000000000000000;//RB ANなし
    INTCON1 = 0b0000000000000000;//割込みネスト（多重割り込み）
    INTCON2 = 0b0000000000000110;//INT1,INT2立下りで割り込み	
    IPC5bits.INT1IP = 2;IPC7bits.INT2IP = 2;//外部割込み優先順位2
    IFS1bits.INT1IF = 0;IFS1bits.INT2IF = 0;//割込みフラグクリアー
    IEC1bits.INT1IE = 1;IEC1bits.INT2IE = 1;;//外部割込み許可
    
	SPI1CON1 = 0b0000011111110010;//マスターモード プライマリ1/4、セカンダリ1/4、クロックactive_L
 	SPI1CON2 = 0b0000000000000000;//
 	SPI1STATbits.SPIROV = 0;
 	SPI1STATbits.SPIEN = 1;//SPI1有効化
    
    T1CON = 0b0000000000100000;//Timer1：プリスケーラー1/64 クロック：fosc/2  
    PR1 = 1000;//T1 カウントmax 1msごとに割り込み発生
    TMR1 = 0;//T1レジスタクリア
    IPC0bits.T1IP = 3;//t1 割込み優先度　3
    IFS0bits.T1IF = 0;//t1 割込みフラグクリア
    IEC0bits.T1IE = 1;//t1 割込み許可
    T1CONbits.TON = 1;// ti タイマースタート
    PLLOE = 0;
    savecnt = 0;
}

void lcd_strobe() {//LCD E ストローブ
    LCD_E = 1;
    __delay_us(1);
    LCD_E = 0;
}


void LCD_command(char c) {
 __delay_us(52); /* >40us */
    unsigned int ic = c;
	unsigned int ip;
    LCD_RS = 0;
    ip = LCD_PORT & 0xFF0F;
    LCD_PORT = ((ic & 0x00F0) + ip); /* E=0, RS=rs, high addr */
    lcd_strobe();

	}


void Putc_LCD(char c, char rs) {
    __delay_us(52); /* >40us */
    unsigned int ip;
    unsigned int ic = c;
	LCD_RS = rs;
    ip = LCD_PORT & 0xFF0F;
    LCD_PORT = ((ic & 0x00F0) + ip); /* E=0, RS=rs, high addr */
    lcd_strobe();
    LCD_PORT = (((ic << 4) & 0x00F0)+ ip); /* E=0, RS=rs, low addr */
    lcd_strobe();
}

void Init_LCD(void) {//LCDイニシャライズ

    __delay_ms(15);
	LCD_command( 0x30); /* E=0, RS=0, command=0x30 */
    __delay_ms(5); /* > 4.1ms */
    lcd_strobe();
    __delay_us(128); /* >100us */
    lcd_strobe();
    __delay_us(128);
    /* set 4bit Band */
	LCD_command(0x20); /* E=0, RS=0, command=0x20 */
//    lcd_strobe();
    Putc_LCD(0x28,LCD_CMD); /* display Band */
    Putc_LCD(0x0C,LCD_CMD); /* display on */
    Putc_LCD(0x01,LCD_CMD); //LCD クリアー
    __delay_ms(10);
    Putc_LCD(0x06,LCD_CMD); /* entry Band */
}

void Puts_LCD(const unsigned char *ptr) {//文字列を表示
    while (*ptr) {
        Putc_LCD(*ptr++, LCD_DAT);
    }
}

void Set_Pos(unsigned char x) {//1行目左端：0　2行目左端：40
    Putc_LCD(((x)&0x7F) | 0x80, LCD_CMD);
}




/***************************************
 * int整数をASCII文字に変換
 ****************************************/
void itostring(char digit, unsigned long int data, char *buffer) {
    char i;

    buffer += digit;
    *buffer = 0; // 最後の数字位置
    for (i = digit; i > 0; i--) { // 変換は下位から上位へ
        buffer--; // ポインター１
        *buffer = (data % 10) + '0'; // ASCIIへ
        data = data / 10; // 次の桁へ
    }
}

void strset(const unsigned char *as, unsigned char *buf) {//文字列をLCD表示用ASCII文字に変換
    while (*as) *buf++ = *as++;
    *buf = 0x00;
}

unsigned char getdigits(unsigned long int s) {
    unsigned char dg = 1;
    unsigned long int su, sm;
    sm = 1;
    su = s;
    while (su > 9) {
        dg++;
        sm = sm * 10;
        su = s / sm;
    }
    return dg;
}


void LCDdisplay(long int FQ) {
    char dg;
	long int F0,F1,F2;
    F0 = FQ/10;
    F2 = F0/1000000;//MHz部分
    F0 = F0-(F2*1000000);//KHz以下 F0=F0%1000000
	F1 = F0/1000;//KHz部分
	F0 = F0-(F1*1000);//Hz部分 F0=F0%1000
    strset("  ", lcd_data);
    Set_Pos(0x00);
    Puts_LCD(lcd_data);
	if (F2 < 10) {dg = 1;} else {dg = 2;}
    itostring(dg, F2, lcd_data); //MHzをASCIIに変換
    Set_Pos(0x02 - dg);
    Puts_LCD(lcd_data);
    strset(".", lcd_data);
    Set_Pos(0x02);
    Puts_LCD(lcd_data);
	itostring(3, F1, lcd_data); //KHzをASCIIに変換
    Set_Pos(0x03);
    Puts_LCD(lcd_data);

    strset(".",lcd_data);
    Set_Pos(0x06);
    Puts_LCD(lcd_data);
    itostring(3, F0, lcd_data); //HzをASCIIに変換
    Set_Pos(0x07);
    Puts_LCD(lcd_data);
	strset("Hz",lcd_data);
    Set_Pos(0x0B);
    Puts_LCD(lcd_data);
    
   strset(BandMsg, lcd_data);
    Set_Pos(0x40);
   Puts_LCD(lcd_data);

}





//データ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)  
    __delay_us(1);
	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 / Div_ratio;
	Freg = (double) (DFreg * kd); //Freg = DFreg;
	MFreg = (Freg >> 14) + MLset;
	LFreg = (Freg & 0x00003FFF) + MLset;
	DDSwrite(LFreg);

          
    __delay_us(5);
	DDSwrite(MFreg);

}

void saveBand() {
    unsigned int FH,FL;
    eeWrite(0,Band);
    FH = FREQ >> 16;
    FL = (unsigned int) FREQ;
    eeWrite(2 * (Band+1),FL);
    eeWrite(4 * (Band+1),FH);

//    RLED = ~RLED;
}

void getnewFreq() {
	unsigned int FH,FL;
    lastFREQ = FREQ;
	FL = eeRead(2 * (Band+1));
    FH = eeRead(4 * (Band+1));
    FREQ = (unsigned long int) FH;
    FREQ =(FREQ << 16) + FL;
	if ((FREQ > 550000000) || (5000000 > FREQ)) {
		switch (Band) { 
			case 0 : FREQ = 10000000;break;
       		case 1 : FREQ = 18200000;break;
       		case 2 : FREQ = 35300000;break;
       		case 3 : FREQ = 71000000;break;
			case 4 : FREQ = 101200000;break;
            case 5 : FREQ = 140500000;break;
            case 6 : FREQ = 181000000;break;
            case 7 : FREQ = 210500000;break;
            case 8 : FREQ = 249000000;break;
            case 9 : FREQ = 283500000;break;
            case 10 : FREQ = 505000000;break;
       		default : FREQ = 70000000;
            }
	}
}
void getBand() {
    Band = eeRead(0);
    if (Band > 16) {
        Band = 0;
       }
}


void initDDS() {
	DDSwrite(0x2100);//DDS reset
	DDSwrite(0xC000);//PHASE0 0
	DDSwrite(0xE000);//PHASE1 0
	
	Freqwrite(Freset,0);//reg0に1MHz書き込み
	Freqwrite(Freset,1);//reg1に1MHz書き込み
    DDSwrite(0x2000);//16bit連続2回送信にて周波数確定
}	
void setPLL(unsigned char M){

    switch (M) { 
       		case 1 : PLLOE = 0;break;
       		case 2 : ioS0 = 1;ioS1 = 1;PLLOE = CALsw;break;
            case 3 : ioS0 = 1;ioS1 = 0;PLLS1 = 1;PLLOE = CALsw;break;
       		case 4 : ioS0 = 0;ioS1 = 0;PLLS0 = 0;PLLS1 = 0;PLLOE = CALsw;break;
			case 8 : ioS0 = 0;ioS1 = 0;PLLS0 = 1;PLLS1 = 1;PLLOE = CALsw;break;
       		default : PLLOE = 0;
   }
    
}

void setBand0() {
    MinFreq = 5000000;//最低周波数
    MaxFreq = 125000000;//最高周波数
    UpDownSpan = 10000;//最小スパン    
    UpDownSpanEX = 1000000;//拡張スパン
    Div_ratio = 1;//目的周波数とDDS周波数の比
    setPLL(Div_ratio);
    strcpy(BandMsg , "Band0 x 1    ");
}

void setBand1() {
    MinFreq = 18000000;//最低周波数
    MaxFreq = 20000000;//最高周波数
    UpDownSpan = 100;//最小スパン    
    UpDownSpanEX = 10000;//拡張スパン
    Div_ratio = 1;//目的周波数とDDS周波数の比
    setPLL(Div_ratio);
    strcpy(BandMsg , "Band1 x 1    ");
}

void setBand2() {
    MinFreq = 35000000;//最低周波数
    MaxFreq = 40000000;//最高周波数
    UpDownSpan = 100;//最小スパン    
    UpDownSpanEX = 10000;//拡張スパン
    Div_ratio = 1;//目的周波数とDDS周波数の比
    setPLL(Div_ratio);
    strcpy(BandMsg , "Band2 x 1    ");
}

void setBand3() {
    MinFreq = 70000000;//最低周波数
    MaxFreq = 73000000;//最高周波数
    UpDownSpan = 100;//最小スパン    
    UpDownSpanEX = 10000;//拡張スパン
    Div_ratio = 1;//目的周波数とDDS周波数の比
    setPLL(Div_ratio);
    strcpy(BandMsg , "Band3 x 1    ");
//     RLED = ~RLED;
}

void setBand4() {
    MinFreq = 101000000;//最低周波数
    MaxFreq = 101500000;//最高周波数
    UpDownSpan = 100;//最小スパン    
    UpDownSpanEX = 10000;//拡張スパン
    Div_ratio = 1;//目的周波数とDDS周波数の比
    setPLL(Div_ratio);
    strcpy(BandMsg , "Band4 x 1    ");
}

void setBand5() {
    MinFreq = 140000000;//最低周波数
    MaxFreq = 144000000;//最高周波数
    UpDownSpan = 100;//最小スパン    
    UpDownSpanEX = 10000;//拡張スパン
    Div_ratio = 2;//目的周波数とDDS周波数の比
    setPLL(Div_ratio);
    strcpy(BandMsg , "Band5 x 2   ");
}

void setBand6() {
    MinFreq = 180680000;//最低周波数
    MaxFreq = 181680000;//最高周波数
    UpDownSpan = 100;//最小スパン    
    UpDownSpanEX = 10000;//拡張スパン
    Div_ratio = 3;//目的周波数とDDS周波数の比
    setPLL(Div_ratio);
    strcpy(BandMsg , "Band6 x 3   ");
}

void setBand7() {
    MinFreq = 210000000;//最低周波数
    MaxFreq = 215000000;//最高周波数
    UpDownSpan = 100;//最小スパン    
    UpDownSpanEX = 10000;//拡張スパン
    Div_ratio = 3;//目的周波数とDDS周波数の比
    setPLL(Div_ratio);
    strcpy(BandMsg , "Band7 x 3   ");
}

void setBand8() {
    MinFreq = 248900000;//最低周波数
    MaxFreq = 249900000;//最高周波数
    UpDownSpan = 100;//最小スパン    
    UpDownSpanEX = 10000;//拡張スパン
    Div_ratio = 4;//目的周波数とDDS周波数の比
    setPLL(Div_ratio);
    strcpy(BandMsg , "Band8 x 4   ");
}

void setBand9() {
    MinFreq = 280000000;//最低周波数
    MaxFreq = 297000000;//最高周波数
    UpDownSpan = 200;//最小スパン    
    UpDownSpanEX = 20000;//拡張スパン
    Div_ratio = 4;//目的周波数とDDS周波数の比
    setPLL(Div_ratio);
    strcpy(BandMsg , "Band9 x 4   ");
}

void setBand10() {
    MinFreq = 500000000;//最低周波数
    MaxFreq = 540000000;//最高周波数
    UpDownSpan = 500;//最小スパン    
    UpDownSpanEX = 25000;//拡張スパン
    Div_ratio = 8;//目的周波数とDDS周波数の比
    setPLL(Div_ratio);
    strcpy(BandMsg , "Band10 x 8  ");
}
void initBand (unsigned int md) {
    //strcat(BandMsg , "");
   	switch (md) { 
   		case 0 : setBand0();break;
       	case 1 : setBand1();break;
       	case 2 : setBand2();break;
       	case 3 : setBand3();break;
   		case 4 : setBand4();break;
        case 5 : setBand5();break;
        case 6 : setBand6();break;
        case 7 : setBand7();break;
        case 8 : setBand8();break;
        case 9 : setBand9();break;
        case 10 : setBand10();break;
       default : setBand3();
   }
    lastBand = Band;//前モード
   
}

void standbyset(){
	if (lastCALsw != CALsw) {
		if (CALsw == 1) {initBand(Band);Freqwrite(FREQ,0);} else {Freqwrite(0,0);PLLOE = 0;}
		lastCALsw = CALsw;
		}
	}
void __attribute__((__interrupt__,__no_auto_psv__)) _INT1Interrupt(void){
 // Band切り替え
 IFS1bits.INT1IF = 0;
 IEC1bits.INT1IE = 0;
 lastBand = Band;
 if (RE1B == 1) {if (Band < 10) {Band ++;}} 
 if (RE1B == 0) {if (Band > 0) {Band --;}}    
 __delay_us(1000); 
 IEC1bits.INT1IE = 1;
 
}
void __attribute__((__interrupt__,__no_auto_psv__)) _INT2Interrupt(void){
 IFS1bits.INT2IF = 0;
 IEC1bits.INT2IE = 0;
        if (RE2B == 1) {
			if (FREQ < MaxFreq) {FREQ = FREQ +UpDownSpanEX;FREQ = FREQ / UpDownSpanEX;FREQ = FREQ * UpDownSpanEX;}	
		}
		if (RE2B == 0) {
			if (FREQ > MinFreq) {
                tempFREQ = FREQ / UpDownSpanEX;tempFREQ = tempFREQ * UpDownSpanEX;
                if ((FREQ - tempFREQ) != 0) {FREQ = FREQ + UpDownSpanEX;} 
                FREQ = FREQ - UpDownSpanEX;FREQ = FREQ / UpDownSpanEX;FREQ = FREQ * UpDownSpanEX;
            }
		}
	__delay_us(1000); 
 IEC1bits.INT2IE = 1;
}
void __attribute__((__interrupt__,__no_auto_psv__)) _T1Interrupt(void){
        unsigned char k;          
    	char curRE;
 IFS0bits.T1IF = 0;
 IEC0bits.T1IE = 0;
  T1CONbits.TON = 0;// ti タイマー1 Stop
	curRE = RE3B * 2 + RE3A;    
    lastRE <<= 2;                      
    lastRE |= ( curRE & 0x03 ); 
    k = (RE_table[(lastRE & 0x0F)]);
	if ((k == 1) && (FREQ < MaxFreq) ){FREQ = FREQ + UpDownSpan;} 
	if ((k == 255) && (FREQ > MinFreq)){FREQ = FREQ - UpDownSpan;}
	
 TMR1 = 0;
  T1CONbits.TON = 1;// ti タイマー1スタート
// RLED = ~RLED;
 IEC0bits.T1IE = 1;
 if (savecnt < 5000) {savecnt ++;}
}


int main() {

initMain();
initDDS();//DDSイニシャライズ
__delay_ms(500);
//RLED =0;
Init_LCD();    //LCDイニシャライズ
__delay_ms(100);
getBand();//EEPROMからBand番号を読み出す
getnewFreq();//EEPROMからlastFREQを読みだす
initBand(Band);
lastFREQ = FREQ;
lastCALsw = 2; //最初は1か0か不明
standbyset();
//Freqwrite(FREQ,0);//reg0にFREQを書き込み
LCDdisplay(FREQ);//周波数表示
//lastCALsw = CALsw;

while(1){
	if (lastFREQ != FREQ) {
		standbyset();//DDS周波数書き換え
		if(CALsw == 1 ) {Freqwrite(FREQ,0);}//reg0にFREQを書き込み
		LCDdisplay(FREQ);//周波数表示
        
        lastFREQ = FREQ;
        saveGO = 1;
		}
	if (lastBand != Band) {getnewFreq();initBand(Band);saveGO =1;}
    if ((savecnt > 500) && (saveGO == 1)) {saveBand();savecnt = 0;saveGO = 0;}//EEPROMに記録
	standbyset();//DDS周波数書き換え


     }
 }
