Snippets

Peter Scargill AD9833 Signal Generator

Updated by Peter Scargill

File snippet.txt Modified

  • Ignore whitespace
  • Hide word diff
+// Simple, low cost tone generator based on the AD9833 module. 4(6)-button control
+// Memory 1        (long press set)
+// Memory 2        (long press set)
+// Frequency Down  (long press tone on/off)
+// Frequency Up    (long press frequency reset to 1Khz)
+// Range Change    1hz 10hz 100hz 1k, 10k, 100k (long press reset to 1k)
+// Output Type     SIN TRIANGLE SQUARE
+
 #include <SPI.h>
 #include "SSD1306Ascii.h"
 #include "SSD1306AsciiAvrI2c.h"
 #include "OneButton.h"
+#include <EEPROM.h>
 
 // 0X3C+SA0 - 0x3C or 0x3D
 #define I2C_ADDRESS 0x3C
-
 SSD1306AsciiAvrI2c oled;
 
 // spi code for the AD9833 from here  http://www.vwlowen.co.uk/arduino/AD9833-waveform-generator/AD9833-waveform-generator.htm
 
 #define SINE 0x2000                    // Define AD9833's waveform register value.
 #define SQUARE 0x2028                  // When we update the frequency, we need to
-#define TRIANGLE 0x2002                // define the waveform when we end writing.
+#define TRIANGLE 0x2002                // define the waveform as well.
 #define REF__FREQ 25000000.0           // On-board crystal reference frequency
 
 #define BEEPER 2
 
+#define M1_PIN 3
+#define M2_PIN 4
 #define FREQ_DOWN_PIN 5
 #define FREQ_UP_PIN 6     // long press=reset to 1000hz
 #define RANGE_PIN 7     // long press=reset to 1khz range
 #define WAVE_PIN 8
 #define FSYNC 10
 
-int wave = 0;
-int waveType = SINE;
-unsigned long freq = 1000L;               // Set initial frequency.
-unsigned long range = 1000;               // Set initial step
+#define UPDATE_DELAY 3000 // 3 seconds to any storage of changes
+
+uint32_t myMillis;
+uint8_t updateValues=0;
 
+struct
+{
+  uint16_t check;
+  uint8_t beepOn;
+  uint8_t waveType;
+  unsigned long freq;
+  unsigned long range;
+  uint8_t m1_waveType;
+  unsigned long m1_freq;
+  uint8_t m2_waveType;
+  unsigned long m2_freq;
+} eeSave;
+
+OneButton m1Button(M1_PIN, true);
+OneButton m2Button(M2_PIN, true);
 OneButton upButton(FREQ_UP_PIN, true);
 OneButton rangeButton(RANGE_PIN, true);
 OneButton downButton(FREQ_DOWN_PIN, true);
 OneButton waveButton(WAVE_PIN, true);
 
