PIC16FのNCOを利用した周波数シンセサイザの製作です。

出力波形は矩形波(0-5V)です

出力周波数範囲は、1Hz~8.388607MHz です

外観

仕様

・出力波形     矩形波

・出力電圧     5V

・出力電圧     1Hz~8.388607MHz

・周波数分解能   

    1Hz(1Hz-1.048575MHz時)

    2Hz(1.048576MHz~2.097151MHz時)

    4Hz(2.097152Hz~4.194303MHz時)

    8Hz(4.194304MHz~8.388607MHz時)

・周波数設定    ロータリースイッチ

・電源電圧     100V(5V ACアダプタ使用)

設計方針

・PICの周辺モジュールであるNCO(Numerically controlled oscillator)を用いる

・水晶4.194304MHz(2^22)をNCOで分周し、周波数分解能1Hzを実現する

・設定周波数は0~9の設定可能なロータリースイッチを7個使用する

・ロータリースイッチの配線数を少なくするために、AD変換を用い0~9を判別する

・シンセサイザーの出力周波数を拡大するためにCLC(Configurable Logic Cell)を用い、T-F/Fを構成しFoscを分周する

・シンセサイザーの出力周波数をLCDで表示する

synthesizerブロック図

ロータリースイッチ

全体ブロック図

回路図

frequency_synthesizer1

内部写真

LCD

ソフトウエア(mainプログラム)

ソフトウエア(周波数設定)

部品表

ソースコード

/*
 * File:   main.c
 *
 * Created on 2018/09/20, 21:16
 */

//-------- ハードウエア --------------
//  RA0(2)  out クロック出力
//  RA1(3)  out 未使用
//  RA2(4)  out 未使用
//  RA3(5)  out 未使用
//  RA4(6)  out 未使用
//  RA5(7)  out 未使用
//  RA6(10) in  OSC2    水晶     
//  RA7(9)  in  OSC1
//
//  RB0(21)    out  LCD D7
//  RB1(22)    out  LCD D6
//  RB2(23)    out  LCD D5
//  RB3(24)    out  LCD D4
//  RB4(25)    out  LCD E
//  RB5(26)    out  LCD RS
//  RB6(27)    in   ICSPCLK
//  RB7(28)    in   ICSPDAT
//
//  RC0(11)    out  未使用
//  RC1(12)    in  ANC1 ロータリーSW
//  RC2(13)    in  ANC2 ロータリーSW
//  RC3(14)    in  ANC3 ロータリーSW
//  RC4(15)    in  ANC4 ロータリーSW
//  RC5(16)    in  ANC5 ロータリーSW
//  RC6(17)    in  ANC6 ロータリーSW
//  RC7(18)    in  ANC7 ロータリーSW
//
//  RE3(1)  in  MCLR

// PIC16F18857 Configuration Bit Settings
// CONFIG1
#pragma config FEXTOSC = HS     // External Oscillator mode selection bits (HS (crystal oscillator) above 4MHz; PFM set to high power)
#pragma config RSTOSC = EXT4X   // Power-up default value for COSC bits (EXTOSC with 4x PLL, with EXTOSC operating per FEXTOSC bits)
//#pragma config RSTOSC = EXT1X   // Power-up default value for COSC bits (EXTOSC operating per FEXTOSC bits)
#pragma config CLKOUTEN = OFF   // Clock Out Enable bit (CLKOUT function is disabled; i/o or oscillator function on OSC2)
#pragma config CSWEN = OFF      // Clock Switch Enable bit (The NOSC and NDIV bits cannot be changed by user software)
#pragma config FCMEN = OFF      // Fail-Safe Clock Monitor Enable bit (FSCM timer disabled)
// CONFIG2
#pragma config MCLRE = ON       // Master Clear Enable bit (MCLR pin is Master Clear function)
#pragma config PWRTE = OFF      // Power-up Timer Enable bit (PWRT disabled)
#pragma config LPBOREN = OFF    // Low-Power BOR enable bit (ULPBOR disabled)
#pragma config BOREN = OFF      // Brown-out reset enable bits (Brown-out reset disabled)
#pragma config BORV = LO        // Brown-out Reset Voltage Selection (Brown-out Reset Voltage (VBOR) set to 1.9V on LF, and 2.45V on F Devices)
#pragma config ZCD = OFF        // Zero-cross detect disable (Zero-cross detect circuit is disabled at POR.)
#pragma config PPS1WAY = ON     // Peripheral Pin Select one-way control (The PPSLOCK bit can be cleared and set only once in software)
#pragma config STVREN = ON      // Stack Overflow/Underflow Reset Enable bit (Stack Overflow or Underflow will cause a reset)
// CONFIG3
#pragma config WDTCPS = WDTCPS_31// WDT Period Select bits (Divider ratio 1:65536; software control of WDTPS)
#pragma config WDTE = OFF       // WDT operating mode (WDT Disabled, SWDTEN is ignored)
#pragma config WDTCWS = WDTCWS_7// WDT Window Select bits (window always open (100%); software control; keyed access not required)
#pragma config WDTCCS = SC      // WDT input clock selector (Software Control)
// CONFIG4
#pragma config WRT = OFF        // UserNVM self-write protection bits (Write protection off)
#pragma config SCANE = not_available// Scanner Enable bit (Scanner module is not available for use)
#pragma config LVP = ON         // Low Voltage Programming Enable bit (Low Voltage programming enabled. MCLR/Vpp pin function is MCLR.)
// CONFIG5
#pragma config CP = OFF         // UserNVM Program memory code protection bit (Program Memory code protection disabled)
#pragma config CPD = OFF        // DataNVM code protection bit (Data EEPROM code protection disabled)


