Motion and button application for BLE sensor - using purple LIS3DH nRF51822.
Revision 13:3450483129a3, committed 2018-06-19
- Comitter:
- electronichamsters
- Date:
- Tue Jun 19 03:39:02 2018 +0000
- Parent:
- 12:9bb01e063498
- Commit message:
- first revision - new example for stuff animal toy
Changed in this revision
LIS3DH.lib | Show annotated file Show diff for this revision Revisions of this file |
main.cpp | Show annotated file Show diff for this revision Revisions of this file |
diff -r 9bb01e063498 -r 3450483129a3 LIS3DH.lib --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/LIS3DH.lib Tue Jun 19 03:39:02 2018 +0000 @@ -0,0 +1,1 @@ +https://os.mbed.com/users/electronichamsters/code/LIS3DH/#972c166f654b
diff -r 9bb01e063498 -r 3450483129a3 main.cpp --- a/main.cpp Sun Aug 27 05:48:45 2017 +0000 +++ b/main.cpp Tue Jun 19 03:39:02 2018 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) Eric Tsai 2017 + * Copyright (c) Eric Tsai 2018 * * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -21,6 +21,8 @@ * BLE sensor as Beacon advertisements. Intended to function with specific BLE observer. * Tested on nRF51822 targets on mbed. * keywords: todo, tochange + * + * LIS3DH on purple board. Random button and motion sensing for modifying toys. */ @@ -33,22 +35,51 @@ #include "toolchain.h" #include "ble/BLE.h" #include "TMP_nrf51/TMP_nrf51.h" - +#include "LIS3DH.h" //https://developer.mbed.org/users/kenjiArai/code/LIS3DH/ /******************************************************************************************* * START tochange: items that may need customization depending on sensors, hardware, and desired behavior *******************************************************************************************/ -const uint16_t Periodic_Update_Seconds = 20; //number of seconds between periodic I/O status re-transmits 900s =15 min. +const uint16_t Periodic_Update_Seconds = 900; //number of seconds between periodic I/O status re-transmits 900s =15 min. #define MyDebugEnb 0 //enables serial output for debug, consumes ~1mA when idle uint8_t magnet_near=0; //this I/O, specifically for reed switch sensor +#define sensorEnb 1 //get readings +#define buttonEnb 1 /* hardware interrupt pins, selected based on hardware *Syntax: Pin "P0.4" on nRF51822 documentation is mbed "p4". * InterruptIn is pulled-up. GND the pin to activate. */ -InterruptIn button1(p0); //nRF51822 P0.0 -InterruptIn button2(p1); //nRF51822 P0.1 +#if buttonEnb +InterruptIn button1(p16); //nRF51822 +InterruptIn button2(p15); //nRF51822 +InterruptIn button3(p12); //nRF51822 +InterruptIn button4(p23); //nRF51822 +InterruptIn button5(p24); //nRF51822 +InterruptIn button6(p25); //nRF51822 +InterruptIn button7(p28); //nRF51822 +InterruptIn button8(p29); //nRF51822 +InterruptIn button9(p30); //nRF51822 + + +#endif + +#if sensorEnb +InterruptIn lis3dh_int1(p1); //nRF51822 P0.1 +//LIS3DH data(p6, p7, (0x19 << 1)); //for purple board, sda=p6, scl=p7 +LIS3DH data(p6, p7, LIS3DH_V_CHIP_ADDR); + +//0001 1001 ---> 0011 0010 +#endif +bool flag_read_acc; + + + + +//purple boards +//InterruptIn button1(p23); //nRF51822 P0.23 +//InterruptIn button2(p24); //nRF51822 P0.24 /****************************************************************************************** * END tochange *******************************************************************************************/ @@ -63,6 +94,7 @@ static Ticker Tic_Debounce; //debounce I/O static Ticker Tic_Periodic; //transmit sensor data on a periodic basis outside I/O events + const uint16_t Periodicity = 1800; //birthday periodicity used for spoof checking, must match gateway. Should be 1800 seconds for 30minutes static Timer Tmr_From_Birthday; //holds number of seconds since birthday, for spoof detection static Ticker Tic_Birthday; //resets Tmr_From_Birthday every Periodicity seconds, for spoof detection @@ -138,6 +170,12 @@ uint8_t Xmit_Cnt = 1; +//track button press on toy +Timer Tmr_Click_Duration; +uint8_t which_button = 0; +uint16_t button_pressed_ms; +const uint8_t reset_addr = 0x31; //LIS3DH_INT1_SOURCE +static Ticker Tic_Motion; //used to stop re-enabled latched motion interrupt /* **** NOT USED **** */ //16byte UUID loading happens here @@ -158,9 +196,45 @@ } PACKED; +//called on tic +void motion_response(void) +{ + Tic_Motion.detach(); + #if sensorEnb + + data.read_reg(reset_addr); //reset's the latched interrupt + #endif + +} + +//called on interrupt +void motion_Callback(void) +{ + + #if MyDebugEnb + device.printf("motion seen \r\n"); + #endif + Tic_Motion.attach(motion_response, 30); //every x seconds, re-enable motion interrupt + if (which_button == 0) //there's a chance motion would over-riding button press event. avoid this. + { + which_button = 11; + Flag_Update_IO = 1; + } + +} + + void debounce_Callback(void) { + //stop timer, save time + Tmr_Click_Duration.stop(); + button_pressed_ms =(uint16_t)(Tmr_Click_Duration.read_ms()); + #if MyDebugEnb + device.printf("sending BLE for button %d \r\n", which_button); + #endif + + Tic_Debounce.detach(); Flag_Update_IO = true; //start advertising /* Note that the buttonPressedCallback() executes in interrupt context, so it is safer to access @@ -171,14 +245,97 @@ //ISR for I/O interrupt void buttonPressedCallback(void) { - Tic_Debounce.attach(debounce_Callback, 1); //ok to attach multiple times, recent one wins + //wait_ms(2); //debounce + //read I/O, mark which button was pressed + + +#if buttonEnb + + + if (button1.read() == 0) //buttons are pulled up, gnd when pressed + { + which_button = 1; + #if MyDebugEnb + device.printf("is 1 button \r\n"); + #endif + } + else if (button2.read() == 0) + { + which_button = 2; + #if MyDebugEnb + device.printf("is 2 button \r\n"); + #endif + } + else if (button3.read() == 0) + { + which_button = 3; + #if MyDebugEnb + device.printf("is 3 button \r\n"); + #endif + } + if (button4.read() == 0) //buttons are pulled up, gnd when pressed + { + which_button = 4; + #if MyDebugEnb + device.printf("is 4 button \r\n"); + #endif + } + else if (button5.read() == 0) + { + which_button = 5; + #if MyDebugEnb + device.printf("is 5 button \r\n"); + #endif + } + else if (button6.read() == 0) + { + which_button = 6; + #if MyDebugEnb + device.printf("is 6 button \r\n"); + #endif + } + if (button7.read() == 0) //buttons are pulled up, gnd when pressed + { + which_button = 7; + #if MyDebugEnb + device.printf("is 7 button \r\n"); + #endif + } + else if (button8.read() == 0) + { + which_button = 8; + #if MyDebugEnb + device.printf("is 8 button \r\n"); + #endif + } + else if (button9.read() == 0) + { + which_button = 9; + #if MyDebugEnb + device.printf("is 9 button \r\n"); + #endif + } + else + { + } +#endif + + + + #if MyDebugEnb + device.printf("interrupt button= %d \r\n", which_button); + #endif + //reset and start timer + Tmr_Click_Duration.reset(); + Tmr_Click_Duration.start(); + } //ISR for I/O interrupt void buttonReleasedCallback(void) { - - Tic_Debounce.attach(debounce_Callback, 1); + + Tic_Debounce.attach(debounce_Callback, 0.3); } @@ -198,6 +355,7 @@ { Flag_Update_IO = true; Flag_Periodic_Call = true; + which_button = 12; //no real button presses, just arbitrarly pick 12 to represent this. } @@ -314,13 +472,13 @@ //while loop doesn't actually loop until reading comlete, use a wait. while (((NRF_ADC->BUSY & ADC_BUSY_BUSY_Msk) >> ADC_BUSY_BUSY_Pos) == ADC_BUSY_BUSY_Busy) {}; - wait_ms(1); + wait_ms(2); //save off RESULT before disabling. //uint16_t myresult = (uint16_t)NRF_ADC->RESULT; //disable ADC to lower bat consumption - NRF_ADC->TASKS_STOP = 1; + //NRF_ADC->TASKS_STOP = 1; //perform disable in main loop //NRF_ADC->ENABLE = ADC_ENABLE_ENABLE_Disabled; //disable to shutdown ADC & lower bat consumption return (uint16_t)NRF_ADC->RESULT; // 10 bit @@ -357,7 +515,7 @@ //while loop doesn't actually loop until reading comlete, use a wait. while (((NRF_ADC->BUSY & ADC_BUSY_BUSY_Msk) >> ADC_BUSY_BUSY_Pos) == ADC_BUSY_BUSY_Busy) {}; - wait_ms(1); //needed because busy while loop doesn't run. + wait_ms(2); //needed because busy while loop doesn't run. //save off RESULT before disabling. //uint16_t myresult = (uint16_t)NRF_ADC->RESULT; @@ -400,6 +558,9 @@ } + + + /* **************************************** * * Main Loop @@ -443,6 +604,55 @@ } device.printf("\r\n"); #endif + + //set motion sensor + + #if sensorEnb + data.setAct(LIS3DH_V_CHIP_ADDR); + #endif + //for puppet, go ahead and pull up all the time. + + #if buttonEnb + + button1.mode(PullUp); + button2.mode(PullUp); + button3.mode(PullUp); + button4.mode(PullUp); + button5.mode(PullUp); + button6.mode(PullUp); + button7.mode(PullUp); + button8.mode(PullUp); + button9.mode(PullUp); + #endif + + #if sensorEnb + lis3dh_int1.mode(PullNone); //if pulled up, will consume 200uA. LIS3DH has pull up enabled. + #endif + + #if buttonEnb + button1.fall(buttonPressedCallback); //enable interrupt + button2.fall(buttonPressedCallback); //enable interrupt + button3.fall(buttonPressedCallback); //enable interrupt + button4.fall(buttonPressedCallback); //enable interrupt + button5.fall(buttonPressedCallback); //enable interrupt + button6.fall(buttonPressedCallback); //enable interrupt + button7.fall(buttonPressedCallback); //enable interrupt + button8.fall(buttonPressedCallback); //enable interrupt + button9.fall(buttonPressedCallback); //enable interrupt + button1.rise(buttonReleasedCallback); //enable interrupt + button2.rise(buttonReleasedCallback); //enable interrupt + button3.rise(buttonReleasedCallback); //enable interrupt + button4.rise(buttonReleasedCallback); //enable interrupt + button5.rise(buttonReleasedCallback); //enable interrupt + button6.rise(buttonReleasedCallback); //enable interrupt + button7.rise(buttonReleasedCallback); //enable interrupt + button8.rise(buttonReleasedCallback); //enable interrupt + button9.rise(buttonReleasedCallback); //enable interrupt + #endif + #if sensorEnb + lis3dh_int1.rise(motion_Callback); //enable interrupt + #endif + while (true) { //Main Loop @@ -452,69 +662,18 @@ device.printf("current time in seconds: %d \r\n", seconds_Old); #endif - //set both pins to pull-up, so they're not floating when we read state - button1.mode(PullUp); - button2.mode(PullUp); + //expect either button1 or button2 is grounded, b/c using SPDT reed switch //the "common" pin on the reed switch should be on GND - uint8_t button1_state = button1.read(); - uint8_t button2_state = button2.read(); + //uint8_t button1_state = button1.read(); + //uint8_t button2_state = button2.read(); + //uint8_t button3_state = button3.read(); - //let's just update the pins on every wake. Insurance against const drain. - //if state == 0, pin is grounded. Unset interrupt and float pin, set the other pin for ISR - if ( (button1_state == 0) && (button2_state == 1) ) - { - magnet_near = 1; - //button1.disable_irq() //don't know if disables IRQ on port or pin - button1.fall(NULL); //disable interrupt - button1.rise(NULL); //disable interrupt - button1.mode(PullNone); //float pin to save battery - - //button2.disable_irq() //don't know if disables IRQ on port or pin - button2.fall(buttonReleasedCallback); //enable interrupt - button2.rise(buttonReleasedCallback); //enable interrupt - button2.mode(PullUp); //pull up on pin to get interrupt - #if MyDebugEnb - device.printf("=== button 1! %d seconds=== \r\n", seconds_Old); - #endif - } //end if button2 - else if ( (button1_state == 1) && (button2_state == 0) ) //assume other pin is open circuit - { - magnet_near = 0; - //button1.disable_irq() //don't know if disables IRQ on port or pin - button1.fall(buttonReleasedCallback); //enable interrupt - button1.rise(buttonReleasedCallback); //enable interrupt - button1.mode(PullUp); //pull up on pin to get interrupt - - //button2.disable_irq() //don't know if disables IRQ on port or pin - button2.fall(NULL); //disable interrupt - button2.rise(NULL); //disable interrupt - button2.mode(PullNone); //float pin to save battery - #if MyDebugEnb - device.printf("=== button 2! === %d seconds\r\n", seconds_Old); - #endif - } //end if button1 - else //odd state, shouldn't happen, suck battery and pullup both pins - { - magnet_near = 2; - //AdvData[4] = 0x33; - //button1.disable_irq() //don't know if disables IRQ on port or pin - button1.fall(buttonReleasedCallback); //disable interrupt - button1.rise(buttonReleasedCallback); //disable interrupt - button1.mode(PullUp); //float pin to save battery - - //button2.disable_irq() //don't know if disables IRQ on port or pin - button2.fall(buttonReleasedCallback); //disable interrupt - button2.rise(buttonReleasedCallback); //disable interrupt - button2.mode(PullUp); //float pin to save battery - #if MyDebugEnb - device.printf("no buttons!! %d seconds\r\n", seconds_Old); - #endif - } //end odd state - - + + + if (Flag_Update_IO) { /* Do blocking calls or whatever hardware-specific action is * necessary to poll the sensor. */ @@ -612,28 +771,82 @@ AdvData[12] = Xmit_Cnt; JSON_loc++; - //start of jason data - //"mag": - JSON_loc = 13; - AdvData[JSON_loc] = 0x22; //ADV_Data[13] = " - JSON_loc++; //14 - AdvData[JSON_loc] = 0x6d; //ADV_Data[14] = m - JSON_loc++; //15 + //start of jason data: "but/?" + //"but" for button + if (which_button<=10) + { + JSON_loc = 13; + AdvData[JSON_loc] = 0x22; //ADV_Data[13] = " + JSON_loc++; //14 + + AdvData[JSON_loc] = 'b'; + JSON_loc++; //15 + + AdvData[JSON_loc] = 'u'; + JSON_loc++; //16 + + AdvData[JSON_loc] = 't'; + JSON_loc++; //17 + + AdvData[JSON_loc] = 0x2f; // "/" + JSON_loc++; //17 + + + //convert magnet variable to string, for magnet sensor, this is easy + //since we only have 1 or 0, but this also works for analog values + memset(&buffer[0], 0, sizeof(buffer)); //clear out buffer + total_chars = sprintf (buffer, "%d", which_button); //returns total number of characters, which is 1 character. + for (int i=0; i < total_chars; i++) + { + AdvData[JSON_loc] = buffer[i]; + JSON_loc++; + } //JSON_loc left at location of next character + + }// if is a button press + + if (which_button==11) + { + JSON_loc = 13; + AdvData[JSON_loc] = 0x22; //ADV_Data[13] = " + JSON_loc++; //14 + + AdvData[JSON_loc] = 's'; + JSON_loc++; //15 + + AdvData[JSON_loc] = 'h'; + JSON_loc++; //16 + + AdvData[JSON_loc] = 'a'; + JSON_loc++; //17 + + AdvData[JSON_loc] = 'k'; + JSON_loc++; //17 + AdvData[JSON_loc] = 'e'; + JSON_loc++; //17 + //AdvData[JSON_loc] = 0x2f; // "/" + //JSON_loc++; //17 + + }// if is a button press - AdvData[JSON_loc] = 0x61; //ADV_Data[15] = a - JSON_loc++; //16 + which_button = 0; //reset which button - AdvData[JSON_loc] = 0x67; //ADV_Data[16] = g - JSON_loc++; //17 - + //for periodic calls, we want to add an extra mqtt level "p", using "/p" //to delineate between MQTT publishes from real world I/O interrupts vs timer interrupts if (Flag_Periodic_Call) { AdvData[JSON_loc] = 0x2f; // ADV_Data[17] = / JSON_loc++; //18 - AdvData[JSON_loc] = 0x70; // ADV_Data[18] =p + AdvData[JSON_loc] = 'p'; + JSON_loc++; //19 + AdvData[JSON_loc] = 'e'; + JSON_loc++; //19 + AdvData[JSON_loc] = 'r'; + JSON_loc++; //19 + AdvData[JSON_loc] = 0x2f; // ADV_Data[17] = / + JSON_loc++; //18 + AdvData[JSON_loc] = 'p'; // ADV_Data[18] =p JSON_loc++; //19 } @@ -646,7 +859,7 @@ //convert magnet variable to string, for magnet sensor, this is easy //since we only have 1 or 0, but this also works for analog values memset(&buffer[0], 0, sizeof(buffer)); //clear out buffer - total_chars = sprintf (buffer, "%d", magnet_near); //returns total number of characters, which is 1 character. + total_chars = sprintf (buffer, "%d", button_pressed_ms); //returns total number of characters, which is 1 character. for (int i=0; i < total_chars; i++) { AdvData[JSON_loc] = buffer[i]; @@ -701,5 +914,8 @@ ble.waitForEvent(); //sleeps until interrupt form ticker or I/O + + + //wait_ms(1000); }//end forever while }//end main