目次

DDS制御スケッチ

 DDSとATmega168を同一基板上に配置して
 ロータリースイッチ、プッシュスイッチ
 等をつけて、任意の周波数の発振器に
 仕立ててみます。



 ボックスに入れたインタフェース部分は
 以下とします。



 ブロック図は、以下です。



 各デバイスに必要なピン数とピン割当てを
 下図を見ながら、考えていきます。



 DDS
  入手したDDSは、電源を含め5ピン必要です。
  電源以外は、次の3ピンで周波数、位相関係
  のパラメータを与えます。
   PB2 W_CLK
   PB1 FQ_UD
   PB0 DATA

  Arduinoのピン番号にあわせると、以下。
   #define W_CLK 10
   #define FQ_UD 9
   #define DATA  8



 LCD
  2行16けたのLCDを利用するとして
  バス幅を4ビットとすると、6ピンが
  まとまっているとよいので、ポートC
  で制御します。
   #define E  19
   #define RS 18
   #define D7 17
   #define D6 16
   #define D5 15
   #define D4 14



 rotary encoder
  ロータリーエンコーダは、2ピンを必要とします。
  A相の立ち上がりエッジを割込みで取得し、その
  ときのB相の論理値で回転方向を確定します。

  Arduinoを構成するATmega168では、PD2、PD3を
  外部割込みピンとできるので、PD2をA相に接続
  します。



  ピンアサインは、以下。

   #define A_PHA 2
   #define B_PHA 3

 toggle switch
  トグルスイッチは、中立の2ピンタイプを使うと
  して考えます。



  接続がないときにスイッチの状態をHに固定するため
  入力ピンをプルアップします。

  論理値の組合せと、機能を決めます。

  10 周波数増減幅を100kHzに固定
  11 周波数増減幅を10kHzに固定
  01 周波数増減幅を1kHzに固定
  00 (使わない)

  ピンアサインを以下とします。



  コードで利用できるように定義します。

   #define C_TOGGLE 0
   #define D_TOGGLE 1

 enter switch
  エンタースイッチは、ロータリーエンコーダで
  設定した周波数を、EERPOM内に記憶する目的で
  使います。

  プッシュスイッチを利用し、内蔵プルアップ抵抗を
  含んだピンに接続します。



  コード利用できるように定義します。

   #define ENTER 4

 PTT switch
  PTTは、送受信の周波数を切り替えるために
  使います。PTTを押すと送信、はなして受信
  の周波数をDDSに与えます。

  プッシュスイッチを利用し、内蔵プルアップ抵抗を
  含んだピンに接続します。



  コード利用できるように定義します。

   #define PTT 5

 ピンアサインを決めたので、具体的なスケッチを
 記述していきます。