//************************ インクルードファイル ***********************
#include <stdio.h>
#include <stdlib.h>
#include <xc.h>


//******************* 関数定義 **************************************************
void init_OSC(void);                                    //オシレータ初期設定
void init_port(void);                                   //PORT初期設定
void init_LCD(void);                                    //LCD初期設定
void set_LCD_port(unsigned char data);                 //LCDポート設定
void set_character_lcd_cmd(unsigned char cmd);        //LCDコマンド設定
void set_character_lcd_data(unsigned char data);      //LCDデータ設定
void LCD_Puts(const char * s);
void clear_character(unsigned char address, unsigned char number);
void display_normal(void);                              //LCD1行目に[ -- FREQUENCY --]を表示
void display_higher(void);                              //LCD1行目に[set higher frequency]を表示
void display_lower(void);                               //LCD1行目に[set lower frequency]を表示
void display_frequency(void);                           //数値表示

void init_NCO(void);                                     //NCO初期設定
void init_CLC1(void);                                    //CLC1初期設定
void init_CLC2(void);                                    //CLC2初期設定
void init_CLC3(void);                                    //CLC3初期設定
void init_ADC(void);                                    //ADC初期設定
unsigned char start_ADC(unsigned char adc_ch);          //ADC開始
void set_frequency(void);                               //周波数設定
void set_frequency1(void);                              //周波数設定1(1Hz-1.048575Hz)
void set_frequency2(void);                              //周波数設定1(Hz)
void set_frequency3(void);                              //周波数設定1(Hz)
void set_frequency4(void);                              //周波数設定1(Hz)

void convert_binaly_ASCII(unsigned long binaly);   //バイナリデータをASCIIに変換する
void test_display_decimal(unsigned long binaly);   //バイナリデーターを10進で表示する



//******************* PORTの定義など ************************
#define LCD_D7  PORTBbits.RB0   
#define LCD_D6  PORTBbits.RB1
#define LCD_D5  PORTBbits.RB2
#define LCD_D4  PORTBbits.RB3
#define LCD_E   PORTBbits.RB4
#define LCD_RS  PORTBbits.RB5
#define _XTAL_FREQ  16777216


//***************************** グローバル変数 **********************************
unsigned long frequency = 1;
unsigned long freq_no7,freq_no6,freq_no5,freq_no4,freq_no3,freq_no2,freq_no1; 

unsigned char   d1000000,d100000,d10000,d1000,d100,d10,d1;      //各桁のascIIコード



//******************** プログラム ***********************************************
//******************** オシレータ初期設定 ***************************************
//  入力    なし           
//  処理    4*PLL            
//  出力    Fosc(4.194304MHz)       
//******************************************************************************
void init_OSC(void){                                    //オシレータ初期設定
    OSCCON2bits.COSC = 2;                               //4.1943056MHz*4PLL=16.777224MHz
    OSCCON2bits.CDIV = 0;                               //1:1  Fosc=16.777224MHz  
}

//******************** PORT初期設定 *********************************************
//  入力    なし       
//  処理        
//  出力           
//******************************************************************************
void init_port(void){               //PORT初期設定  
    TRISA = 0xc0;   ANSELA = 0x00;  LATA = 0;
    TRISB = 0xc0;   ANSELB = 0x00;
    TRISC = 0xfe;   ANSELC = 0xfe; 
    
    RA0PPS = 0x19;                              //RA0:NCO1 OUT
}

//******************** LCD初期設定 *********************************************
//  入力    なし          
//  処理    
//  出力          
//******************************************************************************
void init_LCD(void){                           //LCD初期設定
    LCD_RS = 0;                                 //RS=0:command mode
    LCD_E=0;
    __delay_ms(40);                             //Delay 40ms
    
    set_LCD_port(3);                            //8bitモード(0x30)をセット 
    LCD_E=1;    __delay_us(1);  LCD_E=0;        //Enable 1usec high  
    __delay_ms(5);                              //Delay 4.1msec以上
   
    set_LCD_port(3);                            //8bitモード(0x30)をセット
    LCD_E=1;    __delay_us(1);  LCD_E=0;        //Enable 1usec high   
    __delay_us(100);                            //Delay 100usec

    set_LCD_port(3);                            //8bitモード(0x30)をセット
    LCD_E=1;    __delay_us(1);  LCD_E=0;        //Enable 1usec high 
    __delay_us(37);                             //Delay 37usec

    set_LCD_port(2);                            //4bitモード(0x20)をセット 
    LCD_E=1;    __delay_us(1);  LCD_E=0;        //Enable 1usec high   
    __delay_us(37);                             //Delay 37usec
    
    set_character_lcd_cmd(0x28);                //4bitモード 1/16duty
    set_character_lcd_cmd(0x08);                //4bitモード 表示OFF
    set_character_lcd_cmd(0x01);                //4bitモード クリアディスプレイ
    __delay_ms(2);                              //Delay 1.53msec
    set_character_lcd_cmd(0x06);                //4bitモード 書き込みモード、アドレス+1
    set_character_lcd_cmd(0x0c);                //4bitモード 表示ON

    LCD_Puts(" -- FREQUENCY --");
    set_character_lcd_cmd(0xc0);                //アドレス2行目先頭にする
    LCD_Puts(" 1.000000 [MHz]");                 //display_mode=0  
}


