AD9851 DDS Frequency Unit
with Arduino
d. bodnar   revised 04-16-2015

The goal of this project is to make a front end for the AD9850 or AD9851 DDC frequency generator.
A rotary encoder is used to change frequency and a 2 line LCD displays the current setting.

If the button on the encoder is briefly pressed the digit that the encoder changes is moved to the left (increased x10).  If the button is pressed for 200 ms or more the  digit is moved to the right (decreased x10)

 

This image shows the DDS unit set to 5 MHz - the 100000 shows that turning the rotary encoder will change the 100,000's place up or down.  The scope is attached to the small piece of coax at the bottom.

This view shows the Arduino (rear) and the DDS  board (foreground)

The scope shows a bit over 5 MHz.

 

Rotary_Encoder_v2_4_button_LCD-Combined-w-DDS-8951-w-reverse-BO
////WORKING = 4-11-2015 -
// revisited 5-15-2015

////HOLD BUTTON ON POWER UP TO Change from 9851 to 9850 & visa versa!


// Need to add "hold button to go back in decimal place"
// from  http://www.multiwingspan.co.uk/arduino.php?page=rotary2
#include <Wire.h>
#include <LCD.h>
#include <LiquidCrystal_I2C.h>
#include <EEPROM.h>
#define I2C_ADDR    0x27 // <<----- Add your address here.  Find it from I2C Scanner
#define BACKLIGHT_PIN     3
#define En_pin  2
#define Rw_pin  1
#define Rs_pin  0
#define D4_pin  4
#define D5_pin  5
#define D6_pin  6
#define D7_pin  7

int n = 1;
int valLen = 0;
LiquidCrystal_I2C	lcd(I2C_ADDR, En_pin, Rw_pin, Rs_pin, D4_pin, D5_pin, D6_pin, D7_pin);
// Setting up the counter
long reading = 5000000;
int lowest = 0;
long highest = 99999999;
long changeamnt = 1;
// Timing for polling the encoder
unsigned long currentTime;
unsigned long lastTime;
unsigned long bpTime;  // button press time for single press or hold


int AD9851 = 0; // default is 9850 when = 0, it is AD9851 when = 1


// Pin definitions
const int pinA = 10; //
const int pinB = 11; //
const int buttonPin = 5;     // the number of the pushbutton pin
const int ledPin =  13;      // the number of the LED pin
// Storing the readings
boolean encA;
boolean encB;
boolean lastA = false;
int buttonState = 0;         // variable for reading the pushbutton status
#define W_CLK 6       // Pin 8 - connect to AD9850 module word load clock pin (CLK)
#define FQ_UD 7       // Pin 9 - connect to freq update pin (FQ)
#define DATA 8       // CHANGED Pin 10 - connect to serial data load pin (DATA)
#define RESET 9      // CHANGED Pin 11 - connect to reset pin (RST).

#define pulseHigh(pin) {digitalWrite(pin, HIGH); digitalWrite(pin, LOW); }

// transfers a byte, a bit at a time, LSB first to the 9850 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
  }
}

// frequency calc from datasheet page 8 = <sys clock> * <frequency tuning word>/2^32
void sendFrequency(double frequency) {
  //Serial.println("at sendFreq");
  //fudge to get freq to = input freq

  if (AD9851 == 0) { // using AD9850 chip if = 0
 //   Serial.println("at 9850!!!!");
    int32_t freq = frequency * 4294967295 / 125000000 * 1000000 / 1000005; /////25 / 105 * 100 *1004 / 1001*1000000/1000845;
    for (int b = 0; b < 4; b++, freq >>= 8) {
      tfr_byte(freq & 0xFF);
    }
    tfr_byte(0x000);   // Final control byte, all 0 for 9850 chip

  }
  else {
    int32_t freq = frequency * 25 / 105 * 100 * 1004 / 1001 * 1000000 / 1000845;
    for (int b = 0; b < 4; b++, freq >>= 8) {
      tfr_byte(freq & 0xFF);
    }
    tfr_byte(0x001);   // Final control byte, all 0 for 9850 chip

  }
  pulseHigh(FQ_UD);  // Done!  Should see output
}
void setup() {
  Serial.begin(9600);
  // configure arduino data pins for output
  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 - Datasheet page 12 figure 10
   AD9851 = EEPROM.read(0);
  if (digitalRead(buttonPin) == LOW) { // button pressed
    Serial.print(" AD9851=");
    Serial.println(AD9851);
    if (AD9851 == 0) {
      AD9851 = 1;
      Serial.println("==1");
        EEPROM.write(0, AD9851);
    }
    else {
      AD9851 = 0;
      Serial.println("==0");
        EEPROM.write(0, AD9851);
    }
  }


  lcd.begin (16, 2); //  <<----- My LCD was 16x2
  // Switch on the backlight
  lcd.setBacklightPin(BACKLIGHT_PIN, POSITIVE);
  lcd.setBacklight(HIGH);
  lcd.home (); // go home
  lcd.print("Ver 2.3- 895");
  if (AD9851 == 1) {
    lcd.print("1");
  }
  else {
    lcd.print("0");
  }
  // initialize the LED pin as an output:
  pinMode(ledPin, OUTPUT);
  // initialize the pushbutton pin as an input:
  pinMode(buttonPin, INPUT);
  // set the two pins as inputs with internal pullups
  pinMode(pinA, INPUT_PULLUP);
  pinMode(pinB, INPUT_PULLUP);
  // Set up the timing of the polling
  currentTime = millis();
  lastTime = currentTime;
  // Start the serial monitor for debugging


}
int changeamnt10 = 0;

