Cow Tag

Dependencies:   MMA8452_tag_private BLE_API mbed nRF51822

Files at this revision

API Documentation at this revision

Comitter:
luisbc92
Date:
Tue Feb 09 19:45:55 2016 +0000
Parent:
0:4c7b37b8faad
Commit message:
initial Commit

Changed in this revision

ADXL345.lib Show diff for this revision Revisions of this file
MMA8452.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
--- a/ADXL345.lib	Fri Jan 08 20:41:56 2016 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1 +0,0 @@
-http://mbed.org/users/aberk/code/ADXL345/#bd8f0f20f433
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MMA8452.lib	Tue Feb 09 19:45:55 2016 +0000
@@ -0,0 +1,1 @@
+https://developer.mbed.org/users/luisbc92/code/MMA8452_tag_private/#f92fe1e48ab7
--- a/main.cpp	Fri Jan 08 20:41:56 2016 +0000
+++ b/main.cpp	Tue Feb 09 19:45:55 2016 +0000
@@ -1,58 +1,161 @@
-
 #include "mbed.h"
 #include "BLEDevice.h"
-#include "ADXL345.h"
+#include "MMA8452.h"
+
+// Configuration
+#define BLE_ADV_INTERVAL    500         // Interval between each advertising packet (in MS)
+#define ACC_RATE            10          // Accelerometer sampling rate (in Hz)
+#define ACC_BUFFER_SIZE     10          // Accelerometer history size
 
-// The accelerometer sample rate defines how often advertising
-// packets need to be sent. Each packet can hold 9 samples.
-#define ACC_SAMPLE_RATE     9
+// Algorithm
+#define ALG_PERIOD          1           // Algorithm period
+#define ALG_ACC_AXIS        0           // Which accelerometer axis to use
+#define ALG_UP_THRES        0.3         // Up State Threshold
+#define ALG_UP_TTCKS        10          // Up State Trigger Time
+#define ALG_DOWN_THRES      0.3         // Down State Threshold
+#define ALG_DOWN_TICKS      4           // Down State Trigger Time
 
-// How many times to re-advertise the same packet. For example,
-// if for the given sample rate an advertising packet needs to
-// be sent every second, and ADV_RESEND_COUNT of 2 will send
-// 2 packets per second.
-#define ADV_RESEND_COUNT    10
+// Objects
+BLEDevice   ble;                        // BLE
+DigitalOut  led(P0_2);                  // LED (Active Low)
+InterruptIn btn(P0_3);                  // Button Interrupt (Active Low)
+MMA8452     acc(P0_22, P0_20, 100000);  // Accelerometer
+Ticker      acc_tick;                   // Ticker for the accelerometer
+Ticker      led_tick;                   // Ticker for led
+Ticker      alg_tick;                   // Ticker for algorithm
+
+// Data
+struct acc_ring {
+    double data[3][ACC_BUFFER_SIZE];
+    int head;
+} acc_ring;
+
+enum AlgState {
+    UP,
+    DOWN
+};
 
-BLEDevice   ble;
-ADXL345     acc(P0_9, P0_11, P0_8, P0_10);
-DigitalOut  led(P0_19);
+// Prototypes
+void onError();
+void onAccTick();
+void onButton();
+void onLedTick();
+void ledBlink(int, float);
+void ledStop();
+double getAccLast(int);
+double getAccMean(int);
+void setPayload(uint8_t*, uint8_t);
+
+// Events
+void onError() {
+    led = 1;
+    wait(0.25);
+    led = 0;
+    wait(0.25);
+}
 