/************************ LCD portCにデータを設定 ********************************
*	入力 data
*	処理 LCDデータを設定
*	出力 LCD_D7,LCD_D6,LCD_D5,LCD_D4
*******************************************************************************/
void set_LCD_port(unsigned char data){
    switch(data){
        case 0:     LCD_D7=0;    LCD_D6=0;    LCD_D5=0;    LCD_D4=0;    break;
        case 1:     LCD_D7=0;    LCD_D6=0;    LCD_D5=0;    LCD_D4=1;    break;
        case 2:     LCD_D7=0;    LCD_D6=0;    LCD_D5=1;    LCD_D4=0;    break;
        case 3:     LCD_D7=0;    LCD_D6=0;    LCD_D5=1;    LCD_D4=1;    break;
        case 4:     LCD_D7=0;    LCD_D6=1;    LCD_D5=0;    LCD_D4=0;    break;
        case 5:     LCD_D7=0;    LCD_D6=1;    LCD_D5=0;    LCD_D4=1;    break;
        case 6:     LCD_D7=0;    LCD_D6=1;    LCD_D5=1;    LCD_D4=0;    break;
        case 7:     LCD_D7=0;    LCD_D6=1;    LCD_D5=1;    LCD_D4=1;    break;
        case 8:     LCD_D7=1;    LCD_D6=0;    LCD_D5=0;    LCD_D4=0;    break;
        case 9:     LCD_D7=1;    LCD_D6=0;    LCD_D5=0;    LCD_D4=1;    break;
        case 10:    LCD_D7=1;    LCD_D6=0;    LCD_D5=1;    LCD_D4=0;    break;
        case 11:    LCD_D7=1;    LCD_D6=0;    LCD_D5=1;    LCD_D4=1;    break;
        case 12:    LCD_D7=1;    LCD_D6=1;    LCD_D5=0;    LCD_D4=0;    break;
        case 13:    LCD_D7=1;    LCD_D6=1;    LCD_D5=0;    LCD_D4=1;    break;
        case 14:    LCD_D7=1;    LCD_D6=1;    LCD_D5=1;    LCD_D4=0;    break;
        case 15:    LCD_D7=1;    LCD_D6=1;    LCD_D5=1;    LCD_D4=1;    break;
    }
}


/*********************** LCDにコマンドを設定 ************************************
*	入力 cmd(8bit)
*	処理 LCDにコマンドを設定(RS = 0) + 37usec delay
*	出力 なし
*******************************************************************************/
void set_character_lcd_cmd(unsigned char cmd){
    LCD_RS = 0;                                     //RS=0:command
    
    LCD_E=1;      
    set_LCD_port(cmd >> 4);     __delay_us(1);      //LCD PORTの値(上位4bit)をセット
    LCD_E=0;       
    __delay_us(2);                                  //delay 2usec

    LCD_E=1;     
    set_LCD_port(cmd & 0x0f);   __delay_us(1);      //LCD PORTの値(下位4bit)をセット
    LCD_E=0;    
    __delay_us(37);                                 //delay 37usec
}


/************************ LCDにデータを設定 *************************************
*	入力 data(8bit)
*	処理 LCDにデータを設定(RS=1) + 37usec delay
*	出力 なし
*******************************************************************************/
void set_character_lcd_data(unsigned char data){
    LCD_RS = 1;                                     //RS=1:data
    
    LCD_E=1;     
    set_LCD_port(data >> 4);    __delay_us(1);      //LCD PORTの値(上位4bit)をセット
    LCD_E=0;      
    __delay_us(2);                                  //delay 2uSEC

    LCD_E=1;   
    set_LCD_port(data & 0x0f);  __delay_us(1);      //LCD PORTの値(下位4bit)をセット
    LCD_E=0;    
    __delay_us(37);                                 //delay 37usec
}


/*******************************************************************************
*  LCD_Puts(*s)                                                                *
*    LCDに文字列データを出力する処理                                         *
*    文字列は、NULL(0x00)まで繰返し出力します。                                 *
*                                                                              *
*    *s :  出力する文字列のデータを格納した場所のアドレスを指定                  *
*******************************************************************************/
void LCD_Puts(const char * s){
    while(*s) {
        set_character_lcd_data(*s++);               //data byte の送信(連続送信)
    }
}


//******************** LCD 表示アドレスを設定する ******************************
//  入力    クリア先頭アドレス、クリアバイト数         
//  処理    LCD 表示 をクリアする    
//  出力    なし        
//******************************************************************************
void clear_character(unsigned char address, unsigned char number){
    unsigned char x;
    set_character_lcd_cmd(address);
    for(x=0; x<number; x++)     set_character_lcd_data(' ');  
}

