源程序「Trigger_0514.ino」

  1#include <stdio.h>
  2#include <stdlib.h>
  3#include <string.h>
  4
  5#define REGION_KICK     0
  6#define REGION_TOP      0
  7#define REGION_SQUEEZE  0
  8#define REGION_FLUFF    0
  9#define REGION_PICK     0
 10#define REGION_SLIDE    1
 11
 12static inline bool sign(unsigned long a, unsigned long b) { return a < b; }
 13// Returns whether x is outside of the range [a, b), which may wrap around the maximum value
 14static inline bool outside(unsigned long a, unsigned long b, unsigned long x) {
 15  return sign(x, a) ^ sign(x, b) ^ sign(a, b);
 16}
 17template <typename T> inline void swap(T &a, T &b) { T t = a; a = b; b = t; }
 18inline int cmp_long(const void *a, const void *b) { return (int)(*(long *)a - *(long *)b); }
 19
 20struct FungiCapSensor {
 21  long base;
 22
 23  volatile IO_REG_TYPE *sReg;
 24  IO_REG_TYPE sBit;
 25  volatile IO_REG_TYPE *rReg;
 26  IO_REG_TYPE rBit;
 27
 28  static const long SENSOR_BASE_UNINIT_TAG = 0x3FFFFFF0;
 29  static const long SENSOR_TIMEOUT = 0x3FFFFFFF;
 30
 31  static const int N_SAMPLES_PER_OUTPUT = 11;
 32  static const int N_HIST = 3;
 33  static const int N_SAMPLES_TOTAL = N_HIST * N_SAMPLES_PER_OUTPUT;
 34  long histSamples[N_SAMPLES_TOTAL];
 35
 36  FungiCapSensor(uint8_t sendPin, uint8_t recvPin) {
 37    pinMode(sendPin, OUTPUT);  
 38    pinMode(recvPin, INPUT);
 39    base = SENSOR_BASE_UNINIT_TAG;
 40
 41    sReg = PIN_TO_BASEREG(sendPin);
 42    sBit = PIN_TO_BITMASK(sendPin);
 43    rReg = PIN_TO_BASEREG(recvPin);
 44    rBit = PIN_TO_BITMASK(recvPin);
 45  }
 46
 47  inline long sampleRaw() {
 48    unsigned long t0, tm, t1, t2;
 49
 50    noInterrupts();
 51    DIRECT_WRITE_LOW(sReg, sBit);
 52    DIRECT_MODE_INPUT(rReg, rBit);
 53    DIRECT_MODE_OUTPUT(rReg, rBit);
 54    DIRECT_WRITE_LOW(rReg, rBit);
 55    delayMicroseconds(10);
 56    DIRECT_MODE_INPUT(rReg, rBit);
 57    t0 = micros();
 58    tm = t0 + 2000000;  // May overflow and wrap around
 59    DIRECT_WRITE_HIGH(sReg, sBit);
 60    interrupts();
 61    while (!DIRECT_READ(rReg, rBit)) {
 62      unsigned long T = micros();
 63      if (outside(t0, tm, T)) return SENSOR_TIMEOUT;
 64    }
 65    t1 = micros() - t0;
 66
 67    noInterrupts();
 68    DIRECT_WRITE_HIGH(rReg, rBit);
 69    DIRECT_MODE_OUTPUT(rReg, rBit);
 70    DIRECT_WRITE_HIGH(rReg, rBit);
 71    DIRECT_MODE_INPUT(rReg, rBit);
 72    t0 = micros();
 73    tm = t0 + 2000000;
 74    DIRECT_WRITE_LOW(sReg, sBit);
 75    interrupts();
 76    while (DIRECT_READ(rReg, rBit)) {
 77      unsigned long T = micros();
 78      if (outside(t0, tm, T)) return SENSOR_TIMEOUT;
 79    }
 80    t2 = micros() - t0;
 81
 82    return (t1 + t2) / 4;
 83  }
 84
 85  inline void populateCalibration() {
 86    for (int i = 0; i < N_SAMPLES_TOTAL; i++) histSamples[i] = sampleRaw();
 87  }
 88
 89  inline long sampleCalibrated() {
 90    for (int i = 0; i < N_SAMPLES_TOTAL; i++)
 91      if (i + N_SAMPLES_PER_OUTPUT < N_SAMPLES_TOTAL)
 92        histSamples[i] = histSamples[i + N_SAMPLES_PER_OUTPUT];
 93      else
 94        histSamples[i] = sampleRaw();
 95
 96    long a[N_SAMPLES_TOTAL];
 97    memcpy(a, histSamples, sizeof a);
 98    qsort(a, N_SAMPLES_TOTAL, sizeof(long), cmp_long);
 99    long result = 0;
100    const int I_START = N_SAMPLES_TOTAL / 2 - 5;
101    const int I_END = N_SAMPLES_TOTAL / 2 + 5;
102    for (int i = I_START; i < I_END; i++)
103      if ((result += a[i]) >= SENSOR_TIMEOUT) result = SENSOR_TIMEOUT;
104    // Normalize
105    if (result < SENSOR_TIMEOUT) result = result * 10 / (I_END - I_START);
106
107    long delta = base - result;
108    if (delta >= 0) {
109      if (delta >= 1 && base != SENSOR_BASE_UNINIT_TAG) delta = 1;
110      base -= delta;
111    }
112    return result - base;
113  }
114};
115
116FungiCapSensor sensor[] = {
117#if REGION_SQUEEZE || REGION_FLUFF || REGION_PICK || REGION_SLIDE
118  FungiCapSensor(12, 2),
119#endif
120#if REGION_SQUEEZE || REGION_FLUFF || REGION_PICK || REGION_SLIDE || REGION_TOP
121  FungiCapSensor(12, 3),
122  FungiCapSensor(12, 4),
123#endif
124  FungiCapSensor(12, 5),
125  FungiCapSensor(12, 6),
126  FungiCapSensor(12, 7),
127  FungiCapSensor(12, 8),
128  FungiCapSensor(12, 9),
129  FungiCapSensor(12, 10),
130  FungiCapSensor(12, 11),
131};
132const int N_SENSORS = sizeof sensor / sizeof sensor[0];
133unsigned long lastBaseInc;
134
135template <size_t N, size_t A, size_t B, long ThrAbsl, int ThrRel, int Interval> struct SensorHistoryTrigger {
136  long history[N];
137  size_t ptr;
138  int wait;
139  SensorHistoryTrigger() {
140    ptr = 0;
141    wait = N - 1;
142  }
143  inline int shift(long value) {
144    history[ptr] = value;
145    if (++ptr == N) ptr = 0;
146    if (wait == 0) {
147      bool result = false;
148      // Overall trend
149      int upCount = 0;
150      for (int i = 0; i < N - 1; i++) if (history[i] < history[i + 1]) upCount++;
151      if (upCount > N / 2) {
152        long a[N];
153        memcpy(a, history, sizeof a);
154        qsort(a, N, sizeof(long), cmp_long);
155        result = (a[B] - a[A] >= ThrAbsl && a[B] - a[A] >= a[N - 1] * ThrRel / 16);
156      }
157      if (result) wait = Interval;
158      return (int)result;
159    } else {
160      wait--;
161      return 0;
162    }
163  }
164};
165
166template <long ThrAbslFirst, long ThrAbsl, int Capacity, int CountThr> struct SensorContinuousTrigger {
167  int count;
168  bool state;
169  SensorContinuousTrigger() {
170    count = 0;
171    state = false;
172  }
173  inline int shift(long value) {
174    if (value >= (state ? ThrAbsl : ThrAbslFirst)) {
175      if (count < Capacity) count++;
176    } else {
177      if (count > 0) count--;
178    }
179    bool last = state;
180    state = (count >= CountThr);
181    if (last ^ state) {
182      if (state) count = Capacity;
183      return state ? +1 : -1;
184    } else {
185      return 0;
186    }
187  }
188};
189
190#if REGION_KICK
191#define TRIGGER_INSTANT
192SensorHistoryTrigger<5, 1, 3, 20, 8, 30> triggers[N_SENSORS];
193#endif
194
195#if REGION_TOP
196#define TRIGGER_CONT
197SensorContinuousTrigger<100, 80, 1, 1> triggers[N_SENSORS];
198#endif
199
200#if REGION_SQUEEZE
201#define TRIGGER_CONT
202SensorContinuousTrigger<180, 100, 2, 2> triggers[N_SENSORS];
203#endif
204
205#if REGION_PICK
206#define TRIGGER_CONT
207SensorContinuousTrigger<40, 20, 20, 5> triggers[N_SENSORS];
208#endif
209
210#if REGION_SLIDE
211#define TRIGGER_CONT
212SensorContinuousTrigger<30, 20, 5, 2> triggers[N_SENSORS];
213#endif
214
215void setup() {
216  Serial.begin(9600);
217
218  TCCR1A = (1 << WGM10);
219  TCCR1B = (0 << CS12) | (0 << CS11) | (1 << CS10);
220  TIMSK1 |= (1 << TOIE1);
221  pinMode(13, OUTPUT);
222
223  for (int i = 0; i < N_SENSORS; i++) sensor[i].populateCalibration();
224  lastBaseInc = millis();
225}
226
227ISR(TIMER1_OVF_vect) {
228  static int timerCount = 0, pinStatus = 0;
229  if ((timerCount = ((timerCount + 1) & 32767)) == 0)
230    digitalWrite(13, (pinStatus ^= 1));
231}
232
233void loop() {
234  if (outside(lastBaseInc, lastBaseInc + 1000, millis())) {
235    for (int i = 0; i < N_SENSORS; i++) sensor[i].base++;
236    lastBaseInc = millis();
237  }
238
239  long result[N_SENSORS];
240  for (int i = 0; i < N_SENSORS; i++) {
241    result[i] = sensor[i].sampleCalibrated();
242    if (result[i] >= FungiCapSensor::SENSOR_TIMEOUT) continue;
243    #if defined(TRIGGER_INSTANT) || defined(TRIGGER_CONT)
244      int change = triggers[i].shift(result[i]);
245      if (change) {
246        Serial.print(change == +1 ? "Onset   " : "Release ");
247        Serial.print(i);
248        Serial.print(" @ ");
249        Serial.print(millis());
250        Serial.println();
251      }
252    #endif
253  }
254
255#define INSPECT_SENSORS 1
256#if INSPECT_SENSORS
257  static int count = 0;
258  // if (++count == 16) count = 0; else return;
259  Serial.print("\t");
260  char line[N_SENSORS * 7 + 1];
261  for (int i = 0; i < N_SENSORS; i++)
262    sprintf(line + i * 7, "%6ld\t", result[i]);
263  Serial.print(line);
264  Serial.print("\t|\t");
265  for (int i = 0; i < N_SENSORS; i++)
266    sprintf(line + i * 7, "%6ld\t", sensor[i].base);
267  Serial.println(line);
268#endif
269}
原始文件 (7.2 KiB)