Hiroshi Yamaguchi
/
AnalogIn2
AnalogIn - use median of the sampling data for stabler input value
AnalogIn2.cpp@0:bbe67df5e586, 2011-06-20 (annotated)
- Committer:
- yamaguch
- Date:
- Mon Jun 20 10:47:02 2011 +0000
- Revision:
- 0:bbe67df5e586
0.9
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
yamaguch | 0:bbe67df5e586 | 1 | #include "AnalogIn2.h" |
yamaguch | 0:bbe67df5e586 | 2 | |
yamaguch | 0:bbe67df5e586 | 3 | short int quickSelect(unsigned short arr[], int n); |
yamaguch | 0:bbe67df5e586 | 4 | |
yamaguch | 0:bbe67df5e586 | 5 | AnalogIn2::AnalogIn2(PinName pinName) : pinName(pinName) { |
yamaguch | 0:bbe67df5e586 | 6 | switch (pinName) { |
yamaguch | 0:bbe67df5e586 | 7 | case p15: |
yamaguch | 0:bbe67df5e586 | 8 | channel = 0; |
yamaguch | 0:bbe67df5e586 | 9 | break; |
yamaguch | 0:bbe67df5e586 | 10 | case p16: |
yamaguch | 0:bbe67df5e586 | 11 | channel = 1; |
yamaguch | 0:bbe67df5e586 | 12 | break; |
yamaguch | 0:bbe67df5e586 | 13 | case p17: |
yamaguch | 0:bbe67df5e586 | 14 | channel = 2; |
yamaguch | 0:bbe67df5e586 | 15 | break; |
yamaguch | 0:bbe67df5e586 | 16 | case p18: |
yamaguch | 0:bbe67df5e586 | 17 | channel = 3; |
yamaguch | 0:bbe67df5e586 | 18 | break; |
yamaguch | 0:bbe67df5e586 | 19 | case p19: |
yamaguch | 0:bbe67df5e586 | 20 | channel = 4; |
yamaguch | 0:bbe67df5e586 | 21 | break; |
yamaguch | 0:bbe67df5e586 | 22 | case p20: |
yamaguch | 0:bbe67df5e586 | 23 | channel = 5; |
yamaguch | 0:bbe67df5e586 | 24 | break; |
yamaguch | 0:bbe67df5e586 | 25 | } |
yamaguch | 0:bbe67df5e586 | 26 | read_u16(1); |
yamaguch | 0:bbe67df5e586 | 27 | } |
yamaguch | 0:bbe67df5e586 | 28 | |
yamaguch | 0:bbe67df5e586 | 29 | unsigned short AnalogIn2::read_u16(int nSamples) { |
yamaguch | 0:bbe67df5e586 | 30 | // power on, clk divider /4 |
yamaguch | 0:bbe67df5e586 | 31 | LPC_SC->PCONP |= (1 << 12); |
yamaguch | 0:bbe67df5e586 | 32 | LPC_SC->PCLKSEL0 &= ~(0x3 << 24); |
yamaguch | 0:bbe67df5e586 | 33 | |
yamaguch | 0:bbe67df5e586 | 34 | // software-controlled ADC settings |
yamaguch | 0:bbe67df5e586 | 35 | LPC_ADC->ADCR = (0 << 0) // SEL: 0 = no channels selected |
yamaguch | 0:bbe67df5e586 | 36 | | (25 << 8) // CLKDIV: PCLK max ~= 25MHz, /25 to give safe 1MHz |
yamaguch | 0:bbe67df5e586 | 37 | | (0 << 16) // BURST: 0 = software control |
yamaguch | 0:bbe67df5e586 | 38 | | (0 << 17) // CLKS: not applicable |
yamaguch | 0:bbe67df5e586 | 39 | | (1 << 21) // PDN: 1 = operational |
yamaguch | 0:bbe67df5e586 | 40 | | (0 << 24) // START: 0 = no start |
yamaguch | 0:bbe67df5e586 | 41 | | (0 << 27); // EDGE: not applicable |
yamaguch | 0:bbe67df5e586 | 42 | |
yamaguch | 0:bbe67df5e586 | 43 | switch (pinName) { |
yamaguch | 0:bbe67df5e586 | 44 | case p15:// =p0.23 of LPC1768 |
yamaguch | 0:bbe67df5e586 | 45 | LPC_PINCON->PINSEL1 &= ~((unsigned int)0x3 << 14); |
yamaguch | 0:bbe67df5e586 | 46 | LPC_PINCON->PINSEL1 |= (unsigned int)0x1 << 14; |
yamaguch | 0:bbe67df5e586 | 47 | LPC_PINCON->PINMODE1 &= ~((unsigned int)0x3 << 14); |
yamaguch | 0:bbe67df5e586 | 48 | LPC_PINCON->PINMODE1 |= (unsigned int)0x2 << 14; |
yamaguch | 0:bbe67df5e586 | 49 | break; |
yamaguch | 0:bbe67df5e586 | 50 | case p16:// =p0.24 of LPC1768 |
yamaguch | 0:bbe67df5e586 | 51 | LPC_PINCON->PINSEL1 &= ~((unsigned int)0x3 << 16); |
yamaguch | 0:bbe67df5e586 | 52 | LPC_PINCON->PINSEL1 |= (unsigned int)0x1 << 16; |
yamaguch | 0:bbe67df5e586 | 53 | LPC_PINCON->PINMODE1 &= ~((unsigned int)0x3 << 16); |
yamaguch | 0:bbe67df5e586 | 54 | LPC_PINCON->PINMODE1 |= (unsigned int)0x2 << 16; |
yamaguch | 0:bbe67df5e586 | 55 | break; |
yamaguch | 0:bbe67df5e586 | 56 | case p17:// =p0.25 of LPC1768 |
yamaguch | 0:bbe67df5e586 | 57 | LPC_PINCON->PINSEL1 &= ~((unsigned int)0x3 << 18); |
yamaguch | 0:bbe67df5e586 | 58 | LPC_PINCON->PINSEL1 |= (unsigned int)0x1 << 18; |
yamaguch | 0:bbe67df5e586 | 59 | LPC_PINCON->PINMODE1 &= ~((unsigned int)0x3 << 18); |
yamaguch | 0:bbe67df5e586 | 60 | LPC_PINCON->PINMODE1 |= (unsigned int)0x2 << 18; |
yamaguch | 0:bbe67df5e586 | 61 | break; |
yamaguch | 0:bbe67df5e586 | 62 | case p18:// =p0.26 of LPC1768: |
yamaguch | 0:bbe67df5e586 | 63 | LPC_PINCON->PINSEL1 &= ~((unsigned int)0x3 << 20); |
yamaguch | 0:bbe67df5e586 | 64 | LPC_PINCON->PINSEL1 |= (unsigned int)0x1 << 20; |
yamaguch | 0:bbe67df5e586 | 65 | LPC_PINCON->PINMODE1 &= ~((unsigned int)0x3 << 20); |
yamaguch | 0:bbe67df5e586 | 66 | LPC_PINCON->PINMODE1 |= (unsigned int)0x2 << 20; |
yamaguch | 0:bbe67df5e586 | 67 | break; |
yamaguch | 0:bbe67df5e586 | 68 | case p19:// =p1.30 of LPC1768 |
yamaguch | 0:bbe67df5e586 | 69 | LPC_PINCON->PINSEL3 &= ~((unsigned int)0x3 << 28); |
yamaguch | 0:bbe67df5e586 | 70 | LPC_PINCON->PINSEL3 |= (unsigned int)0x3 << 28; |
yamaguch | 0:bbe67df5e586 | 71 | LPC_PINCON->PINMODE3 &= ~((unsigned int)0x3 << 28); |
yamaguch | 0:bbe67df5e586 | 72 | LPC_PINCON->PINMODE3 |= (unsigned int)0x2 << 28; |
yamaguch | 0:bbe67df5e586 | 73 | break; |
yamaguch | 0:bbe67df5e586 | 74 | case p20:// =p1.31 of LPC1768 |
yamaguch | 0:bbe67df5e586 | 75 | LPC_PINCON->PINSEL3 &= ~((unsigned int)0x3 << 30); |
yamaguch | 0:bbe67df5e586 | 76 | LPC_PINCON->PINSEL3 |= (unsigned int)0x3 << 30; |
yamaguch | 0:bbe67df5e586 | 77 | LPC_PINCON->PINMODE3 &= ~((unsigned int)0x3 << 30); |
yamaguch | 0:bbe67df5e586 | 78 | LPC_PINCON->PINMODE3 |= (unsigned int)0x2 << 30; |
yamaguch | 0:bbe67df5e586 | 79 | break; |
yamaguch | 0:bbe67df5e586 | 80 | } |
yamaguch | 0:bbe67df5e586 | 81 | |
yamaguch | 0:bbe67df5e586 | 82 | // Repeatedly get the sample data until DONE bit |
yamaguch | 0:bbe67df5e586 | 83 | unsigned short a[nSamples]; |
yamaguch | 0:bbe67df5e586 | 84 | for (int i = 0; i < nSamples; i++) { |
yamaguch | 0:bbe67df5e586 | 85 | unsigned int data; |
yamaguch | 0:bbe67df5e586 | 86 | // Select channel and start conversion |
yamaguch | 0:bbe67df5e586 | 87 | LPC_ADC->ADCR &= ~0xFF; |
yamaguch | 0:bbe67df5e586 | 88 | LPC_ADC->ADCR |= 1 << channel; |
yamaguch | 0:bbe67df5e586 | 89 | LPC_ADC->ADCR |= 1 << 24; |
yamaguch | 0:bbe67df5e586 | 90 | do { |
yamaguch | 0:bbe67df5e586 | 91 | data = LPC_ADC->ADGDR; |
yamaguch | 0:bbe67df5e586 | 92 | } while ((data & ((unsigned int)1 << 31)) == 0); |
yamaguch | 0:bbe67df5e586 | 93 | // Stop conversion |
yamaguch | 0:bbe67df5e586 | 94 | LPC_ADC->ADCR &= ~(1 << 24); |
yamaguch | 0:bbe67df5e586 | 95 | |
yamaguch | 0:bbe67df5e586 | 96 | a[i] = data & 65535; |
yamaguch | 0:bbe67df5e586 | 97 | } |
yamaguch | 0:bbe67df5e586 | 98 | |
yamaguch | 0:bbe67df5e586 | 99 | return quickSelect(a, nSamples); |
yamaguch | 0:bbe67df5e586 | 100 | } |
yamaguch | 0:bbe67df5e586 | 101 | |
yamaguch | 0:bbe67df5e586 | 102 | float AnalogIn2::read(int nSamples) { |
yamaguch | 0:bbe67df5e586 | 103 | return (read_u16(nSamples) >> 4) / 4096.0; |
yamaguch | 0:bbe67df5e586 | 104 | } |
yamaguch | 0:bbe67df5e586 | 105 | |
yamaguch | 0:bbe67df5e586 | 106 | AnalogIn2::operator float() { |
yamaguch | 0:bbe67df5e586 | 107 | return read(); |
yamaguch | 0:bbe67df5e586 | 108 | } |
yamaguch | 0:bbe67df5e586 | 109 | |
yamaguch | 0:bbe67df5e586 | 110 | /* |
yamaguch | 0:bbe67df5e586 | 111 | * This Quickselect routine is based on the algorithm described in |
yamaguch | 0:bbe67df5e586 | 112 | * "Numerical recipes in C", Second Edition, |
yamaguch | 0:bbe67df5e586 | 113 | * Cambridge University Press, 1992, Section 8.5, ISBN 0-521-43108-5 |
yamaguch | 0:bbe67df5e586 | 114 | * This code by Nicolas Devillard - 1998. Public domain. */ |
yamaguch | 0:bbe67df5e586 | 115 | |
yamaguch | 0:bbe67df5e586 | 116 | #define SWAP(a,b) {unsigned int t = (a); (a) = (b); (b) = t;} |
yamaguch | 0:bbe67df5e586 | 117 | |
yamaguch | 0:bbe67df5e586 | 118 | short int quickSelect(unsigned short arr[], int n) { |
yamaguch | 0:bbe67df5e586 | 119 | int low = 0, high = n - 1; |
yamaguch | 0:bbe67df5e586 | 120 | unsigned int median = (low + high) / 2; |
yamaguch | 0:bbe67df5e586 | 121 | |
yamaguch | 0:bbe67df5e586 | 122 | for (;;) { |
yamaguch | 0:bbe67df5e586 | 123 | if (high <= low) /* One element only */ |
yamaguch | 0:bbe67df5e586 | 124 | return arr[median]; |
yamaguch | 0:bbe67df5e586 | 125 | if (high == low + 1) { /* Two elements only */ |
yamaguch | 0:bbe67df5e586 | 126 | if (arr[low] > arr[high]) |
yamaguch | 0:bbe67df5e586 | 127 | SWAP(arr[low], arr[high]); |
yamaguch | 0:bbe67df5e586 | 128 | return arr[median]; |
yamaguch | 0:bbe67df5e586 | 129 | } |
yamaguch | 0:bbe67df5e586 | 130 | |
yamaguch | 0:bbe67df5e586 | 131 | /* Find median of low, middle and high items; swap into position low */ |
yamaguch | 0:bbe67df5e586 | 132 | int middle = (low + high) / 2; |
yamaguch | 0:bbe67df5e586 | 133 | if (arr[middle] > arr[high]) |
yamaguch | 0:bbe67df5e586 | 134 | SWAP(arr[middle], arr[high]); |
yamaguch | 0:bbe67df5e586 | 135 | if (arr[low] > arr[high]) |
yamaguch | 0:bbe67df5e586 | 136 | SWAP(arr[low], arr[high]); |
yamaguch | 0:bbe67df5e586 | 137 | if (arr[middle] > arr[low]) |
yamaguch | 0:bbe67df5e586 | 138 | SWAP(arr[middle], arr[low]); |
yamaguch | 0:bbe67df5e586 | 139 | /* Swap low item (now in position middle) into position (low + 1) */ |
yamaguch | 0:bbe67df5e586 | 140 | SWAP(arr[middle], arr[low + 1]); |
yamaguch | 0:bbe67df5e586 | 141 | |
yamaguch | 0:bbe67df5e586 | 142 | /* Nibble from each end towards middle, swapping items when stuck */ |
yamaguch | 0:bbe67df5e586 | 143 | int ll = low + 1; |
yamaguch | 0:bbe67df5e586 | 144 | int hh = high; |
yamaguch | 0:bbe67df5e586 | 145 | for (;;) { |
yamaguch | 0:bbe67df5e586 | 146 | do { |
yamaguch | 0:bbe67df5e586 | 147 | ll++; |
yamaguch | 0:bbe67df5e586 | 148 | } while (arr[low] > arr[ll]); |
yamaguch | 0:bbe67df5e586 | 149 | do { |
yamaguch | 0:bbe67df5e586 | 150 | hh--; |
yamaguch | 0:bbe67df5e586 | 151 | } while (arr[hh] > arr[low]); |
yamaguch | 0:bbe67df5e586 | 152 | if (hh < ll) |
yamaguch | 0:bbe67df5e586 | 153 | break; |
yamaguch | 0:bbe67df5e586 | 154 | SWAP(arr[ll], arr[hh]); |
yamaguch | 0:bbe67df5e586 | 155 | } |
yamaguch | 0:bbe67df5e586 | 156 | |
yamaguch | 0:bbe67df5e586 | 157 | /* Swap middle item (in position low) back into correct position */ |
yamaguch | 0:bbe67df5e586 | 158 | SWAP(arr[low], arr[hh]); |
yamaguch | 0:bbe67df5e586 | 159 | |
yamaguch | 0:bbe67df5e586 | 160 | /* Re-set active partition */ |
yamaguch | 0:bbe67df5e586 | 161 | if (hh <= median) |
yamaguch | 0:bbe67df5e586 | 162 | low = ll; |
yamaguch | 0:bbe67df5e586 | 163 | if (hh >= median) |
yamaguch | 0:bbe67df5e586 | 164 | high = hh - 1; |
yamaguch | 0:bbe67df5e586 | 165 | } |
yamaguch | 0:bbe67df5e586 | 166 | } |