MP3-capable chair with sensor-embedded weight scale.

Dependencies:   ACM1602 SDFileSystem VS1053 mbed ClockControl PowerControl

Committer:
kayekss
Date:
Tue Apr 01 16:19:56 2014 +0000
Revision:
3:64f0ba828a2e
Parent:
2:844bedc9dc63
(1) Photo sensor input is digitized as the circuitry adds an external Schmitt-Trigger (2) Input Selector switch's logic is inverted

Who changed what in which revision?

UserRevisionLine numberNew contents of line
kayekss 0:d9789f57fd9d 1 #include <stdio.h>
kayekss 0:d9789f57fd9d 2 #include "mbed.h"
kayekss 0:d9789f57fd9d 3 #include "defs.h"
kayekss 0:d9789f57fd9d 4 #include "SDFileSystem.h"
kayekss 0:d9789f57fd9d 5 #include "VS1053.h"
kayekss 0:d9789f57fd9d 6 #include "ACM1602.h"
kayekss 1:ef257d63d970 7 #include "ClockControl.h"
kayekss 1:ef257d63d970 8 #include "EthernetPowerControl.h"
kayekss 1:ef257d63d970 9 #include "PowerControl.h"
kayekss 0:d9789f57fd9d 10
kayekss 2:844bedc9dc63 11 // Pin settings for mbed LPC1768
kayekss 1:ef257d63d970 12 SDFileSystem sd(/*MOSI*/ p11, /*MISO*/ p12, /*SCK*/ p13, /*CS*/ p21, /*Mountpoint*/ "sd");
kayekss 1:ef257d63d970 13 VS1053 mp3(/*MOSI*/ p11, /*MISO*/ p12, /*SCK*/ p13,
kayekss 1:ef257d63d970 14 /*CS*/ p22, /*BSYNC*/ p23, /*DREQ*/ p24, /*RST*/ p25, /*SPI freq.*/ 4000000);
kayekss 3:64f0ba828a2e 15 BusIn sens(/*Out: 0*/ p20, /*1*/ p19, /*2*/ p18, /*In: 3*/ p17);
kayekss 3:64f0ba828a2e 16 BusIn test(/*Out: 0*/ p26, /*1*/ p27, /*2*/ p28, /*In: 3*/ p29);
kayekss 1:ef257d63d970 17 ACM1602 lcd(/*SDA*/ p9, /*SCL*/ p10, /*Address*/ 0xa0);
kayekss 1:ef257d63d970 18 DigitalOut audioPower(p30);
kayekss 3:64f0ba828a2e 19 DigitalIn test3(p29);
kayekss 3:64f0ba828a2e 20 DigitalIn test2(p28);
kayekss 3:64f0ba828a2e 21 DigitalIn test1(p27);
kayekss 3:64f0ba828a2e 22 DigitalIn test0(p26);
kayekss 1:ef257d63d970 23 DigitalIn inputSelector(p8);
kayekss 2:844bedc9dc63 24 // Set unused pins to input when using the LPCXpresso board
kayekss 1:ef257d63d970 25 BusIn __dummy(xp21, xp22, xp23, xp24, xp49, xp50, xp51, xp52, xp53);
kayekss 0:d9789f57fd9d 26 Ticker tic;
kayekss 1:ef257d63d970 27 bool inputFrom;
kayekss 1:ef257d63d970 28 size_t totalSizeSent;
kayekss 0:d9789f57fd9d 29
kayekss 0:d9789f57fd9d 30 const char *fileNameList[] = {
kayekss 0:d9789f57fd9d 31 "/sd/Track1.mp3",
kayekss 0:d9789f57fd9d 32 "/sd/Track2.mp3",
kayekss 0:d9789f57fd9d 33 "/sd/Track3.mp3",
kayekss 0:d9789f57fd9d 34 "/sd/Track4.mp3"
kayekss 0:d9789f57fd9d 35 };
kayekss 0:d9789f57fd9d 36
kayekss 0:d9789f57fd9d 37 volatile State state = READY;
kayekss 0:d9789f57fd9d 38 volatile Request request = NONE;
kayekss 0:d9789f57fd9d 39
kayekss 0:d9789f57fd9d 40 /** Setup and initializations */
kayekss 0:d9789f57fd9d 41 void setup(void) {
kayekss 2:844bedc9dc63 42 // Reduce system clock frequency to 48 MHz
kayekss 3:64f0ba828a2e 43 setSystemFrequency(0x03, 0x01, 6, 1);
kayekss 1:ef257d63d970 44
kayekss 1:ef257d63d970 45 // Power down Ethernet PHY
kayekss 1:ef257d63d970 46 PHY_PowerDown();
kayekss 1:ef257d63d970 47
kayekss 1:ef257d63d970 48 // Set pull-up mode
kayekss 1:ef257d63d970 49 inputSelector.mode(PullUp);
kayekss 1:ef257d63d970 50 test3.mode(PullUp);
kayekss 1:ef257d63d970 51 test2.mode(PullUp);
kayekss 1:ef257d63d970 52 test1.mode(PullUp);
kayekss 1:ef257d63d970 53 test0.mode(PullUp);
kayekss 1:ef257d63d970 54 wait(0.1);
kayekss 1:ef257d63d970 55
kayekss 0:d9789f57fd9d 56 // Initialize VS1053
kayekss 0:d9789f57fd9d 57 mp3.hardwareReset();
kayekss 0:d9789f57fd9d 58 mp3.clockUp();
kayekss 0:d9789f57fd9d 59 wait(0.1);
kayekss 0:d9789f57fd9d 60
kayekss 0:d9789f57fd9d 61 // Initialize power supply for audio amplifier circuit
kayekss 0:d9789f57fd9d 62 audioPower = 0;
kayekss 0:d9789f57fd9d 63
kayekss 0:d9789f57fd9d 64 // Setup LCD
kayekss 0:d9789f57fd9d 65 lcd.init();
kayekss 0:d9789f57fd9d 66
kayekss 1:ef257d63d970 67 // Read input selector
kayekss 1:ef257d63d970 68 inputFrom = inputSelector;
kayekss 0:d9789f57fd9d 69 }
kayekss 0:d9789f57fd9d 70
kayekss 0:d9789f57fd9d 71 /** Read voltages from photo sensor pins and detect weightscale point code */
kayekss 0:d9789f57fd9d 72 int readPhotoSensors(void) {
kayekss 0:d9789f57fd9d 73 uint8_t bitPattern;
kayekss 0:d9789f57fd9d 74
kayekss 0:d9789f57fd9d 75 // Read all photo sensor inputs
kayekss 1:ef257d63d970 76 if (inputFrom) {
kayekss 3:64f0ba828a2e 77 // Read from photo sensors when Input Selector reads high
kayekss 3:64f0ba828a2e 78 // (Input is inverted by 74HC14)
kayekss 3:64f0ba828a2e 79 bitPattern = ~sens & 0xf;
kayekss 1:ef257d63d970 80 } else {
kayekss 3:64f0ba828a2e 81 // Read from test pins when Input Selector reads low
kayekss 3:64f0ba828a2e 82 bitPattern = test;
kayekss 1:ef257d63d970 83 }
kayekss 0:d9789f57fd9d 84
kayekss 0:d9789f57fd9d 85 switch (bitPattern) {
kayekss 0:d9789f57fd9d 86 // 1 when open, 0 when shut
kayekss 0:d9789f57fd9d 87 // Higher bit is on outer side
kayekss 0:d9789f57fd9d 88 case 0xf: // 1111: no load
kayekss 0:d9789f57fd9d 89 return 0;
kayekss 0:d9789f57fd9d 90 case 0xe: // 1110: slight load
kayekss 0:d9789f57fd9d 91 return 1;
kayekss 0:d9789f57fd9d 92 case 0xc: // 1100
kayekss 0:d9789f57fd9d 93 return 2;
kayekss 0:d9789f57fd9d 94 case 0x8: // 1000
kayekss 0:d9789f57fd9d 95 return 3;
kayekss 0:d9789f57fd9d 96 case 0x0: // 0000: heavy load
kayekss 0:d9789f57fd9d 97 return 4;
kayekss 0:d9789f57fd9d 98 default: // Other than expectation: erroneous pattern
kayekss 0:d9789f57fd9d 99 return -1;
kayekss 0:d9789f57fd9d 100 }
kayekss 0:d9789f57fd9d 101 }
kayekss 0:d9789f57fd9d 102
kayekss 0:d9789f57fd9d 103 /** Poll/sample weightscale inputs and issue requests */
kayekss 0:d9789f57fd9d 104 void pollAndRequest() {
kayekss 0:d9789f57fd9d 105 const char* stateNameList[] = {
kayekss 0:d9789f57fd9d 106 "STOPPING", // -2
kayekss 0:d9789f57fd9d 107 "CANCELING", // -1
kayekss 0:d9789f57fd9d 108 "READY", // 0
kayekss 0:d9789f57fd9d 109 "PLAYING1", // 1
kayekss 0:d9789f57fd9d 110 "PLAYING2", // 2
kayekss 0:d9789f57fd9d 111 "PLAYING3", // 3
kayekss 0:d9789f57fd9d 112 "PLAYING4" // 4
kayekss 0:d9789f57fd9d 113 };
kayekss 0:d9789f57fd9d 114 int code;
kayekss 0:d9789f57fd9d 115 static int codePrev = 0;
kayekss 0:d9789f57fd9d 116 static uint8_t holdTimes = 0;
kayekss 0:d9789f57fd9d 117
kayekss 0:d9789f57fd9d 118 // Get weightscale point code by reading photo sensors
kayekss 0:d9789f57fd9d 119 code = readPhotoSensors();
kayekss 0:d9789f57fd9d 120
kayekss 0:d9789f57fd9d 121 // Count the times that the given code persists
kayekss 0:d9789f57fd9d 122 if (code == codePrev && code != -1) {
kayekss 0:d9789f57fd9d 123 if (holdTimes < 99) {
kayekss 0:d9789f57fd9d 124 holdTimes++;
kayekss 0:d9789f57fd9d 125 }
kayekss 0:d9789f57fd9d 126 } else {
kayekss 0:d9789f57fd9d 127 holdTimes = 0;
kayekss 0:d9789f57fd9d 128 }
kayekss 1:ef257d63d970 129
kayekss 1:ef257d63d970 130 // Print status to LCD:
kayekss 1:ef257d63d970 131 // current state, photo sensor inputs, hold count,
kayekss 1:ef257d63d970 132 // file size sent to VS1053
kayekss 0:d9789f57fd9d 133 lcd.locate(0, 0);
kayekss 1:ef257d63d970 134 lcd.printf("%-9s in=%2d", stateNameList[state + 2], code);
kayekss 0:d9789f57fd9d 135 lcd.locate(0, 1);
kayekss 1:ef257d63d970 136 lcd.printf("x%2d ", holdTimes);
kayekss 1:ef257d63d970 137 switch (state) {
kayekss 1:ef257d63d970 138 case PLAYING1: case PLAYING2: case PLAYING3: case PLAYING4:
kayekss 1:ef257d63d970 139 if (totalSizeSent >= 1000000) {
kayekss 1:ef257d63d970 140 lcd.printf("%9.2f MB", totalSizeSent / 1048576.0);
kayekss 1:ef257d63d970 141 } else if (totalSizeSent >= 1000) {
kayekss 1:ef257d63d970 142 lcd.printf("%9.2f KB", totalSizeSent / 1024.0);
kayekss 1:ef257d63d970 143 } else {
kayekss 1:ef257d63d970 144 lcd.printf("%6d bytes", totalSizeSent);
kayekss 1:ef257d63d970 145 }
kayekss 1:ef257d63d970 146 break;
kayekss 1:ef257d63d970 147 default:
kayekss 1:ef257d63d970 148 lcd.printf(" <No File>");
kayekss 1:ef257d63d970 149 break;
kayekss 1:ef257d63d970 150 }
kayekss 0:d9789f57fd9d 151
kayekss 0:d9789f57fd9d 152 // Once the point is stable enough, make a request
kayekss 0:d9789f57fd9d 153 if (holdTimes == SETTLING_COUNT) {
kayekss 0:d9789f57fd9d 154 if (code == 0) {
kayekss 0:d9789f57fd9d 155 // Stable no load: stop request
kayekss 0:d9789f57fd9d 156 request = STOP_REQUEST;
kayekss 0:d9789f57fd9d 157 } else {
kayekss 0:d9789f57fd9d 158 // Certain stable load: play request 1..4
kayekss 0:d9789f57fd9d 159 // Ignore cases while playing the same track
kayekss 0:d9789f57fd9d 160 if (state != code) {
kayekss 0:d9789f57fd9d 161 request = (Request) code;
kayekss 0:d9789f57fd9d 162 }
kayekss 0:d9789f57fd9d 163 }
kayekss 0:d9789f57fd9d 164 }
kayekss 0:d9789f57fd9d 165
kayekss 0:d9789f57fd9d 166 // Preserve this time's code
kayekss 0:d9789f57fd9d 167 codePrev = code;
kayekss 0:d9789f57fd9d 168 }
kayekss 0:d9789f57fd9d 169
kayekss 0:d9789f57fd9d 170 /** Player control in accordance with requests */
kayekss 0:d9789f57fd9d 171 void controlTrack() {
kayekss 1:ef257d63d970 172 static FILE *fp = NULL;
kayekss 1:ef257d63d970 173 size_t sizeRead = 0;
kayekss 1:ef257d63d970 174 uint8_t buf[BLOCK_SIZE];
kayekss 0:d9789f57fd9d 175
kayekss 0:d9789f57fd9d 176 switch (state) {
kayekss 0:d9789f57fd9d 177 case READY:
kayekss 0:d9789f57fd9d 178 switch (request) {
kayekss 0:d9789f57fd9d 179 case STOP_REQUEST:
kayekss 0:d9789f57fd9d 180 // Clear stop request
kayekss 0:d9789f57fd9d 181 request = NONE;
kayekss 0:d9789f57fd9d 182 break;
kayekss 1:ef257d63d970 183 case PLAY1_REQUEST: case PLAY2_REQUEST: case PLAY3_REQUEST: case PLAY4_REQUEST:
kayekss 0:d9789f57fd9d 184 fp = fopen(fileNameList[request - 1], "rb");
kayekss 0:d9789f57fd9d 185 if (fp) {
kayekss 1:ef257d63d970 186 clearerr(fp);
kayekss 1:ef257d63d970 187
kayekss 0:d9789f57fd9d 188 // Power supply on
kayekss 0:d9789f57fd9d 189 audioPower = 1;
kayekss 0:d9789f57fd9d 190
kayekss 0:d9789f57fd9d 191 totalSizeSent = 0;
kayekss 0:d9789f57fd9d 192 state = (State) request;
kayekss 0:d9789f57fd9d 193 }
kayekss 0:d9789f57fd9d 194 // Clear play request
kayekss 0:d9789f57fd9d 195 request = NONE;
kayekss 0:d9789f57fd9d 196 break;
kayekss 0:d9789f57fd9d 197 default:
kayekss 0:d9789f57fd9d 198 break;
kayekss 0:d9789f57fd9d 199 }
kayekss 0:d9789f57fd9d 200 break;
kayekss 0:d9789f57fd9d 201 case PLAYING1: case PLAYING2: case PLAYING3: case PLAYING4:
kayekss 0:d9789f57fd9d 202 if (request == NONE) {
kayekss 1:ef257d63d970 203 // Continue playback
kayekss 1:ef257d63d970 204 if (feof(fp)) {
kayekss 1:ef257d63d970 205 // Close when the track reaches the end
kayekss 0:d9789f57fd9d 206 fclose(fp);
kayekss 1:ef257d63d970 207 fp = NULL;
kayekss 0:d9789f57fd9d 208
kayekss 0:d9789f57fd9d 209 // Invoke play request again
kayekss 0:d9789f57fd9d 210 request = (Request) state;
kayekss 0:d9789f57fd9d 211 state = READY;
kayekss 1:ef257d63d970 212 } else {
kayekss 1:ef257d63d970 213 sizeRead = fread(buf, sizeof(char), BLOCK_SIZE, fp);
kayekss 1:ef257d63d970 214 totalSizeSent += mp3.sendDataBlock(buf, sizeRead);
kayekss 0:d9789f57fd9d 215 }
kayekss 0:d9789f57fd9d 216 } else {
kayekss 0:d9789f57fd9d 217 // Cancel current track when something's requested
kayekss 0:d9789f57fd9d 218 fclose(fp);
kayekss 1:ef257d63d970 219 fp = NULL;
kayekss 0:d9789f57fd9d 220 state = CANCELING;
kayekss 0:d9789f57fd9d 221 }
kayekss 0:d9789f57fd9d 222 break;
kayekss 0:d9789f57fd9d 223 case CANCELING:
kayekss 0:d9789f57fd9d 224 if (mp3.sendCancel()) {
kayekss 0:d9789f57fd9d 225 state = STOPPING;
kayekss 0:d9789f57fd9d 226 }
kayekss 0:d9789f57fd9d 227 break;
kayekss 0:d9789f57fd9d 228 case STOPPING:
kayekss 0:d9789f57fd9d 229 if (mp3.stop()) {
kayekss 0:d9789f57fd9d 230 state = READY;
kayekss 0:d9789f57fd9d 231 }
kayekss 0:d9789f57fd9d 232 if (request == STOP_REQUEST) {
kayekss 0:d9789f57fd9d 233 // Clear stop request
kayekss 0:d9789f57fd9d 234 request = NONE;
kayekss 0:d9789f57fd9d 235 // Power supply off
kayekss 0:d9789f57fd9d 236 audioPower = 0;
kayekss 0:d9789f57fd9d 237 }
kayekss 0:d9789f57fd9d 238 break;
kayekss 0:d9789f57fd9d 239 default:
kayekss 0:d9789f57fd9d 240 break;
kayekss 0:d9789f57fd9d 241 }
kayekss 0:d9789f57fd9d 242 }
kayekss 0:d9789f57fd9d 243
kayekss 0:d9789f57fd9d 244 /** Print build timestamp (in JST) */
kayekss 0:d9789f57fd9d 245 void printTimestamp() {
kayekss 0:d9789f57fd9d 246 time_t secBuild;
kayekss 0:d9789f57fd9d 247 struct tm *tmBuild;
kayekss 0:d9789f57fd9d 248 char sbuf[11];
kayekss 0:d9789f57fd9d 249
kayekss 0:d9789f57fd9d 250 secBuild = MBED_BUILD_TIMESTAMP + 9 * 60 * 60;
kayekss 0:d9789f57fd9d 251 tmBuild = localtime(&secBuild);
kayekss 0:d9789f57fd9d 252
kayekss 0:d9789f57fd9d 253 strftime(sbuf, 11, "%Y-%m-%d", tmBuild);
kayekss 0:d9789f57fd9d 254 lcd.locate(0, 0);
kayekss 0:d9789f57fd9d 255 lcd.printf("Build %8s", sbuf);
kayekss 0:d9789f57fd9d 256 wait(0.0);
kayekss 0:d9789f57fd9d 257 strftime(sbuf, 11, "%H:%M:%S", tmBuild);
kayekss 0:d9789f57fd9d 258 lcd.locate(0, 1);
kayekss 0:d9789f57fd9d 259 lcd.printf(" T%8s", sbuf);
kayekss 0:d9789f57fd9d 260 wait(2.0);
kayekss 0:d9789f57fd9d 261 }
kayekss 0:d9789f57fd9d 262
kayekss 0:d9789f57fd9d 263 /** Test files in the SD memory card */
kayekss 0:d9789f57fd9d 264 uint8_t testFiles() {
kayekss 0:d9789f57fd9d 265 FILE *fpTest = NULL;
kayekss 0:d9789f57fd9d 266 bool sdTestResult = 0x00;
kayekss 0:d9789f57fd9d 267
kayekss 0:d9789f57fd9d 268 lcd.cls();
kayekss 0:d9789f57fd9d 269 lcd.locate(0, 0);
kayekss 0:d9789f57fd9d 270 lcd.printf("No memory cards ");
kayekss 0:d9789f57fd9d 271 wait(0.0);
kayekss 0:d9789f57fd9d 272 lcd.locate(0, 0);
kayekss 0:d9789f57fd9d 273 lcd.printf("Track / / / Ok");
kayekss 0:d9789f57fd9d 274 for (uint8_t i = 1; i <= 4; i++) {
kayekss 0:d9789f57fd9d 275 fpTest = fopen(fileNameList[i - 1], "rb");
kayekss 0:d9789f57fd9d 276 if (fpTest) {
kayekss 0:d9789f57fd9d 277 lcd.locate(2 * i + 4, 0);
kayekss 0:d9789f57fd9d 278 lcd.printf("%d", i);
kayekss 0:d9789f57fd9d 279 fclose(fpTest);
kayekss 0:d9789f57fd9d 280 } else {
kayekss 0:d9789f57fd9d 281 sdTestResult |= 0x01 << (i - 1);
kayekss 0:d9789f57fd9d 282 }
kayekss 0:d9789f57fd9d 283 }
kayekss 0:d9789f57fd9d 284 lcd.locate(0, 1);
kayekss 0:d9789f57fd9d 285 if (sdTestResult == 0x00) {
kayekss 0:d9789f57fd9d 286 lcd.printf("SD Test Pass ");
kayekss 0:d9789f57fd9d 287 wait(1.0);
kayekss 0:d9789f57fd9d 288 lcd.cls();
kayekss 0:d9789f57fd9d 289 } else {
kayekss 0:d9789f57fd9d 290 lcd.printf("SD Test Fail ");
kayekss 0:d9789f57fd9d 291 }
kayekss 0:d9789f57fd9d 292 return sdTestResult;
kayekss 0:d9789f57fd9d 293 }
kayekss 0:d9789f57fd9d 294
kayekss 0:d9789f57fd9d 295 /** Main routine */
kayekss 0:d9789f57fd9d 296 int main(void) {
kayekss 0:d9789f57fd9d 297 setup();
kayekss 0:d9789f57fd9d 298
kayekss 0:d9789f57fd9d 299 // Print build timestamp
kayekss 0:d9789f57fd9d 300 printTimestamp();
kayekss 0:d9789f57fd9d 301
kayekss 0:d9789f57fd9d 302 // Test files: Enter an infinite loop on failure
kayekss 0:d9789f57fd9d 303 if (testFiles()) {
kayekss 1:ef257d63d970 304 while (1) {}
kayekss 0:d9789f57fd9d 305 }
kayekss 0:d9789f57fd9d 306
kayekss 0:d9789f57fd9d 307 // Set Ticker interrupt routine
kayekss 0:d9789f57fd9d 308 tic.attach(&pollAndRequest, POLL_INTERVAL_SEC);
kayekss 0:d9789f57fd9d 309
kayekss 0:d9789f57fd9d 310 // Main loop
kayekss 0:d9789f57fd9d 311 while (1) {
kayekss 0:d9789f57fd9d 312 controlTrack();
kayekss 0:d9789f57fd9d 313 }
kayekss 0:d9789f57fd9d 314 }