//******************** LCDに周波数を表示する ************************************
//  入力    freq_no7,freq_no6,freq_no5,freq_no4,freq_no3,freq_no2,freq_no1      
//  処理    LCDの2行目に周波数を表示する
//  出力    なし        
//******************************************************************************
void display_frequency(void){                //表示
    clear_character(0xc0,16);                   //2行目クリア
    set_character_lcd_cmd(0xc0);                //アドレス2行目先頭にする
 
    char character_string[16];
    character_string[0] = 0x20;                                     //sp
    
    if(freq_no7 == 0){
        character_string[1] = 0x20;                                 //sp
        if(freq_no6 == 0){
            character_string[2] = 0x20;                             //sp
            if(freq_no5 == 0){
                character_string[3] = 0x20;                         //sp
                if(freq_no4 == 0){
                    character_string[4] = 0x20;                     //sp
                    if(freq_no3 == 0){
                        character_string[5] = 0x20;                 //sp
                        if(freq_no2 == 0){                          //9Hz-1Hzの表示                 
                            character_string[6] = 0x20;             //sp
                            character_string[7] = 0x20;             //sp
                            character_string[8] = freq_no1 + 0x30;  //
                            character_string[9] = 0x20;             //sp
                            character_string[10] = 0x20;            //sp
                            character_string[11] = '[';             //    
                        }
                        else{                                       //99Hz-10Hzの表示
                            character_string[6] = 0x20;             //sp
                            character_string[7] = freq_no2 + 0x30;  //
                            character_string[8] = freq_no1 + 0x30;  //
                            character_string[9] = 0x20;             //sp
                            character_string[10] = 0x20;            //sp
                            character_string[11] = '[';             //
                        }
                    }
                    else{                                           //999Hz-100Hzの表示
                        character_string[5] = 0x20;                 //sp
                        character_string[6] = freq_no3 + 0x30;      //
                        character_string[7] = freq_no2 + 0x30;      //
                        character_string[8] = freq_no1 + 0x30;      //
                        character_string[9] = 0x20;                 //sp
                        character_string[10] = 0x20;                //sp
                        character_string[11] = '[';                 //
                    }
                }
                else{                                               //9kHz-1kHzの表示
                    character_string[4] = freq_no4 + 0x30;          //
                    character_string[5] = '.';                      //
                    character_string[6] = freq_no3 + 0x30;          //
                    character_string[7] = freq_no2 + 0x30;          //
                    character_string[8] = freq_no1 + 0x30;          //
                    character_string[9] = 0x20;                     //sp
                    character_string[10] = '[';                     //
                    character_string[11] = 'k';                     //
                }
            }
            else{                                                   //99kHz-10kHの表示
                character_string[3] = freq_no5 + 0x30;              //
                character_string[4] = freq_no4 + 0x30;              //
                character_string[5] = '.';                          //
                character_string[6] = freq_no3 + 0x30;              //
                character_string[7] = freq_no2 + 0x30;              //
                character_string[8] = freq_no1 + 0x30;              //
                character_string[9] = 0x20;                         //sp
                character_string[10] = '[';                         //
                character_string[11] = 'k';                         //
            }
        }
        else{                                                       //999kHz-100kHzの表示
            character_string[2] = freq_no6 + 0x30;                  //
            character_string[3] = freq_no5 + 0x30;                  //
            character_string[4] = freq_no4 + 0x30;                  //
            character_string[5] = '.';                              //
            character_string[6] = freq_no3 + 0x30;                  //
            character_string[7] = freq_no2 + 0x30;                  //
            character_string[8] = freq_no1 + 0x30;                  //
            character_string[9] = 0x20;                             //sp
            character_string[10] = '[';                             //
            character_string[11] = 'k';                             //
        }
    }    
    else{                                                           //1MHz以上の表示
        character_string[1] = freq_no7 + 0x30;                      //
        character_string[2] = '.';                                  //
        character_string[3] = freq_no6 + 0x30;                      //
        character_string[4] = freq_no5 + 0x30;                      //
        character_string[5] = freq_no4 + 0x30;                      //
        character_string[6] = freq_no3 + 0x30;                      //
        character_string[7] = freq_no2 + 0x30;                      //
        character_string[8] = freq_no1 + 0x30;                      //
        character_string[9] = 0x20;                                 //sp
        character_string[10] = '[';                                 //
        character_string[11] = 'M';                                 // 
    }  
    
    character_string[12] = 'H';                                     //
    character_string[13] = 'z';                                     //
    character_string[14] = ']';                                     //
    character_string[15] = 0;                                       //null
    
    LCD_Puts(character_string);                                     //数値表示
}

//************** LCD1行目に[-- FREQUENCY --]を表示 **********************
//  入力        
//  処理    
//  出力    なし        
//******************************************************************************
void display_normal(void){                  //LCD1行目に[ -- FREQUENCY --]を表示
    clear_character(0x80,16);                   //1行目クリア
    set_character_lcd_cmd(0x80);                //アドレス1行目先頭にする
    LCD_Puts(" -- FREQUENCY -- ");               // -- FREQUENCY --表示
}

//************** LCD1行目に[set higher frequency]を表示 **********************
//  入力        
//  処理    
//  出力    なし        
//******************************************************************************
void display_higher(void){                  //LCD1行目に[set higher frequency]を表示
    clear_character(0x80,16);                   //1行目クリア
    set_character_lcd_cmd(0x80);                //アドレス1行目先頭にする
    LCD_Puts("Set higher FREQ!");               // -- FREQUENCY --表示  
}

//*************** LCD1行目に[set lower frequency]を表示 **********************
//  入力        
//  処理    
//  出力    なし        
//******************************************************************************
void display_lower(void){                   //LCD1行目に[set lower frequency]を表示
    clear_character(0x80,16);                   //1行目クリア
    set_character_lcd_cmd(0x80);                //アドレス1行目先頭にする
    LCD_Puts("Set lower FREQ!");               // -- FREQUENCY --表示 
}

/******************* バイナリデータをASCIIコードに変換する ***********************
*	入力 0<= binaly <=9999999
*	処理 バイナリ→ASCII変換
*	出力 d1000000,d100000,d10000,d1000,d100,d10,d1
**********************************************************************/
void convert_binaly_ASCII(unsigned long binaly){
    unsigned long syou1,syou10,syou100,syou1000,syou10000,syou100000,syou1000000;

    syou1       = binaly/10;        d1          = binaly%10 + 0x30;
    syou10      = syou1/10;         d10         = syou1%10 + 0x30;
    syou100     = syou10/10;        d100        = syou10%10 + 0x30;
    syou1000    = syou100/10;       d1000       = syou100%10 + 0x30;
    syou10000   = syou1000/10;      d10000      = syou1000%10 + 0x30;
    syou100000  = syou10000/10;     d100000     = syou10000%10 + 0x30;
                                    d1000000    = syou100000%10 + 0x30;
}