+void armUpdate()
+{
+  myMillis=millis()+UPDATE_DELAY;
+  updateValues=1;
+}
+
+void processUpdate()
+{
+  if ((updateValues==1) && (myMillis<millis()))
+  {
+    updateValues=0;
+    EEPROM.put(0, eeSave);
+  }
+}
+
 void setup(void)
 {
+  EEPROM.get(0, eeSave);
+  if (eeSave.check != 0x52c3)
+  {
+    eeSave.check = 0x52c3;
+    eeSave.beepOn = 1;
+    eeSave.waveType = SINE;
+    eeSave.freq = 1000L;
+    eeSave.range = 1000L;
+    eeSave.m1_waveType = SINE;
+    eeSave.m1_freq = 1000L;
+    eeSave.m2_waveType = SINE;
+    eeSave.m2_freq = 1000L;
+    EEPROM.put(0, eeSave);
+  }
+
   oled.begin(&Adafruit128x32, I2C_ADDRESS);
   oled.setFont(Adafruit5x7);
   delay(100);
   pinMode(FREQ_DOWN_PIN, INPUT_PULLUP);    // internal pullup resistors.
   pinMode(RANGE_PIN, INPUT_PULLUP);
   pinMode(WAVE_PIN, INPUT_PULLUP);
-  AD9833setFrequency(freq, waveType);
-
-  upButton.attachClick(clickUp);
-  downButton.attachClick(clickDown);
-  upButton.attachLongPressStart(longPressUp);
-  waveButton.attachClick(clickWave);
+  AD9833setFrequency(eeSave.freq, eeSave.waveType);
+
+  m1Button.attachClick(useM1);
+  m1Button.attachLongPressStart(setM1);
+  m2Button.attachClick(useM2);
+  m2Button.attachLongPressStart(setM2);
+  upButton.attachClick(frequencyUp);
+  upButton.attachLongPressStart(frequencyReset);
+  downButton.attachClick(frequencyDown);
+  downButton.attachLongPressStart(beepToggle);
+  waveButton.attachClick(waveToggle);
   rangeButton.attachClick(rangeSet);
   rangeButton.attachLongPressStart(rangeReset);
-  tone(BEEPER, 4400, 100);
-  delay(160);
-  tone(BEEPER, 4600, 400);
+  if (eeSave.beepOn) {
+    tone(BEEPER, 4400, 100);
+    delay(160);
+    tone(BEEPER, 4600, 400);
+  }
 }
 
-void clickWave()
+void beepToggle()
+{
+  if (eeSave.beepOn)
+  {
+    eeSave.beepOn = 0;
+    tone(BEEPER, 4000, 80);
+  }
+  else
+  {
+    eeSave.beepOn = 1;
+    tone(BEEPER, 5000, 80);
+  }
+  armUpdate();
+}
+void waveToggle()
 {
-  switch (waveType)
+  switch (eeSave.waveType)
   {
-    case SINE: waveType = SQUARE; break;
-    case SQUARE: waveType = TRIANGLE; break;
-    case TRIANGLE: waveType = SINE; break;
-    default: waveType = SINE; break;
+    case SINE: eeSave.waveType = SQUARE; break;
+    case SQUARE: eeSave.waveType = TRIANGLE; break;
+    case TRIANGLE: eeSave.waveType = SINE; break;
+    default: eeSave.waveType = SINE; break;
   }
-  AD9833setFrequency(freq, waveType);
-  tone(BEEPER, 5000, 80);
+  AD9833setFrequency(eeSave.freq, eeSave.waveType);
+  if (eeSave.beepOn) tone(BEEPER, 5000, 80);
+  armUpdate();
+}
+
+void useM1()
+{
+    eeSave.freq=eeSave.m1_freq;
+    eeSave.waveType=eeSave.m1_waveType;
+    AD9833setFrequency(eeSave.freq, eeSave.waveType);
+    if (eeSave.beepOn) tone(BEEPER, 5000, 80);
+    armUpdate();
+}
+
+void setM1()
+{
+    eeSave.m1_freq=eeSave.freq;
+    eeSave.m1_waveType=eeSave.waveType;
+    AD9833setFrequency(eeSave.freq, eeSave.waveType);
+    if (eeSave.beepOn) tone(BEEPER, 4000, 80);
+    armUpdate();
+}
+
+void useM2()
+{
+    eeSave.freq=eeSave.m2_freq;
+    eeSave.waveType=eeSave.m2_waveType;
+    AD9833setFrequency(eeSave.freq, eeSave.waveType);
+    if (eeSave.beepOn) tone(BEEPER, 5000, 80);
+    armUpdate();
+}
+
+void setM2()
+{
+    eeSave.m2_freq=eeSave.freq;
+    eeSave.m2_waveType=eeSave.waveType;
+    AD9833setFrequency(eeSave.freq, eeSave.waveType);
+    if (eeSave.beepOn) tone(BEEPER, 4000, 80);
+    armUpdate();
 }
 
