Lets Make Tech

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
}






 

 

 

 

Arduino Music Box

Credit to David Mills http://webshed.org/wiki/AD9850_Arduino for the code to interface with the signal generator.   

Here is a video to show what to expect from this project. I got a couple of the notes wrong in this video but they have been corrected in the code below.  

 

 

Bill of Materials:

-1 Arduino

-1 LCD display (optional)

-1 AD9850 DDS signal generator

-1 pizzo electric buzzer

 

I will leave the LCD up to you, and just provide instructions on how to make some music with the AD9850 DDS and an Arduino.  

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

Hook the pizzo buzzer to the square wave output and ground.

Now we need some notes, I referred to http://www.phy.mtu.edu/~suits/notefreqs.html to get a few. 

To play a note you can use this function: note(G*10, 750);  Place the desired note, the octave, then the length to play the note.

The octave scale is not linear.

Please note that I do not use real notes in the Waltz program, but it uses relative frequencies. The scale program does use real notes.

A*20 comes after G*10 however these will not be real musical notes.

 

To use real notes start with A*1, A*2, A*4, A*8, etc. If you are not worried about using real notes then just be sure that your are consistent relative the note you start on.  

This code is a little rushed and could be cleaned up a lot and is just for reference. If you use it be sure to credit David Mills http://webshed.org/wiki/AD9850_Arduino   for the part he wrote as well as me for the parts I wrote and 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. 

Below is the code to play Waltz From Sleeping Beauty and the code to play all of the real musical notes.

You can also turn this into a musical instrument by adding buttons that play notes.

Scale

#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

//Notes
#define A 27.5
#define AS 29.14
#define B 30.87
#define C 32.7
#define CS 34.65
#define D 36.71
#define DS 38.89
#define E 41.2
#define F 43.65
#define FS 46.25
#define G 49
#define GS 51.91

float hrz;
float time;
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);
    lcd.setCursor(0, 0);
    lcd.print("Note");
    lcd.setCursor(0, 1);
    lcd.print("Range");
  //SetFrequency(hrz);

}

void loop()
{ 
  int x=1;
  for (int i=0;i<10;i++)
  {
    intro(x);
    x=x*2;
  }
  for (int i=0;i<10;i++)
  {
    outro(x);
    x=x/2;
  }
} 


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
}

void note(float hrz, float time)
{
   SetFrequency(hrz);
   delay(time);
}



void intro(int i)
{
    note(A*i, 250);
    note(AS*i, 250);
    note(B*i, 250);
    note(C*i, 250);
    note(CS*i, 250);
    note(D*i, 250);
    note(DS*i, 250);
    note(E*i, 250);
    note(F*i, 250);
    note(FS*i, 250);
    note(G*i, 250);
    note(GS*i, 250);    
}

void outro(int i)
{
  note(GS*i, 250);  
  note(G*i, 250);
  note(FS*i, 250); 
  note(F*i, 250);
  note(E*i, 250);
  note(DS*i, 250);
  note(D*i, 250);
  note(CS*i, 250);
  note(C*i, 250);
  note(B*i, 250);
  note(AS*i, 250);
  note(A*i, 250);


  
  
}

 

 

 

 

 

 

Waltz From Sleeping Beauty

#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


//Notes
#define A 27.5
#define As 29.14
#define B 30.87
#define C 32.7
#define Cs 34.65
#define D 36.71
#define Ds 38.89
#define E 41.2
#define F 43.65
#define Fs 46.25
#define G 49
#define Gs 51.91

float hrz;
float time;
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);
    lcd.setCursor(0, 0);
    lcd.print("Waltz From");
    lcd.setCursor(0, 1);
    lcd.print("Sleeping Beauty");
  //SetFrequency(hrz);

}

void loop()
{ 
  intro();
  //Start repeat sign
  repeatedmusic();
  repeatedone();
  repeatedmusic();
  repeatedtwo();
  ending();
} 


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
}

void note(float hrz, float time)
{
   SetFrequency(hrz);
   delay(time);
}



void intro()
{
    note(G*10, 1000);
  
  note(Fs*10, 1000);
  
  note(G*10, 750);
  note(E*10, 250);
  
  note(Fs*10, 250);
  note(G*10, 250);
  note(E*10, 250);
  
  note(Fs*10, 500);
  note(A*20, 250);
  
  note(B*20, 500);
  note(Gs*10, 250);
  
  note(A*20, 1500);
  
  note(D*20, 750);
  
  note(Cs*20, 750);

  note(C*20, 500);
  note(A*20, 250);
  
  note(C*20, 250);
  note(B*20, 250);
  note(A*20, 250);
  
  note(E*20, 500);
  note(D*20, 250);
  
  note(C*20, 500);
  note(B*20, 250);
  note(0,1);
  
  note(B*20,250);
  note(A*20,250);
  note(Gs*10, 250);
  
  note(A*20,250);
  note(E*10,250);
  note(Fs*10,250); 
  
  note(G*10,750);
  
  note(Fs*10,750);
  
  note(G*10,500);
  note(E*10,250);
 
  note(Fs*10,250);
  note(G*10, 250);
  note(E*10,250);
  
  note(Fs*10,500);
  note(A*20,250);
  
  note(B*20,500);
  note(Gs*10, 250);
  
  note(A*20,1500);
  
  note(B*20,500);
  note(C*20,250);
  
  note(C*20,250);
  note(Cs*20,500);
  
  note(E*20,500);
  note(D*20,250);
  
  note(D*20,250);
  note(Fs*20,500);
  
  note(G*20,500);
  note(Fs*20,250);
  
  note(Fs*20,250);
  note(E*20,500);
  note(0, 10);
  
  note(D*20,125);
  note(0,125);
  note(Cs*20,125);
  note(D*20,125);
  note(E*20,125);
  
  note(D*20,125);
  note(B*20,125);
  note(A*20,125);
  note(B*20,125);
  note(A*20,125);
  note(Fs*10,125);
  
  note(D*10,125);
  note(0,125);
  note(D*20,500);
  
  note(E*20,500);
  note(Fs*20,250);
}


