A safe using the mbed, dc motor, solenoid, and more!
Dependencies: 4DGL-uLCD-SE DebounceIn Motordriver PinDetect SDFileSystem mbed-rtos mbed
Revision 0:6b5c0ae5acc6, committed 2016-04-29
- Comitter:
- adamlawrence
- Date:
- Fri Apr 29 20:01:29 2016 +0000
- Commit message:
- initial commit;
Changed in this revision
diff -r 000000000000 -r 6b5c0ae5acc6 4DGL-uLCD-SE.lib --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/4DGL-uLCD-SE.lib Fri Apr 29 20:01:29 2016 +0000 @@ -0,0 +1,1 @@ +http://developer.mbed.org/users/4180_1/code/4DGL-uLCD-SE/#e39a44de229a
diff -r 000000000000 -r 6b5c0ae5acc6 DebounceIn.lib --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/DebounceIn.lib Fri Apr 29 20:01:29 2016 +0000 @@ -0,0 +1,1 @@ +http://mbed.org/users/AjK/code/DebounceIn/#31ae5cfb44a4
diff -r 000000000000 -r 6b5c0ae5acc6 Motordriver.lib --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Motordriver.lib Fri Apr 29 20:01:29 2016 +0000 @@ -0,0 +1,1 @@ +http://mbed.org/users/littlexc/code/Motordriver/#3110b9209d3c
diff -r 000000000000 -r 6b5c0ae5acc6 PinDetect.lib --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/PinDetect.lib Fri Apr 29 20:01:29 2016 +0000 @@ -0,0 +1,1 @@ +http://mbed.org/users/AjK/code/PinDetect/#cb3afc45028b
diff -r 000000000000 -r 6b5c0ae5acc6 SDFileSystem.lib --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/SDFileSystem.lib Fri Apr 29 20:01:29 2016 +0000 @@ -0,0 +1,1 @@ +http://developer.mbed.org/users/neilt6/code/SDFileSystem/#c2c1f0b16380
diff -r 000000000000 -r 6b5c0ae5acc6 Speaker.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Speaker.h Fri Apr 29 20:01:29 2016 +0000 @@ -0,0 +1,52 @@ +class Speaker +{ +public: + Speaker(PinName pin) : _pin(pin) { +// _pin(pin) means pass pin to the Speaker Constructor +// precompute 32 sample points on one sine wave cycle +// used for continuous sine wave output later + for(int k=0; k<32; k++) { + Analog_out_data[k] = int (65536.0 * ((1.0 + sin((float(k)/32.0*6.28318530717959)))/2.0)); + // scale the sine wave to 16-bits - as needed for AnalogOut write_u16 arg + } + + } +// class method to play a note based on AnalogOut class + void PlayNote(float frequency, float duration, float volume) { + // scale samples using current volume level arg + for(int k=0; k<32; k++) { + Analog_scaled_data[k] = Analog_out_data[k] * volume; + } + // reset to start of sample array + i=0; + // turn on timer interrupts to start sine wave output + Sample_Period.attach(this, &Speaker::Sample_timer_interrupt, 1.0/(frequency*32.0)); + // play note for specified time + wait(duration); + // turns off timer interrupts + Sample_Period.detach(); + // sets output to mid range - analog zero + this->_pin.write_u16(32768); + + } +private: +// sets up specified pin for analog using AnalogOut class + AnalogOut _pin; + // set up a timer to be used for sample rate interrupts + Ticker Sample_Period; + + //variables used by interrupt routine and PlayNote + volatile int i; + short unsigned Analog_out_data[32]; + short unsigned Analog_scaled_data[32]; + +// Interrupt routine +// used to output next analog sample whenever a timer interrupt occurs + void Sample_timer_interrupt(void) { + // send next analog sample out to D to A + this->_pin.write_u16(Analog_scaled_data[i]); + // increment pointer and wrap around back to 0 at 32 + i = (i+1) & 0x01F; + } +}; +
diff -r 000000000000 -r 6b5c0ae5acc6 TMP36.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/TMP36.h Fri Apr 29 20:01:29 2016 +0000 @@ -0,0 +1,31 @@ +#include "mbed.h" + +//Setup a new class for TMP36 sensor +class TMP36 +{ +public: + TMP36(PinName pin); + TMP36(); + operator float (); + float read(); +private: +//class sets up the AnalogIn pin + AnalogIn _pin; +}; + +TMP36::TMP36(PinName pin) : _pin(pin) +{ +// _pin(pin) means pass pin to the AnalogIn constructor +} + +float TMP36::read() +{ +//convert sensor reading to temperature in degrees C + return ((_pin.read()*3.3)-0.500)*100.0; +} +//overload of float conversion (avoids needing to type .read() in equations) +TMP36::operator float () +{ +//convert sensor reading to temperature in degrees C + return ((_pin.read()*3.3)-0.500)*100.0; +} \ No newline at end of file
diff -r 000000000000 -r 6b5c0ae5acc6 main.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/main.cpp Fri Apr 29 20:01:29 2016 +0000 @@ -0,0 +1,386 @@ +#include "mbed.h" +#include <cmath> +#include "solenoid.h" +#include "rtos.h" +#include "uLCD_4DGL.h" +#include "TMP36.h" +#include "motordriver.h" +#include "PinDetect.h" +#include "mpr121.h" //touchpad +#include "DebounceIn.h" +#include "Speaker.h" //used for playing tones +Speaker mySpeaker(p18); +Serial blue(p13,p14); //blue tooth device +TMP36 myTMP36(p15); //Analog in +Mutex mut; //standard io mutex lock +DigitalOut led1(LED1); +DigitalOut led2(LED2); +DigitalOut led3(LED3); +DigitalOut led4(LED4); +AnalogIn ir(p19); //Sharp IR sensor +uLCD_4DGL uLCD(p28,p27,p30); //create a global lcd object +I2C i2c(p9, p10); +Mpr121 mpr121(&i2c, Mpr121::ADD_VSS); +InterruptIn interrupt(p25); +PinDetect pb1(p21);//push button 1 +PinDetect pb2(p22);//push button 2 +PinDetect pb3(p23);//push button 3 +PinDetect pb4(p24);//push button 4 +Motor left(p26, p16, p17, 1); // pwm, fwd, rev, has brake feature +Solenoid mySolenoid(p8); + char bnum=0; + char bhit=0; +float tempC = 0.0; +bool shadeDown = true; //true shade is down, false shade is up +bool tempMode = false; //false is celcius, true is fahrenheit +int combo[5]; +bool setUp = false; //boolean for initial setup of safe (will be set to true after passcode is entered) +bool locked = true; //boolean if safe is locked or not. +int passCode[5]; +int j = 0; +int passVal = 0; //keeps track of correct input values +bool passed = true; //this boolean will be used to unlock the safe +bool pb1push = false; //pushbutton 1 was pushed boolean +bool pb2push = false; +bool pb3push = false; +bool pb4push = false; +int failVal = 0; //counts failed attempts +int key_code = -17; //set this to a negative number that won't ever be in Simon's array and also isn't a possible value for drawing +void fallInterrupt() { + int i=0; + int value=mpr121.read(0x00); + value +=mpr121.read(0x01)<<8; + // LED demo mod + i=0; + // puts key number out to LEDs for demo + for (i=0; i<12; i++) { + if (((value>>i)&0x01)==1) key_code=i; + } + +} +void unlocker() { + mySolenoid =1; + + wait(2); + mySolenoid = 0; +} +void lockInterrupt() { + //button 1 + pb1push = true; + led1 = 1; + wait(0.5); + led1 = 0; + mySpeaker.PlayNote(400, 0.5, 1.0); +} +void shadeInterrupt() { + //button 2 + pb2push = true; + led2 = 1; + wait(0.5); + led2 = 0; + mySpeaker.PlayNote(800, 0.5, 1.0); +} +void settingsInterrupt() { + //button 3 + //will be able to change passcode. + //change temp display + //change display shade. + pb3push = true; + led3 = 1; + wait(0.5); + led3 = 0; + mySpeaker.PlayNote(1200, 0.5, 1.0); +} + +void exitInterrupt() { + //button 4 + pb4push = true; + led4 = 1; + wait(0.5); + led4 = 0; + mySpeaker.PlayNote(1600, 0.5, 1.0); +} +void setPassword() { + uLCD.cls(); + uLCD.color(WHITE); + uLCD.printf("Please put in your \n 5 digit passcode now \n \n \n \n"); + wait(0.5); + int i = 0; + while(i < 5 && !pb4push) { + if (key_code >= 0) { + combo[i] = key_code; + uLCD.text_height(4); + uLCD.text_width(2); + uLCD.printf("%d ",combo[i]); + i++; + key_code = -4; + } + } + wait(0.5); + uLCD.cls(); + uLCD.printf("Passcode saved. \nLock engaged. \n"); + wait(1); + uLCD.cls(); +} +void shadeMove() { + uLCD.cls(); + if(shadeDown) { + + shadeDown = false; + //turn motor backward. + for (int i = 0; i < 6 ; i ++) { + led1=!led1; + left.speed(.5); + wait(0.2); + } + left.speed(0); + uLCD.printf("Removing shade."); + wait(2); //might need to be longer dependent on actual mplementation speed + uLCD.cls(); + } else { + shadeDown = true; + for (int i = 0; i < 6 ; i ++) { + led1=!led1; + left.speed(-.5); + wait(0.2); + } + left.speed(0); + //turn motor forward + uLCD.printf("Placing shade."); + wait(2); //might need to be longer dependent on actual mplementation speed + uLCD.cls(); + } +} +void bluetoothOn() { + while (!pb4push) { + if (blue.getc()=='!') { + uLCD.locate(0,0); + uLCD.printf("In Bluetooth Mode."); + if (blue.getc()=='B') { //button data packet + bnum = blue.getc(); //button number + bhit = blue.getc(); //1=hit, 0=release + if (blue.getc()==char(~('!' + 'B' + bnum + bhit))) { //checksum OK? + // myled = bnum - '0'; //current button number will appear on LEDs + switch (bnum) { + case '1': //number button 1 + if (bhit=='1') { + unlocker(); + //add hit code here + //open safe (or close safe) dependent on state + } else { + //add release code here + } + break; + case '2': //number button 2 + if (bhit=='1') { + //add hit code here + //move shade + shadeMove(); + } else { + + //add release code here + } + break; + case '3': //number button 3 + if (bhit=='1') { + tempMode = !tempMode; + } else { + //add release code here + } + break; + case '4': //number button 4 + if (bhit=='1') { + //add hit code here + pb4push = true; + } else { + //add release code here + } + break; + + } + } + } + } + } +} +int main() { + set_time(46800); // Set RTC time to Wed, 28 Oct 2009 11:35:37 let's change this to wahtever the presentation day is. +//clock stuff goes here + +pb1.mode(PullUp); //the safe unlock/lock method initiator +pb2.mode(PullUp); //the shade button +pb3.mode(PullUp); //temperature button +pb4.mode(PullUp); //exit routine button +wait(.01); +// Setup Interrupt callback functions for a pb hit +pb1.attach_deasserted(&lockInterrupt); +pb2.attach_deasserted(&shadeInterrupt); +pb3.attach_deasserted(&settingsInterrupt); +pb4.attach_deasserted(&exitInterrupt); +pb1.setSampleFrequency(); +pb2.setSampleFrequency(); +pb3.setSampleFrequency(); +pb4.setSampleFrequency(); +interrupt.fall(&fallInterrupt); //setting up the touch pad for use by assigning a method for the falling side of the touchpad interrupt +interrupt.mode(PullUp); //put the interrupt mode to pull up, so that interrupts will trigger when the touchpad is hit + while(1) { + time_t seconds = time(NULL); + //if ir.read is greater than .5 beep(?) + tempC = myTMP36.read(); + if (!setUp) { + mut.lock(); + uLCD.color(WHITE); + uLCD.printf("Welcome to \nSMART Safe."); + + wait(1.0); + uLCD.cls(); + setPassword(); + mut.unlock(); + setUp = true; + //put in clock + //put in temp + } else if (pb1push) { + pb1push = false; + pb4push = false; + uLCD.cls(); + uLCD.printf("Enter your pass code now.\n"); + while (passVal < 5 && failVal < 5 && !pb4push) { + if(key_code >= 0) { + uLCD.text_height(4); + uLCD.printf("%d ",key_code); + if (key_code == combo[j]) { + passVal++; + passed = true; + } else { + passed = false; + j = 0; + failVal++; + } + key_code = -1; + } + if (passVal == 5 && passed && failVal < 5) { + passed = true; + pb1push = false; + j = 0; + failVal = 0; + uLCD.cls(); + uLCD.printf("Safe unlocked."); + locked = false; + unlocker(); + locked = true; + break; + } + if (failVal == 5) { + uLCD.printf("You have put in \n the wrong password \n five times. \n You are locked out."); + } + } + if(pb4push){ + pb4push = false; + uLCD.printf("Unlocking \nsequence \naborted."); + } + passVal = 0; + failVal = 0; + wait(1); + uLCD.cls(); + } else if (pb2push) { + pb2push = false; + + shadeMove(); + + } else if(pb3push){ + pb3push = false; + uLCD.cls(); + while (!pb4push) { + uLCD.locate(0,0); + uLCD.printf("Change Temperature Format (1)\n"); + uLCD.printf("Change Passcode (2) \n"); + uLCD.printf("Enter BLUETOOTH \n mode (3)\n"); + uLCD.printf("Exit menu (4)"); + wait(1); + if (pb1push) { + pb1push = false; + uLCD.cls(); + uLCD.printf("Fahrenheit (1)\n"); + uLCD.printf("Celcius (2)"); + wait(1); + bool action = false; + while (!pb4push && !action) { + if (pb1push) { + action = true; + pb1push = false; + tempMode = true;//thermometer change to F + break; + } else if (pb2push) { + action = true; + pb2push = false; + tempMode = false;//themometer change to C + break; + } + led1 = !led1; + wait(.5); + } + uLCD.cls(); + } else if (pb2push) { //this is going to change the time of day. + pb2push = false; + uLCD.cls(); + setPassword(); + } else if (pb3push) { + pb3push = false; + bluetoothOn(); + + } + } + uLCD.cls(); + led1 =1; + led2 =1; + pb4push = false; + } else { + float temp = myTMP36.read(); + if (tempMode) { + temp = (temp * 1.8) + 32; + } + if (locked) { + uLCD.text_height(4); + uLCD.color(RED); + uLCD.locate(4,0); + uLCD.printf("Locked"); + uLCD.color(WHITE); + uLCD.text_height(3); + uLCD.locate(1,2); + char buffer[32]; + strftime(buffer, 32, "%I:%M %p\n", localtime(&seconds)); + uLCD.printf("Time %s",buffer); + uLCD.locate(1,4); + if (tempMode) { + uLCD.printf("Temp %3.2f F",temp); + } else { + uLCD.printf("Temp %3.2f C",temp); + } + wait(2); + //uLCD.cls(); + } else { + uLCD.text_height(4); + uLCD.color(GREEN); + uLCD.locate(4,0); + uLCD.printf("Unlocked"); + uLCD.color(WHITE); + uLCD.text_height(3); + uLCD.locate(1,2); + char buffer[32]; + strftime(buffer, 32, "%I:%M %p\n", localtime(&seconds)); + uLCD.printf("Time %s",buffer); + uLCD.locate(1,4); + if (tempMode) { + uLCD.printf("Temp %3.2f F",temp); + } else { + uLCD.printf("Temp %3.2f C",temp); + } + wait(2); + //uLCD.cls(); + + } + + } + + } +}
diff -r 000000000000 -r 6b5c0ae5acc6 mbed-rtos.lib --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mbed-rtos.lib Fri Apr 29 20:01:29 2016 +0000 @@ -0,0 +1,1 @@ +http://mbed.org/users/mbed_official/code/mbed-rtos/#d3d0e710b443
diff -r 000000000000 -r 6b5c0ae5acc6 mbed.bld --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mbed.bld Fri Apr 29 20:01:29 2016 +0000 @@ -0,0 +1,1 @@ +http://mbed.org/users/mbed_official/code/mbed/builds/99a22ba036c9 \ No newline at end of file
diff -r 000000000000 -r 6b5c0ae5acc6 mpr121.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mpr121.cpp Fri Apr 29 20:01:29 2016 +0000 @@ -0,0 +1,221 @@ +/* +Copyright (c) 2011 Anthony Buckton (abuckton [at] blackink [dot} net {dot} au) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#include <mbed.h> +#include <sstream> +#include <string> +#include <list> + +#include <mpr121.h> + +Mpr121::Mpr121(I2C *i2c, Address i2cAddress) +{ + this->i2c = i2c; + + address = i2cAddress; + + // Configure the MPR121 settings to default + this->configureSettings(); +} + + +void Mpr121::configureSettings() +{ + // Put the MPR into setup mode + this->write(ELE_CFG,0x00); + + // Electrode filters for when data is > baseline + unsigned char gtBaseline[] = { + 0x01, //MHD_R + 0x01, //NHD_R + 0x00, //NCL_R + 0x00 //FDL_R + }; + + writeMany(MHD_R,gtBaseline,4); + + // Electrode filters for when data is < baseline + unsigned char ltBaseline[] = { + 0x01, //MHD_F + 0x01, //NHD_F + 0xFF, //NCL_F + 0x02 //FDL_F + }; + + writeMany(MHD_F,ltBaseline,4); + + // Electrode touch and release thresholds + unsigned char electrodeThresholds[] = { + E_THR_T, // Touch Threshhold + E_THR_R // Release Threshold + }; + + for(int i=0; i<12; i++){ + int result = writeMany((ELE0_T+(i*2)),electrodeThresholds,2); + } + + // Proximity Settings + unsigned char proximitySettings[] = { + 0xff, //MHD_Prox_R + 0xff, //NHD_Prox_R + 0x00, //NCL_Prox_R + 0x00, //FDL_Prox_R + 0x01, //MHD_Prox_F + 0x01, //NHD_Prox_F + 0xFF, //NCL_Prox_F + 0xff, //FDL_Prox_F + 0x00, //NHD_Prox_T + 0x00, //NCL_Prox_T + 0x00 //NFD_Prox_T + }; + writeMany(MHDPROXR,proximitySettings,11); + + unsigned char proxThresh[] = { + PROX_THR_T, // Touch Threshold + PROX_THR_R // Release Threshold + }; + writeMany(EPROXTTH,proxThresh,2); + + this->write(FIL_CFG,0x04); + + // Set the electrode config to transition to active mode + this->write(ELE_CFG,0x0c); +} + +void Mpr121::setElectrodeThreshold(int electrode, unsigned char touch, unsigned char release){ + + if(electrode > 11) return; + + // Get the current mode + unsigned char mode = this->read(ELE_CFG); + + // Put the MPR into setup mode + this->write(ELE_CFG,0x00); + + // Write the new threshold + this->write((ELE0_T+(electrode*2)), touch); + this->write((ELE0_T+(electrode*2)+1), release); + + //Restore the operating mode + this->write(ELE_CFG, mode); +} + + +unsigned char Mpr121::read(int key){ + + unsigned char data[2]; + + //Start the command + i2c->start(); + + // Address the target (Write mode) + int ack1= i2c->write(address); + + // Set the register key to read + int ack2 = i2c->write(key); + + // Re-start for read of data + i2c->start(); + + // Re-send the target address in read mode + int ack3 = i2c->write(address+1); + + // Read in the result + data[0] = i2c->read(0); + + // Reset the bus + i2c->stop(); + + return data[0]; +} + + +int Mpr121::write(int key, unsigned char value){ + + //Start the command + i2c->start(); + + // Address the target (Write mode) + int ack1= i2c->write(address); + + // Set the register key to write + int ack2 = i2c->write(key); + + // Read in the result + int ack3 = i2c->write(value); + + // Reset the bus + i2c->stop(); + + return (ack1+ack2+ack3)-3; +} + + +int Mpr121::writeMany(int start, unsigned char* dataSet, int length){ + //Start the command + i2c->start(); + + // Address the target (Write mode) + int ack= i2c->write(address); + if(ack!=1){ + return -1; + } + + // Set the register key to write + ack = i2c->write(start); + if(ack!=1){ + return -1; + } + + // Write the date set + int count = 0; + while(ack==1 && (count < length)){ + ack = i2c->write(dataSet[count]); + count++; + } + // Stop the cmd + i2c->stop(); + + return count; +} + + +bool Mpr121::getProximityMode(){ + if(this->read(ELE_CFG) > 0x0c) + return true; + else + return false; +} + +void Mpr121::setProximityMode(bool mode){ + this->write(ELE_CFG,0x00); + if(mode){ + this->write(ELE_CFG,0x30); //Sense proximity from ALL pads + } else { + this->write(ELE_CFG,0x0c); //Sense touch, all 12 pads active. + } +} + + +int Mpr121::readTouchData(){ + return this->read(0x00); +} \ No newline at end of file
diff -r 000000000000 -r 6b5c0ae5acc6 mpr121.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mpr121.h Fri Apr 29 20:01:29 2016 +0000 @@ -0,0 +1,157 @@ +/* +Copyright (c) 2011 Anthony Buckton (abuckton [at] blackink [dot} net {dot} au) + + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + Parts written by Jim Lindblom of Sparkfun + Ported to mbed by A.Buckton, Feb 2011 +*/ + +#ifndef MPR121_H +#define MPR121_H + +//using namespace std; + +class Mpr121 +{ + +public: + // i2c Addresses, bit-shifted + enum Address { ADD_VSS = 0xb4,// ADD->VSS = 0x5a <-wiring on Sparkfun board + ADD_VDD = 0xb6,// ADD->VDD = 0x5b + ADD_SCL = 0xb8,// ADD->SDA = 0x5c + ADD_SDA = 0xba // ADD->SCL = 0x5d + }; + + // Real initialiser, takes the i2c address of the device. + Mpr121(I2C *i2c, Address i2cAddress); + + bool getProximityMode(); + + void setProximityMode(bool mode); + + int readTouchData(); + + unsigned char read(int key); + + int write(int address, unsigned char value); + int writeMany(int start, unsigned char* dataSet, int length); + + void setElectrodeThreshold(int electrodeId, unsigned char touchThreshold, unsigned char releaseThreshold); + +protected: + // Configures the MPR with standard settings. This is permitted to be overwritten by sub-classes. + void configureSettings(); + +private: + // The I2C bus instance. + I2C *i2c; + + // i2c address of this mpr121 + Address address; +}; + + +// MPR121 Register Defines +#define MHD_R 0x2B +#define NHD_R 0x2C +#define NCL_R 0x2D +#define FDL_R 0x2E +#define MHD_F 0x2F +#define NHD_F 0x30 +#define NCL_F 0x31 +#define FDL_F 0x32 +#define NHDT 0x33 +#define NCLT 0x34 +#define FDLT 0x35 +// Proximity sensing controls +#define MHDPROXR 0x36 +#define NHDPROXR 0x37 +#define NCLPROXR 0x38 +#define FDLPROXR 0x39 +#define MHDPROXF 0x3A +#define NHDPROXF 0x3B +#define NCLPROXF 0x3C +#define FDLPROXF 0x3D +#define NHDPROXT 0x3E +#define NCLPROXT 0x3F +#define FDLPROXT 0x40 +// Electrode Touch/Release thresholds +#define ELE0_T 0x41 +#define ELE0_R 0x42 +#define ELE1_T 0x43 +#define ELE1_R 0x44 +#define ELE2_T 0x45 +#define ELE2_R 0x46 +#define ELE3_T 0x47 +#define ELE3_R 0x48 +#define ELE4_T 0x49 +#define ELE4_R 0x4A +#define ELE5_T 0x4B +#define ELE5_R 0x4C +#define ELE6_T 0x4D +#define ELE6_R 0x4E +#define ELE7_T 0x4F +#define ELE7_R 0x50 +#define ELE8_T 0x51 +#define ELE8_R 0x52 +#define ELE9_T 0x53 +#define ELE9_R 0x54 +#define ELE10_T 0x55 +#define ELE10_R 0x56 +#define ELE11_T 0x57 +#define ELE11_R 0x58 +// Proximity Touch/Release thresholds +#define EPROXTTH 0x59 +#define EPROXRTH 0x5A +// Debounce configuration +#define DEB_CFG 0x5B +// AFE- Analogue Front End configuration +#define AFE_CFG 0x5C +// Filter configuration +#define FIL_CFG 0x5D +// Electrode configuration - transistions to "active mode" +#define ELE_CFG 0x5E + +#define GPIO_CTRL0 0x73 +#define GPIO_CTRL1 0x74 +#define GPIO_DATA 0x75 +#define GPIO_DIR 0x76 +#define GPIO_EN 0x77 +#define GPIO_SET 0x78 +#define GPIO_CLEAR 0x79 +#define GPIO_TOGGLE 0x7A +// Auto configration registers +#define AUTO_CFG_0 0x7B +#define AUTO_CFG_U 0x7D +#define AUTO_CFG_L 0x7E +#define AUTO_CFG_T 0x7F + +// Threshold defaults +// Electrode touch threshold +#define E_THR_T 0x0F +// Electrode release threshold +#define E_THR_R 0x0A +// Prox touch threshold +#define PROX_THR_T 0x02 +// Prox release threshold +#define PROX_THR_R 0x02 + +#endif
diff -r 000000000000 -r 6b5c0ae5acc6 solenoid.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/solenoid.cpp Fri Apr 29 20:01:29 2016 +0000 @@ -0,0 +1,30 @@ +#include "mbed.h" +#include "solenoid.h" +Solenoid::Solenoid(PinName pin, float ondelay, float offdelay) : _pin(pin), ontime(ondelay), offtime(offdelay) +{ + _pin=0; + offtimer.start(); + +} +void Solenoid::Solenoid_Off_Int() +{ + _pin=0;//OFF timer interrupt routine to auto turn off solenoid + offtimer.start(); //start off-time delay count +} +void Solenoid::write(bool value) +{ + if (value!=0) {//ON so do auto off with timer interrupt + while(offtimer.read() < offtime); //wait for min OFF time before next ON allowed + offtimer.stop(); + offtimer.reset(); //reset off timer delay count + tint.attach(this,&Solenoid::Solenoid_Off_Int,ontime);//setup a timer interrupt for on time + } else + offtimer.start(); //solenoid turned off with a write call (not timers) so start off count + _pin = value; +} +Solenoid& Solenoid::operator= (bool value) +{ + write(value); + return *this; +} +
diff -r 000000000000 -r 6b5c0ae5acc6 solenoid.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/solenoid.h Fri Apr 29 20:01:29 2016 +0000 @@ -0,0 +1,18 @@ +#include "mbed.h" +//Solenoid Hello World +//Non blocking with auto off and min off-time delay using timer interrupt and timer setup by class +class Solenoid +{ +public: + Solenoid (PinName pin, float ondelay=0.5, float offdelay=2.0); + void write(bool state); + Solenoid& operator= (bool value); + +private: + void Solenoid_Off_Int(); + DigitalOut _pin; + Timeout tint; + Timer offtimer; + float ontime; + float offtime; +}; \ No newline at end of file
diff -r 000000000000 -r 6b5c0ae5acc6 wave_player/wave_player.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/wave_player/wave_player.cpp Fri Apr 29 20:01:29 2016 +0000 @@ -0,0 +1,211 @@ +//----------------------------------------------------------------------------- +// a sample mbed library to play back wave files. +// +// explanation of wave file format. +// https://ccrma.stanford.edu/courses/422/projects/WaveFormat/ + +// if VERBOSE is uncommented then the wave player will enter a verbose +// mode that displays all data values as it reads them from the file +// and writes them to the DAC. Very slow and unusable output on the DAC, +// but useful for debugging wave files that don't work. +//#define VERBOSE + + +#include <mbed.h> +#include <stdio.h> +#include <wave_player.h> + + +//----------------------------------------------------------------------------- +// constructor -- accepts an mbed pin to use for AnalogOut. Only p18 will work +wave_player::wave_player(AnalogOut *_dac) +{ + wave_DAC=_dac; + wave_DAC->write_u16(32768); //DAC is 0-3.3V, so idles at ~1.6V + verbosity=0; +} + +//----------------------------------------------------------------------------- +// if verbosity is set then wave player enters a mode where the wave file +// is decoded and displayed to the screen, including sample values put into +// the DAC FIFO, and values read out of the DAC FIFO by the ISR. The DAC output +// itself is so slow as to be unusable, but this might be handy for debugging +// wave files that don't play +//----------------------------------------------------------------------------- +void wave_player::set_verbosity(int v) +{ + verbosity=v; +} + +//----------------------------------------------------------------------------- +// player function. Takes a pointer to an opened wave file. The file needs +// to be stored in a filesystem with enough bandwidth to feed the wave data. +// LocalFileSystem isn't, but the SDcard is, at least for 22kHz files. The +// SDcard filesystem can be hotrodded by increasing the SPI frequency it uses +// internally. +//----------------------------------------------------------------------------- +void wave_player::play(FILE *wavefile) +{ + unsigned chunk_id,chunk_size,channel; + unsigned data,samp_int,i; + short unsigned dac_data; + long long slice_value; + char *slice_buf; + short *data_sptr; + unsigned char *data_bptr; + int *data_wptr; + FMT_STRUCT wav_format; + long slice,num_slices; + DAC_wptr=0; + DAC_rptr=0; + for (i=0;i<256;i+=2) { + DAC_fifo[i]=0; + DAC_fifo[i+1]=3000; + } + DAC_wptr=4; + DAC_on=0; + + fread(&chunk_id,4,1,wavefile); + fread(&chunk_size,4,1,wavefile); + while (!feof(wavefile)) { + if (verbosity) + printf("Read chunk ID 0x%x, size 0x%x\n",chunk_id,chunk_size); + switch (chunk_id) { + case 0x46464952: + fread(&data,4,1,wavefile); + if (verbosity) { + printf("RIFF chunk\n"); + printf(" chunk size %d (0x%x)\n",chunk_size,chunk_size); + printf(" RIFF type 0x%x\n",data); + } + break; + case 0x20746d66: + fread(&wav_format,sizeof(wav_format),1,wavefile); + if (verbosity) { + printf("FORMAT chunk\n"); + printf(" chunk size %d (0x%x)\n",chunk_size,chunk_size); + printf(" compression code %d\n",wav_format.comp_code); + printf(" %d channels\n",wav_format.num_channels); + printf(" %d samples/sec\n",wav_format.sample_rate); + printf(" %d bytes/sec\n",wav_format.avg_Bps); + printf(" block align %d\n",wav_format.block_align); + printf(" %d bits per sample\n",wav_format.sig_bps); + } + if (chunk_size > sizeof(wav_format)) + fseek(wavefile,chunk_size-sizeof(wav_format),SEEK_CUR); + break; + case 0x61746164: +// allocate a buffer big enough to hold a slice + slice_buf=(char *)malloc(wav_format.block_align); + if (!slice_buf) { + printf("Unable to malloc slice buffer"); + exit(1); + } + num_slices=chunk_size/wav_format.block_align; + samp_int=1000000/(wav_format.sample_rate); + if (verbosity) { + printf("DATA chunk\n"); + printf(" chunk size %d (0x%x)\n",chunk_size,chunk_size); + printf(" %d slices\n",num_slices); + printf(" Ideal sample interval=%d\n",(unsigned)(1000000.0/wav_format.sample_rate)); + printf(" programmed interrupt tick interval=%d\n",samp_int); + } + +// starting up ticker to write samples out -- no printfs until tick.detach is called + if (verbosity) + tick.attach_us(this,&wave_player::dac_out, 500000); + else + tick.attach_us(this,&wave_player::dac_out, samp_int); + DAC_on=1; + +// start reading slices, which contain one sample each for however many channels +// are in the wave file. one channel=mono, two channels=stereo, etc. Since +// mbed only has a single AnalogOut, all of the channels present are averaged +// to produce a single sample value. This summing and averaging happens in +// a variable of type signed long long, to make sure that the data doesn't +// overflow regardless of sample size (8 bits, 16 bits, 32 bits). +// +// note that from what I can find that 8 bit wave files use unsigned data, +// while 16 and 32 bit wave files use signed data +// + for (slice=0;slice<num_slices;slice+=1) { + fread(slice_buf,wav_format.block_align,1,wavefile); + if (feof(wavefile)) { + printf("Oops -- not enough slices in the wave file\n"); + exit(1); + } + data_sptr=(short *)slice_buf; // 16 bit samples + data_bptr=(unsigned char *)slice_buf; // 8 bit samples + data_wptr=(int *)slice_buf; // 32 bit samples + slice_value=0; + for (channel=0;channel<wav_format.num_channels;channel++) { + switch (wav_format.sig_bps) { + case 16: + if (verbosity) + printf("16 bit channel %d data=%d ",channel,data_sptr[channel]); + slice_value+=data_sptr[channel]; + break; + case 32: + if (verbosity) + printf("32 bit channel %d data=%d ",channel,data_wptr[channel]); + slice_value+=data_wptr[channel]; + break; + case 8: + if (verbosity) + printf("8 bit channel %d data=%d ",channel,(int)data_bptr[channel]); + slice_value+=data_bptr[channel]; + break; + } + } + slice_value/=wav_format.num_channels; + +// slice_value is now averaged. Next it needs to be scaled to an unsigned 16 bit value +// with DC offset so it can be written to the DAC. + switch (wav_format.sig_bps) { + case 8: slice_value<<=8; + break; + case 16: slice_value+=32768; + break; + case 32: slice_value>>=16; + slice_value+=32768; + break; + } + dac_data=(short unsigned)slice_value; + if (verbosity) + printf("sample %d wptr %d slice_value %d dac_data %u\n",slice,DAC_wptr,(int)slice_value,dac_data); + DAC_fifo[DAC_wptr]=dac_data; + DAC_wptr=(DAC_wptr+1) & 0xff; + while (DAC_wptr==DAC_rptr) { + } + } + DAC_on=0; + tick.detach(); + free(slice_buf); + break; + case 0x5453494c: + if (verbosity) + printf("INFO chunk, size %d\n",chunk_size); + fseek(wavefile,chunk_size,SEEK_CUR); + break; + default: + printf("unknown chunk type 0x%x, size %d\n",chunk_id,chunk_size); + data=fseek(wavefile,chunk_size,SEEK_CUR); + break; + } + fread(&chunk_id,4,1,wavefile); + fread(&chunk_size,4,1,wavefile); + } +} + + +void wave_player::dac_out() +{ + if (DAC_on) { +#ifdef VERBOSE + printf("ISR rdptr %d got %u\n",DAC_rptr,DAC_fifo[DAC_rptr]); +#endif + wave_DAC->write_u16(DAC_fifo[DAC_rptr]); + DAC_rptr=(DAC_rptr+1) & 0xff; + } +} +
diff -r 000000000000 -r 6b5c0ae5acc6 wave_player/wave_player.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/wave_player/wave_player.h Fri Apr 29 20:01:29 2016 +0000 @@ -0,0 +1,72 @@ +#include <mbed.h> + +typedef struct uFMT_STRUCT { + short comp_code; + short num_channels; + unsigned sample_rate; + unsigned avg_Bps; + short block_align; + short sig_bps; +} FMT_STRUCT; + + +/** wave file player class. + * + * Example: + * @code + * #include <mbed.h> + * #include <wave_player.h> + * + * AnalogOut DACout(p18); + * wave_player waver(&DACout); + * + * int main() { + * FILE *wave_file; + * + * printf("\n\n\nHello, wave world!\n"); + * wave_file=fopen("/sd/44_8_st.wav","r"); + * waver.play(wave_file); + * fclose(wave_file); + * } + * @endcode + */ +class wave_player { + +public: +/** Create a wave player using a pointer to the given AnalogOut object. + * + * @param _dac pointer to an AnalogOut object to which the samples are sent. + */ +wave_player(AnalogOut *_dac); + +/** the player function. + * + * @param wavefile A pointer to an opened wave file + */ +void play(FILE *wavefile); + +/** Set the printf verbosity of the wave player. A nonzero verbosity level + * will put wave_player in a mode where the complete contents of the wave + * file are echoed to the screen, including header values, and including + * all of the sample values placed into the DAC FIFO, and the sample values + * removed from the DAC FIFO by the ISR. The sample output frequency is + * fixed at 2 Hz in this mode, so it's all very slow and the DAC output isn't + * very useful, but it lets you see what's going on and may help for debugging + * wave files that don't play correctly. + * + * @param v the verbosity level + */ +void set_verbosity(int v); + +private: +void dac_out(void); +int verbosity; +AnalogOut *wave_DAC; +Ticker tick; +unsigned short DAC_fifo[256]; +short DAC_wptr; +volatile short DAC_rptr; +short DAC_on; +}; + +