-void clickUp()
+void frequencyUp()
 {
-  if (freq < 4000000) freq += range; else freq = 4000000;
-  AD9833setFrequency(freq, waveType);
-  tone(BEEPER, 5000, 80);
+  if (eeSave.freq < 4000000L) eeSave.freq += eeSave.range; else eeSave.freq = 4000000L;
+  AD9833setFrequency(eeSave.freq, eeSave.waveType);
+  if (eeSave.beepOn) tone(BEEPER, 5000, 80);
+  armUpdate();
 }
 
-void clickDown()
+void frequencyDown()
 {
-  if (freq >= range) freq -= range; else freq = 1;
-  AD9833setFrequency(freq, waveType);
-  tone(BEEPER, 5000, 80);
+  if (eeSave.freq >= eeSave.range) eeSave.freq -= eeSave.range; else eeSave.freq = 1L;
+  AD9833setFrequency(eeSave.freq, eeSave.waveType);
+  if (eeSave.beepOn) tone(BEEPER, 5000, 80);
+  armUpdate();
 }
 
 void rangeReset()
 {
-  range = 1000;
-  AD9833setFrequency(freq, waveType);
-  tone(BEEPER, 4500, 80);
+  eeSave.range = 1000L;
+  AD9833setFrequency(eeSave.freq, eeSave.waveType);
+  if (eeSave.beepOn) tone(BEEPER, 4500, 80);
+  armUpdate();
 }
 
 void rangeSet()
 {
-  switch (range)
+  switch (eeSave.range)
   {
-    case 1: range = 10; break;
-    case 10: range = 100; break;
-    case 100: range = 1000; break;
-    case 1000: range = 10000; break;
-    case 10000: range = 100000; break;
-    case 100000: range = 1; break;
-    default: range = 1000; break;
-
+    case 1: eeSave.range = 10L; break;
+    case 10: eeSave.range = 100L; break;
+    case 100: eeSave.range = 1000L; break;
+    case 1000: eeSave.range = 10000L; break;
+    case 10000: eeSave.range = 100000L; break;
+    case 100000: eeSave.range = 1L; break;
+    default: eeSave.range = 1000L; break;
   }
-  AD9833setFrequency(freq, waveType);
-  tone(BEEPER, 5000, 80);
+  AD9833setFrequency(eeSave.freq, eeSave.waveType);
+  if (eeSave.beepOn) tone(BEEPER, 5000, 80);
+  armUpdate();
 }
 
 
-void longPressUp()
+void frequencyReset()
 {
-  freq = 1000;
-  AD9833setFrequency(freq, waveType);
-  tone(BEEPER, 4400, 600);
+  eeSave.freq = 1000L;
+  AD9833setFrequency(eeSave.freq, eeSave.waveType);
+  if (eeSave.beepOn) tone(BEEPER, 4400, 600);
+  armUpdate();
 }
 
 
 void loop() {
   // put your main code here, to run repeatedly:
+  m1Button.tick();
+  m2Button.tick();
   upButton.tick();
   downButton.tick();
   waveButton.tick();
   rangeButton.tick();
+  processUpdate();
 }
 
 // AD9833 documentation advises a 'Reset' on first applying power.
 
   oled.setCursor(0, 2);
   char txt[40];
-  sprintf(txt, "Freq: %d,%03d,%03dHz", uint16_t(freq / 1000000), uint16_t((freq % 1000000) / 1000), uint16_t(freq % 1000));
+  sprintf(txt, "Freq: %d,%03d,%03dHz", uint16_t(eeSave.freq / 1000000), uint16_t((eeSave.freq % 1000000) / 1000), uint16_t(eeSave.freq % 1000));
   oled.print(txt);
   oled.clearToEOL();
-
-
   oled.setCursor(0, 3); oled.print("Range: ");
-  switch (range)
+  switch (eeSave.range)
   {
     case 1: oled.print("1Hz"); break;
     case 10: oled.print("10Hz"); break;
     case 100000: oled.print("100KHz"); break;
   }
   oled.clearToEOL();
