/************************************************************************* * QVGA_7SEG_DISP_AD9833_TEST * * 本番に備えてDDSモード(7segで表示)のデモソフトを作ってみる。 * * <DDS部の操作仕様> * @ Step SW(SW3)により可変ステップを設定 *   SWを押す毎に、1, 10, 100, 1000, 10000, 100000, 1000000Hzの、7種類の * 可変ステップを選択する。 * A RE(ロータリエンコーダ:手持ちのノンクリックタイプ使用)により、@で設定されたステップで * 出力周波数を可変する。 * * <その他仕様> * @ 出力周波数範囲= 1Hz〜 10MHz(デフォルトは、1000Hz) * A Step周波数のデフォルト= 1Hz * QVGA : UL024TF * * CPU PIC24FJ64GA002 * * Condition: * 8MHz Internal RC oscillator, 4x PLL (8MHzx4= 32MHz) * Fcy=32MHz/2=16MHz, Tcy=62.5ns * * 2018/10/31 * 作成:N.Ishii ***************************************************************************/ #include "p24FJ64GA002.h" #include "colorlcd_libPIC24FVH_v2.h" // Set Configuration Word 1 _CONFIG1 ( JTAGEN_OFF & // JTAG Port: OFF GCP_OFF & // Code Protect: OFF GWRP_OFF & // Write Protect:OFF BKBUG_OFF & // Background Debug: OFF COE_OFF & // Clip On Emulation: OFF ICS_PGx1 & // Select ICD Pin: EMUC/EMUD-> PGC1/PGD1 For Common Use FWDTEN_OFF // WDT: OFF ) // Set Configuration Word 2 _CONFIG2 ( IESO_OFF & // 2 Speed Start Up: OFF FNOSC_FRCPLL & // 8MHz Internal RC oscillator, 4x PLL-> 8MHzx4=32MHz FCKSM_CSDCMD & // Change Clock Control: OFF Clock Monitor: OFF OSCIOFNC_ON & // OSCO/RA3 function: Used RA3(外部OSCを使う時は、OSCIOFNC_OFFと記述) IOL1WAY_OFF & // RP Register Protection: Unlimited Writes To RP Registers I2C1SEL_PRI & // I2C1 pins Select: Use Primary I2C1 pins POSCMOD_NONE // Oscillator Selection: Primary disabled ) /// DDSコントロールポート定義 #define DDS_FSYNC LATBbits.LATB4 // AD9833 FSYNC #define DDS_SCLK LATAbits.LATA1 // AD9833 SCLK #define DDS_SDATA LATAbits.LATA0 // AD9833 SDATA #define SW1 PORTBbits.RB0 // Step SW #define SW2 PORTBbits.RB1 // 未使用 /// ロータリエンコーダー #define RE_A PORTBbits.RB2 #define RE_B PORTBbits.RB3 /// メッセージテーブル char str_Start[] = "Start Test!!"; char str_Hz1[] = "Hz(FRQ)"; char str_Hz2[] = "Hz(STEP)"; unsigned long FrqSet= 1000; unsigned long StepSet= 1; char ChangeFlag= 0; char SwCount= 1; /// 関数プロトタイプ宣言 void dds_dataset(unsigned long data, unsigned int bt); void freq_to_serial(unsigned long f); //void ltostring(char digit, unsigned long data, char *buffer); /**************************************************************** * 割込み処理関数(RE_A状態変化割込み) * A相の立下りを基準に、B相のレベルを読込んで回転方向を判断 * *<説明> * 電源ON時に、何もしなくてもRE出力が、立上る(両接点オープン時) * ことがあるので、A相の立上りで割込みが入ってしまう。 * 電源ON時に、何もしなくてもRE出力が、Lo(両接点クローズ時) * の場合は、立下がることはないので余分な割込みは入らない。 * そのために、A相の立下りを基準に、判断している。 *****************************************************************/ void __attribute__((interrupt, no_auto_psv)) _CNInterrupt(void) { IFS1bits.CNIF = 0; // Clear CN Interrupt Flag /// RE読込み delay_ms(5); if (!RE_A) { // A相の割込みが入った時、A相が、Loか?(つまり立下りか?) if(RE_B) { // 時計回り(B相が、Hi)だったら、インクリメント FrqSet += StepSet; if(FrqSet > 10000000) FrqSet= 10000000; } else { /// 反時計回り(B相が、Lo)だったら、ディクリメント FrqSet -= StepSet; if(FrqSet < StepSet) FrqSet= StepSet; } ChangeFlag= 1; } } /***************** * メイン関数 ******************/ int main(void) { CLKDIV= 0; // クロック分周 1:1 AD1PCFG= 0xFFFF; // 全ポートをディジタルに指定 /// ポートの入出力モード設定 TRISA = 0xFFE4; // **** // **** // ***RA4:0_RST // RA3:0_LED, RA2:1_未使用, RA1:0_SCLK, RA0:0_SDATA TRISB = 0x000F; // RB15-12:0_DB7-4 // RB11-8:0_DB3-0 // RB7:0_WR, RB6:0_RS, RB5:0_CS, RB4:0_FSYNC // RB3:1_RE-B, RB2:1_RB-A, RB1:1_未使用, RB0:1_STEP SW /// LED消灯 LATAbits.LATA3= 1; // 赤 /// 内部プルアップ設定 CNPU1= 0x00F0; // CN4(RB0):STEP SW, CN5(RB1):SW2, CN6(RB2):RE-A, CN7(RB3):RE-B→ b7-4 /// 状態変化割込み設定 CNEN1 = 0x040; // Valid RE-A:CN6→ b6 IPC4bits.CNIP = 5; IEC1bits.CNIE = 1; //Enable SW INT /// DDS初期化の前に、MCLKが安定するまでの待機時間を追加 delay_ms(100); /// DDS制御信号レベル初期化と、DDSリセットコマンド転送 DDS_FSYNC= 1; // FSYNC(CS)は、アクティブローなので、待機時は、'1' DDS_SCLK= 1; // AD9834は、立下りエッジ読込みなので、待機時は、'1' DDS_SDATA= 0; // DATAは、'0'待機 /// DDS RESET dds_dataset(0x0100, 16); // RESET ON /// 開始メッセージ出力 lcd_Init(); lcd_Clear(BLACK); lcd_Str(0, 0, str_Start, CYAN, BLACK); delay_ms(1000); lcd_Clear(BLACK); /// DDS初期画面表示:FRQ:1000Hz/ STEP:1Hz Draw7seg(0, 4, 1000, 8, WHITE, BLACK); // 周波数設定値 lcd_Str(12, 1, str_Hz1, WHITE, BLACK); // "Hz (FRQ)" Draw7seg(126, 36, 1, 1, GREEN, BLACK); // ステップ設定値 lcd_Str(12, 3, str_Hz2, GREEN, BLACK); // "Hz (STEP)" /* LATAbits.LATA3= 0; // 赤 while(1); */ freq_to_serial(1000); // デフォルトDDS出力= 1000Hz /// Main Loop while(1) { /// SW1(STEP SW)読込み delay_ms(10); // チャッタ回避 if(!SW1) { ++SwCount; if(SwCount > 7) SwCount= 1; Draw7seg(18, 36, 8888888, 7, BLACK, BLACK); // ステップ表示前に、7桁分の表示エリアクリア switch(SwCount){ case 1: StepSet= 1; Draw7seg(126, 36, 1, 1, GREEN, BLACK); break; case 2: StepSet= 10; Draw7seg(108, 36, 10, 2, GREEN, BLACK); break; case 3: StepSet= 100; Draw7seg(90, 36, 100, 3, GREEN, BLACK); break; case 4: StepSet= 1000; Draw7seg(72, 36, 1000, 4, GREEN, BLACK); break; case 5: StepSet= 10000; Draw7seg(54, 36, 10000, 5, GREEN, BLACK); break; case 6: StepSet= 100000; Draw7seg(36, 36, 100000, 6, GREEN, BLACK); break; case 7: StepSet= 1000000; Draw7seg(18, 36, 1000000, 7, GREEN, BLACK); break; default:; break; } while(!SW1); // SWリリース待ち(Hiになるまで待つ) } if(ChangeFlag) { /// DDS出力 freq_to_serial(FrqSet); /// 変数FrqSetの値を、液晶の1行目に表示 Draw7seg(0, 4, FrqSet, 8, WHITE, BLACK); ChangeFlag= 0; } } } /************************************************************************** * serial data send (MSB first) * 16ビット(bt=16で指定)SPI転送 * AD9833は、SCLKの立下りエッジでデータを読込む (規格:SCLK=40MHzmax) ****************************************************************************/ void dds_dataset(unsigned long data, unsigned int bt) { unsigned int i; DDS_FSYNC = 0; for(i = bt; i > 0 ; i--) { DDS_SDATA = (data >> (i - 1)) & 0x00000001; DDS_SCLK = 0; DDS_SCLK = 1; } DDS_FSYNC = 1; } /******************************************************************** * AD9833 DDS control (frequency to serial code) * 希望の出力周波数:fから、シリアルコードを算出し、シリアル転送する。 *********************************************************************/ void freq_to_serial(unsigned long f) { unsigned long msb, lsb; unsigned long data; data = (unsigned long)(((float)f) / (25000000.0 / (1024.0*1024.0*256.0))); // Fmclk/2^28をフロートで計算し、結果を32bit整数型にキャスト msb = (data >> 14) + 0x4000; // 上位14bit送信データ+4000H(周波数レジスタアドレス指定(b15=0.b14=1):FREQ0レジ)を、msbにセット lsb = (data & 0x00003fff) + 0x4000;// 下位14bit送信データ+4000H(周波数レジスタアドレス指定(b15=0.b14=1):FREQ0レジ)を、lsbにセット dds_dataset(0x2000, 16); //// 制御ビットへの書込み(b15=0.b14=0) /// b13:B28='1':2つの連続した16bit転送で完全なコントロールワードをロード /// 以下の、b8,5,1=0 設定でサイン波出力 // b8:RESET='0':解除 // b5:OPBITEN='0':DACが、VOUTに接続される // b3:DIV2='0':OPBITEN='0'の時は、このビットは関係なくなる // b1:MODE='0':上記条件の場合、サイン波出力(b1:MODE='1'で、三角波出力) // dds_dataset(0x2028, 16); // 矩形波出力:DACデータのMSB出力確認のため dds_dataset(lsb, 16); // lsb転送(下位14ビットの周波数レジスタ0のデータを、b15,14のコントロールビットと共に転送) dds_dataset(msb, 16); // msb転送(上位14ビットの周波数レジスタ0のデータを、b15,14のコントロールビットと共に転送) dds_dataset(0xC000, 16); // 位相レジスタ初期化:0 } /* ////////////////////////////////////////////////////////// // Numerical Value-> Ascci Convert (long) ////////////////////////////////////////////////////////// void ltostring(char digit, unsigned long data, char *buffer) { char i; buffer += digit; // 最後の数字位置 for(i=digit; i>0; i--) { // 変換は下位から上位へ buffer--; *buffer = (data % 10) + '0'; // ASCIIへ data = data / 10; // 次の桁へ } } */