/************************************************************************* * DDS_AD9833_Test_2 * * 中華製の「GAOHOU_AD9833 DDS モジュール」を試す。その2 * マスタークロック:25MHz * * <操作仕様> * @ Step SW(SW3)により可変ステップを設定 *   SWを押す毎に、1, 10, 100, 1000, 10000, 100000, 1000000Hzの、7種類の * 可変ステップを選択する。 * A RE(ロータリエンコーダ:手持ちのノンクリックタイプ使用)により、@で設定されたステップで * 出力周波数を可変する。 * * <その他仕様> * @ 出力周波数範囲= 1Hz〜 10MHz(デフォルトは、1000Hz) * A Step周波数のデフォルト= 1Hz * B 液晶表示デザイン * 0 1 2 3 4 5 6 7 8 9 a b c d e f * --------------------------------- * F r q = x x x x x x x x H z * S t e p = x x x x x x x H z * --------------------------------- * * LCD unlook busy : not switch direction (write fixed) * * CPU PIC24FJ64GA002 * * Condition: * 8MHz Internal RC oscillator, 4x PLL (8MHzx4= 32MHz) * Fcy=32MHz/2=16MHz, Tcy=62.5ns * * 2018/10/23 * 作成:N.Ishii ***************************************************************************/ #include "p24FJ64GA002.h" #include "LCD_Lib3.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 // AD9834 sync #define DDS_SCLK LATAbits.LATA4 // AD9834 clock #define DDS_SDATA LATBbits.LATB5 // AD9834 data #define SW1 PORTBbits.RB0 // Step SW #define SW2 PORTBbits.RB1 // 未使用 /// ロータリエンコーダー #define RE_A PORTBbits.RB6 #define RE_B PORTBbits.RB7 /// Message // 可変メッセージ char MsgFrq[] = "Frq = xxxxxxxxHz"; // 固定メッセージ char MsgDefFrq[] = "Frq = 00001000Hz"; char MsgS1[] = "Step = 0000001Hz"; char MsgS10[] = "Step = 0000010Hz"; char MsgS100[] = "Step = 0000100Hz"; char MsgS1K[] = "Step = 0001000Hz"; char MsgS10K[] = "Step = 0010000Hz"; char MsgS100K[] = "Step = 0100000Hz"; char MsgS1M[] = "Step = 1000000Hz"; 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 /// Cheak SW ON: SW1(SKIP) or SW2(BOOST) 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= 0xFFE6; // RA4:SCLK OUT, RA3:赤LED, RA2-1:NOT USED IN, RA0:SCLK_OUT 141224 TRISB= 0x03CF; // RB15-12:D7-4_OUT, RB11:RS_OUT, RB10:STB_OUT, // RB9,8:未使用IN, RB6:RE-A_IN, RB7:RE-B_IN // RB5:SDATA_OUT, RB4:FSYNC_OUT, RB3-2:NOT USED IN, RB1-0:SW2:未使用、SW1:STEP SW /// LED消灯 LATAbits.LATA3= 1; // 赤 /// 内部プルアップ設定 CNPU1= 0x0030; // RB1(CN4):SW2, RB0(CN5):SW1 CNPU2= 0x01E0; // RB6(CN24):RE-A, RB7(CN23):RE-B, RB8(CN22):未使用,RB9(CN21):未使用 /// 状態変化割込み設定 CNEN2 = 0x0100; // Valid RE-A:CN24 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初期化 lcd_clear(); // 全消去 /// デフォルト液晶表示 lcd_str(MsgDefFrq); // 1行目に出力周波数設定表示 lcd_cmd(0xC0); // 2行目の先頭に移動 lcd_str(MsgS1); // 2行目にスキップ周波数設定表示 freq_to_serial(1000); // デフォルトDDS出力= 1000Hz /// Main Loop while(1) { /// SW1(STEP SW)読込み delay_ms(10); // チャッタ回避 if(!SW1) { ++SwCount; if(SwCount > 7) SwCount= 1; lcd_cmd(0xC0); switch(SwCount){ case 1: StepSet= 1; lcd_str(MsgS1); break; case 2: StepSet= 10; lcd_str(MsgS10); break; case 3: StepSet= 100; lcd_str(MsgS100); break; case 4: StepSet= 1000; lcd_str(MsgS1K); break; case 5: StepSet= 10000; lcd_str(MsgS10K); break; case 6: StepSet= 100000; lcd_str(MsgS100K); break; case 7: StepSet= 1000000; lcd_str(MsgS1M); break; default:; break; } while(!SW1); // SWリリース待ち(Hiになるまで待つ) } if(ChangeFlag) { /// DDS出力 freq_to_serial(FrqSet); /// 変数FrqSetの値を、液晶の1行目に表示 ltostring(8, FrqSet, MsgFrq + 6); lcd_cmd(0x80); lcd_str(MsgFrq); 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; // 次の桁へ } }