入出力方向設定  Arduinoであっても、AVRと同じ使い方ができます。  マイコンのプログラムを記述する場合、ピンの  入出力方向と初期値を最初に指定します。  Arduinoの場合、関数setupの中に、初期値と入出力  の方向を定義していきます。  ポートBにDDSを接続するので、PORTBとDDRBを  利用して、初期化します。    #define W_CLK 10    #define FQ_UD 9    #define DATA 8 PORTB = 0x00 ; DDRB = 0xff ; /* all output */  ポートCにLCDを接続するので、PORTCとDDRCを  初期化します。    #define E 19    #define RS 18    #define D7 17    #define D6 16    #define D5 15    #define D4 14 PORTC = 0x00 ; DDRC = 0xff ; /* all output */  ポートDにスイッチ類を接続するので、PORTDとDDRDを  初期化します。PORTDは、プルアップ抵抗を生かすため  該当ビットに1を設定します。    #define C_TOGGLE 0    #define D_TOGGLE 1    #define A_PHA 2    #define B_PHA 3    #define ENTER 4    #define PTT 5 PORTD = 0xff ; /* pull up */ DDRD = 0x00 ; /* all input */  関数setupにまとめると、以下。    #define C_TOGGLE 0    #define D_TOGGLE 1    #define A_PHA 2    #define B_PHA 3    #define ENTER 4    #define PTT 5    #define W_CLK 10    #define FQ_UD 9    #define DATA 8    #define E 19    #define RS 18    #define D7 17    #define D6 16    #define D5 15    #define D4 14 void setup() { // initialize switches pin assignment PORTD = 0xff ; /* pull up */ DDRD = 0x00 ; /* all input */ // initialize DDS pin assignment PORTB = 0x00 ; DDRB = 0xff ; /* all output */ // initialize LCD pin assignment PORTC = 0x00 ; DDRC = 0xff ; /* all output */ }
DDSパラメータ設定  DDSは、32ビットの周波数分周比と8ビットのコマンド  の合計40ビットをシリアル処理で転送します。  32ビットは、LSBから順番にDATAに出力し  W_CLKのfalling_edgeで、内部レジスタに  記憶させます。  コマンドも同様にLSBから順番にシリアル転送します。  コマンドは固定として、周波数だけを変更する関数 update_freqを定義しました。 typedef unsigned long ULONG ; void update_freq(ULONG x) { int i ; int tmp ; // enable FQ_UD PORTB &= ~0x02 ; // send frequency for ( i = 0 ; i < 32 ; i++ ) { // impress PORTB &= ~0x01 ; if ( x & 1 ) { PORTB |= 0x01 ; } // clock : H PORTB |= 0x04 ; // shift x >>= 1 ; // clock : L PORTB &= ~0x04 ; } // send command tmp = 0 ; for ( i = 0 ; i < 8 ; i++ ) { // impress (DATA) PORTB &= ~0x01 ; if ( tmp & 1 ) { PORTB |= 0x01 ; } // clock : H (W_CLK) PORTB |= 0x04 ; // shift tmp >>= 1 ; // clock : L (W_CLK) PORTB &= ~0x04 ; } // disable FQ_UD PORTB |= 0x02 ; }  論理演算を利用し該当するビットをセット、リセット。  また、シフト演算でLSBを順次切り替えています。
ロータリーエンコーダ処理  周波数を増減するために、ロータリーエンコーダを  利用します。  ロータリーエンコーダのA相のrising_edgeを、外部  割込みで検知して、周波数を増やすのか減らすのか  を判断します。  Arduinoは、外部割込みをattachInterruptで処理します。  関数attachInterruptは、外部割込みピンのどちらを  利用するのかを指定し、実際に仕事をする関数名を  聞いて、レベルトリガーかエッジトリガーの選択が  できるようになっています。  実際に仕事をする関数(割込みハンドラ)をincdecfreqと  します。関数定義は、以下です。 void incdecfreq(void) { int dir ; // default dir = -1 ; // get B phase if ( PORTD & 0x08 ) { dir = 1 ; } // update frequency frequency += dir * displacement ; }  A相は、ポートDのPD2に接続するので、setupの中に  次のステートメントを入れておきます。 attachInterrupt(0,incdecfreq,RISING)  AVRは、外部割込みはINT0、INT1をもち、それぞれ  ピンはPD2、PD3にアサインされています。A相が  どちらのピンに接続されているかを確認してから  関数attachInterruptのパラメータを決めます。  外部割込みを使えるように、setupに追加します。 void setup() { // initialize switches pin assignment PORTD = 0xff ; /* pull up */ DDRD = 0x00 ; /* all input */ // initialize DDS pin assignment PORTB = 0x00 ; DDRB = 0xff ; /* all output */ // initialize LCD pin assignment PORTC = 0x00 ; DDRC = 0xff ; /* all output */ // enable INT0 attachInterrupt(0,incdecfreq,RISING) }
周波数幅設定  周波数増減は、ロータリーエンコーダを利用しますが  増減幅は、トグルスイッチで指定します。  中立があるトグルスイッチで、3状態を指定できます。  タイマー割込みで、2ビットのスイッチ状態を  常に読込み、シフトレジスタに状態を入れます。  タイマー割込み処理の内容を簡単で、以下。 typedef unsinged char UBYTE ; UBYTE tmp ; UBYTE csft100 ; UBYTE csft10 ; UBYTE csft1 ; UBYTE dflag ; // MtTimer2 interrupt handler void update_sw() { // shift csft100 <<= 1 ; csft10 <<= 1 ; csft1 <<= 1 ; // mask csft100 &= 0x03 ; csft10 &= 0x03 ; csft1 &= 0x03 ; // get switch state tmp = PIND & 0x03 ; // update if ( tmp == 0x01 ) { csft100 |= ON ; } // displacement = 100 if ( tmp == 0x03 ) { csft10 |= ON ; } // displacement = 10 if ( tmp == 0x02 ) { csft1 |= ON ; } // displacement = 1 // judge if ( csft100 == 0x01 ) { dflag = 1 ; } if ( csft10 == 0x03 ) { dflag = 3 ; } if ( csft1 == 0x01 ) { dflag = 2 ; } }  2スイッチの状態を取得し、計数フラグに値を  入れ、関数loopの中にある処理ブロックに通知  します。  計数フラグを受取る側では、フラグ値を利用して  周波数幅を設定します。  計数フラグの値で、周波数幅を設定しますが  すでに該当値になっていれば、再設定なしで  終了します。 関数loop内の周波数幅設定ブロック処理は、次の  ように簡単になります。 UBYTE displacement ; if ( dflag == 1 ) { dflag = 0 ; if ( displacement != 100 ) { displacement = 100 ; } } if ( dflag == 3 ) { dflag = 0 ; if ( displacement != 10 ) { displacement = 10 ; } } if ( dflag == 2 ) { dflag = 0 ; if ( displacement != 1 ) { displacement = 1 ; } }  割込み処理を使えるように、関連するパラメータを  setup内で設定します。 void setup() { // initialize switches pin assignment PORTD = 0xff ; /* pull up */ DDRD = 0x00 ; /* all input */ // initialize DDS pin assignment PORTB = 0x00 ; DDRB = 0xff ; /* all output */ // initialize LCD pin assignment PORTC = 0x00 ; DDRC = 0xff ; /* all output */ // enable INT0 attachInterrupt(0,incdecfreq,RISING) // 10ms period MsTimer2::set(10,update_sw); // enable Timer2 MsTimer2::start(); // initialize values tmp = 0 ; csft100 = 0 ; csft10 = 0 ; csft1 = 0 ; dflag = OFF ; displacement = 10 ; }  タイマー割込みで、常にスイッチ状態を通知されますが  該当周波数幅であれば設定なし、異なれば設定する仕様  です。
周波数記憶  Enterボタンは、ロータリーエンコーダで設定した  送信と受信の周波数を内蔵EEPROMに記憶します。  周波数を記憶しておくと、電源を入れたときに  その周波数を採用します。  Enterボタンの状態は、シフトレジスタを利用して  逐次記憶していきます。記憶値から、rising_edge  を抽出して、loopの中にある処理ブロックに通知  します(方式は、周波数幅設定と同じです)。  いつ押されるかわからないときは、タイマー割込み  を利用してrising_edgeを捕捉します。  タイマー割込みを使うので、次のようにシフトレジスタ  とフラグを利用します。 typedef unsinged char UBYTE ; UBYTE tmp ; UBYTE csft100 ; UBYTE csft10 ; UBYTE csft1 ; UBYTE esft ; UBYTE dflag ; UBYTE eflag ; // MtTimer2 interrupt handler void update_sw() { // shift csft100 <<= 1 ; csft10 <<= 1 ; csft1 <<= 1 ; esft <<= 1 ; // mask csft100 &= 0x03 ; csft10 &= 0x03 ; csft1 &= 0x03 ; esft &= 0x03 ; // get switch state tmp = PIND & 0x13 ; // update if ( (tmp & 0x03) == 0x01 ) { csft100 |= ON ; } // displacement = 100 if ( (tmp & 0x03) == 0x03 ) { csft10 |= ON ; } // displacement = 10 if ( (tmp & 0x03) == 0x02 ) { csft1 |= ON ; } // displacement = 1 if ( (tmp & 0x10) == 0x10 ) { esft |= ON ; } // enter // judge if ( csft100 == 0x01 ) { dflag = 1 ; } if ( csft10 == 0x03 ) { dflag = 3 ; } if ( csft1 == 0x01 ) { dflag = 2 ; } if ( esft == 0x01 ) { eflag = ON ; } } 関数loop内の周波数記憶処理は、次のように単純です。 if ( eflag == ON ) { eflag = OFF ; // show '*' display_enter('*',15); // store both frequency store_frequency(); // clear '*' display_enter(' ',15); }  LCDには、周波数を記録していることがわかるよう  '*'を表示し、記録が終われば消します。  2つの関数store_frequency、display_enterは  後で定義します。
送受信切替え  PTTボタンは、送受信周波数を切り替えます。  通常は、DDSには受信周波数を発振させておき  PTTボタンを押すと、送信周波数に切替えます。  方式は、Enterボタンと同じです。 typedef unsinged char UBYTE ; UBYTE tmp ; UBYTE csft100 ; UBYTE csft10 ; UBYTE csft1 ; UBYTE esft ; UBYTE psft ; UBYTE dflag ; UBYTE eflag ; UBYTE pflag ; // MtTimer2 interrupt handler void update_sw() { // shift csft100 <<= 1 ; csft10 <<= 1 ; csft1 <<= 1 ; esft <<= 1 ; psft <<= 1 ; // mask csft100 &= 0x03 ; csft10 &= 0x03 ; csft1 &= 0x03 ; esft &= 0x03 ; psft &= 0x03 ; // get switch state tmp = PIND & 0x13 ; // update if ( (tmp & 0x03) == 0x01 ) { csft100 |= ON ; } // displacement = 100 if ( (tmp & 0x03) == 0x03 ) { csft10 |= ON ; } // displacement = 10 if ( (tmp & 0x03) == 0x02 ) { csft1 |= ON ; } // displacement = 1 if ( (tmp & 0x10) == 0x10 ) { esft |= ON ; } // enter if ( (tmp & 0x20) == 0x20 ) { psft |= ON ; } // PTT // judge if ( csft100 == 0x01 ) { dflag = 1 ; } if ( csft10 == 0x03 ) { dflag = 3 ; } if ( csft1 == 0x01 ) { dflag = 2 ; } if ( esft == 0x01 ) { eflag = ON ; } if ( psft == 0x01 ) { pflag = ON ; } } 関数loop内の処理は、状態値stateを用意して  送信(Tx表示)、受信(Rx表示)単純です。 if ( pflag == ON ) { pflag = OFF ; // judge if ( state > 0 ) { state-- ; // send Receive frequency update_freq(rcvfreq); // show "Rx" display_trmsg(OFF); } else { state++ ; // send Transmitt frequency update_freq(trxfreq); // show "Tx" display_trmsg(ON); } }  setupの中に必要なパラメータを入れます。 void setup() { // initialize switches pin assignment PORTD = 0xff ; /* pull up */ DDRD = 0x00 ; /* all input */ // initialize DDS pin assignment PORTB = 0x00 ; DDRB = 0xff ; /* all output */ // initialize LCD pin assignment PORTC = 0x00 ; DDRC = 0xff ; /* all output */ // enable INT0 attachInterrupt(0,incdecfreq,RISING) // 10ms period MsTimer2::set(10,update_sw); // enable Timer2 MsTimer2::start(); // initialize values tmp = 0 ; csft100 = 0 ; csft10 = 0 ; csft1 = 0 ; dflag = OFF ; eflag = OFF ; pflag = OFF ; displacement = 10 ; state = 0 ; // select receive frequency }  スケッチにまとめます。 #include <EEPROM.h> #include <MsTimer2.h> #include <LiquidCrystal.h> // 14:RS 15:E 16:DB4 17:DB5 18:DB6 19:DB7 LiquidCrystal lcd(14,15,16,17,18,19); #define FRQMAX 7200 #define FRQMIN 7000 #define ROTA 2 #define ROTB 3 #define SWINC 4 #define SWDEC 5 #define ENTER 6 #define PTT 7 #define DDS_DAT 8 #define DDS_FQ_UD 9 #define DDS_W_CLK 10 #define Scalemulti 34.35973837 #define OFF 0 #define ON OFF+1 char iflag ; char dflag ; char zflag ; char eflag ; char fflag ; char aflag ; char isft ; char dsft ; char zsft ; char esft ; char fsft ; char asft ; char displacement ; char state ; int xtfreq ; int xrfreq ; int freq ; /* MtTimer2 interrupt handler */ void update_sw() { // shift isft <<= 1 ; dsft <<= 1 ; zsft <<= 1 ; esft <<= 1 ; fsft <<= 1 ; asft <<= 1 ; /* get frequency code */ if ( digitalRead(ROTA) == HIGH ) { fsft |= ON ; } /* get displacement 100 */ if ( digitalRead(SWINC) == HIGH ) { isft |= ON ; } /* get displacement 10 */ if ( digitalRead(SWINC) == LOW && digitalRead(SWDEC) == LOW ) { zsft |= ON ; zsft &= 0x03 ; } /* get displacement 1 */ if ( digitalRead(SWDEC) == HIGH ) { dsft |= ON ; } /* get enter code */ if ( digitalRead(ENTER) == HIGH ) { esft |= ON ; } /* get PTT code */ if ( digitalRead(PTT) == HIGH ) { asft |= ON ; } /* judge frequency update */ if ( fsft == 3 ) { fflag = 1 ; if ( digitalRead(ROTB) == HIGH ) { fflag = 2 ; } } /* displacement 10 */ if ( zsft == 3 ) { zflag = ON ; } /* displacement 100 */ if ( isft == 3 ) { iflag = ON ; } /* displacement 1 */ if ( dsft == 3 ) { dflag = ON ; } /* confirmation */ if ( esft == 3 ) { eflag = ON ; } /* select transmmit frequency */ if ( asft == 3 ) { aflag = 1 ; } /* select receive frequency */ if ( asft == 0 ) { aflag = 2 ; } } /* send frequency value to DDS */ void send_frq(int x) { double ddsftx ; int ddsft ; /* calculate */ ddsftx = x * 1000.0 * Scalemulti ; ddsft = int(ddsftx) ; /* enable */ digitalWrite(DDS_FQ_UD,LOW); /* send frequency */ shiftOut(DDS_DAT,DDS_W_CLK,LSBFIRST,ddsft); shiftOut(DDS_DAT,DDS_W_CLK,LSBFIRST,(ddsft >> 8)); shiftOut(DDS_DAT,DDS_W_CLK,LSBFIRST,(ddsft >> 16)); shiftOut(DDS_DAT,DDS_W_CLK,LSBFIRST,(ddsft >> 24)); /* send phase */ ddsft = 0 ; shiftOut(DDS_DAT,DDS_W_CLK,LSBFIRST,ddsft); /* disable */ digitalWrite(DDS_FQ_UD,HIGH); } /* store */ void store_frq(char which,int x) { byte dh ; byte dl ; /* separate */ dl = x & 0xff ; dh = (x >> 8) & 0xff ; /* store frequency */ if ( which ) { EEPROM.write(dl,2); EEPROM.write(dh,3); } else { EEPROM.write(dl,0); EEPROM.write(dh,1); } } /* load */ int load_frq(char x) { byte dh ; byte dl ; /* get frequency informations */ if ( x ) { dl = EEPROM.read(2); dh = EEPROM.read(3); } else { dl = EEPROM.read(0); dh = EEPROM.read(1); } /* */ return( (dh << 8) | dl ) ; } /* LCD handler */ void show_frq(int xx,int yy) { byte i ; byte msg[8] ; /* frequency */ *(msg+0) = xx / 1000 ; xx %= 1000 ; *(msg+1) = xx / 100 ; xx %= 100 ; *(msg+2) = xx / 10 ; *(msg+3) = xx % 10 ; *(msg+4) = yy / 1000 ; yy %= 1000 ; *(msg+5) = yy / 100 ; yy %= 100 ; *(msg+6) = yy / 10 ; *(msg+7) = yy % 10 ; /* conversion */ *(msg+0) += '0' ; *(msg+1) += '0' ; *(msg+2) += '0' ; *(msg+3) += '0' ; *(msg+4) += '0' ; *(msg+5) += '0' ; *(msg+6) += '0' ; *(msg+7) += '0' ; /* show */ lcd.setCursor(0,0) ; lcd.write("Tx="); lcd.setCursor(0,1) ; lcd.write("Rx="); for ( i = 0 ; i < 4 ; i++ ) { lcd.setCursor(i+3, 0); lcd.write(msg[i]); lcd.setCursor(i+3, 1); lcd.write(msg[i+4]); } } /* */ void show_disp(int x) { byte i ; int xx; char msg[3] ; /* displacement */ xx = x ; *(msg+0) = xx / 100 ; xx %= 100 ; *(msg+1) = xx / 10 ; *(msg+2) = xx % 10 ; *(msg+0) += '0' ; *(msg+1) += '0' ; *(msg+2) += '0' ; /* zero suppresion */ if ( x == 10 ) { *(msg+0) = ' ' ; } if ( x == 1 ) { *(msg+0) = *(msg+1) = ' ' ; } for ( i = 0 ; i < 3 ; i++ ) { lcd.setCursor(8+i,1) ; lcd.write(msg[0]); } } void show_aster(int x) { lcd.setCursor(9,0) ; if ( x ) { lcd.write('*'); } else { lcd.write(' '); } } void show_txrx(int x) { lcd.setCursor(12,0) ; if ( x ) { lcd.write("Tx"); } else { lcd.write("Rx"); } } void setup() { /* inputs */ pinMode(ROTA,INPUT); pinMode(ROTB,INPUT); pinMode(SWINC,INPUT); pinMode(SWDEC,INPUT); pinMode(ENTER,INPUT); pinMode(PTT,INPUT); /* outputs */ pinMode(DDS_DAT,OUTPUT); pinMode(DDS_FQ_UD,OUTPUT); pinMode(DDS_W_CLK,OUTPUT); /* set 16 characters , 2 lines */ lcd.begin(16, 2); /* display off cursor */ lcd.noCursor(); /* initialize */ iflag = OFF ; dflag = OFF ; zflag = OFF ; eflag = OFF ; fflag = 0 ; aflag = 0 ; isft = 0 ; dsft = 0 ; zsft = 0 ; esft = 0 ; fsft = 0 ; asft = 0 ; displacement = 10 ; state = OFF ; /* load transmit frequency */ xtfreq = load_frq(0) ; /* load receive frequency */ xrfreq = load_frq(1) ; /* show LCD */ show_frq(xtfreq,xrfreq) ; show_txrx(state) ; /* 10ms period */ MsTimer2::set(10,update_sw); /* enable */ MsTimer2::start(); } void loop() { /*========================== ' increment switch handling '===========================*/ if ( iflag == 1 ) { iflag = 0 ; /* clear flag */ /* increment */ xtfreq += displacement ; if ( xtfreq > FRQMAX ) { xtfreq = FRQMAX ; } xrfreq = xtfreq - 455 ; /* show LCD */ show_frq(xtfreq,xrfreq) ; } /*========================== ' decrement switch handling '===========================*/ if ( dflag == 2 ) { dflag = 0 ; /* clear flag */ xtfreq -= displacement ; if ( xtfreq < FRQMIN ) { xtfreq = FRQMIN ; } xrfreq = xtfreq - 455 ; /* show LCD */ show_frq(xtfreq,xrfreq); } /*================================= ' 100 displacement handling '==================================*/ if ( iflag == ON ) { iflag = OFF ; displacement = 100 ; show_disp(displacement) ; } /*================================= ' 10 displacement handling '==================================*/ if ( zflag == ON ) { zflag = OFF ; if ( displacement != 10 ) { displacement = 10 ; show_disp(displacement) ; } } /*================================= ' 1 displacement handling '==================================*/ if ( dflag == ON ) { dflag = OFF ; displacement = 1 ; show_disp(displacement) ; } /*========================== ' enter switch handling '===========================*/ if ( eflag == ON ) { eflag = OFF ; /* show */ show_aster( ON ) ; /* update */ send_frq(xtfreq) ; send_frq(xrfreq) ; /* store both frequency */ store_frq(0,xtfreq); store_frq(1,xrfreq); /* wait 500ms */ delay(500) ; /* show */ show_aster( OFF ) ; } /*================================== ' set transmmit frequency handling '===================================*/ if ( aflag == 1 ) { aflag = 0 ; /* clear flag */ /* judge */ if ( state == OFF ) { state = ON ; /* change transmmit mode */ /* set transmmit frequency */ send_frq(xtfreq); /* show */ show_frq(xtfreq,xrfreq) ; show_txrx(state) ; } } /*================================ ' set receive frequency handling '=================================*/ if ( aflag == 2 ) { aflag = 0 ; /* clear flag */ /* judge */ if ( state == ON ) { state = OFF ; /* change receive mode */ /* set receive frequency */ send_frq(xrfreq); /* show */ show_frq(xtfreq,xrfreq) ; show_txrx(state) ; } } }

目次

inserted by FC2 system