Signal Generator
I threw this together real quick to test out a signal generator and it is a bit sloppy and written around someone else's code (their code isn't sloppy mine is). This code should just be used as a reference or for testing and credit given to David Mills for the part of the code that I borrowed from him.
This tutorial shows how to make a signal generator using the AD9850 DDS signal generator, an Arduino, and a potentiometer. I used code written by David Mills http://webshed.org/wiki/AD9850_Arduino to interface with the signal generator and added to it to allow you to set the frequency using a potentiometer and change the mode between Hz, kHz, and MHz by pressing a button. As David Mills requested, don't claim the code as your own or try to prevent anyone else using it other than that do with it what you will.
If you are interested in making music with this check out this previous post.
BOM
-1 Arduino
-1 LCD display (optional)
-1 AD9850 DDS signal generator
-1 Touch button
Connections
Note the connections between the arduino and the AD9850 DDS signal generator. Feel free to change them if you need.
#define CLOCK 2 //pin connections for DDS
#define LOAD 3
#define DATA 7
#define RESET 8
For the LCD I used the following connections LiquidCrystal lcd(5, 6, 9, 10, 11, 12); For additional help connecting the LCD see this tutorial.
Note that in this tutorial they use different pins and it uses a potentiometer being used on pin 3, I just used a resistor to ground. The value will vary between screens and it is just used to set contrast. If your screen is all black or white you may need to use a different resistor or adjust the pot.
For the pot and button I used the following pins
#define POTPIN A0
#define MODE 13
Use the button to change the mode, then depending on what mode it is, change how you interpret the pot.
Interpreting the pot, convert the reading from the pot to a value between 0 and 1,000 for mode 1, 1,000-1,000,000 for mode 2, and 1,000,000-30,000,000 for mode 3. You will want to limit it to 30,000,000 because past that the hardware doesn't work. You may need to edit the code I used for the potentiometer that you use.
Send this to the AD9850 DDS signal generator using the code that David Mills wrote.
Pro tip: Display the frequency and mode on the LCD so you know what you are doing.
Alternative inputs: The potentiometer I used wasn't very accurate and the value changed a lot when set all the way up or down. Use buttons or a keypad to set the frequency to get an exact amount and easily set it how you want.
The complete code:
#include <LiquidCrystal.h>
LiquidCrystal lcd(5, 6, 9, 10, 11, 12);
#define DDS_CLOCK 125000000
#define CLOCK 2 //pin connections for DDS
#define LOAD 3
#define DATA 7
#define RESET 8
#define POTPIN A0
#define MODE 13
float hrz;
float pot;
float temp;
int mode=0;
int moderead;
void setup()
{
pinMode(DATA, OUTPUT);
pinMode(CLOCK, OUTPUT);
pinMode(LOAD, OUTPUT);
pinMode(RESET, OUTPUT);
pinMode(POTPIN, INPUT);
pinMode(MODE, INPUT);
AD9850_init();
AD9850_reset();
lcd.begin(16, 2);
Serial.begin(9600);
//SetFrequency(hrz);
}
void loop()
{
moderead=digitalRead(MODE);
pot=analogRead(POTPIN); //14-1000
hrz=((pot-6)*10000000);
if (moderead==LOW)
{
mode++;
delay(500);
if (mode>2)
{
mode=0;
}
}
if (mode==0)
{
hrz=(hrz/10000000);
lcd.setCursor(0, 1);
lcd.print("MODE: Hz");
}
if (mode==1)
{
hrz=(hrz/10000);
lcd.setCursor(0, 1);
lcd.print("MODE: KHz");
}
if (mode==2)
{
hrz=(hrz/100);
lcd.setCursor(0, 1);
lcd.print("MODE: MHz");
}
if (mode!=3)
{
if (hrz<0)
{
hrz=0;
if (temp>1000)
{
lcd.clear();
}
lcd.setCursor(0, 0);
lcd.print(hrz,1);
lcd.print("HZ ");
}
if (hrz>0 && hrz<1000)
{
if (temp>1000)
{
lcd.clear();
}
lcd.setCursor(0, 0);
lcd.print(hrz,1);
lcd.print("HZ ");
}
if (hrz>1000 && hrz<1000000)
{
if (temp<1000|| temp>1000000)
{
lcd.clear();
}
lcd.setCursor(0, 0);
lcd.print(hrz/1000,1);
lcd.print("KHZ ");
}
if (hrz>1000000 && hrz<30000000)
{
if (temp<1000000)
{
lcd.clear();
}
lcd.setCursor(0, 0);
lcd.print(hrz/1000000,1);
lcd.print("MHZ ");
}
if (hrz>30000000)
{
hrz=30000000;
if (temp<1000000)
{
lcd.clear();
}
lcd.setCursor(0, 0);
lcd.print(hrz/1000000,1);
lcd.print("MHZ ");
}
SetFrequency(hrz);
temp=hrz;
}
}
void SetFrequency(unsigned long frequency)
{
unsigned long tuning_word = (frequency * pow(2, 32)) / DDS_CLOCK;
digitalWrite (LOAD, LOW);
shiftOut(DATA, CLOCK, LSBFIRST, tuning_word);
shiftOut(DATA, CLOCK, LSBFIRST, tuning_word >> 8);
shiftOut(DATA, CLOCK, LSBFIRST, tuning_word >> 16);
shiftOut(DATA, CLOCK, LSBFIRST, tuning_word >> 24);
shiftOut(DATA, CLOCK, LSBFIRST, 0x0);
digitalWrite (LOAD, HIGH);
}
void AD9850_init()
{
digitalWrite(RESET, LOW);
digitalWrite(CLOCK, LOW);
digitalWrite(LOAD, LOW);
digitalWrite(DATA, LOW);
}
void AD9850_reset()
{
//reset sequence is:
// CLOCK & LOAD = LOW
// Pulse RESET high for a few uS (use 5 uS here)
// Pulse CLOCK high for a few uS (use 5 uS here)
// Set DATA to ZERO and pulse LOAD for a few uS (use 5 uS here)
// data sheet diagrams show only RESET and CLOCK being used to reset the device, but I see no output unless I also
// toggle the LOAD line here.
digitalWrite(CLOCK, LOW);
digitalWrite(LOAD, LOW);
digitalWrite(RESET, LOW);
delay(5);
digitalWrite(RESET, HIGH); //pulse RESET
delay(5);
digitalWrite(RESET, LOW);
delay(5);
digitalWrite(CLOCK, LOW);
delay(5);
digitalWrite(CLOCK, HIGH); //pulse CLOCK
delay(5);
digitalWrite(CLOCK, LOW);
delay(5);
digitalWrite(DATA, LOW); //make sure DATA pin is LOW
digitalWrite(LOAD, LOW);
delay(5);
digitalWrite(LOAD, HIGH); //pulse LOAD
delay(5);
digitalWrite(LOAD, LOW);
// Chip is RESET now
}