デジタル・シンセサイザ基板(AD9834)でスイーパーを作る

投稿日 2014/07/07

CQ出版社トライアルシリーズ「デジタル周波数シンセサイザ基板」で最高周波数25MHzのスイーパーを作ってみました。

AD9834_SWEEPER_1.jpg

写真1: AD9834 DDS搭載基板で作ったスイーパー

0 - 25MHz 1Hzステップ

 

信号発生器にスイープ機能を持たせたものです。

 

「デジタル周波数シンセサイザ基板」付属のDDS基板にはアナログデバイセズ社のDDS AD9834と、その制御にPIC 18F14K50マイクロプロセッサ、その他付属回路が搭載されています。

 

ファームウェア書き込み器pickitを接続できるICSP信号も出ているので、自分で作成したファームウェアを簡単に書き込みことができます。

 

スイーパーに仕立てるために、LCD表示器を追加し、最低発振周波数と最高発振周波数、周波数ステップ、周波数切り替え時間を指定できるようにしました。

 

これらはボタンなどで切り替えられるようにしたいところですが、今回は手を抜いてソースコードのパラメータ定義の変更により、指定することにしました。

 

例えば、 スイープ 0Hzから25000000Hz 1Hzステップ 1mS間隔というように指定します。

 

ソースコード上では、

#define MODE SWEEP <- スイープを指定

#define LOWEST_FEREQ 0 <-最低周波数

#define HIGHEST_FREQ 25000000 //25MHz <- 最高周波数

#define STEP 1000  //1KHz <- 周波数ステップ

#define DELTA 1 //1mS <- 周波数切り替え時間

 

勿論スイープさせなければ単一周波数の発振器となります。

 

ソースコード上では、

#define MODE SINGLE <- シングルを指定

#define FREQ 10000000  //10MHz <- 周波数の指定

 

「デジタル周波数シンセサイザ基板」は25MHzのLPF、ジッタの少ない75MHzの基準クロック用水晶発振器、低ノイズのLDOなど、いろいろ考慮された回路設計となっており、簡易信号発生器としては十分な性能と思います。

 

配線

LCDとPIC 18F14K50の配線は、

 

Vcc  JP1 pin1 (基板上面に出ている3.3Vを空きピンのpin1につないでおく)

GND JP1 pin3

照度調整の半固定抵抗はLCD上に取り付けました(10KΩ)

RS   RB4 JP1 pin11

W    LCD上でGNDに接続

E     RB5 JP1 pin12

D4 RC1 JP1 pin14

D5 RC2 JP1 pin13

D6 RC3 JP1 pin8

D7 RC4 JP1 pin7

 

出力信号はBNCコネクタを直接基板に取り付けて取り出します。JP2の pin4が芯線、pin1,2,3,5,6 ...がGNDです。(コネクタ接続用のGNDパターンを利用したほうがよいかも知れません)

 

電源は5VをJP1 pin2、GNDをJP1 pin4に接続します。


 

スプリアスの観測

APB-3でスプリアスを観測してみました。

 

出力信号が0dBmを超えており、そのままAPB-3に入力すると過入力となるので-18dBのアッテネータを通して-10dBm以下に減衰させて入力しました。

AD9834_SWEEPER_2.jpg

1MHz, 10MHz, 20MHz, 25MHzで観測しました。センター周波数を25MHz、スパンを50MHzにして観測しています。

 

1MHz(左上)では第5スプリアスまで-60dBm以下です。

 

10MHz(右上)では第2、第3、第4スプリアスが観測されています。いずれも-50dBm以下です。

 

20MHz(左下)では第2スプリアスまで観測されています。

 

25MHz(右下)では第2スプリアス(50MHz)が右端にありますが、それ以上はAPB-3では観測不能です。

 

いずれのスプリアスも-50dBm以下ですので、こんなものでしょう。

 

スプリアスが-50dBm以下であれば、オシロで見ても正弦波にしか見えません。

AD9834_SWEEPER_3.jpg

20MHzの波形

 

 

スイープさせるとスプリアスが変化する様子がよくわかります。

 

参考

 

mbed AD9834 DDS

    この記事ではマスタクロックに48MHzを使用しています。

 

mbed AD9834 FSKの実験

 

PSoc3 AD9833 DDSによる波形発生

 

 

 

 ソースコード

すべてのソースコードをmain.cにインクルードする形にしています。

CPUはPIC 18F14K50

開発環境は microchip MPLAB X IDE

 

構成

main.h

lcd.h

main.c

 

 

main.h

 

#pragma config CPUDIV = CLKDIV2 // Fosc:24MHz

#pragma config USBDIV = OFF

#pragma config FOSC   = HS

#pragma config PLLEN  = ON

#pragma config FCMEN  = OFF