-void accRead() {
-    int data[3];
-    static int8_t buffer[28];
-    static uint8_t index = 0;
-    static uint8_t count;
+void onAccTick() {
+    // Increment head
+    acc_ring.head++;
+    if (acc_ring.head >= ACC_BUFFER_SIZE) acc_ring.head = 0;
     
-    acc.getOutput(data);
+    // Read accelerometer
+    acc.readXGravity(&acc_ring.data[0][acc_ring.head]);
+    acc.readYGravity(&acc_ring.data[1][acc_ring.head]);
+    acc.readZGravity(&acc_ring.data[2][acc_ring.head]);
+}
+
+void onButton() {
+    ledBlink(3, 1);
+}
+
+int led_blink;
+void onLedTick() {
+    led = !led;         // Invert LED state
     
-    // Fill buffer
-    buffer[index] = (int8_t)(data[0] >> 8);
-    buffer[index+1] = (int8_t)(data[1] >> 8);
-    buffer[index+2] = (int8_t)(data[2] >> 8);
-    index += 3;
+    if (led == 1)       // If led was turned off
+        led_blink--;    // Decrement blink counter
+        
+    if (led_blink == 0)
+        led_tick.detach();
+}
+
+void onAlgTick() {
+    static AlgState state = UP;
+    static AlgState last = DOWN;
+    static int timer;
+    
+    double pos = getAccMean(ALG_ACC_AXIS);
+    
+    switch (state) {
+        case UP:
+            if (pos < ALG_DOWN_THRES) {
+                timer = 0;
+            } else {
+                ledBlink(1, 1);
+            }
+            if (timer > ALG_DOWN_TICKS) {
+                state = DOWN;
+            }
+            break;
+            
+        case DOWN:
+            if (pos > ALG_UP_THRES) {
+                timer = 0;
+            } else {
+                ledBlink(1, 1);
+            }
+            if (timer > 10) {
+                state = UP;
+            }
+            break;
+    }
     
-    // If buffer is full (9 readings) update advertising packet
-    if (index >= 27) {
-        index = 0;                      // Reset buffer index
-        count += 1;                     // Increase packet count
-        buffer[27] = count;             // Append packet count
-        ble.clearScanResponse();        // Clear advertising packet and add data
-        ble.accumulateScanResponse(GapAdvertisingData::MANUFACTURER_SPECIFIC_DATA, (uint8_t*)buffer, sizeof(buffer));
-        ble.setAdvertisingPayload();
-        led = 0;                        // Flash led
-        wait(0.01);
-        led = 1;
+    if (state != last) {
+        last = state;
+        setPayload((uint8_t*)&state, 1);
+        ledBlink(2, 0.25);
     }
+    
+    timer++;
 }
-    
-    
+
+// Functions
+void setPayload(uint8_t * data, uint8_t size) {
+    ble.clearScanResponse();
+    ble.accumulateScanResponse(GapAdvertisingData::MANUFACTURER_SPECIFIC_DATA, data, size);
+    ble.setAdvertisingPayload();
+}
+
+void ledBlink(int num, float period) {
+    led = 0;
+    led_blink = num;
+    led_tick.attach(&onLedTick, period/2);
+}
+
+void ledStop() {
+    led_blink = 0;
+    led_tick.detach();
+}
+
+double getAccLast(int axis) {
+    return acc_ring.data[axis][acc_ring.head];
+}
+
+double getAccMean(int axis) {
+    double mean = 0;
+    for (int i = 0; i < ACC_BUFFER_SIZE; i++) {
+        mean += acc_ring.data[axis][i];
+    }
+    return (mean / (float)ACC_BUFFER_SIZE);
+}
+
+
 int main(void) {
-    // Turn off led
-    led = 0;
-    
-    // Calculate advertising interval
-    uint16_t adv_interval;
-    adv_interval = (uint16_t)((9.0 / (float)ACC_SAMPLE_RATE) * 1000.0 / (float)ADV_RESEND_COUNT);
+    // Initialize LED and Button
+    led = 1;
+    btn.mode(PullUp);
+    btn.fall(&onButton);
     
     // Initialize BLE
     uint8_t tagAddress[6];
@@ -69,18 +172,24 @@
         GapAdvertisingData::COMPLETE_LOCAL_NAME,
         tagName,
         sizeof(tagName));
-    ble.setAdvertisingInterval(adv_interval);               // Advertising interval
+    ble.setAdvertisingInterval((uint16_t)((float)BLE_ADV_INTERVAL / 0.625));    // Advertising interval
     ble.startAdvertising();                                 // Start advertising
     
-    // Setup ticker to read accelerometer
-    acc.setPowerControl(0x00);      // Standby for configuration
-    acc.setDataFormatControl(0x05); // +-4g, left-justified,
-    acc.setDataRate(ADXL345_12HZ5); // 12.5Hz Internal Sample Rate
-    acc.setPowerControl(0x08);      // Measurement mode
-    Ticker acc_read;
-    acc_read.attach(&accRead, (1.0 / (float)ACC_SAMPLE_RATE));
+    // Initialize accelerometer
+    char acc_id;
+    acc.getDeviceID(&acc_id);                               // Check if accelerometer succesfully comunicates
+    if (acc_id != 0x2A) onError();
+    acc.standby();                                          // Put into standby mode before configuration
+    acc.setDataRate(acc.RATE_12_5);                         // Set hardware data rate to 12.5Hz
+    acc.setDynamicRange(acc.DYNAMIC_RANGE_2G);              // Set dynamic range up to 2G
+    acc.setBitDepth(acc.BIT_DEPTH_12);                      // Set bit depth to 12bits for resolution
+    acc.activate();                                         // Activate accelerometer
+    acc_tick.attach(&onAccTick, (1.0 / (float)ACC_RATE));   // Setup periodic reads
     
-    while(1) {
-        ble.waitForEvent();     // Sleep
+    // Setup algorithm
+    alg_tick.attach(&onAlgTick, ALG_PERIOD);
+    
+    while (1) {
+        ble.waitForEvent();
     }
 }