Snippets
Created by
Peter Scargill
last modified
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 | // 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 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
#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);
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(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);
if (eeSave.beepOn) {
tone(BEEPER, 4400, 100);
delay(160);
tone(BEEPER, 4600, 400);
}
}
void beepToggle()
{
if (eeSave.beepOn)
{
eeSave.beepOn = 0;
tone(BEEPER, 4000, 80);
}
else
{
eeSave.beepOn = 1;
tone(BEEPER, 5000, 80);
}
armUpdate();
}
void waveToggle()
{
switch (eeSave.waveType)
{
case SINE: eeSave.waveType = SQUARE; break;
case SQUARE: eeSave.waveType = TRIANGLE; break;
case TRIANGLE: eeSave.waveType = SINE; break;
default: eeSave.waveType = SINE; break;
}
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 frequencyUp()
{
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 frequencyDown()
{
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()
{
eeSave.range = 1000L;
AD9833setFrequency(eeSave.freq, eeSave.waveType);
if (eeSave.beepOn) tone(BEEPER, 4500, 80);
armUpdate();
}
void rangeSet()
{
switch (eeSave.range)
{
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(eeSave.freq, eeSave.waveType);
if (eeSave.beepOn) tone(BEEPER, 5000, 80);
armUpdate();
}
void frequencyReset()
{
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.
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(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 (eeSave.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 (eeSave.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
}
|
Comments (2)
You can clone a snippet to your computer for local editing. Learn more.
Happy new year to everyone except the idiot who keeps spamming my snippets… “Linda Melson” - If I can trace you - you’ll regret the spam for the rest of your life.
Those who are passionate about puzzle games will definitely love Block Blast, with its extremely attractive features and gameplay.