Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependencies: LSM9DS1_Library_cal PinDetect mbed-rtos mbed
main.cpp
00001 #include "mbed.h" 00002 #include "rtos.h" 00003 #include "mpr121.h" 00004 #include "PinDetect.h" 00005 #include "LSM9DS1.h" 00006 00007 // Sound waveform synthesizer 00008 // The program precomputes 128 data points on one wave cycle 00009 // for triangular, sawtooth, and sine waves. These are stored 00010 // and outout to the PWM to vary the PWM duty cycle. A very high 00011 // PWM frequency is used and the frequency of the output soundwave 00012 // is changed by changing the sampling rate. The program uses the 00013 // IMU to shift frequencies, the keypad to choose center frequencies, 00014 // the RGB LED to visually display pitch, and a pushbutton to switch between wave modes. 00015 00016 #define PI 3.141592653589793238462 00017 00018 InterruptIn irq(p11); 00019 I2C i2c1(p9,p10); 00020 Mpr121 touchpad(&i2c1, Mpr121::ADD_VSS); 00021 PwmOut PWM(p26); 00022 Serial pc(USBTX,USBRX); 00023 LSM9DS1 IMU(p28, p27, 0xD6, 0x3C); 00024 Mutex stdio_mutex; 00025 00026 PwmOut RGBLED_r(p21); 00027 PwmOut RGBLED_g(p22); 00028 PwmOut RGBLED_b(p23); 00029 00030 PinDetect pb1(p17); 00031 DigitalOut led1(LED1); 00032 DigitalOut led2(LED2); 00033 DigitalOut led3(LED3); 00034 DigitalOut led4(LED4); 00035 00036 //Global variables used by interrupt routines and threads 00037 volatile int i=0; 00038 volatile int j=0; 00039 float sineInit[128]; 00040 float sawInit[128]; 00041 float triInit[128]; 00042 volatile float baseFreq = 440; 00043 float maxDeltaFreq = 200; 00044 float maxDeltaXAxis = 15; 00045 volatile float freq = 900; 00046 volatile float deltaFreq = 0; 00047 volatile float deltaXAxis = 0; 00048 volatile float deltaXAxisOld = 0; 00049 float frequencyScales[12] = {261.626, 293.665, 329.628, 349.228, 391.995, 440.0, 00050 493.883, 523.251, 587.33, 659.255, 783.991, 880}; 00051 00052 enum Waveforms {sine=0,sawTooth,triangle}; 00053 Waveforms wave = sine; 00054 00055 //Samples IMU every .5 seconds and adjusts frequencies accordingly 00056 void sample_IMU(void const *args) 00057 { 00058 while(1) { 00059 if(IMU.accelAvailable()) { 00060 stdio_mutex.lock(); 00061 deltaXAxisOld = deltaXAxis; 00062 deltaXAxis = (0.0024*IMU.readAccel(X_AXIS)); //Measures difference of IMU from base value of 0 00063 stdio_mutex.unlock(); 00064 } 00065 Thread::wait(500); 00066 } 00067 } 00068 00069 //Plays the current waveform at the current frequency 00070 void playSineWave() { 00071 while(j<150) { //Controls how many cycles. Plays about 3 full cycles 00072 switch(wave) { 00073 case sine: 00074 PWM = (sineInit[i]); 00075 break; 00076 case sawTooth: 00077 PWM = sawInit[i]; 00078 break; 00079 case triangle: 00080 PWM = triInit[i]; 00081 break; 00082 default: 00083 led2 = 0; 00084 led3 = 0; 00085 led4 = 0; 00086 break; 00087 } 00088 //(1.0 + sin((float(i)*freq*6.28318530717959/(128.0))))/2.0); 00089 // increment pointer and wrap around back to 0 at 128 00090 if(i>60) { 00091 j++; 00092 } 00093 i = (i+1) & 0x07F; 00094 wait_us(1000000.0/((freq+deltaFreq)*128)); 00095 } 00096 00097 //At the end of 3 cycles, reset counters 00098 i=0; 00099 j=0; 00100 00101 int value=touchpad.read(0x00); 00102 value +=touchpad.read(0x01)<<8; 00103 if (value == 0) { 00104 //Reset values if keypad is not being touched 00105 PWM = 0; 00106 deltaFreq = 0; 00107 deltaXAxis = 0; 00108 RGBLED_r = 0; 00109 RGBLED_g = 0; 00110 RGBLED_b = 0; 00111 } else { 00112 //If the keypad has a nonzero value, update the frequency and play more cycles 00113 stdio_mutex.lock(); 00114 float diff = (abs(deltaXAxis - deltaXAxisOld) > 2) ? deltaXAxis : deltaXAxisOld; //Makes the delta frequency resistant to noise in the IMU 00115 stdio_mutex.unlock(); 00116 00117 //Calculates delta frequency from center frequency based off of IMU accelerometer 00118 if(abs(diff) > maxDeltaXAxis) 00119 deltaFreq = maxDeltaFreq; 00120 else { 00121 deltaFreq = diff/maxDeltaXAxis*maxDeltaFreq; 00122 } 00123 00124 RGBLED_r = abs(freq-deltaFreq-220)/880; 00125 RGBLED_g = abs(freq-220)/880; 00126 RGBLED_b = abs(freq+deltaFreq-220)/880;; 00127 playSineWave(); 00128 } 00129 } 00130 00131 //Called when the touchpad is tapped 00132 void fallInterrupt() { 00133 int key_code=0; 00134 int n=0; 00135 int value=touchpad.read(0x00); 00136 value +=touchpad.read(0x01)<<8; 00137 for (n=0; n<12; n++) { 00138 if (((value>>n)&0x01)==1) { 00139 key_code=n+1; 00140 } 00141 } 00142 //sets frequency based on the tapped value 00143 freq = frequencyScales[key_code-1]; 00144 if (value != 0) { 00145 playSineWave(); 00146 } 00147 } 00148 00149 //Switches the current waveform and leds 00150 void pb1_released_callback(void){ 00151 if (wave == triangle) { 00152 led2 = 1; 00153 led3 = 0; 00154 led4 = 0; 00155 wave = sine; 00156 } else if (wave == sine) { 00157 led2 = 0; 00158 led3 = 1; 00159 led4 = 0; 00160 wave = sawTooth; 00161 } else { 00162 led2 = 0; 00163 led3 = 0; 00164 led4 = 1; 00165 wave = triangle; 00166 } 00167 } 00168 00169 int main() 00170 { 00171 pc.printf("Program starting."); 00172 PWM.period(1.0/200000.0); 00173 led2 = 1; 00174 led3 = 0; 00175 led4 = 0; 00176 00177 // Precompute 128 sample points on one wave cycle for three wave forms 00178 // used for continuous wave output later 00179 for(int k=0; k<128; k++) { 00180 sineInit[k] = 1.0*((1.0 + sin((float(k)/128.0*2*PI)))/2.0); 00181 sawInit[k] = (1.0 + ((-2.0*1.0/PI)*atan(cos(float(k)*PI/128.0)/sin(float(k)*PI/128.0))))/2.0; 00182 triInit[k] = (1.0 + ((2.0*1.0/PI)*asin(sin(2.0*PI*float(k)/128.0))))/2.0; 00183 // scale the waves from 0.0 to 1.0 - as needed for AnalogOut arg 00184 } 00185 00186 //Configure the IMU 00187 IMU.begin(); 00188 if (!IMU.begin()) { 00189 pc.printf("Failed to communicate with LSM9DS1.\n"); 00190 } 00191 IMU.calibrate(1); 00192 00193 //Configure the Push button 00194 pb1.mode(PullUp); 00195 wait(0.01); 00196 pb1.attach_deasserted(&pb1_released_callback); 00197 pb1.setSampleFrequency(); 00198 00199 //Set up the I2C Touch keypad interrupt 00200 irq.fall(&fallInterrupt); 00201 irq.mode(PullUp); 00202 00203 //And the IMU Sample thread 00204 Thread t1(sample_IMU); 00205 00206 while(1) {} 00207 }
Generated on Mon Jul 25 2022 04:27:35 by
1.7.2