erste funktionsfähige Version 0.2, noch Arduino Uno

This commit is contained in:
2026-01-18 18:24:21 +01:00
parent 481bb49ac0
commit 7da6388650
4 changed files with 1026 additions and 0 deletions

View File

@ -0,0 +1,292 @@
/*
0004_DenshaBekutoru Version 0.1 Test
Target dev board (later): Arduino Pro Mini 5V / 16 MHz (ATmega328P)
----------------------------------------------------------------------------
State machine (direction memory)
----------------------------------------------------------------------------
Inputs derived from v1, v2, VdiffThreshold:
N (Neutral): |v1 - v2| <= VdiffThreshold
D1 (v1>>v2): (v1 - v2) > VdiffThreshold
D2 (v2>>v1): (v2 - v1) > VdiffThreshold
State encoding:
0 = NONE
2 = DIR1
3 = DIR2
Transition table:
Current \ Input | N (neutral) | D1 (v1>>v2) | D2 (v2>>v1)
-----------------------------------------------------------------
0 (NONE) | 0 | 2 | 3
2 (DIR1) | 2 | 2 | 3
3 (DIR2) | 3 | 2 | 3
Mermaid (documentation)
-----------------------
stateDiagram-v2
[*] --> NONE
state "0 : NONE" as NONE
state "2 : DIR1 (v1>>v2)" as DIR1
state "3 : DIR2 (v2>>v1)" as DIR2
NONE --> NONE : |v1 - v2| <= T
NONE --> DIR1 : v1 - v2 > T
NONE --> DIR2 : v2 - v1 > T
DIR1 --> DIR1 : |v1 - v2| <= T
DIR1 --> DIR1 : v1 - v2 > T
DIR1 --> DIR2 : v2 - v1 > T
DIR2 --> DIR2 : |v1 - v2| <= T
DIR2 --> DIR2 : v2 - v1 > T
DIR2 --> DIR1 : v1 - v2 > T
*/
const unsigned long SAMPLE_WINDOW_MS = 100; // averaging window per measurement
const unsigned long SAMPLE_DELAY_US = 500; // delay between ADC samples (~2 kHz)
const uint8_t ADC_PIN_1 = A2; // Pro Mini A2 -> later ATtiny85 PB3 (XTAL1, Pin 2)
const uint8_t ADC_PIN_2 = A3; // Pro Mini A3 -> later ATtiny85 PB4 (XTAL2, Pin 3)
// Direction LEDs (avoid D0/D1 because you may want RX/TX later)
const uint8_t LED_DIR1_PIN = 2; // D2
const uint8_t LED_DIR2_PIN = 3; // D3
const unsigned int LED_BLINK_ON_MS = 150;
const unsigned int LED_BLINK_OFF_MS = 150;
// Serial output control (0 = no output, 1 = output)
bool SerialOutputAllow = true;
// ---- Calibration parameters ----
const uint16_t AverageRepeat = 100; // number of init measurements
const float VdiffThresholdMargin = 1.50f; // multiplier (e.g., 1.5 = +50% margin)
const float VdiffThresholdMinVolts = 0.03f; // floor in volts
// Globals: latest measured averaged voltages
float v1 = 0.0f;
float v2 = 0.0f;
// Calibration globals
float VdiffBaseline = 0.0f; // median(|V1-V2|) measured at boot (no movement)
float VdiffThreshold = 0.0f; // final threshold used for direction decision
// Direction encoding:
// 0 = NONE, 2 = DIR1, 3 = DIR2
byte direction = 0;
static inline float absf(float x) { return (x >= 0.0f) ? x : -x; }
static inline float maxf(float a, float b) { return (a > b) ? a : b; }
// -----------------------------------------------------------------------------
// LED helpers
// -----------------------------------------------------------------------------
static void blinkLED(uint8_t pin, uint8_t times)
{
for (uint8_t i = 0; i < times; i++) {
digitalWrite(pin, HIGH);
delay(LED_BLINK_ON_MS);
digitalWrite(pin, LOW);
delay(LED_BLINK_OFF_MS);
}
}
static void initBlinkSequence()
{
// LED at Output 2 blinks 2 times
blinkLED(LED_DIR1_PIN, 2);
// LED at Output 3 blinks 3 times
blinkLED(LED_DIR2_PIN, 3);
}
static void applyDirectionOutputs()
{
digitalWrite(LED_DIR1_PIN, LOW);
digitalWrite(LED_DIR2_PIN, LOW);
if (direction == 2) {
digitalWrite(LED_DIR1_PIN, HIGH);
} else if (direction == 3) {
digitalWrite(LED_DIR2_PIN, HIGH);
}
}
// -----------------------------------------------------------------------------
// Measurement
// -----------------------------------------------------------------------------
static void measureAveragedVoltages()
{
unsigned long startTime = millis();
unsigned long sum1 = 0;
unsigned long sum2 = 0;
unsigned long samples = 0;
while (millis() - startTime < SAMPLE_WINDOW_MS) {
sum1 += analogRead(ADC_PIN_1);
sum2 += analogRead(ADC_PIN_2);
samples++;
delayMicroseconds(SAMPLE_DELAY_US);
}
float avg1 = (float)sum1 / samples;
float avg2 = (float)sum2 / samples;
// Convert ADC value to voltage (default analog reference = Vcc ~ 5V)
v1 = avg1 * (5.0f / 1023.0f);
v2 = avg2 * (5.0f / 1023.0f);
}
// -----------------------------------------------------------------------------
// Median helpers (for calibration)
// -----------------------------------------------------------------------------
static void sortFloatArray(float *a, uint16_t n)
{
// Insertion sort (n=100 is small, OK)
for (uint16_t i = 1; i < n; i++) {
float key = a[i];
int16_t j = (int16_t)i - 1;
while (j >= 0 && a[j] > key) {
a[j + 1] = a[j];
j--;
}
a[j + 1] = key;
}
}
static float medianOfSortedFloatArray(const float *a, uint16_t n)
{
if (n == 0) return 0.0f;
if (n & 1) {
return a[n / 2];
} else {
return (a[(n / 2) - 1] + a[n / 2]) * 0.5f;
}
}
// Calibrate baseline + threshold once at boot/reset
// Parameter must be only AverageRepeat.
static void calibrateVdiffThreshold(uint16_t averageRepeat)
{
if (averageRepeat < 1) averageRepeat = 1;
if (averageRepeat > 200) averageRepeat = 200; // RAM safety cap
float diffs[200];
for (uint16_t i = 0; i < averageRepeat; i++) {
measureAveragedVoltages();
diffs[i] = absf(v1 - v2); // baseline mismatch sample
}
sortFloatArray(diffs, averageRepeat);
VdiffBaseline = medianOfSortedFloatArray(diffs, averageRepeat);
// Final threshold with margin + floor
VdiffThreshold = maxf(VdiffBaseline * VdiffThresholdMargin, VdiffThresholdMinVolts);
}
// -----------------------------------------------------------------------------
// State machine
// -----------------------------------------------------------------------------
static void updateDirectionFromVoltages()
{
const float diff = v1 - v2;
const float absDiff = absf(diff);
// Neutral region: hold direction
if (absDiff <= VdiffThreshold) {
return;
}
// Clear dominance: set direction deterministically
// diff > 0 => v1 >> v2 => DIR1 (2)
// diff < 0 => v2 >> v1 => DIR2 (3)
direction = (diff > 0.0f) ? (byte)2 : (byte)3;
}
// -----------------------------------------------------------------------------
// Serial output
// -----------------------------------------------------------------------------
static void serialPrintAll()
{
if (!SerialOutputAllow) return;
Serial.print("A2 for PB3 XTAL1, Pin2: ");
Serial.print(v1, 3);
Serial.print(" V | ");
Serial.print("A3 for PB4 XTAL2, Pin3: ");
Serial.print(v2, 3);
Serial.print(" V | ");
Serial.print("|V1-V2|: ");
Serial.print(absf(v1 - v2), 3);
Serial.print(" V | ");
Serial.print("VdiffBaseline: ");
Serial.print(VdiffBaseline, 3);
Serial.print(" V | ");
Serial.print("VdiffThresholdMargin: ");
Serial.print(VdiffThresholdMargin, 2);
Serial.print(" x | ");
Serial.print("VdiffThresholdMinVolts: ");
Serial.print(VdiffThresholdMinVolts, 3);
Serial.print(" V | ");
Serial.print("VdiffThreshold: ");
Serial.print(VdiffThreshold, 3);
Serial.print(" V | ");
Serial.print("direction: ");
Serial.println(direction);
}
// -----------------------------------------------------------------------------
// Arduino entry points
// -----------------------------------------------------------------------------
void setup() {
Serial.begin(115200);
pinMode(ADC_PIN_1, INPUT);
pinMode(ADC_PIN_2, INPUT);
pinMode(LED_DIR1_PIN, OUTPUT);
pinMode(LED_DIR2_PIN, OUTPUT);
// Initial calibration (assumes no movement)
calibrateVdiffThreshold(AverageRepeat);
// Init blink sequence: 2x on D2, 3x on D3
initBlinkSequence();
// One measurement for initial display + initial direction
measureAveragedVoltages();
updateDirectionFromVoltages();
applyDirectionOutputs();
if (SerialOutputAllow) {
Serial.println("=== DenshaBekutoru 0004 Version 0.1 Test (Arduino Uno Test) ===");
Serial.println(" ~~~ InitStart ~~~");
Serial.print(" AverageRepeat: ");
Serial.println(AverageRepeat);
Serial.println(" ~~~ InitEnd ~~~");
}
serialPrintAll();
}
void loop() {
measureAveragedVoltages();
updateDirectionFromVoltages();
applyDirectionOutputs();
serialPrintAll();
delay(300);
}