ARDUINO NANO CODE
#include <Wire.h>
#include <Adafruit_MCP4725.h>
#include <Encoder.h>
#include <LiquidCrystal.h>
// Constants
#define DAC_RESOLUTION (9)
#define DEBOUNCE_DELAY 50 // Debounce delay for rotary encoder
#define FREQUENCY_STEP 1 // Frequency step for rotary encoder (change to 1 Hz as
preferred)
#define BUZZER_PIN 2 // Buzzer pin
// Rotary encoder pins
#define ENCODER_CLK_PIN 12
#define ENCODER_DT_PIN 11
#define ENCODER_SW_PIN 10
// LCD pins
#define LCD_RS 14
#define LCD_EN 15
#define LCD_D4 6
#define LCD_D5 5
#define LCD_D6 4
#define LCD_D7 3
Adafruit_MCP4725 dac;
Encoder encoder(ENCODER_CLK_PIN, ENCODER_DT_PIN);
LiquidCrystal lcd(LCD_RS, LCD_EN, LCD_D4, LCD_D5, LCD_D6, LCD_D7);
int lastEncoderValue = 0;
bool lastButtonState = HIGH;
unsigned long lastDebounceTime = 0;
// Variables for waveform and frequency
int waveformType = 0; // 0: square, 1: sine, 2: triangle, 3: sawtooth, 4: inverted sawtooth
int frequency = 1; // Initial frequency in Hz
// Lookup tables
const PROGMEM uint16_t DACLookup_FullSine_9Bit[512] = {
2048, 2073, 2098, 2123, 2148, 2174, 2199, 2224,
2249, 2274, 2299, 2324, 2349, 2373, 2398, 2423,
2448, 2472, 2497, 2521, 2546, 2570, 2594, 2618,
2643, 2667, 2690, 2714, 2738, 2762, 2785, 2808,
2832, 2855, 2878, 2901, 2924, 2946, 2969, 2991,
3013, 3036, 3057, 3079, 3101, 3122, 3144, 3165,
3186, 3207, 3227, 3248, 3268, 3288, 3308, 3328,
3347, 3367, 3386, 3405, 3423, 3442, 3460, 3478,
3496, 3514, 3531, 3548, 3565, 3582, 3599, 3615,
3631, 3647, 3663, 3678, 3693, 3708, 3722, 3737,
3751, 3765, 3778, 3792, 3805, 3817, 3830, 3842,
3854, 3866, 3877, 3888, 3899, 3910, 3920, 3930,
3940, 3950, 3959, 3968, 3976, 3985, 3993, 4000,
4008, 4015, 4022, 4028, 4035, 4041, 4046, 4052,
4057, 4061, 4066, 4070, 4074, 4077, 4081, 4084,
4086, 4088, 4090, 4092, 4094, 4095, 4095, 4095,
4095, 4095, 4095, 4095, 4094, 4092, 4090, 4088,
4086, 4084, 4081, 4077, 4074, 4070, 4066, 4061,
4057, 4052, 4046, 4041, 4035, 4028, 4022, 4015,
4008, 4000, 3993, 3985, 3976, 3968, 3959, 3950,
3940, 3930, 3920, 3910, 3899, 3888, 3877, 3866,
3854, 3842, 3830, 3817, 3805, 3792, 3778, 3765,
3751, 3737, 3722, 3708, 3693, 3678, 3663, 3647,
3631, 3615, 3599, 3582, 3565, 3548, 3531, 3514,
3496, 3478, 3460, 3442, 3423, 3405, 3386, 3367,
3347, 3328, 3308, 3288, 3268, 3248, 3227, 3207,
3186, 3165, 3144, 3122, 3101, 3079, 3057, 3036,
3013, 2991, 2969, 2946, 2924, 2901, 2878, 2855,
2832, 2808, 2785, 2762, 2738, 2714, 2690, 2667,
2643, 2618, 2594, 2570, 2546, 2521, 2497, 2472,
2448, 2423, 2398, 2373, 2349, 2324, 2299, 2274,
2249, 2224, 2199, 2174, 2148, 2123, 2098, 2073,
2048, 2023, 1998, 1973, 1948, 1922, 1897, 1872,
1847, 1822, 1797, 1772, 1747, 1723, 1698, 1673,
1648, 1624, 1599, 1575, 1550, 1526, 1502, 1478,
1453, 1429, 1406, 1382, 1358, 1334, 1311, 1288,
1264, 1241, 1218, 1195, 1172, 1150, 1127, 1105,
1083, 1060, 1039, 1017, 995, 974, 952, 931,
910, 889, 869, 848, 828, 808, 788, 768,
749, 729, 710, 691, 673, 654, 636, 618,
600, 582, 565, 548, 531, 514, 497, 481,
465, 449, 433, 418, 403, 388, 374, 359,
345, 331, 318, 304, 291, 279, 266, 254,
242, 230, 219, 208, 197, 186, 176, 166,
156, 146, 137, 128, 120, 111, 103, 96,
88, 81, 74, 68, 61, 55, 50, 44,
39, 35, 30, 26, 22, 19, 15, 12,
10, 8, 6, 4, 2, 1, 1, 0,
0, 0, 1, 1, 2, 4, 6, 8,
10, 12, 15, 19, 22, 26, 30, 35,
39, 44, 50, 55, 61, 68, 74, 81,
88, 96, 103, 111, 120, 128, 137, 146,
156, 166, 176, 186, 197, 208, 219, 230,
242, 254, 266, 279, 291, 304, 318, 331,
345, 359, 374, 388, 403, 418, 433, 449,
465, 481, 497, 514, 531, 548, 565, 582,
600, 618, 636, 654, 673, 691, 710, 729,
749, 768, 788, 808, 828, 848, 869, 889,
910, 931, 952, 974, 995, 1017, 1039, 1060,
1083, 1105, 1127, 1150, 1172, 1195, 1218, 1241,
1264, 1288, 1311, 1334, 1358, 1382, 1406, 1429,
1453, 1478, 1502, 1526, 1550, 1575, 1599, 1624,
1648, 1673, 1698, 1723, 1747, 1772, 1797, 1822,
1847, 1872, 1897, 1922, 1948, 1973, 1998, 2023,
};
const PROGMEM uint16_t DACLookup_Triangle_100[100] = {
0, 82, 164, 246, 328, 410, 491, 573,
655, 737, 819, 901, 983, 1065, 1147, 1229,
1310, 1392, 1474, 1556, 1638, 1720, 1802, 1884,
1966, 2048, 2129, 2211, 2293, 2375, 2457, 2539,
2621, 2703, 2785, 2867, 2948, 3030, 3112, 3194,
3276, 3358, 3440, 3522, 3604, 3686, 3767, 3849,
3931, 4013, 4095, 4013, 3931, 3849, 3767, 3686,
3604, 3522, 3440, 3358, 3276, 3194, 3112, 3030,
2948, 2867, 2785, 2703, 2621, 2539, 2457, 2375,
2293, 2211, 2129, 2048, 1966, 1884, 1802, 1720,
1638, 1556, 1474, 1392, 1310, 1229, 1147, 1065,
983, 901, 819, 737, 655, 573, 491, 410,
328, 246, 164, 82
};
const PROGMEM uint16_t DACLookup_Sawtooth_100[100] = {
0, 41, 82, 123, 164, 205, 246, 287, 328, 369,
410, 451, 492, 533, 574, 615, 656, 697, 738, 779,
820, 861, 902, 943, 984, 1025, 1066, 1107, 1148, 1189,
1230, 1271, 1312, 1353, 1394, 1435, 1476, 1517, 1558, 1599,
1640, 1681, 1722, 1763, 1804, 1845, 1886, 1927, 1968, 2009,
2050, 2091, 2132, 2173, 2214, 2255, 2296, 2337, 2378, 2419,
2460, 2501, 2542, 2583, 2624, 2665, 2706, 2747, 2788, 2829,
2870, 2911, 2952, 2993, 3034, 3075, 3116, 3157, 3198, 3239,
3280, 3321, 3362, 3403, 3444, 3485, 3526, 3567, 3608, 3649,
3690, 3731, 3772, 3813, 3854, 3895, 3936, 3977, 4018, 4059 // Ensure the total number of
values is exactly 100
};
const PROGMEM uint16_t DACLookup_InvertedSawtooth_100[100] = {
4054, 4013, 3972, 3931, 3890, 3849, 3808, 3767, 3726,
3685, 3644, 3603, 3562, 3521, 3480, 3439, 3398, 3357, 3316,
3275, 3234, 3193, 3152, 3111, 3070, 3029, 2988, 2947, 2906,
2865, 2824, 2783, 2742, 2701, 2660, 2619, 2578, 2537, 2496,
2455, 2414, 2373, 2332, 2291, 2250, 2209, 2168, 2127, 2086,
2045, 2004, 1963, 1922, 1881, 1840, 1799, 1758, 1717, 1676,
1635, 1594, 1553, 1512, 1471, 1430, 1389, 1348, 1307, 1266,
1225, 1184, 1143, 1102, 1061, 1020, 979, 938, 897, 856,
815, 774, 733, 692, 651, 610, 569, 528, 487, 446,
405, 364, 323, 282, 241, 200, 159, 118, 77, 36,
0 // Ensure the total number of values is exactly 100
};
void setup() {
[Link](115200);
[Link](0x60);
[Link](400000L); // Increase I2C speed to 400kHz
pinMode(ENCODER_SW_PIN, INPUT_PULLUP);
pinMode(BUZZER_PIN, OUTPUT); // Set buzzer pin as output
// Initialize LCD
[Link](16, 2);
displayGreeting();
delay(2000); // Display greeting for 2 seconds
// Display initial waveform and frequency
updateLCD();
}
void displayGreeting() {
[Link]();
[Link](0, 0);
[Link]("Welcome to");
[Link](0, 1);
[Link]("MIT INNOVATION");
delay(2000); // Display for 2 seconds
[Link]();
[Link](0, 0);
[Link]("Waveform");
[Link](0, 1);
[Link]("Generator");
delay(2000); // Display for 2 seconds
[Link]();
}
void generateSineWave() {
static unsigned long lastUpdate = 0;
static uint16_t i = 0;
if (micros() - lastUpdate > (1000000 / frequency / 512)) { // Update based on frequency
uint16_t dac_value = pgm_read_word(&(DACLookup_FullSine_9Bit[i]));
[Link](dac_value, false);
[Link](dac_value); // Print DAC value to Serial for plotting
i = (i + 1) % 512;
lastUpdate = micros();
}
}
void generateSquareWave() {
static unsigned long lastUpdate = 0;
static bool high = true;
if (micros() - lastUpdate > (1000000 / frequency / 2)) { // Update based on frequency
[Link](high ? 4095 : 0, false);
[Link](high ? 4095 : 0); // Print the voltage to the Serial Monitor
high = !high;
lastUpdate = micros();
}
}
void generateTriangleWave() {
static unsigned long lastUpdate = 0;
static uint16_t i = 0;
if (micros() - lastUpdate > (1000000 / frequency / 100)) { // Update based on frequency
uint16_t value = pgm_read_word(&(DACLookup_Triangle_100[i]));
[Link](value, false);
[Link](value); // Print the DAC value to the Serial Monitor
i = (i + 1) % 100;
lastUpdate = micros();
}
}
void generateSawtoothWave() {
static unsigned long lastUpdate = 0;
static uint16_t i = 0;
if (micros() - lastUpdate > (1000000 / frequency / 100)) { // Update based on frequency
uint16_t value = pgm_read_word(&(DACLookup_Sawtooth_100[i]));
[Link](value, false);
[Link](value); // Print the DAC value to the Serial Monitor
i = (i + 1) % 100;
lastUpdate = micros();
}
}
void generateInvertedSawtoothWave() {
static unsigned long lastUpdate = 0;
static uint16_t i = 0;
if (micros() - lastUpdate > (1000000 / frequency / 100)) { // Update based on frequency
uint16_t value = pgm_read_word(&(DACLookup_InvertedSawtooth_100[i]));
[Link](value, false);
[Link](value); // Print the DAC value to the Serial Monitor
i = (i + 1) % 100;
lastUpdate = micros();
}
}
void soundBuzzer() {
tone(BUZZER_PIN, 1000); // Sound the buzzer at 1000 Hz
delay(100); // Duration of the buzzer sound
noTone(BUZZER_PIN); // Turn off the buzzer
}
void updateLCD() {
[Link]();
[Link](0, 0); // Move to the first line
switch (waveformType) {
case 0:
[Link]("Wave: Square");
break;
case 1:
[Link]("Wave: Sine");
break;
case 2:
[Link]("Wave: Triangle");
break;
case 3:
[Link]("Wave: Sawtooth");
break;
case 4:
[Link]("Wave: Inv. Sawtooth");
break;
}
[Link](0, 1); // Move to the second line
[Link]("Freq: ");
[Link](frequency);
[Link](" Hz");
}
void loop() {
long encoderPos = [Link]();
int encoderValue = encoderPos / 4; // Adjust based on encoder resolution
if (encoderValue != lastEncoderValue) {
frequency -= (encoderValue - lastEncoderValue) * FREQUENCY_STEP;
if (frequency < 1) frequency = 1; // Prevent negative frequencies
lastEncoderValue = encoderValue;
updateLCD();
}
bool buttonState = digitalRead(ENCODER_SW_PIN);
if (buttonState == LOW && lastButtonState == HIGH) {
waveformType = (waveformType + 1) % 5; // Cycle through waveform types (5 types: square,
sine, triangle, sawtooth, inverted sawtooth)
soundBuzzer(); // Sound buzzer to indicate waveform change
updateLCD();
delay(DEBOUNCE_DELAY); // Debounce delay
}
lastButtonState = buttonState;
// Generate waveform
switch (waveformType) {
case 0:
generateSquareWave();
break;
case 1:
generateSineWave();
break;
case 2:
generateTriangleWave();
break;
case 3:
generateSawtoothWave();
break;
case 4:
generateInvertedSawtoothWave();
break;
}
}