//********************* バイナリデーターを10進で表示する *************************
//  入力   0 < binaly < 9999999  
//  処理    LCDにbinalyデータを10進に変換し表示する
//  出力    LCD
//******************************************************************************
void test_display_decimal(unsigned long binaly){   //バイナリデーターを10進で表示する
    clear_character(0x80,16);                   //1行目クリア
    set_character_lcd_cmd(0x80);                //アドレス1行目先頭にする
    
        char character_string[8];
        convert_binaly_ASCII(binaly);                           //バイナリーデータをASCIIコードに変換
        character_string[0] = d1000000;
        character_string[1] = d100000;
        character_string[2] = d10000;
        character_string[3] = d1000;
        character_string[4] = d100;
        character_string[5] = d10;
        character_string[6] = d1;
        character_string[7] = 0;								//null
        
    LCD_Puts(character_string);                                     //数値表示
} 


//******************** CLC1初期設定 ********************************************
//  入力    Fosc(16.777224MHz            
//  処理    2分周(JK-F/F→T-F/F)
//  出力    CLC1OUT(8.388608MHz)      
//******************************************************************************
void init_CLC1(void){                                    //CLC1初期設定
    //lc1g1をFoscにセット
    CLC1SEL0bits.LC1D1S = 4;                               //入力信号Fosc(16.777224MHz)を選択
    CLC1GLS0bits.LC1G1D1T = 1;  CLC1GLS0bits.LC1G1D1N = 0;
    CLC1GLS0bits.LC1G1D2T = 0;  CLC1GLS0bits.LC1G1D2N = 0;
    CLC1GLS0bits.LC1G1D3T = 0;  CLC1GLS0bits.LC1G1D3N = 0;
    CLC1GLS0bits.LC1G1D4T = 0;  CLC1GLS0bits.LC1G1D4N = 0;
    CLC1POLbits.LC1G1POL = 0;                               //gate0 output polarity
    //lc1g2(J入力)をHにする
    CLC1GLS1bits.LC1G2D1T = 0;  CLC1GLS1bits.LC1G2D1N = 0;
    CLC1GLS1bits.LC1G2D2T = 0;  CLC1GLS1bits.LC1G2D2N = 0;
    CLC1GLS1bits.LC1G2D3T = 0;  CLC1GLS1bits.LC1G2D3N = 0;
    CLC1GLS1bits.LC1G2D4T = 0;  CLC1GLS1bits.LC1G2D4N = 0;
    CLC1POLbits.LC1G2POL = 1;                               //gate1 output polarity
    //lc1g4(K入力)をHにする
    CLC1GLS3bits.LC1G4D1T = 0;  CLC1GLS3bits.LC1G4D1N = 0;
    CLC1GLS3bits.LC1G4D2T = 0;  CLC1GLS3bits.LC1G4D2N = 0;
    CLC1GLS3bits.LC1G4D3T = 0;  CLC1GLS3bits.LC1G4D3N = 0;
    CLC1GLS3bits.LC1G4D4T = 0;  CLC1GLS3bits.LC1G4D4N = 0;
    CLC1POLbits.LC1G4POL = 1;                               //gate3 output polarity
    //lc1g3(RESET入力)をLにする
    CLC1GLS2bits.LC1G3D1T = 0;  CLC1GLS2bits.LC1G3D1N = 0;
    CLC1GLS2bits.LC1G3D2T = 0;  CLC1GLS2bits.LC1G3D2N = 0;
    CLC1GLS2bits.LC1G3D3T = 0;  CLC1GLS2bits.LC1G3D3N = 0;
    CLC1GLS2bits.LC1G3D4T = 0;  CLC1GLS2bits.LC1G3D4N = 0;
    CLC1POLbits.LC1G3POL = 0;                               //gate2 output polarity
    //JK-F/Fにセットする
    CLC1CONbits.LC1MODE = 6;            //JK-F/Fを選択
   
    //出力設定
    CLC1POLbits.LC1G1POL = 0;           //CLC1 OUTPUT Polarity is not invert
    CLC1CONbits.LC1EN = 1;              //cofigration logic cell enable
}