-
   oled.setCursor(108, 2);
-  switch (waveType)
+  switch (eeSave.waveType)
   {
     case SINE: oled.print("SIN"); break;
     case TRIANGLE: oled.print("TRI"); break;
     case SQUARE: oled.print("SQR"); break;
   }
-
   oled.clearToEOL();
 
 }
Created by Peter Scargill

File snippet.txt Added

  • Ignore whitespace
  • Hide word diff
+#include <SPI.h>
+#include "SSD1306Ascii.h"
+#include "SSD1306AsciiAvrI2c.h"
+#include "OneButton.h"
+
+// 0X3C+SA0 - 0x3C or 0x3D
+#define I2C_ADDRESS 0x3C
+
+SSD1306AsciiAvrI2c oled;
+
+// spi code for the AD9833 from here  http://www.vwlowen.co.uk/arduino/AD9833-waveform-generator/AD9833-waveform-generator.htm
+
+#define SINE 0x2000                    // Define AD9833's waveform register value.
+#define SQUARE 0x2028                  // When we update the frequency, we need to
+#define TRIANGLE 0x2002                // define the waveform when we end writing.
+#define REF__FREQ 25000000.0           // On-board crystal reference frequency
+
+#define BEEPER 2
+
+#define FREQ_DOWN_PIN 5
+#define FREQ_UP_PIN 6     // long press=reset to 1000hz
+#define RANGE_PIN 7     // long press=reset to 1khz range
+#define WAVE_PIN 8
+#define FSYNC 10
+
+int wave = 0;
+int waveType = SINE;
+unsigned long freq = 1000L;               // Set initial frequency.
+unsigned long range = 1000;               // Set initial step
+
+OneButton upButton(FREQ_UP_PIN, true);
+OneButton rangeButton(RANGE_PIN, true);
+OneButton downButton(FREQ_DOWN_PIN, true);
+OneButton waveButton(WAVE_PIN, true);
+
+void setup(void)
+{
+  oled.begin(&Adafruit128x32, I2C_ADDRESS);
+  oled.setFont(Adafruit5x7);
+  delay(100);
+  oled.clear();
+  oled.print("Signal Generator 1.0");
+
+  SPI.begin();
+  SPI.setDataMode(SPI_MODE2);
+  //delay(50);
+  AD9833reset();
+  pinMode(FREQ_UP_PIN, INPUT_PULLUP);      // Set pins for rotary encoders as INPUTS and enable
+  pinMode(FREQ_DOWN_PIN, INPUT_PULLUP);    // internal pullup resistors.
+  pinMode(RANGE_PIN, INPUT_PULLUP);
+  pinMode(WAVE_PIN, INPUT_PULLUP);
+  AD9833setFrequency(freq, waveType);
+
+  upButton.attachClick(clickUp);
+  downButton.attachClick(clickDown);
+  upButton.attachLongPressStart(longPressUp);
+  waveButton.attachClick(clickWave);
+  rangeButton.attachClick(rangeSet);
+  rangeButton.attachLongPressStart(rangeReset);
+  tone(BEEPER, 4400, 100);
+  delay(160);
+  tone(BEEPER, 4600, 400);
+}
+
+void clickWave()
+{
+  switch (waveType)
+  {
+    case SINE: waveType = SQUARE; break;
+    case SQUARE: waveType = TRIANGLE; break;
+    case TRIANGLE: waveType = SINE; break;
+    default: waveType = SINE; break;
+  }
+  AD9833setFrequency(freq, waveType);
+  tone(BEEPER, 5000, 80);
+}
+
+void clickUp()
+{
+  if (freq < 4000000) freq += range; else freq = 4000000;
+  AD9833setFrequency(freq, waveType);
+  tone(BEEPER, 5000, 80);
+}
+
+void clickDown()
+{
+  if (freq >= range) freq -= range; else freq = 1;
+  AD9833setFrequency(freq, waveType);
+  tone(BEEPER, 5000, 80);
+}
+
+void rangeReset()
+{
+  range = 1000;
+  AD9833setFrequency(freq, waveType);
+  tone(BEEPER, 4500, 80);
+}
+
+void rangeSet()
+{
+  switch (range)
+  {
+    case 1: range = 10; break;
+    case 10: range = 100; break;
+    case 100: range = 1000; break;
+    case 1000: range = 10000; break;
+    case 10000: range = 100000; break;
+    case 100000: range = 1; break;
+    default: range = 1000; break;
+
+  }
+  AD9833setFrequency(freq, waveType);
+  tone(BEEPER, 5000, 80);
+}
+
+
+void longPressUp()
+{
+  freq = 1000;
+  AD9833setFrequency(freq, waveType);
+  tone(BEEPER, 4400, 600);
+}
+
+
+void loop() {
+  // put your main code here, to run repeatedly:
+  upButton.tick();
+  downButton.tick();
+  waveButton.tick();
+  rangeButton.tick();
+}
+
+// AD9833 documentation advises a 'Reset' on first applying power.
+void AD9833reset() {
+  WriteRegister(0x100);   // Write '1' to AD9833 Control register bit D8.
+  delay(10);
+}
+
+// Set the frequency and waveform registers in the AD9833.
+void AD9833setFrequency(long frequency, int Waveform) {
+
+  long FreqWord = (frequency * pow(2, 28)) / REF__FREQ;
+
+  int MSB = (int)((FreqWord & 0xFFFC000) >> 14);    //Only lower 14 bits are used for data
+  int LSB = (int)(FreqWord & 0x3FFF);
+
+  //Set control bits 15 ande 14 to 0 and 1, respectively, for frequency register 0
+  LSB |= 0x4000;
+  MSB |= 0x4000;
+
+  WriteRegister(0x2100);
+  WriteRegister(LSB);                  // Write lower 16 bits to AD9833 registers
+  WriteRegister(MSB);                  // Write upper 16 bits to AD9833 registers.
+  WriteRegister(0xC000);               // Phase register
+  WriteRegister(Waveform);             // Exit & Reset to SINE, SQUARE or TRIANGLE
+
+  oled.setCursor(0, 2);
+  char txt[40];
+  sprintf(txt, "Freq: %d,%03d,%03dHz", uint16_t(freq / 1000000), uint16_t((freq % 1000000) / 1000), uint16_t(freq % 1000));
+  oled.print(txt);
+  oled.clearToEOL();
+
+
+  oled.setCursor(0, 3); oled.print("Range: ");
+  switch (range)
+  {
+    case 1: oled.print("1Hz"); break;
+    case 10: oled.print("10Hz"); break;
+    case 100: oled.print("100Hz"); break;
+    case 1000: oled.print("1KHz"); break;
+    case 10000: oled.print("10KHz"); break;
+    case 100000: oled.print("100KHz"); break;
+  }
+  oled.clearToEOL();
+
+  oled.setCursor(108, 2);
+  switch (waveType)
+  {
+    case SINE: oled.print("SIN"); break;
+    case TRIANGLE: oled.print("TRI"); break;
+    case SQUARE: oled.print("SQR"); break;
+  }
+
+  oled.clearToEOL();
+
+}
+
+
+void WriteRegister(int dat) {
+  digitalWrite(FSYNC, LOW);           // Set FSYNC low before writing to AD9833 registers
+  delayMicroseconds(10);              // Give AD9833 time to get ready to receive data.
+  SPI.transfer(highByte(dat));        // Each AD9833 register is 32 bits wide and each 16
+  SPI.transfer(lowByte(dat));         // bits has to be transferred as 2 x 8-bit bytes.
+  digitalWrite(FSYNC, HIGH);          //Write done. Set FSYNC high
+}
HTTPS SSH

You can clone a snippet to your computer for local editing. Learn more.