void loop()
{
  sendFrequency(reading);


  //lcd.blink();
  buttonState = digitalRead(buttonPin);
  if (buttonState == LOW) {    //LOW indicates that the button has been pressed
    // turn LED on:
    bpTime = millis();  // save time

    while (digitalRead(buttonPin) == LOW) { // stay here till button released
    }

    if (millis() - bpTime <= 200 ) {
      Serial.print("Millis<500 = ");
      Serial.println(millis() - bpTime );
      digitalWrite(ledPin, HIGH);
      changeamnt = changeamnt * 10;
      changeamnt10 = changeamnt10 + 1;
      if (changeamnt == 10000000) {
        changeamnt10 = 0;
        changeamnt = 1;
      }
    }
    else {
      Serial.print("Millis>500 = ");
      Serial.println(millis() - bpTime );
      digitalWrite(ledPin, HIGH);
      changeamnt = changeamnt / 10;
      changeamnt10 = changeamnt10 - 1;
      if (changeamnt <= 0) {
        changeamnt10 = 10000000;
        changeamnt = 1;
      }
    }
    Serial.print("change = ");
    Serial.println(changeamnt);
    lcd.noBlink();
    lcd.setCursor(0, 1); // 2nd line

    lcd.print(changeamnt, DEC);
    lcd.print("          ");
    delay(200);
    int zz = (changeamnt10);
    Serial.print("zz = "); Serial.println(zz);
    lcd.setCursor(4 - (zz + 3) + 5 + 8, 0);
    lcd.blink();
  }
  else {
    // turn LED off:
    digitalWrite(ledPin, LOW);
  }
  // Read elapsed time
  currentTime = millis();
  // Check if it's time to read
  if (currentTime >= (lastTime + 2)) // was 5
  {
    // read the two pins
    encA = digitalRead(pinA);
    encB = digitalRead(pinB);
    // check if A has gone from high to low
    if ((!encA) && (lastA))
    {
      // check if B is high
      if (encB)
      {
        // clockwise
        if (reading + changeamnt <= highest)
        {
          reading = reading + changeamnt;
          Serial.println("fwd");
        }
      }
      else
      {
        // anti-clockwise
        if (reading - changeamnt >= 0)
        {
          reading = reading - changeamnt;
          Serial.println("bkw");
        }
      }
      // Output reading for debugging
      Serial.println(reading);
      lcd.setCursor (0, 0);       // go to start of 1st line
      lcd.print("Freq=          ");
      decLength();
      valLen = 15 - valLen;
      lcd.setCursor(valLen, 0);
      lcd.print(reading, DEC);
      // lcd.print("          ");
      int zz = (changeamnt10);
      Serial.print("zz = "); Serial.println(zz);
      lcd.setCursor(4 - (zz + 3) + 5 + 8, 0);
      lcd.blink();
      decLength();
      // lcd.setCursor(9,1);
      // lcd.print(valLen);
    }
    // store reading of A and millis for next loop
    lastA = encA;
    lastTime = currentTime;
  }
}

void decLength() {
  if (reading > 9999999)
    valLen = 8;
  else if (reading > 999999)
    valLen = 7;
  else if (reading > 99999)
    valLen = 6;
  else if (reading > 9999)
    valLen = 5;
  else if (reading > 999)
    valLen = 4;
  else if (reading > 99)
    valLen = 3;
  else if (reading > 9)
    valLen = 2;
  else
    valLen = 1;
}