//******************** CLC2初期設定 ********************************************
//  入力    CLC1OUT(8.388608MHz)            
//  処理    2分周(JK-F/F→T-F/F)
//  出力    CLC2OUT(4.1943056MHz)      
//******************************************************************************
void init_CLC2(void){                                    //CLC2初期設定
    //lc1g1をCLC1OUTにセット
    CLC2SEL0bits.LC2D1S = 32;                               //入力信号CLC1OUT(8.388608MHz)を選択
    CLC2GLS0bits.LC2G1D1T = 1;  CLC2GLS0bits.LC2G1D1N = 0;
    CLC2GLS0bits.LC2G1D2T = 0;  CLC2GLS0bits.LC2G1D2N = 0;
    CLC2GLS0bits.LC2G1D3T = 0;  CLC2GLS0bits.LC2G1D3N = 0;
    CLC2GLS0bits.LC2G1D4T = 0;  CLC2GLS0bits.LC2G1D4N = 0;
    CLC2POLbits.LC2G1POL = 0;                               //gate0 output polarity
    //lc1g2(J入力)をHにする
    CLC2GLS1bits.LC2G2D1T = 0;  CLC2GLS1bits.LC2G2D1N = 0;
    CLC2GLS1bits.LC2G2D2T = 0;  CLC2GLS1bits.LC2G2D2N = 0;
    CLC2GLS1bits.LC2G2D3T = 0;  CLC2GLS1bits.LC2G2D3N = 0;
    CLC2GLS1bits.LC2G2D4T = 0;  CLC2GLS1bits.LC2G2D4N = 0;
    CLC2POLbits.LC2G2POL = 1;                               //gate1 output polarity
    //lc1g4(K入力)をHにする
    CLC2GLS3bits.LC2G4D1T = 0;  CLC2GLS3bits.LC2G4D1N = 0;
    CLC2GLS3bits.LC2G4D2T = 0;  CLC2GLS3bits.LC2G4D2N = 0;
    CLC2GLS3bits.LC2G4D3T = 0;  CLC2GLS3bits.LC2G4D3N = 0;
    CLC2GLS3bits.LC2G4D4T = 0;  CLC2GLS3bits.LC2G4D4N = 0;
    CLC2POLbits.LC2G4POL = 1;                               //gate3 output polarity
    //lc1g3(RESET入力)をLにする
    CLC2GLS2bits.LC2G3D1T = 0;  CLC2GLS2bits.LC2G3D1N = 0;
    CLC2GLS2bits.LC2G3D2T = 0;  CLC2GLS2bits.LC2G3D2N = 0;
    CLC2GLS2bits.LC2G3D3T = 0;  CLC2GLS2bits.LC2G3D3N = 0;
    CLC2GLS2bits.LC2G3D4T = 0;  CLC2GLS2bits.LC2G3D4N = 0;
    CLC2POLbits.LC2G3POL = 0;                               //gate2 output polarity
    //JK-F/Fにセットする
    CLC2CONbits.LC2MODE = 6;            //JK-F/Fを選択
   
    //出力設定
    CLC2POLbits.LC2G1POL = 0;           //CLC2 OUTPUT Polarity is not invert
    CLC2CONbits.LC2EN = 1;              //cofigration logic cell enable
}

//******************** CLC3初期設定 *********************************************
//  入力    CLC2OUT(4.1943056MHz)            
//  処理    2分周(JK-F/F→T-F/F)
//  出力    CLC3OUT(2.097152MHz)      
//******************************************************************************
void init_CLC3(void){                                    //CLC3初期設定
    //lc1g1をCLC2OUTにセット
    CLC3SEL0bits.LC3D1S = 33;                               //入力信号CLC2OUT(4.1943056MHz)を選択
    CLC3GLS0bits.LC3G1D1T = 1;  CLC3GLS0bits.LC3G1D1N = 0;
    CLC3GLS0bits.LC3G1D2T = 0;  CLC3GLS0bits.LC3G1D2N = 0;
    CLC3GLS0bits.LC3G1D3T = 0;  CLC3GLS0bits.LC3G1D3N = 0;
    CLC3GLS0bits.LC3G1D4T = 0;  CLC3GLS0bits.LC3G1D4N = 0;
    CLC3POLbits.LC3G1POL = 0;                               //gate0 output polarity
    //lc1g2(J入力)をHにする
    CLC3GLS1bits.LC3G2D1T = 0;  CLC3GLS1bits.LC3G2D1N = 0;
    CLC3GLS1bits.LC3G2D2T = 0;  CLC3GLS1bits.LC3G2D2N = 0;
    CLC3GLS1bits.LC3G2D3T = 0;  CLC3GLS1bits.LC3G2D3N = 0;
    CLC3GLS1bits.LC3G2D4T = 0;  CLC3GLS1bits.LC3G2D4N = 0;
    CLC3POLbits.LC3G2POL = 1;                               //gate1 output polarity
    //lc1g4(K入力)をHにする
    CLC3GLS3bits.LC3G4D1T = 0;  CLC3GLS3bits.LC3G4D1N = 0;
    CLC3GLS3bits.LC3G4D2T = 0;  CLC3GLS3bits.LC3G4D2N = 0;
    CLC3GLS3bits.LC3G4D3T = 0;  CLC3GLS3bits.LC3G4D3N = 0;
    CLC3GLS3bits.LC3G4D4T = 0;  CLC3GLS3bits.LC3G4D4N = 0;
    CLC3POLbits.LC3G4POL = 1;                              //gate3 output polarity
    //lc1g3(RESET入力)をLにする
    CLC3GLS2bits.LC3G3D1T = 0;  CLC3GLS2bits.LC3G3D1N = 0;
    CLC3GLS2bits.LC3G3D2T = 0;  CLC3GLS2bits.LC3G3D2N = 0;
    CLC3GLS2bits.LC3G3D3T = 0;  CLC3GLS2bits.LC3G3D3N = 0;
    CLC3GLS2bits.LC3G3D4T = 0;  CLC3GLS2bits.LC3G3D4N = 0;
    CLC3POLbits.LC3G3POL = 0;                               //gate2 output polarity
    //JK-F/Fにセットする
    CLC3CONbits.LC3MODE = 6;            //JK-F/Fを選択
   
    //出力設定
    CLC3POLbits.LC3G1POL = 0;           //CLC3 OUTPUT Polarity is not invert
    CLC3CONbits.LC3EN = 1;              //cofigration logic cell enable
}