#pragma config IESO   = OFF

#pragma config PWRTEN = ON

#pragma config BOREN  = NOSLP // Sleep時に停止

#pragma config BORV   = 27 // 2.7V

//#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

 

#define _XTAL_FREQ 24000000

 

#define OFF 0;

#define ON 1;

#define READ 1;

#define WRITE 0;

#define LOW 0

#define HIGH 1

#define TRUE 1

#define FALSE 0

 

#define SDATA LATCbits.LATC0

#define FSYNC LATCbits.LATC7

#define SCLK LATBbits.LATB6

 

#define SWEEP 0

#define SINGLE 1

 

char string[17];

 

lcd.h

 

///////////////////////////////////////////////

//  液晶表示器制御ライブラリ 16 x 2 or 20 x 4 LCD 4bit Para

//////////////////////////////////////////////

 

const int lcd_adrbase[4] = { 0x80, 0xC0, 0x94, 0xD4 }; // 4行LCDの行アドレス

 

//////// データ出力サブ関数

#define RS PORTBbits.RB4

#define E PORTBbits.RB5

//D4 RC1

//D5 RC2

//D6 RC3

//D7 RC4

 

unsigned char dcb = 0x0C; //Display ON, Sursor Off, Blink Off

 

void lcd_out(int code, int flag)

{

LATC = (code & 0xF0) >> 3; //出力データ上位4ビット

if (flag == 0) //表示データかコマンドか

RS = 1; //表示データの場合RS=1

else

RS = 0; //コマンドデータの場合RS=0

Nop(); Nop(); //NOP スキュー確保 60ns以上

E = 1; //STB ON

__delay_us(100);

E = 0; //STB OFF

__delay_us(100);

}

 

//////// 1文字表示関数

void lcd_data(int asci)

{

lcd_out(asci, 0); //上位4ビット出力

lcd_out(asci << 4, 0); //下位4ビット出力

__delay_us(50); //50μsec待ち

}

 

/////// コマンド出力関数

void lcd_cmd(int cmd)

{

lcd_out(cmd, 1); //上位4ビット出力

lcd_out(cmd << 4, 1); //下位4ビット出力

if((cmd == 0x01) || (cmd == 0x02))

__delay_ms(2); //2msec待ち

else

__delay_us(50); //50usec待ち

}

 

void lcd_setposition(unsigned char column, unsigned char row){

lcd_cmd(lcd_adrbase[row] + column);

}

 

/////// 文字列出力関数

void lcd_str(int column, int row, char *str)

{

lcd_setposition(column, row );

 

while(*str != 0x00) //文字列の終わり判定

{

lcd_data(*str); //文字列1文字出力

str++; //ポインタ+1

}

}

 

void lcd_cursoron(void){

    dcb = dcb | 0x02;

    lcd_cmd(dcb);

}

 

void lcd_cursoroff(void){

    dcb = dcb & 0xFD;

    lcd_cmd(dcb);

}

 

void lcd_cursorshiftright(unsigned char cols){

    unsigned char i;

    for(i = 0; i < cols; i++){

lcd_cmd(0x14);

__delay_ms(1);

    }

}

 

void lcd_cursorshiftleft(unsigned char cols){

    unsigned char i;

    for(i = 0; i < cols; i++){

lcd_cmd(0x10);

__delay_ms(1);

}

}

 

void lcd_blinkon(void){

    dcb = dcb | 0x01;

    lcd_cmd(dcb);

}

 

void lcd_blinkoff(void){

    dcb = dcb & 0xFE;

    lcd_cmd(dcb);

}

 

void lcd_clearall(void){

    lcd_cmd(0x01);

}

 

void lcd_clearline1(void){

    lcd_str(0, 0, "                    ");

}

 

void lcd_clearline2(void){

    lcd_str(0, 1, "                    ");

}

 

void lcd_clearline3(void){

    lcd_str(0, 2, "                    ");

}

 

void lcd_clearline4(void){

    lcd_str(0, 3, "                    ");

}

 

void lcd_init(void){

E = 0;

__delay_ms(15); //15msec

lcd_out(0x30, 1); //8bit mode set

__delay_ms(5);

lcd_out(0x30, 1); //8bit mode set

__delay_ms(5);/////1000

lcd_out(0x30, 1); //8bit mode set

__delay_ms(2);///1000

lcd_out(0x20, 1); //4bit mode set

__delay_ms(1);

lcd_cmd(0x2E); //DL=0 4bit mode

lcd_cmd(0x08); //display off C=D=B=0

lcd_cmd(0x01); //all clear

__delay_ms(5);

lcd_cmd(0x06); //entry I/D=1 S=0

lcd_cmd(dcb); //display on D=1 C=B=0

__delay_ms(2); //1.6msec

}

 