void repeatedmusic()
{
  note(G*20,125);  
  note(0,125);
  note(As*20,125);
  note(B*20,125);
  note(C*20,125);
  note(B*20,125);
  
  note(D*20,125);
  note(0,125);
  note(G*10,125);
  note(A*20,125);
  note(B*20,125);
  note(A*20,125);
  
  note(B*20,125);
  note(0,125);
  note(Fs*10,125);
  note(G*10,125);
  note(A*20,125);
  note(G*10,125);
  
  note(B*20,125);
  note(A*20,125);
  note(G*10,125);
  note(Fs*10,125);
  note(G*10,125);
  note(E*10,125);
  
  note(D*10,125);
  note(0,125);
  note(Cs*20,125);
  note(D*20,125);
  note(E*20,125);
  note(D*20,125);
  
  note(Fs*20,125);
  note(E*20,125);
  note(D*20,125);
  note(Cs*20,125);
  note(D*20,125);
  note(As*20,125);
  
  note(B*20,125);
  note(0,125);
  note(D*20,500);
  
  note(E*20,500);
  note(Fs*20,250);
  
  note(G*20,125);
  note(0,125);
  note(As*20,125);
  note(B*20,125);
  note(C*20,125);
  note(B*20,125);
  
  note(D*20,125);
  note(0,125);
  note(Gs*10,125);
  note(A*20,125);
  note(B*20,125);
  note(A*20,125);
  
  note(B*20,125);
  note(0,125);
  note(Fs*10,125);
  note(G*10,125);
  note(A*20,125);
  note(G*10,125);
  
  note(B*20,125);
  note(A*20,125);
  note(G*10,125);
  note(Fs*10,125);
  note(G*10,125);
  note(E*10,125);
  
  note(Cs*10,125);
  note(0,125);
  note(C*20,125);
  note(Cs*20,125);
  note(D*20,125);
  note(Cs*20,125);
  
}


void repeatedone()
{
    note(Fs*20,125);
    note(E*20,125);
    note(D*20,125);
    note(Cs*20,125);
    note(B*20,125);
    note(A*20,125);
    
    note(D*20,125);
    note(0,125);
    note(D*20,500);
    
    note(E*20,500);
    note(Fs*20,250);
}

void repeatedtwo()
{
  note(D*20,125);
  note(Cs*20,125);
  note(B*20,125);
  note(A*20,125);
  note(G*10,125);
  note(Fs*10,125); 
  
}

void ending()
{
  note(D*20,125);
  note(C*20,125);
  note(B*20,125);
  note(A*20,125);
  note(B*20,125);
  note(A*20,125);
  
  note(G*10,125);
  note(Fs*10,125);
  note(G*10,125);
  note(Fs*10,125);
  note(E*10,125);
  note(D*10,125);
  
  note(Fs*10,125);
  note(E*10,125);
  note(D*10,125);
  note(C*10,125);
  note(E*10,125);
  note(D*10,125);
  
  note(C*10,125);
  note(B*10,125);
  note(D*10,125);
  note(C*10,125);
  note(B*10,125);
  note(D*10,125);
  
  note(G*10,750);
  
  note(Fs*10,750);
  
  note(G*10,500);
  note(C*10,250);
  
  note(E*10,250);
  note(E*10,250);
  
  note(Fs*10,250);
  note(G*10,250);
  note(E*10,250);
  
  note(F*10,500);
  note(A*20,250);
  
  note(B*20,500);
  note(G*10,250);
  
  note(A*20,1500);
  
  note(Ds*20,750);
  
  note(D*20,750);
  
  note(C*20,500);
  note(A*20,250);
  
  note(C*20,250);
  note(B*20,250);
  note(A*20,250);
  
  note(E*20,500);
  note(D*20,250);
  
  note(C*20,500);
  note(B*20,250);
  delay(1);
  
  note(B*20,250);
  note(A*20,250);
  note(G*10,250);
  
  note(A*20,250);
  note(E*10,250);
  note(F*10,250);
  
  note(G*10,750);
  
  note(F*10,750);
  
  note(G*10,500);
  note(E*10,250);
  
  note(Fs*10,250);
  note(G*10,250);
  note(Gs*10,250);
  
  note(A*20,500);
  note(Fs*10,250);
  
  note(B*20,500);
  note(Gs*20,250);
  
  note(A*20,125);
  note(0,125);
  note(E*10,125);
  note(Gs*5,125);
  note(A*10,125);
  note(C*10,125);
  
  note(E*10,125);
  note(Ds*10,125);
  note(E*10,125);
  note(Gs*10,125);
  note(A*20,125);
  note(C*20,125);
  
  note(Ds*20,500);
  note(E*20,250);
  
  note(E*20,250);
  note(Fs*20,500);
  
  note(A*40,250);
  note(G*20,250);
  
  note(G*20,250); 
  note(B*40,500);
  
  note(C*40,500);
  note(B*40,250);
  
  note(B*40,250);
  note(A*40,500);
  
  note(G*20,125);
  note(0,125);
  note(Fs*20,125);
  note(G*20,125);
  note(D*20,125);
  note(B*20,125);
  
  note(G*10,125);
  note(0,625);
}
Home