//******************** NCO初期設定 *********************************************
//  入力    CLC3OUT(2.097152MHz)            
//  処理    Overflow = (2097152*IncrementValue)/2^21=IncrementValue        
//  出力    NCO1OUT(1Hz-1.048576MHz)        
//******************************************************************************
void init_NCO(void){               //NCO初期設定
    NCO1CLKbits.N1CKS = 3;          //NCO1 clock is CLC3OUT(2.097152MHz))
    NCO1CONbits.N1PFM = 0;          //NCO1 fix duty cycle mode
    NCO1CONbits.N1POL = 0;          //NCO1OUT not inverted
    NCO1CONbits.N1OUT = 1;          //NCO1OUT enable
    NCO1ACCL = 0;                   //NCO1 ACCL = 0
    NCO1ACCH = 0;                   //NCO1 ACCH = 0
    NCO1ACCU = 0;                   //NCO1 ACCU = 0
    NCO1INCU = 0x0f;
    NCO1INCH = 0x42;
    NCO1INCL = 0x40;                //1MHz=1000000=0x0f4240
   
    NCO1CONbits.N1EN = 1;           //NCO1 enable
}   

//******************** ADC初期設定 ******************************
//  入力    ロータリースイッチの電圧            
//  処理    入力電圧から0-9の数値に変換する Tad=7.63uSec
//  出力    0-9の数値
//******************************************************************************
void init_ADC(void){            //ADC初期設定
    ADCON0bits.ADCS = 0;            //ADC clk is Fosc
    ADCLKbits.ADCCS = 0x3f;         //ADC conversion clk is Fosc/16=16.777224/128=131kHz(7.63uSec)
    ADREFbits.ADNREF = 0;           //Vref- is VSS
    ADREFbits.ADPREF = 0;           //Vref+ is VDD
    ADPCH = 0x11;                   //ANC1 入力
    ADCON0bits.ADFM0 = 0;           //ADC出力フォーマット:左詰
    ADCON0bits.ADCONT = 0;          //ADGO is cleared upon completion of each conversion trigger
    ADCON0bits.ADON = 1;            //ADS is enable  
}

//******************** ADC開始 ******************************
//  入力    adc_ch(1-7)           
//  処理    入力電圧から0-9の数値に変換する
//  出力    ad_number(0-9)
//******************************************************************************
unsigned char start_ADC(unsigned char adc_ch){                                        //ADC開始
    unsigned char ad_number;
    ADPCH = 0x10 + adc_ch;              //入力adc_chをセット
    ADCON0bits.ADGO = 1;                //ADCスタート
    while(ADCON0bits.ADGO == 1){}       //AD変換完了を待つ
    
    if(ADRESH < 14)         ad_number = 0;
    else if(ADRESH < 42)    ad_number = 1;
    else if(ADRESH < 70)    ad_number = 2;
    else if(ADRESH < 99)    ad_number = 3;
    else if(ADRESH < 127)   ad_number = 4;
    else if(ADRESH < 155)   ad_number = 5;
    else if(ADRESH < 184)   ad_number = 6;
    else if(ADRESH < 212)   ad_number = 7;
    else if(ADRESH < 240)   ad_number = 8;
    else                    ad_number = 9;
    
    return ad_number;   
}

//*************************** 周波数設定1  **************************************
//  入力    frequency(1Hz-1.048575Hz),CLC3OUT(2.097152MHz) 
//          freq_no7,freq_no6,freq_no5,freq_no4,freq_no3,freq_no2,freq_no1;
//  処理    NCOに周波数を設定,表示する
//  出力    frequency,freq_no7,freq_no6,freq_no5,freq_no4,freq_no3,freq_no2,freq_no1
//******************************************************************************
void set_frequency1(void){                              //周波数設定1
    unsigned char nco_u,nco_h,nco_l;
    
    NCO1CLKbits.N1CKS = 4;                                      //NCO入力:CLC3OUT
    
    nco_u = (unsigned char)((frequency >> 16) & 0x0000000f);
    nco_h = (unsigned char)((frequency >> 8) & 0x000000ff);
    nco_l = (unsigned char)(frequency & 0x000000ff);
    NCO1INCU = nco_u;                                           //NCOに値を設定
    NCO1INCH = nco_h;                                           //
    NCO1INCL = nco_l;                                            //
    display_normal();                                           //LCD1行目に[ -- FREQUENCY --]を表示
    display_frequency();                                        //表示
}

//*************************** 周波数設定2  **************************************
//  入力    frequency(1.048576MHz-2.097151MHz),CLC2OUT(4.1943056MHz) 
//          freq_no7,freq_no6,freq_no5,freq_no4,freq_no3,freq_no2,freq_no1;
//  処理    NCOに周波数を設定,表示する
//  出力    frequency,freq_no7,freq_no6,freq_no5,freq_no4,freq_no3,freq_no2,freq_no1
//******************************************************************************
void set_frequency2(void){                              //周波数設定2
    unsigned long frequency2;
    unsigned char nco_u,nco_h,nco_l;
    
        NCO1CLKbits.N1CKS = 3;                                      //NCO入力:CLC2OUT
        frequency2 = frequency >> 1;                             //frequency/2
    
    nco_u = (unsigned char)((frequency2 >> 16) & 0x0000000f);
    nco_h = (unsigned char)((frequency2 >> 8) & 0x000000ff);
    nco_l = (unsigned char)(frequency2 & 0x000000ff);
    NCO1INCU = nco_u;                                           //NCOに値を設定
    NCO1INCH = nco_h;                                           //
    NCO1INCL = nco_l;                                            //
    display_normal();                                           //LCD1行目に[ -- FREQUENCY --]を表示
    display_frequency();                                        //表示
}

