This project allows for the sending of MIDI messages, and setting of variable resistances, controlled by a distance sensor. MIDI input messages can also be used to set the variable resistance.
Dependencies: N5110 PinDetect SRF08 USBDevice mbed PowerControl
main.cpp
00001 /** 00002 @file main.cpp 00003 00004 @brief Program implementation 00005 00006 */ 00007 #include "main.h" 00008 00009 int main () { 00010 00011 ///Powerdown the Ethernet peripheral 00012 PHY_PowerDown(); 00013 00014 ///Read parameter variables from VALS.csv 00015 readNumberValuesFromFile(); 00016 ///Resise the smoothing values vector 00017 smoothingValues .resize(numberValues [distanceSmoothing]+1); 00018 00019 ///Set MCP4151 chip select high initially 00020 CS = 1; 00021 /// Set the MCP4151 SPI for 16 bit mode 3 00022 MCP4151.format(16,3); 00023 /// Set MCP4151 clock frequency to 1000000 00024 MCP4151.frequency(1000000); 00025 00026 ///Initialise the screen and print splash screen 00027 lcd.init(); 00028 lcd.printString("EXPRESSIONATOR",0,1); 00029 lcd.printString("version 1.0",0,2); 00030 lcd.printString("Toby O'Connell",0,4); 00031 wait(3); 00032 00033 ///Setup callback function for range finder ticker 00034 startRangingTicker.attach(&startRangingFlag, 0.1); 00035 00036 ///Set the initial range finder distance 00037 SRF08.setRangeRegister((int)((numberValues [maxDistance]-43.0)/43.0)); 00038 00039 ///Setup callback function for when MIDI messages are received 00040 midi.attach(receivedMIDI); 00041 00042 ///Setup callbacks functions for button presses 00043 buttonA.attach_asserted(&aPressed); //Attach functions to button presses 00044 buttonB.attach_asserted(&bPressed); 00045 buttonC.attach_asserted(&cPressed); 00046 buttonD.attach_asserted(&dPressed); 00047 00048 ///Set button press doubounce freqencies to the default of 20ms 00049 buttonA.setSampleFrequency(); 00050 buttonB.setSampleFrequency(); 00051 buttonC.setSampleFrequency(); 00052 buttonD.setSampleFrequency(); 00053 00054 ///Open the buttons.bmp image in binary, skip the header and copy into a buffer before closing 00055 img = fopen("/local/BUTTONS.BMP", "rb"); 00056 fseek (img , 54 , SEEK_SET); 00057 fread(imgbuffer , (84*3*48), 1, img ); 00058 fclose(img ); 00059 00060 ///Show initial menu 00061 showScreen(); 00062 ///Create infinite while loop to run program repeatedly 00063 while(1) { 00064 if(aButtonFlag ){ 00065 if (menu [state ].screenType == menuType || digitArrowPosition + 1 >= maxValLen ) { 00066 ///screenSelect() if button A is pressed and the screen type is a menu or a page type that is confirmed 00067 screenSelect(); 00068 } else { 00069 ///incrementDigitArrowPos() if button A is pressed and the screen type is not a menu or a page type that is confirmed 00070 incrementDigitArrowPos(); 00071 } 00072 aButtonFlag = 0; 00073 } 00074 if(bButtonFlag ){ 00075 if (menu [state ].screenType == menuType || digitArrowPosition - 1 < 0) { 00076 ///screenBack() if button B is pressed and the screen type is a menu or a page type that is reverted 00077 screenBack(); 00078 } else { 00079 ///decrementDigitArrowPos() if button B is pressed and the screen type is not a menu or a page type that is confirmed 00080 decrementDigitArrowPos(); 00081 } 00082 bButtonFlag = 0; 00083 } 00084 if(cButtonFlag ){ 00085 if (menu [state ].screenType == menuType) { 00086 ///menuUp() if button C is pressed and the screen type is a menu 00087 menuUp(); 00088 } else { 00089 ///incrementValue() if button C is pressed and the screen type is not a menu 00090 incrementValue(); 00091 } 00092 cButtonFlag = 0; 00093 } 00094 if(dButtonFlag ){ 00095 if (menu [state ].screenType == menuType) { 00096 ///menuDown() if button D is pressed and the screen type is a menu 00097 menuDown(); 00098 } else { 00099 ///decrementValue() if button D is pressed and the screen type is not a menu 00100 decrementValue(); 00101 } 00102 dButtonFlag = 0; 00103 } 00104 if(rangingStartFlag ) { 00105 ///Start ranging if the startRangingTicker has fired 00106 rangingStart(); 00107 rangingStartFlag = 0; 00108 } 00109 if(rangeGetFlag ) { 00110 ///Start ranging if the getRangeTimeout has fired 00111 rangeGet(); 00112 rangeGetFlag = 0; 00113 } 00114 if(measuredDistanceFlag ) { 00115 if(numberValues [MIDIOutputOn]) { 00116 ///writeMIDI() if the distance has just been measured and MIDI output is on 00117 writeMIDI(distanceFraction ); 00118 } 00119 if(numberValues [resistanceSourceIndex] == sensorSource) { 00120 ///writeMCP4151() if the distance has just been measured and the resistance source is the ultrasonic sensor 00121 writeMCP4151(distanceFraction ); 00122 } 00123 ///showScreen() if the distance has just been measured and the screen type is the display screen 00124 if(menu [state ].screenType == displayType) showScreen(); 00125 measuredDistanceFlag = 0; 00126 } 00127 if(receivedMIDIFlag ) { 00128 if(numberValues [resistanceSourceIndex] == MIDISource) { 00129 ///writeMCP4151() if a MIDI message has been received and the resistance source is the MIDI input 00130 writeMCP4151(receivedMIDIValue /127.0); 00131 } 00132 ///showScreen() if a MIDI message has been received and the screen type is the display screen 00133 if(menu [state ].screenType == displayType) showScreen(); 00134 receivedMIDIFlag = 0; 00135 } 00136 } 00137 } 00138 00139 00140 void aPressed() { aButtonFlag = 1; } //raise button flags 00141 void bPressed() { bButtonFlag = 1; } 00142 void cPressed() { cButtonFlag = 1; } 00143 void dPressed() { dButtonFlag = 1; } 00144 00145 void startRangingFlag() { rangingStartFlag = 1;} //raise ranging star flag 00146 void getRangeFlag() { rangeGetFlag = 1;} //raise range get flag 00147 00148 void screenSelect() { 00149 if (menu [state ].screenType == pageType) { 00150 ///If exiting a page type screen checkValidity() and do the immediateUpdates() 00151 checkValidity(); 00152 writeNumberValuesToFile(); 00153 immediateUpdates(); 00154 } 00155 ///Change to the next state based on the menu arrow position 00156 state = menu [state ].nextState [menuArrowPosition ]; //Set new menu state basted on arrow position 00157 if (menu [state ].screenType == pageType) { 00158 ///if entering a page type screen save the associated value to oldValue for reverting back 00159 oldValue = numberValues [menu [state ].associatedValueIndex ]; 00160 } 00161 ///Reset menu and digit arrow posiitons 00162 menuArrowPosition = 0; 00163 digitArrowPosition = 0; 00164 ///Update the display 00165 showScreen(); 00166 } 00167 void screenBack() { 00168 if (menu [state ].screenType == pageType) { 00169 ///If reverting back out of a page type screen set the assoicated value to its previous value 00170 numberValues [menu [state ].associatedValueIndex ] = oldValue ; 00171 } 00172 ///Go to FSM parent state 00173 state = menu [state ].previousState ; 00174 ///Reset menu and digit arrow posiitons 00175 menuArrowPosition = 0; 00176 digitArrowPosition = 0; 00177 ///Update the display 00178 showScreen(); 00179 } 00180 void menuUp() { 00181 ///Decrement the menu arrow position 00182 menuArrowPosition = (menuArrowPosition + menu [state ].listLength - 1) % menu [state ].listLength; 00183 ///Update the display 00184 showScreen(); 00185 } 00186 void menuDown() { 00187 ///Increment the menu arrow position 00188 menuArrowPosition = (menuArrowPosition + 1) % menu [state ].listLength; 00189 ///Update the display 00190 showScreen(); 00191 } 00192 00193 void incrementDigitArrowPos() { 00194 ///Increment the digit arrow position 00195 digitArrowPosition += 1; 00196 ///Update the display 00197 showScreen(); 00198 } 00199 void decrementDigitArrowPos() { 00200 ///Increment the digit arrow position 00201 digitArrowPosition -= 1; 00202 ///Update the display 00203 showScreen(); 00204 } 00205 00206 void incrementValue() { 00207 ///Set the increment to '1' 00208 increment = 1; 00209 ///amend the value 00210 amendValue(); 00211 } 00212 00213 void decrementValue() { 00214 ///Set the increment to '-1' 00215 increment = -1; 00216 ///amend the value 00217 amendValue(); 00218 } 00219 00220 int amendNumberValue(int value) { 00221 ///Get the digit at the current arrow position 00222 int currentDigit = (int)(value / pow(10.0,maxValLen -1-digitArrowPosition ))%10; 00223 00224 if((currentDigit == 9 && increment == + 1) || (currentDigit == 0 && increment == - 1)) { 00225 ///If the digit is will become greater than 9 or less then 0, wrap around 00226 value = value - increment * 9 * pow(10.0,maxValLen -1-digitArrowPosition ); 00227 } else { 00228 ///If not, increment / decrement the value 00229 value = value + increment * pow(10.0,maxValLen -1-digitArrowPosition ); 00230 } 00231 00232 ///return the value 00233 return value; 00234 } 00235 00236 void amendValue() { 00237 00238 switch(menu [state ].associatedValueType) { 00239 case INT: 00240 ///If the associated is an int style number amendNumberValue() 00241 numberValues [menu [state ].associatedValueIndex ] = amendNumberValue(numberValues [menu[state ].associatedValueIndex]); 00242 break; 00243 case INDEX: 00244 ///If the associated is an index style number increment / decrement it 00245 numberValues [menu[state ].associatedValueIndex] = (maxNumberValues [menu[state ].associatedMaxValueIndex] + numberValues [menu[state ].associatedValueIndex] + increment ) % maxNumberValues [menu[state ].associatedMaxValueIndex]; 00246 break; 00247 case BOOL: 00248 ///If the associated is a boolean style number invert it 00249 numberValues [menu[state ].associatedValueIndex] = !numberValues [menu[state ].associatedValueIndex]; 00250 break; 00251 } 00252 ///Update the display 00253 showScreen(); 00254 } 00255 00256 00257 00258 void showScreen() { 00259 ///Clear the screen 00260 lcd.clear(); 00261 ///Show the title 00262 lcd.printString(menu [state ].title,0,0); 00263 if(menu [state ].screenType == menuType) { 00264 for (int i = 0;i <= 3; i++) { 00265 ///If the screen type is a menu, print the items in its list 00266 lcd.printString(menu [state ].list[i],6,i+1); 00267 } 00268 if(menu [state ].listLength > 0) { 00269 ///if the list has items in it, then show show the menu arrow pointer 00270 lcd.printString(">",0,menuArrowPosition +1); 00271 } 00272 } else if(menu [state ].screenType == pageType) { 00273 switch (menu [state ].associatedValueType) { 00274 case INT: 00275 ///If the screen type is a parameter editing page and the associated value is an int type number, displayNumber() and show the digit arrow pointer 00276 displayNumber(numberValues [menu [state ].associatedValueIndex],maxNumberValues [menu [state ].associatedMaxValueIndex]); 00277 lcd.printString("^",digitArrowPosition *6+7,3); 00278 break; 00279 case INDEX: 00280 ///If the screen type is a parameter editing page and the associated value is an index type number, displayList() 00281 displayList(valueLists [menu [state ].associatedValueList],numberValues [menu [state ].associatedValueIndex]); 00282 break; 00283 case BOOL: 00284 ///If the screen type is a parameter editing page and the associated value is a boolean type number, displayBool() 00285 displayBool(numberValues [menu [state ].associatedValueIndex]); 00286 break; 00287 } 00288 } else { 00289 ///If the screen type is the display screen, displayMeasured() 00290 displayMeasured(); 00291 } 00292 ///Draw the buttons.bmp image to the screen using drawBMP() 00293 drawBMP(); 00294 } 00295 00296 void displayNumber(int value, int maxValue) { 00297 char buffer[14]; 00298 ///Find the maximum length the incoming value could be 00299 maxValLen = sprintf(buffer,"%d",maxValue); 00300 ///Find the actual length of the incoming value 00301 valLen = sprintf(buffer,"%d",value); 00302 ///Print the value to the screen, filling any unused digit spaces with zeros 00303 for(int i = 0; i <= maxValLen - valLen ; i++) { 00304 lcd.printString("0",6*i+7,2); 00305 } 00306 lcd.printString(buffer,6*(maxValLen -valLen)+7,2); 00307 } 00308 00309 void displayList(string list[], int listIndex) { 00310 char buffer[14]; 00311 maxValLen = 1; 00312 ///Display the list element at the list index 00313 valLen = sprintf(buffer,"%s",list[listIndex].c_str()); 00314 lcd.printString(buffer,7,2); 00315 } 00316 00317 void displayBool(bool toggle) { 00318 char buffer[14]; 00319 maxValLen = 1; 00320 ///Print "On" if the boolean value is 1 and "Off" if the boolean value is 0 00321 valLen = sprintf(buffer,"%s", toggle ? "On" : "Off"); 00322 lcd.printString(buffer,7,2); 00323 } 00324 00325 void displayMeasured() { 00326 char buffer[14]; 00327 ///Print the distance measured by the SRF08 00328 sprintf(buffer,"D: %d",measuredDistance ); 00329 lcd.printString(buffer,7,1); 00330 ///If the MIDI output is on, print the MIDI output value, else print "OFF" 00331 if(numberValues [MIDIOutputOn] == 1) { 00332 sprintf(buffer,"MO: %d",(int)(distanceFraction *127)); 00333 } else { 00334 sprintf(buffer,"MO: OFF"); 00335 } 00336 lcd.printString(buffer,7,2); 00337 ///Print the input MIDI value 00338 sprintf(buffer,"MI: %d",receivedMIDIValue ); 00339 lcd.printString(buffer,7,3); 00340 if(numberValues [resistanceSourceIndex] == sensorSource) { 00341 ///If the resistance source is the SRF08, print the resistance based on that distance 00342 sprintf(buffer,"R: %d",(int)(numberValues [minResistance]+distanceFraction *(numberValues [maxResistance]-numberValues [minResistance]))); 00343 } else if(numberValues [resistanceSourceIndex] == MIDISource) { 00344 ///If the resistance source is the the MIDI input, print the resistance based on the MIDI value 00345 sprintf(buffer,"R: %d",(int)(numberValues [minResistance]+(receivedMIDIValue /127.0)*(numberValues [maxResistance]-numberValues [minResistance]))); 00346 } else { 00347 ///If the resistance source is set to OFF, print "OFF" 00348 sprintf(buffer,"R: OFF"); 00349 } 00350 lcd.printString(buffer,7,4); 00351 } 00352 00353 void rangingStart() { 00354 ///detach the getRangeTimeout 00355 getRangeTimeout.detach(); 00356 ///start the SRF08 ranging 00357 SRF08.startRanging(CM); 00358 ///reattach the getRangeTimeout 00359 getRangeTimeout.attach(&getRangeFlag,0.07); 00360 } 00361 00362 void rangeGet() { 00363 ///Get the measured distance from the SRF08 00364 measuredDistance = SRF08.getRange(); 00365 //Convert the measuredDistance to a float between 0 and 1 00366 distanceFraction = (measuredDistance * 10 - numberValues [minDistance]) / (float)(numberValues [maxDistance]-numberValues [minDistance]); 00367 ///If the distanceFraction is > 1 or < 0, limit it to 1 or 0 00368 if(distanceFraction > 1) distanceFraction = 1; 00369 if(distanceFraction < 0) distanceFraction = 0; 00370 ///smooth() the distance fraction 00371 distanceFraction = smooth(distanceFraction ); 00372 measuredDistanceFlag = 1; 00373 } 00374 00375 void receivedMIDI(MIDIMessage msg) { 00376 if(msg.type() == MIDIMessage::ControlChangeType && msg.controller() == numberValues [MIDIInputController] && msg.channel() == numberValues [MIDIInputChannel]) { 00377 ///If the MIDI message is the right controller change on the right channel, save the value 00378 receivedMIDIValue = msg.value(); 00379 receivedMIDIFlag = 1; 00380 } 00381 } 00382 00383 00384 float smooth(float value) { 00385 ///Erase the first element in the smoothing vector 00386 smoothingValues .erase(smoothingValues .begin()); 00387 ///Add the value to the end of the smoothing vector 00388 smoothingValues .push_back(value); 00389 ///Sum the values in the smoothing vector 00390 float sum = 0; 00391 for(int i = 0; i < smoothingValues .size(); i++) { 00392 sum += smoothingValues [i]; 00393 } 00394 ///Return the mean average of the smoothing vector contents 00395 return sum/(smoothingValues .size()); 00396 } 00397 00398 00399 00400 void writeMCP4151(float value) { 00401 ///Scale the max and min resistances for 0 to 10000 down to 0 to 255. 00402 int scaledMax = (int)(numberValues [maxResistance]/(10000/255.0)); 00403 int scaledMin = (int)(numberValues [minResistance]/(10000/255.0)); 00404 ///Convert the 0 to 1 float value to a 0 to 255 int value for the MCP4151 SPI digital potentiometer 00405 int writeValue = (int)(1 + scaledMin + value * (scaledMax - scaledMin)); 00406 ///Chip enable 00407 CS = 0; 00408 ///Write the new value 00409 MCP4151.write(writeValue); 00410 ///Chip disable 00411 CS = 1; 00412 } 00413 00414 void writeMIDI(float value) { 00415 ///Convert the 0 to 1 float valye to 0 to 127 int value for the MIDI message 00416 int writeValue = (int)(value * 127); 00417 ///Write the 0 to 255 value to the MIDI output 00418 midi.write(MIDIMessage::ControlChange(numberValues [MIDIOutputController],writeValue,numberValues [MIDIOutputChannel])); 00419 } 00420 00421 void drawBMP() { 00422 ///Iterate through each pixel in the image buffer 00423 for (int i = 0; i < 84*48 ; i++) { 00424 if (imgbuffer [i*3] == 0) { 00425 ///If the pixel is not white, write it to the screen 00426 lcd.setPixel(i%84,47-(int)(i/84)); 00427 } 00428 } 00429 lcd.refresh(); 00430 } 00431 00432 void readNumberValuesFromFile() { 00433 ///Open the VALS.csv file 00434 ifstream csvValuesRead("/local/VALS.csv"); 00435 for(int i = 0; i < 11; i++) { 00436 ///Copy each line of the csv file to a each element in the numberValues array 00437 string line; 00438 getline(csvValuesRead, line); 00439 stringstream convertor(line); 00440 convertor >> numberValues [i]; 00441 } 00442 ///Close the VALS.csv file 00443 csvValuesRead.close(); 00444 } 00445 00446 void writeNumberValuesToFile() { 00447 ///Open the VALS.csv file 00448 FILE *csvValuesWrite = fopen("/local/VALS.csv","w"); 00449 for(int i = 0; i < 11; i++) { 00450 ///Write each element in the numberValues array to each line in the csv file 00451 fprintf(csvValuesWrite,"%d\n",numberValues [i]); 00452 } 00453 ///Close the VALS.csv file 00454 fclose(csvValuesWrite); 00455 } 00456 00457 void checkValidity() { 00458 if(numberValues [menu [state ].associatedValueIndex] > maxNumberValues [menu [state ].associatedMaxValueIndex]) { 00459 ///If the associated value is greater than the associated max value after being altered, revert back to the original 00460 numberValues [menu [state ].associatedValueIndex ] = oldValue ; 00461 } 00462 if(numberValues [minResistance] >= numberValues [maxResistance]) { 00463 if(menu [state ].associatedValueIndex == minResistance) { 00464 ///If the min resistance is greater than the max resistance make it 1 less than the maximum 00465 numberValues [minResistance] = numberValues [maxResistance] - 1; 00466 } else { 00467 ///If the max resistance is less than the max resistance make it 1 more than the minimum 00468 numberValues [maxResistance] = numberValues [minResistance] + 1; 00469 } 00470 } 00471 if(numberValues [minDistance] >= numberValues [maxDistance]) { 00472 if(menu [state ].associatedValueIndex == minDistance) { 00473 ///If the min distance is greater than the max distance make it 1 less than the maximum 00474 numberValues [minDistance] = numberValues [maxDistance] - 1; 00475 } else { 00476 ///If the max distance is less than the max distance make it 1 more than the minimum 00477 numberValues [maxDistance] = numberValues [minDistance] + 1; 00478 } 00479 } 00480 } 00481 00482 void immediateUpdates() { 00483 if(menu [state ].associatedValueIndex == maxDistance) { 00484 ///If the associated value is the max distance, set the range of the SRF08 00485 SRF08.setRangeRegister((int)((numberValues [maxDistance]-43.0)/43.0)); 00486 } 00487 if(menu [state ].associatedValueIndex == distanceSmoothing) { 00488 ///If the associated value is the distanceSmoothing value, resize the smoothingValues vector 00489 smoothingValues .resize(numberValues [distanceSmoothing]+1); 00490 } 00491 }
Generated on Thu Jul 14 2022 00:29:32 by 1.7.2