main.c

 

// デジタル周波数シンセサイザ基板をスイーパーに仕立てる by JF1VRR

// Hist. V1.00A 2014/07/06 New!

//

#include <xc.h>

#include <p18F14K50.h>

#include <stdio.h>

 

#include "main.h"

#include "lcd.h"

 

void Delay_ms(int cnt){

    for(int i = 0; i < cnt; i++){

        __delay_ms(1);

    }

}

 

static void init_sys(void){

    ANSEL = 0x00; // all Digital

    ANSELH = 0x00; // all Digital

 

    LATC = 0x00; // all LOW

    LATB = 0x00;                        // all LOW

    TRISA = 0x00; // RA :all out

    TRISB = 0x00; // RB all out

    TRISC = 0x00; // RC all out

}

 

void serial_out(unsigned int data) {

    FSYNC = 0;

    data & 0x8000? SDATA = 1 : SDATA = 0; SCLK = 0; SCLK = 1;

    data & 0x4000? SDATA = 1 : SDATA = 0; SCLK = 0; SCLK = 1;

    data & 0x2000? SDATA = 1 : SDATA = 0; SCLK = 0; SCLK = 1;

    data & 0x1000? SDATA = 1 : SDATA = 0; SCLK = 0; SCLK = 1;

    data & 0x0800? SDATA = 1 : SDATA = 0; SCLK = 0; SCLK = 1;

    data & 0x0400? SDATA = 1 : SDATA = 0; SCLK = 0; SCLK = 1;

    data & 0x0200? SDATA = 1 : SDATA = 0; SCLK = 0; SCLK = 1;

    data & 0x0100? SDATA = 1 : SDATA = 0; SCLK = 0; SCLK = 1;

    data & 0x0080? SDATA = 1 : SDATA = 0; SCLK = 0; SCLK = 1;

    data & 0x0040? SDATA = 1 : SDATA = 0; SCLK = 0; SCLK = 1;

    data & 0x0020? SDATA = 1 : SDATA = 0; SCLK = 0; SCLK = 1;

    data & 0x0010? SDATA = 1 : SDATA = 0; SCLK = 0; SCLK = 1;

    data & 0x0008? SDATA = 1 : SDATA = 0; SCLK = 0; SCLK = 1;

    data & 0x0004? SDATA = 1 : SDATA = 0; SCLK = 0; SCLK = 1;

    data & 0x0002? SDATA = 1 : SDATA = 0; SCLK = 0; SCLK = 1;

    data & 0x0001? SDATA = 1 : SDATA = 0; SCLK = 0; SCLK = 1;

    FSYNC = 1;

}

 

#define MODE                 SWEEP           //SEEP or SINGLE

#define FREQ                  25000000      //1MHz

#define LOWEST_FREQ    0                  //0Hz

#define HIGHEST_FREQ   25000000     //25MHz_

#define STEP                   1000            //1KHz

#define DELTA                 1                 //1mS

 

 

int main(void) {

    float SetFreq;

    unsigned long temp, freqdata;

    unsigned int Uptemp, Lowtemp;

    unsigned char mode;

    unsigned int delta;

    unsigned long step;

    unsigned long lowest_freq;

    unsigned long highest_freq;

    unsigned long freq;

 

    init_sys();

    lcd_init();

 

    lcd_str(0, 0, "AD9843 SWEEPER  ");

    lcd_str(0, 1, "      by JF1VRR ");

    Delay_ms(2000);

    

    SCLK = 1;

    SDATA = 0;

    FSYNC = 1;

 

    mode = MODE;

    freq = FREQ;

    lowest_freq = LOWEST_FREQ;

    highest_freq = HIGHEST_FREQ;

    step = STEP;

    delta = DELTA;

 

    lcd_str(0, 1, "SWEEPING NOW!   ");

    if(mode == SINGLE) lowest_freq = highest_freq = freq;

    freqdata = lowest_freq;

    do {

        //SetFreq = 5.592405 * (unsigned long)freqdata; //MCLK = 48MHz

        SetFreq = 3.57913941 * (unsigned long)freqdata; //MCLK = 75MHz

        temp = (unsigned long)SetFreq;

        Lowtemp = (unsigned int)(temp & 0x3FFF);

        Uptemp = (unsigned int)((temp/16384) & 0x3FFF);

        serial_out(0x2028);

        serial_out(Lowtemp + 0x4000);

        serial_out(Uptemp + 0x4000);

        Delay_ms(delta);

        freqdata = freqdata + step;

    } while (freqdata < highest_freq);

 

    lcd_str(0, 1, "COMP. XXXXXXXXHz");

    sprintf(string, "%8ld", highest_freq);

    lcd_str(6, 1, string);

 

    while(1);

}

 

 

 

(JF1VRR)