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: mbed FastIO FastPWM USBDevice
Fork of Pinscape_Controller by
ccdSensor.h@45:c42166b2878c, 2016-02-15 (annotated)
- Committer:
- mjr
- Date:
- Mon Feb 15 20:30:32 2016 +0000
- Revision:
- 45:c42166b2878c
- Parent:
- 44:b5ac89b9cd5d
- Child:
- 47:df7a88cd249c
More work in progress on CCD speedups;
Who changed what in which revision?
| User | Revision | Line number | New contents of line |
|---|---|---|---|
| mjr | 17:ab3cec0c8bf4 | 1 | // CCD plunger sensor |
| mjr | 17:ab3cec0c8bf4 | 2 | // |
| mjr | 35:e959ffba78fd | 3 | // This class implements our generic plunger sensor interface for the |
| mjr | 35:e959ffba78fd | 4 | // TAOS TSL1410R and TSL1412R linear sensor arrays. Physically, these |
| mjr | 35:e959ffba78fd | 5 | // sensors are installed with their image window running parallel to |
| mjr | 35:e959ffba78fd | 6 | // the plunger rod, spanning the travel range of the plunger tip. |
| mjr | 35:e959ffba78fd | 7 | // A light source is positioned on the opposite side of the rod, so |
| mjr | 35:e959ffba78fd | 8 | // that the rod casts a shadow on the sensor. We sense the position |
| mjr | 35:e959ffba78fd | 9 | // by looking for the edge of the shadow. |
| mjr | 35:e959ffba78fd | 10 | // |
| mjr | 35:e959ffba78fd | 11 | // These sensors can take an image quickly, but it takes a significant |
| mjr | 35:e959ffba78fd | 12 | // amount of time to transfer the image data from the sensor to the |
| mjr | 35:e959ffba78fd | 13 | // microcontroller, since each pixel's analog voltage level must be |
| mjr | 35:e959ffba78fd | 14 | // sampled serially. It takes about 20us to sample a pixel accurately. |
| mjr | 35:e959ffba78fd | 15 | // The TSL1410R has 1280 pixels, and the 1412R has 1536. Sampling |
| mjr | 35:e959ffba78fd | 16 | // every pixel would thus take about 25ms or 30ms respectively. |
| mjr | 35:e959ffba78fd | 17 | // This is too slow for a responsive feel in the UI, and much too |
| mjr | 35:e959ffba78fd | 18 | // slow to track the plunger release motion in real time. To improve |
| mjr | 35:e959ffba78fd | 19 | // on the read speed, we only sample a subset of pixels for each |
| mjr | 35:e959ffba78fd | 20 | // reading - for higher speed at the expense of spatial resolution. |
| mjr | 35:e959ffba78fd | 21 | // The sensor's native resolution is much higher than we need, so |
| mjr | 35:e959ffba78fd | 22 | // this is a perfectly equitable trade. |
| mjr | 17:ab3cec0c8bf4 | 23 | |
| mjr | 35:e959ffba78fd | 24 | #include "plunger.h" |
| mjr | 17:ab3cec0c8bf4 | 25 | |
| mjr | 17:ab3cec0c8bf4 | 26 | |
| mjr | 25:e22b88bd783a | 27 | // PlungerSensor interface implementation for the CCD |
| mjr | 35:e959ffba78fd | 28 | class PlungerSensorCCD: public PlungerSensor |
| mjr | 17:ab3cec0c8bf4 | 29 | { |
| mjr | 17:ab3cec0c8bf4 | 30 | public: |
| mjr | 44:b5ac89b9cd5d | 31 | PlungerSensorCCD( |
| mjr | 44:b5ac89b9cd5d | 32 | int nativePix, int highResPix, int lowResPix, |
| mjr | 44:b5ac89b9cd5d | 33 | PinName si, PinName clock, PinName ao1, PinName ao2) |
| mjr | 43:7a6364d82a41 | 34 | : ccd(nativePix, si, clock, ao1, ao2) |
| mjr | 17:ab3cec0c8bf4 | 35 | { |
| mjr | 44:b5ac89b9cd5d | 36 | this->highResPix = highResPix; |
| mjr | 44:b5ac89b9cd5d | 37 | this->lowResPix = lowResPix; |
| mjr | 44:b5ac89b9cd5d | 38 | this->pix = new uint16_t[highResPix]; |
| mjr | 17:ab3cec0c8bf4 | 39 | } |
| mjr | 17:ab3cec0c8bf4 | 40 | |
| mjr | 17:ab3cec0c8bf4 | 41 | // initialize |
| mjr | 35:e959ffba78fd | 42 | virtual void init() |
| mjr | 17:ab3cec0c8bf4 | 43 | { |
| mjr | 17:ab3cec0c8bf4 | 44 | // flush any random power-on values from the CCD's integration |
| mjr | 17:ab3cec0c8bf4 | 45 | // capacitors, and start the first integration cycle |
| mjr | 17:ab3cec0c8bf4 | 46 | ccd.clear(); |
| mjr | 17:ab3cec0c8bf4 | 47 | } |
| mjr | 17:ab3cec0c8bf4 | 48 | |
| mjr | 17:ab3cec0c8bf4 | 49 | // Perform a low-res scan of the sensor. |
| mjr | 44:b5ac89b9cd5d | 50 | virtual bool lowResScan(float &pos) |
| mjr | 17:ab3cec0c8bf4 | 51 | { |
| mjr | 44:b5ac89b9cd5d | 52 | // If we haven't sensed the direction yet, do a high-res scan |
| mjr | 44:b5ac89b9cd5d | 53 | // first, so that we can get accurate direction data. Return |
| mjr | 44:b5ac89b9cd5d | 54 | // the result of the high-res scan if successful, since it |
| mjr | 44:b5ac89b9cd5d | 55 | // provides even better data than the caller requested from us. |
| mjr | 44:b5ac89b9cd5d | 56 | // This will take longer than the caller wanted, but it should |
| mjr | 44:b5ac89b9cd5d | 57 | // only be necessary to do this once after the system stabilizes |
| mjr | 44:b5ac89b9cd5d | 58 | // after startup, so the timing difference won't affect normal |
| mjr | 44:b5ac89b9cd5d | 59 | // operation. |
| mjr | 44:b5ac89b9cd5d | 60 | if (dir == 0) |
| mjr | 44:b5ac89b9cd5d | 61 | return highResScan(pos); |
| mjr | 44:b5ac89b9cd5d | 62 | |
| mjr | 17:ab3cec0c8bf4 | 63 | // read the pixels at low resolution |
| mjr | 44:b5ac89b9cd5d | 64 | ccd.read(pix, lowResPix); |
| mjr | 17:ab3cec0c8bf4 | 65 | |
| mjr | 44:b5ac89b9cd5d | 66 | // set the loop variables for the sensor orientation |
| mjr | 44:b5ac89b9cd5d | 67 | int si = 0; |
| mjr | 44:b5ac89b9cd5d | 68 | if (dir < 0) |
| mjr | 44:b5ac89b9cd5d | 69 | si = lowResPix - 1; |
| mjr | 44:b5ac89b9cd5d | 70 | |
| mjr | 44:b5ac89b9cd5d | 71 | // Figure the shadow edge threshold. Use the midpoint between |
| mjr | 44:b5ac89b9cd5d | 72 | // the average levels of a few pixels at each end. |
| mjr | 44:b5ac89b9cd5d | 73 | uint16_t shadow = uint16_t( |
| mjr | 44:b5ac89b9cd5d | 74 | (long(pix[0]) + long(pix[1]) + long(pix[2]) |
| mjr | 44:b5ac89b9cd5d | 75 | + long(pix[lowResPix-1]) + long(pix[lowResPix-2]) + long(pix[lowResPix-3]) |
| mjr | 44:b5ac89b9cd5d | 76 | )/6); |
| mjr | 17:ab3cec0c8bf4 | 77 | |
| mjr | 17:ab3cec0c8bf4 | 78 | // find the current tip position |
| mjr | 44:b5ac89b9cd5d | 79 | for (int n = 0 ; n < lowResPix ; ++n, si += dir) |
| mjr | 17:ab3cec0c8bf4 | 80 | { |
| mjr | 17:ab3cec0c8bf4 | 81 | // check to see if we found the shadow |
| mjr | 17:ab3cec0c8bf4 | 82 | if (pix[si] <= shadow) |
| mjr | 17:ab3cec0c8bf4 | 83 | { |
| mjr | 44:b5ac89b9cd5d | 84 | // got it - normalize to the 0.0..1.0 range and return success |
| mjr | 44:b5ac89b9cd5d | 85 | pos = float(n)/lowResPix; |
| mjr | 35:e959ffba78fd | 86 | return true; |
| mjr | 17:ab3cec0c8bf4 | 87 | } |
| mjr | 17:ab3cec0c8bf4 | 88 | } |
| mjr | 17:ab3cec0c8bf4 | 89 | |
| mjr | 35:e959ffba78fd | 90 | // didn't find a shadow - return failure |
| mjr | 35:e959ffba78fd | 91 | return false; |
| mjr | 17:ab3cec0c8bf4 | 92 | } |
| mjr | 17:ab3cec0c8bf4 | 93 | |
| mjr | 17:ab3cec0c8bf4 | 94 | // Perform a high-res scan of the sensor. |
| mjr | 44:b5ac89b9cd5d | 95 | virtual bool highResScan(float &pos) |
| mjr | 17:ab3cec0c8bf4 | 96 | { |
| mjr | 17:ab3cec0c8bf4 | 97 | // read the array |
| mjr | 44:b5ac89b9cd5d | 98 | ccd.read(pix, highResPix); |
| mjr | 17:ab3cec0c8bf4 | 99 | |
| mjr | 44:b5ac89b9cd5d | 100 | // Sense the orientation of the sensor if we haven't already. If |
| mjr | 44:b5ac89b9cd5d | 101 | // that fails, we must not have enough contrast to find a shadow edge |
| mjr | 44:b5ac89b9cd5d | 102 | // in the image, so there's no point in looking any further - just |
| mjr | 44:b5ac89b9cd5d | 103 | // return failure. |
| mjr | 44:b5ac89b9cd5d | 104 | if (dir == 0 && !senseOrientation(highResPix)) |
| mjr | 44:b5ac89b9cd5d | 105 | return false; |
| mjr | 44:b5ac89b9cd5d | 106 | |
| mjr | 44:b5ac89b9cd5d | 107 | // Get the average brightness for a few pixels at each end. |
| mjr | 44:b5ac89b9cd5d | 108 | long b1 = (long(pix[0]) + long(pix[1]) + long(pix[2]) + long(pix[3]) + long(pix[4])) / 5; |
| mjr | 44:b5ac89b9cd5d | 109 | long b2 = (long(pix[highResPix-1]) + long(pix[highResPix-2]) + long(pix[highResPix-3]) |
| mjr | 44:b5ac89b9cd5d | 110 | + long(pix[highResPix-4]) + long(pix[highResPix-5])) / 5; |
| mjr | 44:b5ac89b9cd5d | 111 | |
| mjr | 17:ab3cec0c8bf4 | 112 | // Work from the bright end to the dark end. VP interprets the |
| mjr | 17:ab3cec0c8bf4 | 113 | // Z axis value as the amount the plunger is pulled: zero is the |
| mjr | 17:ab3cec0c8bf4 | 114 | // rest position, and the axis maximum is fully pulled. So we |
| mjr | 17:ab3cec0c8bf4 | 115 | // essentially want to report how much of the sensor is lit, |
| mjr | 17:ab3cec0c8bf4 | 116 | // since this increases as the plunger is pulled back. |
| mjr | 44:b5ac89b9cd5d | 117 | int si = 0; |
| mjr | 18:5e890ebd0023 | 118 | long hi = b1; |
| mjr | 44:b5ac89b9cd5d | 119 | if (dir < 0) |
| mjr | 44:b5ac89b9cd5d | 120 | si = highResPix - 1, hi = b2; |
| mjr | 17:ab3cec0c8bf4 | 121 | |
| mjr | 17:ab3cec0c8bf4 | 122 | // Figure the shadow threshold. In practice, the portion of the |
| mjr | 17:ab3cec0c8bf4 | 123 | // sensor that's not in shadow has all pixels consistently near |
| mjr | 17:ab3cec0c8bf4 | 124 | // saturation; the first drop in brightness is pretty reliably the |
| mjr | 17:ab3cec0c8bf4 | 125 | // start of the shadow. So set the threshold level to be closer |
| mjr | 17:ab3cec0c8bf4 | 126 | // to the bright end's brightness level, so that we detect the leading |
| mjr | 17:ab3cec0c8bf4 | 127 | // edge if the shadow isn't perfectly sharp. Use the point 1/3 of |
| mjr | 17:ab3cec0c8bf4 | 128 | // the way down from the high top the low side, so: |
| mjr | 17:ab3cec0c8bf4 | 129 | // |
| mjr | 17:ab3cec0c8bf4 | 130 | // threshold = lo + (hi - lo)*2/3 |
| mjr | 17:ab3cec0c8bf4 | 131 | // = lo + hi*2/3 - lo*2/3 |
| mjr | 17:ab3cec0c8bf4 | 132 | // = lo - lo*2/3 + hi*2/3 |
| mjr | 17:ab3cec0c8bf4 | 133 | // = lo*1/3 + hi*2/3 |
| mjr | 17:ab3cec0c8bf4 | 134 | // = (lo + hi*2)/3 |
| mjr | 17:ab3cec0c8bf4 | 135 | // |
| mjr | 18:5e890ebd0023 | 136 | // Now, 'lo' is always one of b1 or b2, and 'hi' is the other |
| mjr | 18:5e890ebd0023 | 137 | // one, so we can rewrite this as: |
| mjr | 18:5e890ebd0023 | 138 | long midpt = (b1 + b2 + hi)/3; |
| mjr | 17:ab3cec0c8bf4 | 139 | |
| mjr | 17:ab3cec0c8bf4 | 140 | // If we have enough contrast, proceed with the scan. |
| mjr | 17:ab3cec0c8bf4 | 141 | // |
| mjr | 17:ab3cec0c8bf4 | 142 | // If the bright end and dark end don't differ by enough, skip this |
| mjr | 17:ab3cec0c8bf4 | 143 | // reading entirely. Either we have an overexposed or underexposed frame, |
| mjr | 17:ab3cec0c8bf4 | 144 | // or the sensor is misaligned and is either fully in or out of shadow |
| mjr | 17:ab3cec0c8bf4 | 145 | // (it's supposed to be mounted such that the edge of the shadow always |
| mjr | 17:ab3cec0c8bf4 | 146 | // falls within the sensor, for any possible plunger position). |
| mjr | 18:5e890ebd0023 | 147 | if (labs(b1 - b2) > 0x1000) |
| mjr | 17:ab3cec0c8bf4 | 148 | { |
| mjr | 17:ab3cec0c8bf4 | 149 | uint16_t *pixp = pix + si; |
| mjr | 44:b5ac89b9cd5d | 150 | for (int n = 0 ; n < highResPix ; ++n, pixp += dir) |
| mjr | 17:ab3cec0c8bf4 | 151 | { |
| mjr | 17:ab3cec0c8bf4 | 152 | // if we've crossed the midpoint, report this position |
| mjr | 18:5e890ebd0023 | 153 | if (long(*pixp) < midpt) |
| mjr | 17:ab3cec0c8bf4 | 154 | { |
| mjr | 44:b5ac89b9cd5d | 155 | // normalize to the 0.0..1.0 range and return success |
| mjr | 44:b5ac89b9cd5d | 156 | pos = float(n)/highResPix; |
| mjr | 17:ab3cec0c8bf4 | 157 | return true; |
| mjr | 17:ab3cec0c8bf4 | 158 | } |
| mjr | 17:ab3cec0c8bf4 | 159 | } |
| mjr | 17:ab3cec0c8bf4 | 160 | } |
| mjr | 17:ab3cec0c8bf4 | 161 | |
| mjr | 17:ab3cec0c8bf4 | 162 | // we didn't find a shadow - return no reading |
| mjr | 17:ab3cec0c8bf4 | 163 | return false; |
| mjr | 17:ab3cec0c8bf4 | 164 | } |
| mjr | 17:ab3cec0c8bf4 | 165 | |
| mjr | 44:b5ac89b9cd5d | 166 | // Infer the sensor orientation from the image data. This determines |
| mjr | 44:b5ac89b9cd5d | 167 | // which end of the array has the brighter pixels. In some cases it |
| mjr | 44:b5ac89b9cd5d | 168 | // might not be possible to tell: if the light source is turned off, |
| mjr | 44:b5ac89b9cd5d | 169 | // or if the plunger is all the way to one extreme so that the entire |
| mjr | 44:b5ac89b9cd5d | 170 | // pixel array is in shadow or in full light. To sense the direction |
| mjr | 44:b5ac89b9cd5d | 171 | // we need to have a sufficient difference in brightness between the |
| mjr | 44:b5ac89b9cd5d | 172 | // two ends of the array to be confident that one end is in shadow |
| mjr | 44:b5ac89b9cd5d | 173 | // and the other isn't. On success, sets member variable 'dir' and |
| mjr | 44:b5ac89b9cd5d | 174 | // returns true; on failure (i.e., we don't have sufficient contrast |
| mjr | 44:b5ac89b9cd5d | 175 | // to sense the orientation), returns false and leaves 'dir' unset. |
| mjr | 44:b5ac89b9cd5d | 176 | bool senseOrientation(int n) |
| mjr | 44:b5ac89b9cd5d | 177 | { |
| mjr | 44:b5ac89b9cd5d | 178 | // get the total brightness for the first few pixels at |
| mjr | 44:b5ac89b9cd5d | 179 | // each end of the array (a proxy for the average - just |
| mjr | 44:b5ac89b9cd5d | 180 | // save time by skipping the divide-by-N) |
| mjr | 44:b5ac89b9cd5d | 181 | long a = long(pix[0]) + long(pix[1]) + long(pix[2]) |
| mjr | 44:b5ac89b9cd5d | 182 | + long(pix[3]) + long(pix[4]); |
| mjr | 44:b5ac89b9cd5d | 183 | long b = long(pix[n-1]) + long(pix[n-2]) + long(pix[n-3]) |
| mjr | 44:b5ac89b9cd5d | 184 | + long(pix[n-4]) + long(pix[n-5]); |
| mjr | 44:b5ac89b9cd5d | 185 | |
| mjr | 44:b5ac89b9cd5d | 186 | // if the difference is too small, we can't tell |
| mjr | 44:b5ac89b9cd5d | 187 | const long minPct = 10; |
| mjr | 44:b5ac89b9cd5d | 188 | const long minDiff = 65535*5*minPct/100; |
| mjr | 44:b5ac89b9cd5d | 189 | if (labs(a - b) < minDiff) |
| mjr | 44:b5ac89b9cd5d | 190 | return false; |
| mjr | 44:b5ac89b9cd5d | 191 | |
| mjr | 44:b5ac89b9cd5d | 192 | // we now know the orientation - set the 'dir' member variable |
| mjr | 44:b5ac89b9cd5d | 193 | // for future use |
| mjr | 44:b5ac89b9cd5d | 194 | if (a > b) |
| mjr | 44:b5ac89b9cd5d | 195 | dir = 1; |
| mjr | 44:b5ac89b9cd5d | 196 | else |
| mjr | 44:b5ac89b9cd5d | 197 | dir = -1; |
| mjr | 44:b5ac89b9cd5d | 198 | |
| mjr | 44:b5ac89b9cd5d | 199 | // success |
| mjr | 44:b5ac89b9cd5d | 200 | return true; |
| mjr | 44:b5ac89b9cd5d | 201 | } |
| mjr | 44:b5ac89b9cd5d | 202 | |
| mjr | 45:c42166b2878c | 203 | // Send an exposure report to the joystick interface. |
| mjr | 45:c42166b2878c | 204 | // |
| mjr | 45:c42166b2878c | 205 | // Mode bits: |
| mjr | 45:c42166b2878c | 206 | // 0x01 -> send processed pixels (default is raw pixels) |
| mjr | 45:c42166b2878c | 207 | // 0x02 -> low res scan (default is high res scan) |
| mjr | 45:c42166b2878c | 208 | virtual void sendExposureReport(USBJoystick &js, uint8_t mode) |
| mjr | 17:ab3cec0c8bf4 | 209 | { |
| mjr | 45:c42166b2878c | 210 | // get the number of pixels according to the high res/low res mode |
| mjr | 45:c42166b2878c | 211 | int npix = (mode & 0x02 ? lowResPix : highResPix); |
| mjr | 45:c42166b2878c | 212 | |
| mjr | 45:c42166b2878c | 213 | // do a scan |
| mjr | 45:c42166b2878c | 214 | ccd.read(pix, npix); |
| mjr | 43:7a6364d82a41 | 215 | |
| mjr | 17:ab3cec0c8bf4 | 216 | // send reports for all pixels |
| mjr | 17:ab3cec0c8bf4 | 217 | int idx = 0; |
| mjr | 45:c42166b2878c | 218 | while (idx < npix) |
| mjr | 45:c42166b2878c | 219 | js.updateExposure(idx, npix, pix); |
| mjr | 17:ab3cec0c8bf4 | 220 | |
| mjr | 17:ab3cec0c8bf4 | 221 | // The pixel dump requires many USB reports, since each report |
| mjr | 17:ab3cec0c8bf4 | 222 | // can only send a few pixel values. An integration cycle has |
| mjr | 17:ab3cec0c8bf4 | 223 | // been running all this time, since each read starts a new |
| mjr | 17:ab3cec0c8bf4 | 224 | // cycle. Our timing is longer than usual on this round, so |
| mjr | 17:ab3cec0c8bf4 | 225 | // the integration won't be comparable to a normal cycle. Throw |
| mjr | 17:ab3cec0c8bf4 | 226 | // this one away by doing a read now, and throwing it away - that |
| mjr | 17:ab3cec0c8bf4 | 227 | // will get the timing of the *next* cycle roughly back to normal. |
| mjr | 44:b5ac89b9cd5d | 228 | ccd.read(pix, highResPix); |
| mjr | 17:ab3cec0c8bf4 | 229 | } |
| mjr | 17:ab3cec0c8bf4 | 230 | |
| mjr | 35:e959ffba78fd | 231 | protected: |
| mjr | 45:c42166b2878c | 232 | // Pixel buffer. We allocate this to be big enough for the high-res scan, |
| mjr | 45:c42166b2878c | 233 | // which is the most pixels we'll need to capture. |
| mjr | 35:e959ffba78fd | 234 | uint16_t *pix; |
| mjr | 44:b5ac89b9cd5d | 235 | |
| mjr | 44:b5ac89b9cd5d | 236 | // number of pixels in a high-res scan |
| mjr | 44:b5ac89b9cd5d | 237 | int highResPix; |
| mjr | 44:b5ac89b9cd5d | 238 | |
| mjr | 44:b5ac89b9cd5d | 239 | // number of pixels in a low-res scan |
| mjr | 44:b5ac89b9cd5d | 240 | int lowResPix; |
| mjr | 17:ab3cec0c8bf4 | 241 | |
| mjr | 44:b5ac89b9cd5d | 242 | // Sensor orientation. +1 means that the "tip" end - which is always |
| mjr | 44:b5ac89b9cd5d | 243 | // the brighter end in our images - is at the 0th pixel in the array. |
| mjr | 44:b5ac89b9cd5d | 244 | // -1 means that the tip is at the nth pixel in the array. 0 means |
| mjr | 44:b5ac89b9cd5d | 245 | // that we haven't figured it out yet. |
| mjr | 44:b5ac89b9cd5d | 246 | int dir; |
| mjr | 43:7a6364d82a41 | 247 | |
| mjr | 44:b5ac89b9cd5d | 248 | public: |
| mjr | 17:ab3cec0c8bf4 | 249 | // the low-level interface to the CCD hardware |
| mjr | 35:e959ffba78fd | 250 | TSL1410R ccd; |
| mjr | 17:ab3cec0c8bf4 | 251 | }; |
| mjr | 35:e959ffba78fd | 252 | |
| mjr | 35:e959ffba78fd | 253 | |
| mjr | 35:e959ffba78fd | 254 | // TSL1410R sensor |
| mjr | 35:e959ffba78fd | 255 | class PlungerSensorTSL1410R: public PlungerSensorCCD |
| mjr | 35:e959ffba78fd | 256 | { |
| mjr | 35:e959ffba78fd | 257 | public: |
| mjr | 35:e959ffba78fd | 258 | PlungerSensorTSL1410R(PinName si, PinName clock, PinName ao1, PinName ao2) |
| mjr | 45:c42166b2878c | 259 | : PlungerSensorCCD(1280, 256, 80, si, clock, ao1, ao2) |
| mjr | 35:e959ffba78fd | 260 | { |
| mjr | 35:e959ffba78fd | 261 | } |
| mjr | 35:e959ffba78fd | 262 | }; |
| mjr | 35:e959ffba78fd | 263 | |
| mjr | 35:e959ffba78fd | 264 | // TSL1412R |
| mjr | 35:e959ffba78fd | 265 | class PlungerSensorTSL1412R: public PlungerSensorCCD |
| mjr | 35:e959ffba78fd | 266 | { |
| mjr | 35:e959ffba78fd | 267 | public: |
| mjr | 35:e959ffba78fd | 268 | PlungerSensorTSL1412R(PinName si, PinName clock, PinName ao1, PinName ao2) |
| mjr | 45:c42166b2878c | 269 | : PlungerSensorCCD(1536, 256, 128, si, clock, ao1, ao2) |
| mjr | 35:e959ffba78fd | 270 | { |
| mjr | 35:e959ffba78fd | 271 | } |
| mjr | 35:e959ffba78fd | 272 | }; |
