MP3-capable chair with sensor-embedded weight scale.
Dependencies: ACM1602 SDFileSystem VS1053 mbed ClockControl PowerControl
main.cpp
00001 #include <stdio.h> 00002 #include "mbed.h" 00003 #include "defs.h" 00004 #include "SDFileSystem.h" 00005 #include "VS1053.h" 00006 #include "ACM1602.h" 00007 #include "ClockControl.h" 00008 #include "EthernetPowerControl.h" 00009 #include "PowerControl.h" 00010 00011 // Pin settings for mbed LPC1768 00012 SDFileSystem sd(/*MOSI*/ p11, /*MISO*/ p12, /*SCK*/ p13, /*CS*/ p21, /*Mountpoint*/ "sd"); 00013 VS1053 mp3(/*MOSI*/ p11, /*MISO*/ p12, /*SCK*/ p13, 00014 /*CS*/ p22, /*BSYNC*/ p23, /*DREQ*/ p24, /*RST*/ p25, /*SPI freq.*/ 4000000); 00015 BusIn sens(/*Out: 0*/ p20, /*1*/ p19, /*2*/ p18, /*In: 3*/ p17); 00016 BusIn test(/*Out: 0*/ p26, /*1*/ p27, /*2*/ p28, /*In: 3*/ p29); 00017 ACM1602 lcd(/*SDA*/ p9, /*SCL*/ p10, /*Address*/ 0xa0); 00018 DigitalOut audioPower(p30); 00019 DigitalIn test3(p29); 00020 DigitalIn test2(p28); 00021 DigitalIn test1(p27); 00022 DigitalIn test0(p26); 00023 DigitalIn inputSelector(p8); 00024 // Set unused pins to input when using the LPCXpresso board 00025 BusIn __dummy(xp21, xp22, xp23, xp24, xp49, xp50, xp51, xp52, xp53); 00026 Ticker tic; 00027 bool inputFrom; 00028 size_t totalSizeSent; 00029 00030 const char *fileNameList[] = { 00031 "/sd/Track1.mp3", 00032 "/sd/Track2.mp3", 00033 "/sd/Track3.mp3", 00034 "/sd/Track4.mp3" 00035 }; 00036 00037 volatile State state = READY; 00038 volatile Request request = NONE; 00039 00040 /** Setup and initializations */ 00041 void setup(void) { 00042 // Reduce system clock frequency to 48 MHz 00043 setSystemFrequency(0x03, 0x01, 6, 1); 00044 00045 // Power down Ethernet PHY 00046 PHY_PowerDown(); 00047 00048 // Set pull-up mode 00049 inputSelector.mode(PullUp); 00050 test3.mode(PullUp); 00051 test2.mode(PullUp); 00052 test1.mode(PullUp); 00053 test0.mode(PullUp); 00054 wait(0.1); 00055 00056 // Initialize VS1053 00057 mp3.hardwareReset(); 00058 mp3.clockUp(); 00059 wait(0.1); 00060 00061 // Initialize power supply for audio amplifier circuit 00062 audioPower = 0; 00063 00064 // Setup LCD 00065 lcd.init(); 00066 00067 // Read input selector 00068 inputFrom = inputSelector; 00069 } 00070 00071 /** Read voltages from photo sensor pins and detect weightscale point code */ 00072 int readPhotoSensors(void) { 00073 uint8_t bitPattern; 00074 00075 // Read all photo sensor inputs 00076 if (inputFrom) { 00077 // Read from photo sensors when Input Selector reads high 00078 // (Input is inverted by 74HC14) 00079 bitPattern = ~sens & 0xf; 00080 } else { 00081 // Read from test pins when Input Selector reads low 00082 bitPattern = test; 00083 } 00084 00085 switch (bitPattern) { 00086 // 1 when open, 0 when shut 00087 // Higher bit is on outer side 00088 case 0xf: // 1111: no load 00089 return 0; 00090 case 0xe: // 1110: slight load 00091 return 1; 00092 case 0xc: // 1100 00093 return 2; 00094 case 0x8: // 1000 00095 return 3; 00096 case 0x0: // 0000: heavy load 00097 return 4; 00098 default: // Other than expectation: erroneous pattern 00099 return -1; 00100 } 00101 } 00102 00103 /** Poll/sample weightscale inputs and issue requests */ 00104 void pollAndRequest() { 00105 const char* stateNameList[] = { 00106 "STOPPING", // -2 00107 "CANCELING", // -1 00108 "READY", // 0 00109 "PLAYING1", // 1 00110 "PLAYING2", // 2 00111 "PLAYING3", // 3 00112 "PLAYING4" // 4 00113 }; 00114 int code; 00115 static int codePrev = 0; 00116 static uint8_t holdTimes = 0; 00117 00118 // Get weightscale point code by reading photo sensors 00119 code = readPhotoSensors(); 00120 00121 // Count the times that the given code persists 00122 if (code == codePrev && code != -1) { 00123 if (holdTimes < 99) { 00124 holdTimes++; 00125 } 00126 } else { 00127 holdTimes = 0; 00128 } 00129 00130 // Print status to LCD: 00131 // current state, photo sensor inputs, hold count, 00132 // file size sent to VS1053 00133 lcd.locate(0, 0); 00134 lcd.printf("%-9s in=%2d", stateNameList[state + 2], code); 00135 lcd.locate(0, 1); 00136 lcd.printf("x%2d ", holdTimes); 00137 switch (state) { 00138 case PLAYING1: case PLAYING2: case PLAYING3: case PLAYING4: 00139 if (totalSizeSent >= 1000000) { 00140 lcd.printf("%9.2f MB", totalSizeSent / 1048576.0); 00141 } else if (totalSizeSent >= 1000) { 00142 lcd.printf("%9.2f KB", totalSizeSent / 1024.0); 00143 } else { 00144 lcd.printf("%6d bytes", totalSizeSent); 00145 } 00146 break; 00147 default: 00148 lcd.printf(" <No File>"); 00149 break; 00150 } 00151 00152 // Once the point is stable enough, make a request 00153 if (holdTimes == SETTLING_COUNT) { 00154 if (code == 0) { 00155 // Stable no load: stop request 00156 request = STOP_REQUEST; 00157 } else { 00158 // Certain stable load: play request 1..4 00159 // Ignore cases while playing the same track 00160 if (state != code) { 00161 request = (Request) code; 00162 } 00163 } 00164 } 00165 00166 // Preserve this time's code 00167 codePrev = code; 00168 } 00169 00170 /** Player control in accordance with requests */ 00171 void controlTrack() { 00172 static FILE *fp = NULL; 00173 size_t sizeRead = 0; 00174 uint8_t buf[BLOCK_SIZE]; 00175 00176 switch (state) { 00177 case READY: 00178 switch (request) { 00179 case STOP_REQUEST: 00180 // Clear stop request 00181 request = NONE; 00182 break; 00183 case PLAY1_REQUEST: case PLAY2_REQUEST: case PLAY3_REQUEST: case PLAY4_REQUEST: 00184 fp = fopen(fileNameList[request - 1], "rb"); 00185 if (fp) { 00186 clearerr(fp); 00187 00188 // Power supply on 00189 audioPower = 1; 00190 00191 totalSizeSent = 0; 00192 state = (State) request; 00193 } 00194 // Clear play request 00195 request = NONE; 00196 break; 00197 default: 00198 break; 00199 } 00200 break; 00201 case PLAYING1: case PLAYING2: case PLAYING3: case PLAYING4: 00202 if (request == NONE) { 00203 // Continue playback 00204 if (feof(fp)) { 00205 // Close when the track reaches the end 00206 fclose(fp); 00207 fp = NULL; 00208 00209 // Invoke play request again 00210 request = (Request) state; 00211 state = READY; 00212 } else { 00213 sizeRead = fread(buf, sizeof(char), BLOCK_SIZE, fp); 00214 totalSizeSent += mp3.sendDataBlock(buf, sizeRead); 00215 } 00216 } else { 00217 // Cancel current track when something's requested 00218 fclose(fp); 00219 fp = NULL; 00220 state = CANCELING; 00221 } 00222 break; 00223 case CANCELING: 00224 if (mp3.sendCancel()) { 00225 state = STOPPING; 00226 } 00227 break; 00228 case STOPPING: 00229 if (mp3.stop()) { 00230 state = READY; 00231 } 00232 if (request == STOP_REQUEST) { 00233 // Clear stop request 00234 request = NONE; 00235 // Power supply off 00236 audioPower = 0; 00237 } 00238 break; 00239 default: 00240 break; 00241 } 00242 } 00243 00244 /** Print build timestamp (in JST) */ 00245 void printTimestamp() { 00246 time_t secBuild; 00247 struct tm *tmBuild; 00248 char sbuf[11]; 00249 00250 secBuild = MBED_BUILD_TIMESTAMP + 9 * 60 * 60; 00251 tmBuild = localtime(&secBuild); 00252 00253 strftime(sbuf, 11, "%Y-%m-%d", tmBuild); 00254 lcd.locate(0, 0); 00255 lcd.printf("Build %8s", sbuf); 00256 wait(0.0); 00257 strftime(sbuf, 11, "%H:%M:%S", tmBuild); 00258 lcd.locate(0, 1); 00259 lcd.printf(" T%8s", sbuf); 00260 wait(2.0); 00261 } 00262 00263 /** Test files in the SD memory card */ 00264 uint8_t testFiles() { 00265 FILE *fpTest = NULL; 00266 bool sdTestResult = 0x00; 00267 00268 lcd.cls(); 00269 lcd.locate(0, 0); 00270 lcd.printf("No memory cards "); 00271 wait(0.0); 00272 lcd.locate(0, 0); 00273 lcd.printf("Track / / / Ok"); 00274 for (uint8_t i = 1; i <= 4; i++) { 00275 fpTest = fopen(fileNameList[i - 1], "rb"); 00276 if (fpTest) { 00277 lcd.locate(2 * i + 4, 0); 00278 lcd.printf("%d", i); 00279 fclose(fpTest); 00280 } else { 00281 sdTestResult |= 0x01 << (i - 1); 00282 } 00283 } 00284 lcd.locate(0, 1); 00285 if (sdTestResult == 0x00) { 00286 lcd.printf("SD Test Pass "); 00287 wait(1.0); 00288 lcd.cls(); 00289 } else { 00290 lcd.printf("SD Test Fail "); 00291 } 00292 return sdTestResult; 00293 } 00294 00295 /** Main routine */ 00296 int main(void) { 00297 setup(); 00298 00299 // Print build timestamp 00300 printTimestamp(); 00301 00302 // Test files: Enter an infinite loop on failure 00303 if (testFiles()) { 00304 while (1) {} 00305 } 00306 00307 // Set Ticker interrupt routine 00308 tic.attach(&pollAndRequest, POLL_INTERVAL_SEC); 00309 00310 // Main loop 00311 while (1) { 00312 controlTrack(); 00313 } 00314 }
Generated on Fri Jul 15 2022 00:07:31 by 1.7.2