/////////////////////////////////////////////////////////////////////////// // File name: // Description: DDS ローカル制御 // Rotary Encorderで周波数の増減 // Notes: 48MHzクロック // SDATAT RC0 // DDS制御 // SCLK RB6 // DDS制御 // FSYNC RC7 // DDS制御 // SCL RC1 // I2C LCD制御 // SDA RC2 // I2C LCD制御 // B_pin RC3 // Rotary Encocrder // btnCmd RC4 // Rotary Encocrder // LED_GRN RC5 // Rotary Encocrder // A_pin RC6 // Rotary Encocrder // LCD_pwr RB4 // I2C LCD電源 // btnUp RB5 // PushSW // btnDn RB7 // PushSW // Language: MPLAB C18 // Target: PIC18F14K50 // --- Copyright (C) 2011-2012 Kazuo Iwamoto All Rights Reserved. --- // // ここから、Myコメント // CQ_DDS_SWEEPERプロジェクト // <動作仕様> // @ DWN_SWを押さないで、P_ONした場合 //   通常モード //   REによるマニュアル設定 // // A DWN_SWを押して、P_ONした場合 //   SWEEPERモード //   10k〜 20MHzまでのスイープ動作 //   ON SWを、START SWとして使う。 //   SWリードに割込みは使わない。 //   RB4ポート出力に、SYNCパルスを出力 // // 2020/9/25 N.Ishii ///////////////////////////////////////////////////////////////////////// #include #include #include #include "SW_i2cLCD.h" #define MonCnt 5 // チャタリングの防止時間 //-- DDS 関連 設定値 ------------------------------------------------- #define SDATA_TRI TRISCbits.TRISC0 #define SCLK_TRI TRISBbits.TRISB6 #define FSYNC_TRI TRISCbits.TRISC7 #define SDATA_LAT LATCbits.LATC0 #define SCLK_LAT LATBbits.LATB6 #define FSYNC_LAT LATCbits.LATC7 #define dds_ctrl 0x0000 #define dds_reset 0x0100 //-- SW 関連 設定値 ------------------------------------------------- #define A_pin PORTCbits.RC6 #define B_pin PORTCbits.RC3 #define btnUp !PORTBbits.RB5 #define btnDn !PORTBbits.RB7 #define btnCmd PORTCbits.RC4 #define LED_GRN LATCbits.LATC5 #define MODE PORTBbits.RB7 // 200924 #define SYNC LATBbits.LATB4 // 200924 //-- コンフィグレーション -------- //14K50 #pragma config CPUDIV = NOCLKDIV #pragma config USBDIV = OFF #pragma config FOSC = HS #pragma config PLLEN = ON #pragma config FCMEN = OFF #pragma config IESO = OFF #pragma config PWRTEN = OFF #pragma config BOREN = OFF #pragma config BORV = 30 // #pragma config VREGEN = ON #pragma config WDTEN = OFF #pragma config WDTPS = 32768 #pragma config MCLRE = OFF #pragma config HFOFST = OFF #pragma config STVREN = ON #pragma config LVP = OFF #pragma config XINST = OFF #pragma config BBSIZ = OFF #pragma config CP0 = OFF #pragma config CP1 = OFF #pragma config CPB = OFF #pragma config WRT0 = OFF #pragma config WRT1 = OFF #pragma config WRTB = OFF #pragma config WRTC = OFF #pragma config EBTR0 = OFF #pragma config EBTR1 = OFF #pragma config EBTRB = OFF //-- Bootloaderを使用するため変更となる各ベクトル ------------------- extern void _startup (void); void isr_high(void); void isr_low(void); #define REMAPPED_RESET_VECTOR_ADDRESS 0x1000 #define REMAPPED_H_ISR_VECTOR_ADDRESS 0x1008 #define REMAPPED_L_ISR_VECTOR_ADDRESS 0x1018 #pragma code reset_vect = REMAPPED_RESET_VECTOR_ADDRESS void _reset (void){ _asm goto _startup _endasm } #pragma interrupt isr_high #pragma interruptlow isr_low save = WREG,BSR,STATUS #pragma code h_int_vect = REMAPPED_H_ISR_VECTOR_ADDRESS void _h_isr (void){ _asm goto isr_high _endasm } #pragma code l_int_vect = REMAPPED_L_ISR_VECTOR_ADDRESS void _l_isr (void){ _asm goto isr_low _endasm } //-- Bootloaderを使用しないときの各ベクトル ------------------- #pragma code HIGH_INTERRUPT_VECTOR = 0x08 void High_ISR (void){_asm goto REMAPPED_H_ISR_VECTOR_ADDRESS _endasm} #pragma code LOW_INTERRUPT_VECTOR = 0x18 void Low_ISR (void){_asm goto REMAPPED_L_ISR_VECTOR_ADDRESS _endasm} #pragma udata // ----------変数の宣言と初期値の設定------------- char btnUpCnt = MonCnt; // チャタリング防止回数定義 char btnUpClean = 0; // チャタリングを排除したSW信号 char btnUpPressed = 0; // チャタリングを排除した「押された」マーク char btnDnCnt = MonCnt; // チャタリング防止回数定義 char btnDnClean = 0; // チャタリングを排除したSW信号 char btnDnPressed = 0; // チャタリングを排除した「押された」マーク char btnCmdCnt = MonCnt; // チャタリング防止回数定義 char btnCmdClean = 0; // チャタリングを排除したSW信号 char btnCmdPressed = 0; // チャタリングを排除した「押された」マーク char waveOut = 0; // DDS 出力 /// スイープ機能用変数 /// 200924 unsigned long F_Start= 10000; unsigned long F_Step= 2000; int Step_Count; int Max_Step_Count= 45; //-------プロトタイプ-------------------------------------------------- char readRE(void); void ito_st(unsigned long, char *, char ); char dspCmdPos(char); void setDDS(int); // DDSに16bitデータを送信 long freq2data(long); // 周波数をDDSデータ値に変換 void setFreq(long); // 周波数データ値をDDSに設定 void InitDDS(void); // DDS初期化 void delay_1sec(void); // 200924 #pragma code //----------------------高優先割込------------------------ void isr_high(){ if(INTCONbits.TMR0IF){ //Timer0からの割込を確認 INTCONbits.TMR0IF = 0; // 割込フラッグをクリア //***************チャタリング防止******************************* // 5.5mSの割込みルーチン内にプログラム // pushSWのチャタリングを排除したSWcleanを生成 // さらに、SWが押されると SWpressed が「1」になる //************************************************************** // チャタリング防止 ------------------------------------ if(btnUpCnt){ // チャタリング防止中なら if(btnUpClean == btnUp) // SWの状態が一致か btnUpCnt--; // 一致なら5回確認 else btnUpCnt = MonCnt; // 不一致なら、さらに5回確認 }else{ // 防止終了後に if(btnUpClean != btnUp){ // SWの状態が変更されたら btnUpClean = btnUp; // 変更状態を反映 if(btnUpClean)btnUpPressed = 1; // ONなら「押された」を1に btnUpCnt = MonCnt; // チャタリング防止期間をセット } } // チャタリング防止 ------------------------------------ if(btnDnCnt){ if(btnDnClean == btnDn) btnDnCnt--; else btnDnCnt = MonCnt; }else{ if(btnDnClean != btnDn){ btnDnClean = btnDn; if(btnDnClean)btnDnPressed = 1; btnDnCnt = MonCnt; } } // チャタリング防止 ------------------------------------ if(btnCmdCnt){ if(btnCmdClean == btnCmd) btnCmdCnt--; else btnCmdCnt = MonCnt; }else{ if(btnCmdClean != btnCmd){ btnCmdClean = btnCmd; if(btnCmdClean)btnCmdPressed = 1; btnCmdCnt = MonCnt; } } // ----------------------------------------------------------- } } //-----------------低優先割込の処理------------------------ void isr_low(){ } // //----------------------メインプログラム------------------------ void main(void){ char cmdPos = 0; // Rotary Encで更新される位 char RE_dir; // Rotary Encの変化量 char msg[] = "12,456,890Hz"; long count = 800; // 発振周波数 char i; long j; PORTA = 0; PORTB = 0; PORTC = 0; TRISA = 0b11111111; // PortA すべて入力 TRISB = 0b10101111; // PortB4 出力 TRISC = 0b01011111; // PortC すべて入力 ANSEL = 0b00000000; // デジタル ANSELH = 0b00000000; /// 電源投入時の、モードピン(DOWN SW)の状態を読込み、各処理に分岐 if(MODE){ OpenTimer0( // Timer 0 設定(5.5mSecごと) TIMER_INT_ON & T0_16BIT & T0_SOURCE_INT & T0_PS_1_1 ); INTCON2bits.TMR0IP = 1; // 高優先割込 RCONbits.IPEN=1; // 2段階の割込に設定 INTCONbits.GIEH=1; // 高優先割込を許可 INTCONbits.GIEL=0; // 低優先割込を無効 LCD_int(); // LCD初期化 readRE(); // Rotary Enc空読み ito_st(count, msg, 10); // 上桁 LCD_str(msg); // 周波数を表示 dspCmdPos(cmdPos); // 下桁 表示 LCD_posyx(1,12); // 出力offを表示 LCD_ROMstr(" OFF"); InitDDS(); // DDS初期化 // *************** 繰返しループ *************************************** while(1){ RE_dir = readRE(); // エンコーダの変化分を得る if(RE_dir){ // エンコーダが変化していれば j=1; // ---- cmdPosから変化させる i=cmdPos; // ---- 単位を10のべき数 while(i--)j *= 10; // ---- 計算でjに得る count += (RE_dir * j); // 変化分を加算する if(count < 0)count=0; // 有効範囲の確認・修正 if(count > 20000000)count=20000000; ito_st(count, msg, 10); // 文字に変換し LCD_posyx(0,0); // 周波数を表示 LCD_str(msg); // if(waveOut){ // 出力中なら setFreq(count); // 周波数を更新 } } // cmd bottonを押したとき ------------------------------------ if(btnCmdPressed){ // ボタンが押されたら btnCmdPressed=0; LCD_posyx(1,12); // 出力表示位置を指示 if(waveOut){ // 出力ON中なら LCD_ROMstr(" OFF"); // 表示をoff LED_GRN=0; // 緑LEDをoff waveOut=0; // 出力flagをoff setDDS(dds_reset); // DDSをリセット }else{ // 出力OFF中なら LCD_ROMstr("=ON="); // 表示をON LED_GRN=1; // 緑LEDをON waveOut=1; // 出力flagをON setFreq(count); // DDSに周波数設定しON } } // up bottonを押したとき ------------------------------------ if(btnUpPressed){ // ボタンが押されたら btnUpPressed=0; if(++cmdPos > 7)cmdPos = 7; // cmdPosを確認・修正 dspCmdPos(cmdPos); // cmdPosの位置を表示 } // up bottonを押したとき ------------------------------------ if(btnDnPressed){ // ボタンが押されたら btnDnPressed=0; if(--cmdPos < 0)cmdPos = 0; // cmdPosを確認・修正 dspCmdPos(cmdPos); // cmdPosの位置を表示 } // } // end of while(1) } else{ //// スイープ・モードを実行 // SYNC= 0; LCD_int(); // LCD初期化 /// 1行目に"Sweep Mode"表示 LCD_posyx(0,0); LCD_ROMstr("Sweep Mode"); setFreq(10000); // デフォルトDDS出力設定= 10000Hz SYNC= 0; //// Main Loop while(1){ do { delay_2ms; // チャッタ回避 }while(btnCmd); // Start SW ON 待ち(ON/OFF SWと兼用) /// 同期パルス出力 SYNC= 1; delay_1ms; SYNC= 0; while(F_Start != 20000000) { /// スイープ中だったら実行(1つ手前の、18000000Hzまで実行中) if(F_Step == 2000000) Max_Step_Count= 5; // 10Mから上は、12M,14M,16M,18Mまでこのループでスイープ /// 各周波数帯での、DDSステップ出力 for(Step_Count= 0; Step_Count < Max_Step_Count; ++Step_Count) { /// 変数F_Startの値を、液晶の2行目に表示 ito_st(F_Start, msg, 10); LCD_posyx(1,0); LCD_str(msg); setFreq(F_Start); // F出力(10000, 12000, 14000, 16000・・・) delay_1sec(); F_Start += F_Step; } F_Step *= 10; // 次の周波数帯の、ステップ数セット(20k, 200k, 2000k) } /// 変数F_Startの値を、液晶の2行目に表示(最終周波数:20000000Hz) ito_st(F_Start, msg, 10); LCD_posyx(1,0); LCD_str(msg); setFreq(F_Start); // 最終周波数:20000000Hz出力 /// スイープが終了したら、開始周波数とステップ数を初期化 F_Start= 10000; F_Step= 2000; Max_Step_Count= 45; /// 2行目に"Sweep End"表示 LCD_posyx(1,0); LCD_ROMstr("Sweep End "); } } } // end of main //------------------ readRE ------------------------------ // 直前の状況と今回の状況を合わせた16通りの組合せから // 左右どちらに回転をしたのか判定することができる // 戻り値は (-1,0,1) の3通り //-------------------------------------------------------- char readRE(void){ static char RE_states[] = {0,-1,1,0,1,0,0,-1,-1,0,0,1,0,1,-1,0}; static char RE_old = 0; // 共通変数(値は保存) char RE_now; RE_now = B_pin * 2 + A_pin; // 今回情報の読取 RE_old <<= 2; // 前回の読取値と RE_old |= ( RE_now & 0x03 ); // 今回の読取値を組合わせる return ( RE_states[( RE_old & 0x0F )]); // 変化分を戻り値をする } //------------------ dspCmdPos ------------------------------ // comPos記号^を画面に表示する //-------------------------------------------------------- char dspCmdPos(char cmdPos){ char pos[]={9,8,7,5,4,3,1,0}; LCD_posyx(1,0); // position Markを表示 LCD_ROMstr("__M___K___"); LCD_posyx(1,pos[cmdPos]); // 変更位置を表示 LCD_dat('^'); } //****** 正整数を文字列に変換する関数 ************************ // num 変換する整数 (ゼロサプレスあり) // strAdd 変換結果の格納される文字列 (コンマ あり) // digit 変換される文字数 //************************************************************ void ito_st(unsigned long num, char *strAdd, char digit){ char i; char flag=1; //ゼロサプレス Flag char coma=0; //コンマ Flag strAdd += digit; // 文字列の最後 for(i=digit; i>0; i--) { // 下位桁から処理 strAdd--; // 1桁上に if (flag == 1){ if (coma++ == 3){ //コンマ の位置か *strAdd = ','; //コンマ を格納 coma=0; }else{ // 1桁の数値を文字で格納 *strAdd = (num % 10) + 0x30; num = num / 10; // 次桁の準備 if (num == 0) flag=0; // ゼロなら以降は抑制 } }else{ // 上位の0は抑制する *strAdd = 0x20; // 0の代わりにスペース格納 } } } // ------------------------------------------------------------------- // DDSに16bitデータを送信する // ------------------------------------------------------------------- void setDDS(int data){ char i; SDATA_TRI=0; // SDATAを出力に設定 FSYNC_LAT=0; // FSYNCをLow for(i=0;i<16;i++){ SDATA_LAT=(data>>(15-i)) & 1; // DATAを順に出力 SCLK_LAT=0; // SCLKをLow SCLK_LAT=1; // SCLKをHi } FSYNC_LAT=1; // FSYNCをHi SDATA_TRI=1; // SDATAを入力に設定 } // ------------------------------------------------------------------- // 周波数をDDSにセットするデータ値に変換する // ------------------------------------------------------------------- long freq2data(long data){ return (long)(((float)data)/(75000000.0f/1024.0f/1024.0f/256.0f)); } // ------------------------------------------------------------------- // 周波数データ値をDDSに設定する // ------------------------------------------------------------------- void setFreq(long data){ data = freq2data(data); // 周波数をDDSデータ値に変換 setDDS(0x1000 | dds_ctrl); // MSB周波数Regを選択 setDDS(0x4000 | (data>>14)); // 周波数をFREQ0に書込 setDDS(0x0000 | dds_ctrl); // LSB周波数Regを選択 setDDS(0x4000 | (data & 0x03FFF)); // 周波数をFREQ0に書込 } // ------------------------------------------------------------------- // DDSを初期設定する // ------------------------------------------------------------------- void InitDDS(void){ SCLK_TRI =0; // SCLKを出力に設定 FSYNC_TRI =0; // FSYNCを出力に設定 setDDS(dds_reset); // Reset ON } // ------------------------------------------------------------------- // 1秒遅延関数 // ------------------------------------------------------------------- void delay_1sec(void){ int i; for(i= 0;i<500;i++){ delay_2ms; } }