//*************************** 周波数設3  **************************************
//  入力    frequency(2.097152MHz-4.1943055MHz),CLC1OUT(8.388608MHz) 
//          freq_no7,freq_no6,freq_no5,freq_no4,freq_no3,freq_no2,freq_no1;
//  処理    NCOに周波数を設定,表示する
//  出力    frequency,freq_no7,freq_no6,freq_no5,freq_no4,freq_no3,freq_no2,freq_no1
//******************************************************************************
void set_frequency3(void){                              //周波数設定3
    unsigned long frequency3;
    unsigned char nco_u,nco_h,nco_l;
    
    NCO1CLKbits.N1CKS = 2;                                      //NCO入力:CLC1OUT
    frequency3 = frequency >> 2;                                 //frequency/4
    
    nco_u = (unsigned char)((frequency3 >> 16) & 0x0000000f);
    nco_h = (unsigned char)((frequency3 >> 8) & 0x000000ff);
    nco_l = (unsigned char)(frequency3 & 0x000000ff);
    NCO1INCU = nco_u;                                           //NCOに値を設定
    NCO1INCH = nco_h;                                           //
    NCO1INCL = nco_l;                                            //
    display_normal();                                           //LCD1行目に[ -- FREQUENCY --]を表示
    display_frequency();                                        //表示
}

//*************************** 周波数設定4  **************************************
//  入力    frequency(4.1943056MHz-8.388607Hz),Fosc(16.777224MHz) 
//          freq_no7,freq_no6,freq_no5,freq_no4,freq_no3,freq_no2,freq_no1;
//  処理    NCOに周波数を設定,表示する
//  出力    frequency,freq_no7,freq_no6,freq_no5,freq_no4,freq_no3,freq_no2,freq_no1
//******************************************************************************
void set_frequency4(void){                              //周波数設定4
    unsigned long frequency4;
    unsigned char nco_u,nco_h,nco_l;
    
    NCO1CLKbits.N1CKS = 0;                                      //NCO入力:Fosc
    frequency4 = frequency >> 3;                                 //frequency/8
    
    
    nco_u = (unsigned char)((frequency4 >> 16) & 0x0000000f);
    nco_h = (unsigned char)((frequency4 >> 8) & 0x000000ff);
    nco_l = (unsigned char)(frequency4 & 0x000000ff);
    NCO1INCU = nco_u;                                           //NCOに値を設定
    NCO1INCH = nco_h;                                           //
    NCO1INCL = nco_l;                                            //
    display_normal();                                           //LCD1行目に[ -- FREQUENCY --]を表示
    display_frequency();                                        //表示
}

//*************************** 周波数設定  **************************************
//  入力    frequency 
//          freq_no7,freq_no6,freq_no5,freq_no4,freq_no3,freq_no2,freq_no1;
//  処理    NCOに周波数を設定,表示する
//  出力    frequency,freq_no7,freq_no6,freq_no5,freq_no4,freq_no3,freq_no2,freq_no1
//******************************************************************************
void set_frequency(void){                              //周波数設定
    unsigned long temp_frequency;
    unsigned char adc_ch;
    
    for(adc_ch=1; adc_ch<8; adc_ch++){
        switch(adc_ch){
            case 1: freq_no1 = start_ADC(adc_ch);   break; 
            case 2: freq_no2 = start_ADC(adc_ch);   break; 
            case 3: freq_no3 = start_ADC(adc_ch);   break;
            case 4: freq_no4 = start_ADC(adc_ch);   break;
            case 5: freq_no5 = start_ADC(adc_ch);   break;
            case 6: freq_no6 = start_ADC(adc_ch);   break;
            case 7: freq_no7 = start_ADC(adc_ch);   break;                 
        }    
    }
    temp_frequency = 1000000*freq_no7 + 100000*freq_no6 + 10000*freq_no5 + 1000*freq_no4 + 100*freq_no3 + 10*freq_no2 + freq_no1;   //
//    test_display_decimal(temp_frequency);                   //TEST バイナリデーターを10進で表示する
//    __delay_ms(100);                                        //TEST Delay 40ms
    
    if(temp_frequency != frequency){                                //前の値と異なる場合のみレジスタ設定および表示を行う
        frequency = temp_frequency; 
        
        if(frequency == 0){                                             //frequencyが0のとき警告を表示する          
            display_higher();                                           //LCD1行目に[set higher frequency]を表示
            display_frequency();                                        //表示
        }
        else if(frequency < 0x100000)   set_frequency1();               //周波数設定1(1Hz         -1.048575MHz)
        else if(frequency < 0x200000)   set_frequency2();               //周波数設定2(1.048576MHz -2.097151MHz)
        else if(frequency < 0x400000)   set_frequency3();               //周波数設定3(2.097152MHz -4.1943055MHz)
        else if(frequency < 0x800000)   set_frequency4();               //周波数設定4(4.1943056MHz-8.388607MHz)

        else if(frequency > 0x7fffff){                                   //frequencyが8388607よりも大きいとき警告を表示する     
            display_lower();                                            //LCD1行目に[set lower frequency]を表示
            display_frequency();                                        //表示
        }
    }   
}

 

    
//***************************** MAIN Routine  **********************************
//******************************************************************************
void main(void) {
    init_OSC();                     //オシレータ初期設定
    init_port();                    //PORT初期設定
    init_LCD();                     //LCD初期設定
    init_NCO();                     //NCO初期設定
    init_CLC1();                    //CLC1初期設定
    init_CLC2();                    //CLC2初期設定
    init_CLC3();                    //CLC3初期設定
    init_ADC();                     //ADC初期設定
    
    while(1){
        set_frequency();            //周波数設定
    }
}




















 






















ソースファイル