AnalogIn - use median of the sampling data for stabler input value

Dependencies:   mbed

Files at this revision

API Documentation at this revision

Comitter:
yamaguch
Date:
Mon Jun 20 10:47:02 2011 +0000
Commit message:
0.9

Changed in this revision

AnalogIn2.cpp Show annotated file Show diff for this revision Revisions of this file
AnalogIn2.h 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
mbed.bld Show annotated file Show diff for this revision Revisions of this file
diff -r 000000000000 -r bbe67df5e586 AnalogIn2.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/AnalogIn2.cpp	Mon Jun 20 10:47:02 2011 +0000
@@ -0,0 +1,166 @@
+#include "AnalogIn2.h"
+
+short int quickSelect(unsigned short arr[], int n);
+
+AnalogIn2::AnalogIn2(PinName pinName) : pinName(pinName) {
+    switch (pinName) {
+        case p15:
+            channel = 0;
+            break;
+        case p16:
+            channel = 1;
+            break;
+        case p17:
+            channel = 2;
+            break;
+        case p18:
+            channel = 3;
+            break;
+        case p19:
+            channel = 4;
+            break;
+        case p20:
+            channel = 5;
+            break;
+    }
+    read_u16(1);
+}
+
+unsigned short AnalogIn2::read_u16(int nSamples) {
+    // power on, clk divider /4
+    LPC_SC->PCONP |= (1 << 12);
+    LPC_SC->PCLKSEL0 &= ~(0x3 << 24);
+
+    // software-controlled ADC settings
+    LPC_ADC->ADCR = (0 << 0) // SEL: 0 = no channels selected
+                    | (25 << 8)    // CLKDIV: PCLK max ~= 25MHz, /25 to give safe 1MHz
+                    | (0 << 16)    // BURST: 0 = software control
+                    | (0 << 17)    // CLKS: not applicable
+                    | (1 << 21)    // PDN: 1 = operational
+                    | (0 << 24)    // START: 0 = no start
+                    | (0 << 27);   // EDGE: not applicable
+
+    switch (pinName) {
+        case p15:// =p0.23 of LPC1768
+            LPC_PINCON->PINSEL1 &= ~((unsigned int)0x3 << 14);
+            LPC_PINCON->PINSEL1 |= (unsigned int)0x1 << 14;
+            LPC_PINCON->PINMODE1 &= ~((unsigned int)0x3 << 14);
+            LPC_PINCON->PINMODE1 |= (unsigned int)0x2 << 14;
+            break;
+        case p16:// =p0.24 of LPC1768
+            LPC_PINCON->PINSEL1 &= ~((unsigned int)0x3 << 16);
+            LPC_PINCON->PINSEL1 |= (unsigned int)0x1 << 16;
+            LPC_PINCON->PINMODE1 &= ~((unsigned int)0x3 << 16);
+            LPC_PINCON->PINMODE1 |= (unsigned int)0x2 << 16;
+            break;
+        case p17:// =p0.25 of LPC1768
+            LPC_PINCON->PINSEL1 &= ~((unsigned int)0x3 << 18);
+            LPC_PINCON->PINSEL1 |= (unsigned int)0x1 << 18;
+            LPC_PINCON->PINMODE1 &= ~((unsigned int)0x3 << 18);
+            LPC_PINCON->PINMODE1 |= (unsigned int)0x2 << 18;
+            break;
+        case p18:// =p0.26 of LPC1768:
+            LPC_PINCON->PINSEL1 &= ~((unsigned int)0x3 << 20);
+            LPC_PINCON->PINSEL1 |= (unsigned int)0x1 << 20;
+            LPC_PINCON->PINMODE1 &= ~((unsigned int)0x3 << 20);
+            LPC_PINCON->PINMODE1 |= (unsigned int)0x2 << 20;
+            break;
+        case p19:// =p1.30 of LPC1768
+            LPC_PINCON->PINSEL3 &= ~((unsigned int)0x3 << 28);
+            LPC_PINCON->PINSEL3 |= (unsigned int)0x3 << 28;
+            LPC_PINCON->PINMODE3 &= ~((unsigned int)0x3 << 28);
+            LPC_PINCON->PINMODE3 |= (unsigned int)0x2 << 28;
+            break;
+        case p20:// =p1.31 of LPC1768
+            LPC_PINCON->PINSEL3 &= ~((unsigned int)0x3 << 30);
+            LPC_PINCON->PINSEL3 |= (unsigned int)0x3 << 30;
+            LPC_PINCON->PINMODE3 &= ~((unsigned int)0x3 << 30);
+            LPC_PINCON->PINMODE3 |= (unsigned int)0x2 << 30;
+            break;
+    }
+
+    // Repeatedly get the sample data until DONE bit
+    unsigned short a[nSamples];
+    for (int i = 0; i < nSamples; i++) {
+        unsigned int data;
+        // Select channel and start conversion
+        LPC_ADC->ADCR &= ~0xFF;
+        LPC_ADC->ADCR |= 1 << channel;
+        LPC_ADC->ADCR |= 1 << 24;
+        do {
+            data = LPC_ADC->ADGDR;
+        } while ((data & ((unsigned int)1 << 31)) == 0);
+        // Stop conversion
+        LPC_ADC->ADCR &= ~(1 << 24);
+
+        a[i] = data & 65535;
+    }
+
+    return quickSelect(a, nSamples);
+}
+
+float AnalogIn2::read(int nSamples) {
+    return (read_u16(nSamples) >> 4) / 4096.0;
+}
+
+AnalogIn2::operator float() {
+    return read();
+}
+
+/*
+ * This Quickselect routine is based on the algorithm described in
+ * "Numerical recipes in C", Second Edition,
+ * Cambridge University Press, 1992, Section 8.5, ISBN 0-521-43108-5
+ * This code by Nicolas Devillard - 1998. Public domain. */
+
+#define SWAP(a,b) {unsigned int t = (a); (a) = (b); (b) = t;}
+
+short int quickSelect(unsigned short arr[], int n) {
+    int low = 0, high = n - 1;
+    unsigned int median = (low + high) / 2;
+
+    for (;;) {
+        if (high <= low) /* One element only */
+            return arr[median];
+        if (high == low + 1) { /* Two elements only */
+            if (arr[low] > arr[high])
+                SWAP(arr[low], arr[high]);
+            return arr[median];
+        }
+
+        /* Find median of low, middle and high items; swap into position low */
+        int middle = (low + high) / 2;
+        if (arr[middle] > arr[high])
+            SWAP(arr[middle], arr[high]);
+        if (arr[low] > arr[high])
+            SWAP(arr[low], arr[high]);
+        if (arr[middle] > arr[low])
+            SWAP(arr[middle], arr[low]);
+        /* Swap low item (now in position middle) into position (low + 1) */
+        SWAP(arr[middle], arr[low + 1]);
+
+        /* Nibble from each end towards middle, swapping items when stuck */
+        int ll = low + 1;
+        int hh = high;
+        for (;;) {
+            do {
+                ll++;
+            } while (arr[low] > arr[ll]);
+            do {
+                hh--;
+            } while (arr[hh] > arr[low]);
+            if (hh < ll)
+                break;
+            SWAP(arr[ll], arr[hh]);
+        }
+
+        /* Swap middle item (in position low) back into correct position */
+        SWAP(arr[low], arr[hh]);
+
+        /* Re-set active partition */
+        if (hh <= median)
+            low = ll;
+        if (hh >= median)
+            high = hh - 1;
+    }
+}
\ No newline at end of file
diff -r 000000000000 -r bbe67df5e586 AnalogIn2.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/AnalogIn2.h	Mon Jun 20 10:47:02 2011 +0000
@@ -0,0 +1,18 @@
+#ifndef MBED_ANALOG_IN2
+#define MBED_ANALOG_IN2
+
+#include "mbed.h"
+
+class AnalogIn2 {
+public:
+    AnalogIn2(PinName pinName);
+    float read(int nSamples = 10);
+    unsigned short read_u16(int nSamples = 10);
+    operator float();
+    
+private:
+    PinName pinName;
+    int channel;
+};
+
+#endif
\ No newline at end of file
diff -r 000000000000 -r bbe67df5e586 main.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main.cpp	Mon Jun 20 10:47:02 2011 +0000
@@ -0,0 +1,12 @@
+#include "mbed.h"
+#include "AnalogIn2.h"
+
+AnalogIn2 a20(p20);
+AnalogIn2 a15(p15);
+
+int main() {
+    printf("Temperature AnalogIn2 test\n");
+    printf("a15 %d, %f\n", a15.read_u16(), (3.3 * a15.read() - 0.424) / 0.00625);
+    printf("a20 %d, %f\n", a20.read_u16(100), (3.3 * a20.read(100) - 0.424) / 0.00625);
+    wait(1);
+}
\ No newline at end of file
diff -r 000000000000 -r bbe67df5e586 mbed.bld
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed.bld	Mon Jun 20 10:47:02 2011 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/mbed_official/code/mbed/builds/49a220cc26e0