Sunday 2 February 2014

Updated AD9850 VFO

I recently blogged about the AD9850 frequency synthesiser (DDS). This can output any frequency up to 40MHz under program control from an Arduino.

I have just received a new display shield and here is the AD9850 controlled by the Arduino and a display of amateur band and frequency. As the shield has only 5 buttons for user input (the sixth is a Reset button). I have chosen to use them for:

1 Select band - step through the amateur bands, on each band the band edges are known and when selected a mid band frequency is programmed

2 Left/right +/-10KHz and up/down +/-10Hz buttons. this make tuning a bit arduous as you have to push the buttons many times to tune a band, but you can tune to the nearest 10Hz.

The display shield has a series of resistors that mean the buttons output various voltages, these are measured by the analog input as digital 0-1023 data.

2014 02 02 10 17 17

Code

#include "LiquidCrystal.h"

// DDS-9850 module programmer, with LCD display and button inputs


#define RESET 0     // Pin  RST
#define DATA 1      // Pin  DATA
#define FQ_UD 2     // Pin  FQ
#define W_CLK 3     // Pin  CLK
#define D4 4        // LCD data pins
#define D5 5
#define D6 6
#define D7 7
#define RS 8        // LCD RS * EN pins
#define EN 9
#define BUTTONS A0   // button sensor

// short high pulse
#define pulseHigh(pin) {digitalWrite(pin, HIGH); digitalWrite(pin, LOW); }

// names of bands
char bandName[][5] = {"160", "80", "60", "40", "30", "20", "17", "15", "12", "10"};

// array lookup of lower, current and upper band limits
#define LOWER 0
#define CURRENT 1
#define UPPER 2

// band limits
double freqRange[10][3] = {
    {1810000, 1900000, 2000000},
    {3500000, 3600000, 3800000},
    {5258000, 5100000,5406500},
    {7000000, 7100000, 7200000},
    {10100000, 10300000, 10150000},
    {14000000, 14200000, 14350000},
    {18068000, 18050000, 18168000},
    {21000000, 21250000, 21450000},
    {24890000, 24700000, 24990000},
    {28000000, 28500000, 29700000}
};

// LCD object
LiquidCrystal lcd(RS, EN, D4, D5, D6, D7);

// band number
int band;

// actual frequency
float frequency; 

void setup()
{
  pinMode(FQ_UD, OUTPUT);
  pinMode(W_CLK, OUTPUT);
  pinMode(DATA, OUTPUT);
  pinMode(RESET, OUTPUT);
   
  pulseHigh(RESET);
  pulseHigh(W_CLK);
  pulseHigh(FQ_UD);  // this pulse enables serial mode
  
  lcd.begin(16, 2);
  
  band = 0; // 160m band 0
  frequency = freqRange[band][CURRENT]; // init frequency mid-band
}

void loop() 
{
  int x;
  
  x = analogRead(BUTTONS);
  if (x < 100)
  {
    while(analogRead(BUTTONS) < 100);
    if(frequency < freqRange[band][UPPER]) frequency += 10000;
  }
  else if (x < 200) 
  {
    while(analogRead(BUTTONS) < 200);
    if(frequency < freqRange[band][UPPER]) frequency += 10;
  }
  else if (x < 400)
  {
    while(analogRead(BUTTONS) < 400);
    if(frequency > freqRange[band][LOWER]) frequency -= 10;
  }
  else if (x < 600)
  {
    while(analogRead(BUTTONS) < 600);
    if(frequency > freqRange[band][LOWER]) frequency -= 10000;
  }
  else if (x < 800)
  {
    while(analogRead(BUTTONS) < 800);
    freqRange[band][CURRENT] = frequency; // save rpvious band freq
    if(band < 9) band++;
    else band = 0;
    frequency = freqRange[band][CURRENT]; // load current band last freq
  }
  
  lcdDisplay(bandName[band], frequency);
  sendFrequency(frequency);  // freq Hz
}

// display LCD band & freq
void lcdDisplay(char* b, double f)
{

  lcd.setCursor(0,0); // write band & freq
  lcd.print("Band = ");
  lcd.setCursor(0, 1);
  lcd.print("Freq = ");
  
  delay(100); // stop flicker
  lcd.setCursor(7,0); // clear band data
  lcd.print("   ");
  lcd.setCursor(7,0); // write band data
  lcd.print(b);

  lcd.setCursor(7, 1); // clear freq data
  lcd.print("        ");
  lcd.setCursor(7, 1); // write freq data
  lcd.print(f/1000);

}

// frequency calc =  * /2^32
void sendFrequency(double frequency) 
{
  int32_t freq = frequency * 4294967295/125000000;  // note 125 MHz clock on 9850
  
  for (int b=0; b<4; b++, freq>>=8) 
  {
    tfr_byte(freq & 0xFF);
  }
  tfr_byte(0x000);   // Final control byte, all 0
  pulseHigh(FQ_UD);
}

// transfers a byte, a bit at a time, LSB first via serial DATA line
void tfr_byte(byte data)
{
  for (int i=0; i<8; i++, data>>=1) 
  {
    digitalWrite(DATA, data & 0x01);
    pulseHigh(W_CLK);   //after each bit sent, CLK is pulsed high
  }
}


No comments: