Files

197 lines
5.9 KiB
Arduino
Raw Permalink Normal View History

2026-03-07 17:39:12 -06:00
#include <Arduino.h>
#include <util/atomic.h>
2026-04-11 21:15:01 -05:00
// ── ADC Interrupt-driven 3-channel read (A2, A3, A0) ─────────
// Channel index: 0 → A2 (sensor 0), 1 → A3 (sensor 1), 2 → A0 (raw ref)
static const uint8_t adc_mux[3] = {2, 3, 0};
2026-03-07 17:39:12 -06:00
2026-04-11 21:15:01 -05:00
volatile uint16_t adc_result[3] = {0, 0, 0};
volatile bool adc_ready[3] = {false, false, false};
volatile uint8_t adc_channel = 0;
2026-03-07 17:39:12 -06:00
2026-04-11 21:15:01 -05:00
void setupADC() {
ADMUX = (1 << REFS0) | adc_mux[0]; // AVCC ref, start on A2
ADCSRA = (1 << ADEN) | (1 << ADIE) | (1 << ADPS2); // /16 prescaler
2026-03-07 17:39:12 -06:00
ADCSRA |= (1 << ADSC);
}
2026-04-11 21:15:01 -05:00
// ── OOR digital inputs ───────────────────────────────────────
#define OOR_PIN_0 12 // HIGH = out of range, sensor 0 (A2)
#define OOR_PIN_1 13 // HIGH = out of range, sensor 1 (A3)
2026-03-07 17:39:12 -06:00
2026-04-11 21:15:01 -05:00
volatile bool OOR[2];
2026-03-07 17:39:12 -06:00
ISR(ADC_vect) {
uint16_t sample = ADC;
2026-04-11 21:15:01 -05:00
uint8_t ch = adc_channel;
uint8_t next = (ch + 1) % 3;
if (ch < 2) {
// Sensor channels: filter by OOR
OOR[ch] = digitalRead(ch == 0 ? OOR_PIN_0 : OOR_PIN_1);
if (!OOR[ch]) {
adc_result[ch] = sample;
adc_ready[ch] = true;
}
} else {
// A0: no OOR, always store
adc_result[2] = sample;
adc_ready[2] = true;
2026-03-07 17:39:12 -06:00
}
2026-04-11 21:15:01 -05:00
ADMUX = (ADMUX & 0xF0) | adc_mux[next];
adc_channel = next;
ADCSRA |= (1 << ADSC);
2026-03-07 17:39:12 -06:00
}
2026-04-11 21:15:01 -05:00
// ── ADC → mm linear mappings (raw range: 1626 mm) ──────────
#define adcToMM0(adc) ((float)map(adc, 178, 895, 1600, 2600) / 100.0f)
#define adcToMM1(adc) ((float)map(adc, 176, 885, 1600, 2600) / 100.0f)
// Subtract mounting offsets so both sensors share the same position frame:
// Sensor 0 raw 1626 mm 16 → 010 mm
// Sensor 1 raw 1626 mm 6 → 1020 mm
#define OFFSET_MM0 15.6f
#define OFFSET_MM1 6.2f
2026-03-07 17:39:12 -06:00
2026-04-11 21:15:01 -05:00
// ── Boundary tracking (in-range only, per sensor) ────────────
2026-03-07 17:39:12 -06:00
#define TRACK_N 10
2026-04-11 21:15:01 -05:00
uint16_t lowestVals[2][TRACK_N];
uint16_t highestVals[2][TRACK_N];
uint8_t lowestCount[2] = {0, 0};
uint8_t highestCount[2] = {0, 0};
static void trackLowest(uint8_t s, uint16_t val) {
uint16_t *lv = lowestVals[s];
uint8_t &lc = lowestCount[s];
if (lc < TRACK_N) {
uint8_t i = lc;
while (i > 0 && lv[i - 1] > val) { lv[i] = lv[i - 1]; i--; }
lv[i] = val;
lc++;
} else if (val < lv[TRACK_N - 1]) {
2026-03-07 17:39:12 -06:00
uint8_t i = TRACK_N - 1;
2026-04-11 21:15:01 -05:00
while (i > 0 && lv[i - 1] > val) { lv[i] = lv[i - 1]; i--; }
lv[i] = val;
2026-03-07 17:39:12 -06:00
}
}
2026-04-11 21:15:01 -05:00
static void trackHighest(uint8_t s, uint16_t val) {
uint16_t *hv = highestVals[s];
uint8_t &hc = highestCount[s];
if (hc < TRACK_N) {
uint8_t i = hc;
while (i > 0 && hv[i - 1] < val) { hv[i] = hv[i - 1]; i--; }
hv[i] = val;
hc++;
} else if (val > hv[TRACK_N - 1]) {
2026-03-07 17:39:12 -06:00
uint8_t i = TRACK_N - 1;
2026-04-11 21:15:01 -05:00
while (i > 0 && hv[i - 1] < val) { hv[i] = hv[i - 1]; i--; }
hv[i] = val;
2026-03-07 17:39:12 -06:00
}
}
static void resetTracking() {
2026-04-11 21:15:01 -05:00
lowestCount[0] = highestCount[0] = 0;
lowestCount[1] = highestCount[1] = 0;
2026-03-07 17:39:12 -06:00
}
static void printBoundaries() {
2026-04-11 21:15:01 -05:00
for (uint8_t s = 0; s < 2; s++) {
Serial.print(F("--- Sensor "));
Serial.print(s);
Serial.println(F(": 10 Lowest In-Range ADC Values ---"));
for (uint8_t i = 0; i < lowestCount[s]; i++) Serial.println(lowestVals[s][i]);
Serial.print(F("--- Sensor "));
Serial.print(s);
Serial.println(F(": 10 Highest In-Range ADC Values ---"));
for (uint8_t i = 0; i < highestCount[s]; i++) Serial.println(highestVals[s][i]);
2026-03-07 17:39:12 -06:00
}
}
// ── State ────────────────────────────────────────────────────
bool sampling = false;
2026-04-08 22:25:46 -05:00
bool rawMode = false;
2026-03-07 17:39:12 -06:00
// ═════════════════════════════════════════════════════════════
void setup() {
2026-04-11 21:15:01 -05:00
Serial.begin(115200);
pinMode(OOR_PIN_0, INPUT);
pinMode(OOR_PIN_1, INPUT);
2026-03-07 17:39:12 -06:00
setupADC();
2026-04-08 22:25:46 -05:00
Serial.println(F("Send '1' to start sampling, '0' to stop and print bounds, '2' for raw ADC output."));
2026-03-07 17:39:12 -06:00
}
void loop() {
// ── Serial command handling ──────────────────────────────
if (Serial.available() > 0) {
String cmd = Serial.readStringUntil('\n');
cmd.trim();
if (cmd.charAt(0) == '1') {
sampling = true;
2026-04-08 22:25:46 -05:00
rawMode = false;
2026-03-07 17:39:12 -06:00
resetTracking();
Serial.println(F("Sampling started."));
2026-04-08 22:25:46 -05:00
} else if (cmd.charAt(0) == '2') {
sampling = true;
rawMode = true;
Serial.println(F("Raw ADC output started."));
2026-03-07 17:39:12 -06:00
} else if (cmd.charAt(0) == '0') {
sampling = false;
2026-04-08 22:25:46 -05:00
rawMode = false;
2026-03-07 17:39:12 -06:00
Serial.println(F("Sampling stopped."));
printBoundaries();
}
}
// ── Main sample path ────────────────────────────────────
if (!sampling) return;
2026-04-11 21:15:01 -05:00
uint16_t val[3];
bool ready[3];
2026-03-07 17:39:12 -06:00
ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
2026-04-11 21:15:01 -05:00
for (uint8_t i = 0; i < 3; i++) {
ready[i] = adc_ready[i];
val[i] = adc_result[i];
adc_ready[i] = false;
}
2026-03-07 17:39:12 -06:00
}
2026-04-11 21:15:01 -05:00
if (!ready[0] && !ready[1]) return;
2026-03-07 17:39:12 -06:00
2026-04-08 22:25:46 -05:00
if (rawMode) {
2026-04-11 21:15:01 -05:00
if (ready[0]) {
Serial.print(adcToMM0(val[0]) - OFFSET_MM0);
Serial.print(F(", "));
Serial.println(val[2]);
}
if (ready[1]) {
Serial.print(adcToMM1(val[1]) - OFFSET_MM1);
Serial.print(F(", "));
Serial.println(val[2]);
}
2026-04-08 22:25:46 -05:00
return;
}
2026-04-11 21:15:01 -05:00
// Apply offset for whichever sensor(s) are in range
if (ready[0]) {
float mm = adcToMM0(val[0]) - OFFSET_MM0;
trackLowest(0, val[0]);
trackHighest(0, val[0]);
Serial.print(val[0]);
Serial.print(F(", "));
Serial.print(mm, 2);
Serial.println(F(" mm (s0)"));
}
if (ready[1]) {
float mm = adcToMM1(val[1]) - OFFSET_MM1;
trackLowest(1, val[1]);
trackHighest(1, val[1]);
Serial.print(val[1]);
Serial.print(F(", "));
Serial.print(mm, 2);
Serial.println(F(" mm (s1)"));
}
2026-03-07 17:39:12 -06:00
}