Waveform generator

Dependencies:   4DGL-uLCD-SE AFG_project PinDetect RPG mbed

Files at this revision

API Documentation at this revision

Comitter:
carsonbrown27
Date:
Thu Dec 08 05:06:29 2022 +0000
Commit message:
Final Version

Changed in this revision

4DGL-uLCD-SE.lib Show annotated file Show diff for this revision Revisions of this file
AFG_project.lib Show annotated file Show diff for this revision Revisions of this file
PinDetect.lib Show annotated file Show diff for this revision Revisions of this file
RPG.lib Show annotated file Show diff for this revision Revisions of this file
SongPlayer.h Show annotated file Show diff for this revision Revisions of this file
main.cpp Show annotated file Show diff for this revision Revisions of this file
mbed.bld Show annotated file Show diff for this revision Revisions of this file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/4DGL-uLCD-SE.lib	Thu Dec 08 05:06:29 2022 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/4180_1/code/4DGL-uLCD-SE/#2cb1845d7681
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/AFG_project.lib	Thu Dec 08 05:06:29 2022 +0000
@@ -0,0 +1,1 @@
+https://os.mbed.com/users/carsonbrown27/code/AFG_project/#2fa202e02c48
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/PinDetect.lib	Thu Dec 08 05:06:29 2022 +0000
@@ -0,0 +1,1 @@
+https://os.mbed.com/users/AjK/code/PinDetect/#cb3afc45028b
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/RPG.lib	Thu Dec 08 05:06:29 2022 +0000
@@ -0,0 +1,1 @@
+https://os.mbed.com/users/canderson199/code/RPG/#0b389c2c21b5
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/SongPlayer.h	Thu Dec 08 05:06:29 2022 +0000
@@ -0,0 +1,41 @@
+#include "mbed.h"
+// new class to play a note on Speaker based on PwmOut class
+class SongPlayer
+{
+public:
+    SongPlayer(PinName pin) : _pin(pin) {
+// _pin(pin) means pass pin to the constructor
+    }
+// class method to play a note based on PwmOut class
+    void PlaySong(float frequency[], float duration[], float volume=1.0) {
+        vol = volume;
+        notecount = 0;
+        _pin.period(1.0/frequency[notecount]);
+        _pin = volume/2.0;
+        noteduration.attach(this,&SongPlayer::nextnote, duration[notecount]);
+        // setup timer to interrupt for next note to play
+        frequencyptr = frequency;
+        durationptr = duration;
+        //returns after first note starts to play
+    }
+    void nextnote();
+private:
+    Timeout noteduration;
+    PwmOut _pin;
+    int notecount;
+    float vol;
+    float * frequencyptr;
+    float * durationptr;
+};
+//Interrupt Routine to play next note
+void SongPlayer::nextnote()
+{
+    _pin = 0.0;
+    notecount++; //setup next note in song
+    if (durationptr[notecount]!=0.0) {
+        _pin.period(1.0/frequencyptr[notecount]);
+        noteduration.attach(this,&SongPlayer::nextnote, durationptr[notecount]);
+        _pin = vol/2.0;
+    } else
+        _pin = 0.0; //turn off on last note
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main.cpp	Thu Dec 08 05:06:29 2022 +0000
@@ -0,0 +1,447 @@
+#include "mbed.h"
+#include "PinDetect.h"
+#include "uLCD_4DGL.h"
+#include "SongPlayer.h"
+#include "RPG.h"
+#include "MODDMA.h"
+#include "SignalGenDAC.h"
+#include "SignalGenDefs.h"
+#include <cstdlib>
+#include <string.h>
+
+//TO DO:
+//Serial Code (Generate Waveform from GUI)
+
+PinDetect pb_w(p5);
+PinDetect pb_v(p6);
+PinDetect pb_k(p7);
+InterruptIn rpg_a(p14,PullUp);
+InterruptIn rpg_b(p15,PullUp);
+PinDetect pb_rpg(p16);
+PwmOut red(p21); // R
+PwmOut blue(p22); // G
+PwmOut green(p23); // B
+uLCD_4DGL uLCD(p28,p27,p30);
+SongPlayer mySpeaker(p26);
+RPG rpg(p14, p15, p16);
+SignalGenDAC signal;
+Serial pc(USBTX, USBRX);
+
+float note[18]= {1568.0,1396.9,1244.5, 0.0};
+float duration[18]= {0.48,0.24,0.72, 0.0};
+volatile int waveform = 0;
+volatile int values = 1;
+volatile bool khz = true;
+volatile bool generated = false;
+volatile bool prepared = false; 
+volatile int places = 1;
+float scaling[6] = {0.001, 0.01, 0.1, 1, 10, 100};
+volatile float amplitude = 5;
+volatile float offset = 0;
+volatile float frequency = 10;
+volatile int duty_cycle = 50;
+volatile int direction = 0;
+volatile int value_count = 0;
+
+/*
+*** WAVEFORMS ***
+0: dc_offset (offset)
+1: sine (amplitude, offset, frequency)
+2: square (amplitude, offset, frequency)
+3: triangle (amplitude, offset, frequency)
+4: ramp (amplitude, offset, frequency)
+5: pulse (amplitude, offset, frequency, duty_cycle)
+
+*** VALUES ***
+0: amplitude (Default: 5, Resolution: 0.01, Range: -5 to 5)
+1: offset (Default: 0, Resolution: 0.01, Range: -5 to 5)
+2: frequency (Default: 10KHz, Resolution: 1, Range(Hz): 10 to 999, Range(KHz: 1 to 20)
+3: duty_cycle (Default: 50, Resolution: 1, Range: 0 to 100)
+
+*** UNITS ***
+false: Hz
+true: KHz
+
+*** PLACES ***
+0: Thousandths (frequency(KHz))
+1: Hundredths (amplitude, offset, frequency(KHz))
+2: Tenths (amplitude, offset, frequency(KHz))
+3: Ones (amplitude, offset, frequency(KHz), frequency(Hz), duty cycle)
+4: Tens (frequency(KHz), frequency(Hz), duty cycle)
+5: Hundreds (frequency(Hz))
+*/
+
+float map(float x, float in_min, float in_max, float out_min, float out_max) {
+    return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
+}
+
+void updateLCD(void) {
+    value_count = 0;
+    uLCD.cls();
+    // Printing Offset
+    uLCD.locate(1,1);
+    if (values == 1) {
+        uLCD.color(GREEN);
+    } else {
+        uLCD.color(BLUE);
+    }
+    uLCD.printf("Offset: %3.2f", offset);
+    if (waveform != 0) {
+        // Printing Amplitude
+        uLCD.locate(1,0); 
+        if (values == 0) {
+            uLCD.color(GREEN);
+        } else {
+            uLCD.color(BLUE);
+        }
+        uLCD.printf("Amplitude: %3.2f", amplitude);
+        // Printing Frequency
+        uLCD.locate(1,2); 
+        if (values == 2) {
+            uLCD.color(GREEN);
+        } else {
+            uLCD.color(BLUE);
+        }
+        if (khz) {
+            uLCD.printf("Freq(KHz): %3.3f", frequency);
+        } else {
+            uLCD.printf("Freq(Hz): %3.3f", frequency);
+        }
+    }
+    if (waveform == 5) {
+        // Printing Duty Cycle
+        uLCD.locate(1,3);
+        if (values == 3) {
+            uLCD.color(GREEN);
+        } else {
+            uLCD.color(BLUE);
+        }
+        uLCD.printf("Duty Cycle: %3.0d", duty_cycle);
+    }
+    //Printing Places
+    uLCD.locate(1,5);
+    uLCD.color(BLUE);
+    uLCD.printf("Place: %3.3f", scaling[places]);
+    //Printing Waveform
+    uLCD.locate(1,6); 
+    uLCD.color(BLUE);
+    uLCD.printf("Waveform:");
+    uLCD.locate(1,7); 
+    uLCD.color(BLUE);
+    switch (waveform) {
+        case 0:
+            uLCD.printf("DC Offset\n");
+            break;
+        case 1:
+            uLCD.printf("Sine\n");
+            break;
+        case 2:
+            uLCD.printf("Square\n");
+            break;
+        case 3:
+            uLCD.printf("Triangle\n");
+            break;
+        case 4:
+            uLCD.printf("Ramp\n");
+            break;
+        case 5:
+            uLCD.printf("Pulse\n");
+            break;
+        default:
+            break;
+    }
+}
+
+void updateValue(void) {
+    float scale = scaling[places];
+    switch (values) {
+        case 0: // amplitude
+            amplitude += value_count * scale;
+            if (amplitude > 5.0) {
+                amplitude = 5.0;
+            } else if (amplitude < -5.0) {
+                amplitude = -5.0;
+            }
+            uLCD.locate(1,0); 
+            uLCD.color(GREEN);
+            uLCD.printf("Amplitude: %3.2f", amplitude);
+            break;
+        case 1: // offset
+            offset += value_count * scale;
+            if (offset > 5.0) {
+                offset = 5.0;
+            } else if (offset < -5.0) {
+                offset = -5.0;
+            }
+            uLCD.locate(1,1); 
+            uLCD.color(GREEN);
+            uLCD.printf("Offset: %3.2f", offset);
+            break;
+        case 2: // frequency
+            frequency += value_count * scale;
+            if (frequency > 999 && !khz) {
+                frequency = 999;
+            } else if (frequency < 10 && !khz) {
+                frequency = 10;
+            } else if (frequency > 20 && khz) {
+                frequency = 20;
+            } else if (frequency < 0 && khz) {
+                frequency = 0;
+            }
+            uLCD.locate(1,2); 
+            uLCD.color(GREEN);
+            if (khz) {
+                uLCD.printf("Freq(KHz): %3.3f", frequency);
+            } else {
+                uLCD.printf("Freq(Hz): %3.3f", frequency);
+            }
+            break;
+        case 3: // duty cycle
+            duty_cycle += value_count * scale;
+            if (duty_cycle > 100) {
+                duty_cycle = 100;
+            } else if (duty_cycle < 0) {
+                duty_cycle = 0;
+            }
+            uLCD.locate(1,3);
+            uLCD.color(GREEN);
+            uLCD.printf("Duty Cycle: %3.0d", duty_cycle);
+            break;
+        default:
+            break;
+    }
+    value_count = 0;
+}
+
+void changeWaveform(void) {
+    if (waveform < 5) {
+        waveform++;
+    } else {
+        waveform = 0;
+    }
+    if (waveform == 0) {
+        values = 1;
+        places = 1;
+    }
+    updateLCD();
+}
+
+void changeValues(void) {
+    switch (waveform) {
+        case 0: // dc_offset
+            break;
+        case 5: // pulse
+            if (values < 3) {
+                values++;
+            } else {
+                values = 0;
+            }
+            break;
+        default:
+            if (values < 2) {
+                values++;
+            } else {
+                values = 0;
+            }
+            break;
+    }
+    switch (values) {
+        case 0: // amplitude
+            places = 1;
+            break;
+        case 1: // offset
+            places = 1;
+            break;
+        case 2: // frequency
+            if (!khz) {
+                places = 3;
+            } else {
+                places = 0;
+            }
+            break;
+        case 3: // duty cycle
+            places = 3;
+            break;
+        default:
+            break;
+    }    
+    updateLCD();
+}
+
+void changePlaces(void) {
+    switch (values) {
+        case 0: // amplitude
+            if (places < 3) {
+                places++;
+            } else {
+                places = 1;
+            }
+            break;
+        case 1: // offset
+            if (places < 3) {
+                places++;
+            } else {
+                places = 1;
+            }
+            break;
+        case 2: // frequency
+            if (!khz && places < 5) {
+                places++;
+            } else if (!khz) {
+                khz = true;
+                places = 0;
+                frequency = 0;
+            } else if (khz && places < 4) {
+                places++;
+            } else if (khz) {
+                khz = false;
+                places = 3;
+                frequency = 0;
+            }
+            break;
+        case 3: // duty cycle
+            if (places < 4) {
+                places++;
+            } else {
+                places = 3;
+            }
+            break;
+        default:
+            break;
+    }
+    updateLCD();
+}
+
+void adjustValues(void) {
+    value_count += rpg.dir();
+}
+
+void generate(void)
+{
+    if (!generated && !prepared) {
+        uLCD.cls();
+        uLCD.locate(1,0);
+        uLCD.color(BLUE);
+        uLCD.printf("Waveform is being prepared");
+        float adjusted_frequency = frequency;
+        if (khz) {
+            adjusted_frequency *= 1000.0;
+        }
+        switch (waveform) {
+            case 0: // dc_offset
+                signal.PrepareWaveform(SG_SQUARE, 10000, 100, map(offset, -5, 5, 0, 3.3), 0);
+                break;
+            case 1: // sine
+                signal.PrepareWaveform(SG_SINE, adjusted_frequency, 50, map(amplitude, -5, 5, 0, 3.3), map(offset, -5, 5, 0, 3.3));
+                break;
+            case 2: // square
+                signal.PrepareWaveform(SG_SQUARE, adjusted_frequency, 50, map(amplitude, -5, 5, 0, 3.3), map(offset, -5, 5, 0, 3.3));
+                break;
+            case 3: // triangle
+                signal.PrepareWaveform(SG_TRIANGLE, adjusted_frequency, 50, map(amplitude, -5, 5, 0, 3.3), map(offset, -5, 5, 0, 3.3));
+                break;
+            case 4: // ramp
+                signal.PrepareWaveform(SG_SAWTOOTH, adjusted_frequency, 50, map(amplitude, -5, 5, 0, 3.3), map(offset, -5, 5, 0, 3.3));
+                break;
+            case 5: // pulse
+                signal.PrepareWaveform(SG_SQUARE, adjusted_frequency, duty_cycle, map(amplitude, -5, 5, 0, 3.3), map(offset, -5, 5, 0, 3.3));
+                break;
+            default:
+                break;
+        }
+        wait(1.0);
+        mySpeaker.PlaySong(note,duration);
+        red = 1.0;
+        green = 0.0;
+        blue = 1.0;
+        prepared = true;
+    } else if (!generated) {
+        uLCD.cls();
+        uLCD.locate(1,0);
+        uLCD.color(BLUE);
+        uLCD.printf("Waveform is being generated");
+        signal.Start();
+        red = 1.0;
+        green = 1.0;
+        blue = 0.0;
+        generated = true;
+    } else {
+        signal.Stop();
+        red = 0.0;
+        green = 1.0;
+        blue = 1.0;
+        updateLCD();
+        prepared = false;
+        generated = false;
+    }
+}
+
+int main() {
+    pb_w.mode(PullUp);
+    pb_v.mode(PullUp);
+    pb_k.mode(PullUp);
+    pb_rpg.mode(PullDown);
+    wait(.001);
+    pb_w.attach_deasserted(&changeWaveform);
+    pb_v.attach_deasserted(&changeValues);
+    pb_k.attach_deasserted(&changePlaces);
+    pb_rpg.attach_deasserted(&generate);
+    pb_w.setSampleFrequency();
+    pb_v.setSampleFrequency();
+    pb_k.setSampleFrequency();
+    pb_rpg.setSampleFrequency();
+    red = 0.0; // 1.0 is off, 0.0 on
+    green = 1.0;
+    blue = 1.0;
+    rpg_a.rise(&adjustValues);
+    rpg_a.fall(&adjustValues);
+    rpg_b.rise(&adjustValues);
+    rpg_b.fall(&adjustValues);
+    updateLCD();
+    while(1) {
+        if (!generated && !prepared && value_count != 0) {
+            updateValue();
+        }
+        if (pc.readable()) {
+            char str[100];
+            char* message = pc.gets(str, 100);
+            pc.printf(message);
+            if (prepared && !generated) {
+                pc.printf("generating");
+                generate();
+            } else if (prepared && generated) {
+                pc.printf("stopping");
+                generate();
+            } else {
+                uLCD.locate(1,8);
+                uLCD.color(GREEN);
+                uLCD.printf("%s", message);
+                char* token = strtok(message, ",");
+                char* waveformStr = token;
+                token = strtok(NULL, ",");
+                char* amplitudeStr = token;
+                token = strtok(NULL, ",");
+                char* offsetStr = token;
+                token = strtok(NULL, ",");
+                char* frequencyStr = token;
+                token = strtok(NULL, ",");
+                char* duty_cycleStr = token;
+                waveform = atoi(waveformStr);
+                amplitude = atof(amplitudeStr);
+                offset = atof(offsetStr);
+                frequency = atof(frequencyStr);
+                if (frequency >= 1000.0) {
+                    khz = true;
+                    frequency /= 1000.0;
+                } else {
+                    khz = false;
+                }
+                duty_cycle = atoi(duty_cycleStr);
+                updateLCD();
+                prepared = false;
+                generated = false;
+                generate();
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed.bld	Thu Dec 08 05:06:29 2022 +0000
@@ -0,0 +1,1 @@
+https://os.mbed.com/users/mbed_official/code/mbed/builds/65be27845400
\ No newline at end of file