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: 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
--- /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
--- /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
--- /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
--- /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
--- /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
--- /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;
+ }
+};
+
--- /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
--- /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();
+
+ }
+
+ }
+
+ }
+}
--- /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
--- /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
--- /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
--- /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
--- /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;
+}
+
--- /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
--- /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;
+ }
+}
+
--- /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;
+};
+
+