3 Commits

Author SHA1 Message Date
b66ee7f50e small adjustmens after 1st build 2026-03-08 14:30:27 +01:00
d49c06e2ad Adapted to PCB 2026-02 2026-03-07 18:45:56 +01:00
e512cac398 some Details and Review - ready for make 2026-02-24 20:43:06 +01:00
41 changed files with 2406 additions and 994 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 210 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 246 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 164 KiB

View File

@ -0,0 +1,25 @@
"Reference","Value","Datasheet","Footprint","Qty","DNP"
"A1","Arduino_Pro_Mini_Socket_NoSPH_V2","https://docs.arduino.cc/retired/boards/arduino-pro-mini","arduino-library:Arduino_Pro_Mini_Socket_NoSPH_V2","1",""
"C4","4.7µF","~","Capacitor_THT:CP_Axial_L10.0mm_D6.0mm_P15.00mm_Horizontal","1",""
"C5","100nF","~","Capacitor_THT:C_Disc_D3.0mm_W1.6mm_P2.50mm","1",""
"D1,D2","1N4148","https://assets.nexperia.com/documents/data-sheet/1N4148_1N4448.pdf","Diode_THT:D_DO-35_SOD27_P7.62mm_Horizontal","2",""
"D3","1N5819","http://www.vishay.com/docs/88525/1n5817.pdf","Diode_THT:D_DO-41_SOD81_P10.16mm_Horizontal","1",""
"D4","LED Green","~","LED_THT:LED_D3.0mm","1",""
"D5","LED Yellow","~","LED_THT:LED_D3.0mm","1",""
"D10","LED: HL_A.1","","LED_THT:LED_D5.0mm_Clear","1",""
"D11","LED: HL_A.2","","LED_THT:LED_D5.0mm_Clear","1",""
"D12","LED: HL_B.1","","LED_THT:LED_D5.0mm_Clear","1",""
"D13","LED: HL_B.2","","LED_THT:LED_D5.0mm_Clear","1",""
"J1","from Lego","~","Connector_PinHeader_2.54mm:PinHeader_1x04_P2.54mm_Vertical","1",""
"J2","Headlight GND","~","Connector_PinSocket_2.54mm:PinSocket_1x04_P2.54mm_Vertical","1",""
"J3","Headlight GND; A1,2/B1,2","~","Connector_PinSocket_2.54mm:PinSocket_1x05_P2.54mm_Vertical","1",""
"J4","Headlight Test","~","Connector_PinHeader_2.54mm:PinHeader_1x05_P2.54mm_Horizontal","1",""
"J5","I2C","~","Connector_PinHeader_2.54mm:PinHeader_1x03_P2.54mm_Vertical","1",""
"J6","TX/RX","~","Connector_PinHeader_2.54mm:PinHeader_1x03_P2.54mm_Vertical","1",""
"J7","Add. Lights","~","Connector_PinSocket_2.54mm:PinSocket_1x04_P2.54mm_Vertical","1",""
"J8","LDR (~1MOhm) Option","~","Connector_PinHeader_2.54mm:PinHeader_1x02_P2.54mm_Vertical","1",""
"R1,R2","1.5k","~","Resistor_THT:R_Axial_DIN0204_L3.6mm_D1.6mm_P5.08mm_Horizontal","2",""
"R3,R4,R5,R6,R7,R8","220","~","Resistor_THT:R_Axial_DIN0204_L3.6mm_D1.6mm_P5.08mm_Horizontal","6",""
"R9","10k","~","Resistor_THT:R_Axial_DIN0204_L3.6mm_D1.6mm_P5.08mm_Horizontal","1",""
"RV1","1MOhm","~","Potentiometer_THT:Potentiometer_Piher_PT-10-V10_Vertical","1",""
"U1,U2","PC817","http://www.soselectronic.cz/a_info/resource/d/pc817.pdf","Package_DIP:DIP-4_W7.62mm","2",""
1 Reference Value Datasheet Footprint Qty DNP
2 A1 Arduino_Pro_Mini_Socket_NoSPH_V2 https://docs.arduino.cc/retired/boards/arduino-pro-mini arduino-library:Arduino_Pro_Mini_Socket_NoSPH_V2 1
3 C4 4.7µF ~ Capacitor_THT:CP_Axial_L10.0mm_D6.0mm_P15.00mm_Horizontal 1
4 C5 100nF ~ Capacitor_THT:C_Disc_D3.0mm_W1.6mm_P2.50mm 1
5 D1,D2 1N4148 https://assets.nexperia.com/documents/data-sheet/1N4148_1N4448.pdf Diode_THT:D_DO-35_SOD27_P7.62mm_Horizontal 2
6 D3 1N5819 http://www.vishay.com/docs/88525/1n5817.pdf Diode_THT:D_DO-41_SOD81_P10.16mm_Horizontal 1
7 D4 LED Green ~ LED_THT:LED_D3.0mm 1
8 D5 LED Yellow ~ LED_THT:LED_D3.0mm 1
9 D10 LED: HL_A.1 LED_THT:LED_D5.0mm_Clear 1
10 D11 LED: HL_A.2 LED_THT:LED_D5.0mm_Clear 1
11 D12 LED: HL_B.1 LED_THT:LED_D5.0mm_Clear 1
12 D13 LED: HL_B.2 LED_THT:LED_D5.0mm_Clear 1
13 J1 from Lego ~ Connector_PinHeader_2.54mm:PinHeader_1x04_P2.54mm_Vertical 1
14 J2 Headlight GND ~ Connector_PinSocket_2.54mm:PinSocket_1x04_P2.54mm_Vertical 1
15 J3 Headlight GND; A1,2/B1,2 ~ Connector_PinSocket_2.54mm:PinSocket_1x05_P2.54mm_Vertical 1
16 J4 Headlight Test ~ Connector_PinHeader_2.54mm:PinHeader_1x05_P2.54mm_Horizontal 1
17 J5 I2C ~ Connector_PinHeader_2.54mm:PinHeader_1x03_P2.54mm_Vertical 1
18 J6 TX/RX ~ Connector_PinHeader_2.54mm:PinHeader_1x03_P2.54mm_Vertical 1
19 J7 Add. Lights ~ Connector_PinSocket_2.54mm:PinSocket_1x04_P2.54mm_Vertical 1
20 J8 LDR (~1MOhm) Option ~ Connector_PinHeader_2.54mm:PinHeader_1x02_P2.54mm_Vertical 1
21 R1,R2 1.5k ~ Resistor_THT:R_Axial_DIN0204_L3.6mm_D1.6mm_P5.08mm_Horizontal 2
22 R3,R4,R5,R6,R7,R8 220 ~ Resistor_THT:R_Axial_DIN0204_L3.6mm_D1.6mm_P5.08mm_Horizontal 6
23 R9 10k ~ Resistor_THT:R_Axial_DIN0204_L3.6mm_D1.6mm_P5.08mm_Horizontal 1
24 RV1 1MOhm ~ Potentiometer_THT:Potentiometer_Piher_PT-10-V10_Vertical 1
25 U1,U2 PC817 http://www.soselectronic.cz/a_info/resource/d/pc817.pdf Package_DIP:DIP-4_W7.62mm 2

View File

@ -1,7 +1,7 @@
{ {
"board": { "board": {
"active_layer": 0, "active_layer": 0,
"active_layer_preset": "", "active_layer_preset": "All Layers",
"auto_track_width": true, "auto_track_width": true,
"hidden_netclasses": [], "hidden_netclasses": [],
"hidden_nets": [], "hidden_nets": [],
@ -64,7 +64,7 @@
39, 39,
40 40
], ],
"visible_layers": "fffffff_fffffffe", "visible_layers": "fffffff_ffffffff",
"zone_display_mode": 0 "zone_display_mode": 0
}, },
"git": { "git": {

View File

@ -61,7 +61,7 @@
"drc_exclusions": [ "drc_exclusions": [
"courtyards_overlap|116847500|113255000|4b518c68-cacc-4ba0-bdd7-4ed203d87dd8|c5b5c5e2-5bf5-406f-bc2c-791c87e4bd5a", "courtyards_overlap|116847500|113255000|4b518c68-cacc-4ba0-bdd7-4ed203d87dd8|c5b5c5e2-5bf5-406f-bc2c-791c87e4bd5a",
"courtyards_overlap|116847500|116747500|4b518c68-cacc-4ba0-bdd7-4ed203d87dd8|ce87971b-d681-44d7-9fb7-23a15933148a", "courtyards_overlap|116847500|116747500|4b518c68-cacc-4ba0-bdd7-4ed203d87dd8|ce87971b-d681-44d7-9fb7-23a15933148a",
"courtyards_overlap|126372500|116747500|4b518c68-cacc-4ba0-bdd7-4ed203d87dd8|1094a2e1-479d-4870-8b87-1411fc6da792", "courtyards_overlap|126372500|116747500|1094a2e1-479d-4870-8b87-1411fc6da792|4b518c68-cacc-4ba0-bdd7-4ed203d87dd8",
"courtyards_overlap|130322874|113255000|4b518c68-cacc-4ba0-bdd7-4ed203d87dd8|ee659d06-72c1-451a-8938-35a721a086e2" "courtyards_overlap|130322874|113255000|4b518c68-cacc-4ba0-bdd7-4ed203d87dd8|ee659d06-72c1-451a-8938-35a721a086e2"
], ],
"meta": { "meta": {
@ -101,7 +101,7 @@
"padstack": "warning", "padstack": "warning",
"pth_inside_courtyard": "ignore", "pth_inside_courtyard": "ignore",
"shorting_items": "error", "shorting_items": "error",
"silk_edge_clearance": "warning", "silk_edge_clearance": "ignore",
"silk_over_copper": "warning", "silk_over_copper": "warning",
"silk_overlap": "warning", "silk_overlap": "warning",
"skew_out_of_range": "error", "skew_out_of_range": "error",
@ -507,7 +507,7 @@
}, },
"schematic": { "schematic": {
"annotate_start_num": 0, "annotate_start_num": 0,
"bom_export_filename": "", "bom_export_filename": "0004-DenshaBekutoru_v0.2.csv",
"bom_fmt_presets": [], "bom_fmt_presets": [],
"bom_fmt_settings": { "bom_fmt_settings": {
"field_delimiter": ",", "field_delimiter": ",",
@ -557,11 +557,35 @@
"label": "DNP", "label": "DNP",
"name": "${DNP}", "name": "${DNP}",
"show": true "show": true
},
{
"group_by": false,
"label": "#",
"name": "${ITEM_NUMBER}",
"show": false
},
{
"group_by": false,
"label": "Sim.Device",
"name": "Sim.Device",
"show": false
},
{
"group_by": false,
"label": "Sim.Pins",
"name": "Sim.Pins",
"show": false
},
{
"group_by": false,
"label": "Description",
"name": "Description",
"show": false
} }
], ],
"filter_string": "", "filter_string": "",
"group_symbols": true, "group_symbols": true,
"name": "Grouped By Value", "name": "",
"sort_asc": true, "sort_asc": true,
"sort_field": "Reference" "sort_field": "Reference"
}, },
@ -594,7 +618,7 @@
}, },
"net_format_name": "Spice Model", "net_format_name": "Spice Model",
"page_layout_descr_file": "", "page_layout_descr_file": "",
"plot_directory": "./", "plot_directory": "/home/tgohle/Desktop/git/ToGo-Lab/0004-DenshaBekutoru/KiCad/0004-DenshaBekutoru_v0.2/",
"spice_current_sheet_as_root": false, "spice_current_sheet_as_root": false,
"spice_external_command": "spice \"%I\"", "spice_external_command": "spice \"%I\"",
"spice_model_current_sheet_as_root": true, "spice_model_current_sheet_as_root": true,

View File

@ -6,8 +6,8 @@
(paper "A4") (paper "A4")
(title_block (title_block
(title "DenshaBekutoru 電車ベクトル (Train Vector)") (title "DenshaBekutoru 電車ベクトル (Train Vector)")
(date "2026-02-01") (date "2026-03-08")
(rev "#003") (rev "#005 1st bld.")
(company "ToGo-Lab") (company "ToGo-Lab")
(comment 1 "- https://togo-lab.io/") (comment 1 "- https://togo-lab.io/")
(comment 2 "- Email: tgohle@togo-lab.io") (comment 2 "- Email: tgohle@togo-lab.io")
@ -5902,9 +5902,9 @@
) )
(uuid "0f47aaa2-d5fd-479c-9cd8-bfe8a8174c43") (uuid "0f47aaa2-d5fd-479c-9cd8-bfe8a8174c43")
) )
(text "Detachable part of PCB (I),\nOption. If communication\nis needed.\n" (text "Detachable part of PCB (I),\nOption. If communication\nis needed.\n\n! not tested\n"
(exclude_from_sim no) (exclude_from_sim no)
(at 93.218 80.518 0) (at 93.472 82.042 0)
(effects (effects
(font (font
(size 1.27 1.27) (size 1.27 1.27)
@ -5913,9 +5913,9 @@
) )
(uuid "13419e56-d967-466e-bc8e-26537e73dd52") (uuid "13419e56-d967-466e-bc8e-26537e73dd52")
) )
(text "Detachable part of PCB, Option\nIf used, control PWM (Light) by \n- LDR (dark ~ 1Mohm) or\n- Potentiometer 1Mohm (manually aqdjusted)" (text "Detachable part of PCB, Option\nIf used, control PWM (Light) by \n- LDR (dark ~ 1Mohm) or\n- Potentiometer 1Mohm (manually aqdjusted)\n\n! Not tested"
(exclude_from_sim no) (exclude_from_sim no)
(at 78.486 171.958 0) (at 78.232 170.18 0)
(effects (effects
(font (font
(size 1.27 1.27) (size 1.27 1.27)
@ -5935,7 +5935,7 @@
) )
(uuid "2f37a28e-8a64-4672-a892-5431464a2db8") (uuid "2f37a28e-8a64-4672-a892-5431464a2db8")
) )
(text "PWM LED drive Arduino Pro Mini (ATmega328P)\n- PWM pins used: D3 (Timer2, 8-bit) and D9 (Timer1, 16-bit)\n- Control via analogWrite() → 0255 on both timers (no practical difference for LEDs)\n- Each PWM pin drives 2× white LEDs in parallel, each LED with its own 220 Ω resistor\n- Approx. current per LED ≈ 78 mA, per pin ≈ 15 mA → safe for MCU\n- D0/D1 (TX/RX) free for later communication\n- Timer0 untouched → millis()/delay() unaffected\n- No Servo / tone / IR usage planned → no timer conflicts expected\n- Remember, Unsused D/A Connectors: Unconnected (no Pullup), but:\n Digital ones: \"pinMode(pin, INPUT_PULLUP);\" and Ax: nothing." (text "PWM LED drive Arduino Pro Mini (ATmega328P)\n- PWM pins used: D3 (Timer2, 8-bit) and D9 (Timer1, 16-bit)\n- Control via analogWrite() → 0255 on both timers (no practical difference for LEDs)\n- Each PWM pin drives 2× white LEDs in parallel, each LED with its own 220 Ω resistor\n- Approx. current per LED ≈ 78 mA, per pin ≈ 15 mA → safe for MCU\n- D0/D1 (TX/RX) free for later communication\n- Timer0 untouched → millis()/delay() unaffected\n- No Servo / tone / IR usage planned → no timer conflicts expected\n- Remember, Unsused D/A Connectors: Unconnected (no Pullup), but:\n Digital ones: \"pinMode(pin, INPUT_PULLUP);\" and Ax: nothing.\n- all R smallest type (1/4W), due small footprint"
(exclude_from_sim no) (exclude_from_sim no)
(at 128.778 49.53 0) (at 128.778 49.53 0)
(effects (effects
@ -5967,7 +5967,7 @@
) )
(uuid "9433f522-95dc-40eb-b260-abe7c4605d43") (uuid "9433f522-95dc-40eb-b260-abe7c4605d43")
) )
(text "Detachable part of PCB (I)\nAdditional PWM Lights\n- Timer1, (D9): D10\n- Timer2, (D3): D11\n! Don't forget Resistors" (text "Detachable part of PCB (I)\nAdditional PWM Lights\n- Timer1, (D9): D10\n- Timer2, (D3): D11\n! Don't forget Resistors\n\n! Not tested"
(exclude_from_sim no) (exclude_from_sim no)
(at 246.38 66.04 0) (at 246.38 66.04 0)
(effects (effects
@ -7071,7 +7071,7 @@
) )
) )
) )
(property "Value" "1.8k" (property "Value" "1.5k"
(at 58.42 118.11 90) (at 58.42 118.11 90)
(effects (effects
(font (font
@ -7204,7 +7204,7 @@
) )
) )
) )
(property "Value" "1.8k" (property "Value" "1.5k"
(at 58.42 106.68 90) (at 58.42 106.68 90)
(effects (effects
(font (font

File diff suppressed because it is too large Load Diff

Binary file not shown.

After

Width:  |  Height:  |  Size: 292 KiB

View File

@ -1,31 +0,0 @@
Info: Processing symbol 'J7:Connector_PinSocket_2.54mm:PinSocket_1x04_P2.54mm_Vertical'.
Info: Processing symbol 'U2:Package_DIP:DIP-4_W7.62mm'.
Info: Processing symbol 'U1:Package_DIP:DIP-4_W7.62mm'.
Info: Processing symbol 'RV1:Potentiometer_THT:Potentiometer_Piher_PT-10-V10_Vertical'.
Info: Processing symbol 'R9:Resistor_THT:R_Axial_DIN0204_L3.6mm_D1.6mm_P1.90mm_Vertical'.
Info: Processing symbol 'R8:Resistor_THT:R_Axial_DIN0204_L3.6mm_D1.6mm_P1.90mm_Vertical'.
Info: Processing symbol 'R7:Resistor_THT:R_Axial_DIN0204_L3.6mm_D1.6mm_P1.90mm_Vertical'.
Info: Processing symbol 'R6:Resistor_THT:R_Axial_DIN0204_L3.6mm_D1.6mm_P1.90mm_Vertical'.
Info: Processing symbol 'R5:Resistor_THT:R_Axial_DIN0204_L3.6mm_D1.6mm_P1.90mm_Vertical'.
Info: Processing symbol 'R4:Resistor_THT:R_Axial_DIN0204_L3.6mm_D1.6mm_P5.08mm_Horizontal'.
Info: Processing symbol 'R3:Resistor_THT:R_Axial_DIN0204_L3.6mm_D1.6mm_P5.08mm_Horizontal'.
Info: Processing symbol 'R2:Resistor_THT:R_Axial_DIN0204_L3.6mm_D1.6mm_P5.08mm_Horizontal'.
Info: Processing symbol 'R1:Resistor_THT:R_Axial_DIN0204_L3.6mm_D1.6mm_P5.08mm_Horizontal'.
Info: Processing symbol 'J8:Connector_PinHeader_2.54mm:PinHeader_1x02_P2.54mm_Vertical'.
Info: Processing symbol 'A1:arduino-library:Arduino_Pro_Mini_Socket_NoSPH_V2'.
Info: Processing symbol 'J6:Connector_JST:JST_PH_B3B-PH-K_1x03_P2.00mm_Vertical'.
Info: Processing symbol 'J5:Connector_JST:JST_PH_B3B-PH-K_1x03_P2.00mm_Vertical'.
Info: Processing symbol 'J4:Connector_PinSocket_2.54mm:PinSocket_1x05_P2.54mm_Vertical'.
Info: Processing symbol 'J3:Connector_PinSocket_2.54mm:PinSocket_1x05_P2.54mm_Horizontal'.
Info: Processing symbol 'J2:Connector_PinSocket_2.54mm:PinSocket_1x04_P2.54mm_Vertical'.
Info: Processing symbol 'J1:Connector_PinHeader_2.54mm:PinHeader_1x04_P2.54mm_Horizontal'.
Info: Processing symbol 'D5:LED_THT:LED_D1.8mm_W3.3mm_H2.4mm'.
Info: Processing symbol 'D4:LED_THT:LED_D1.8mm_W3.3mm_H2.4mm'.
Info: Processing symbol 'D3:Diode_THT:D_DO-41_SOD81_P10.16mm_Horizontal'.
Info: Processing symbol 'D2:Diode_THT:D_DO-35_SOD27_P7.62mm_Horizontal'.
Info: Processing symbol 'D1:Diode_THT:D_DO-35_SOD27_P7.62mm_Horizontal'.
Info: Processing symbol 'C5:Capacitor_THT:C_Disc_D3.0mm_W1.6mm_P2.50mm'.
Info: Processing symbol 'C4:Capacitor_THT:CP_Axial_L10.0mm_D6.0mm_P15.00mm_Horizontal'.
Info: Total warnings: 0, errors: 0.

View File

@ -0,0 +1,287 @@
/*
0004_DenshaBekutoru 1st Version PCB
PCB Version : 2026/02 (Order F016895)
Target dev board : Arduino Pro Mini 5V / 16 MHz (ATmega328P)
----------------------------------------------------------------------------
State machine (direction memory) + Hysteresis (Version A)
----------------------------------------------------------------------------
We use two thresholds:
T_hold (smaller): below -> treat as neutral and HOLD state
T_enter (larger) : above -> allow direction change (set by sign)
Behavior:
If |diff| <= T_hold : hold direction
If |diff| >= T_enter : set direction by sign
Else (between) : hold direction
Presets (implemented as multipliers of the calibrated VdiffThreshold):
T_hold = 1.0 * VdiffThreshold
T_enter = 2.0 * VdiffThreshold
Inputs derived from v1, v2: diff = v1 - v2
*/
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 = A0; // Pro Mini A0 -> (PCB dependend!)
const uint8_t ADC_PIN_2 = A1; // Pro Mini A1 -> (PCB dependend")
// Direction LEDs (avoid D0/D1 because you may want RX/TX later)
const uint8_t LED_DIR1_PIN = 3; // D3
const uint8_t LED_DIR2_PIN = 9; // D9
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
// ---- Hysteresis presets (multipliers of VdiffThreshold) ----
const float THOLD_MULT = 1.0f; // T_hold = THOLD_MULT * VdiffThreshold
const float TENTER_MULT = 2.0f; // T_enter = TENTER_MULT * VdiffThreshold
// 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; // calibrated base threshold (used to derive T_hold/T_enter)
// Hysteresis thresholds (derived once after calibration)
float T_hold = 0.0f;
float T_enter = 0.0f;
// 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 + VdiffThreshold once at boot/reset
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);
// Calibrated base threshold with margin + floor
VdiffThreshold = maxf(VdiffBaseline * VdiffThresholdMargin, VdiffThresholdMinVolts);
// Derive hysteresis thresholds (Version A)
T_hold = THOLD_MULT * VdiffThreshold;
T_enter = TENTER_MULT * VdiffThreshold;
}
// -----------------------------------------------------------------------------
// State machine with hysteresis (Version A)
// -----------------------------------------------------------------------------
static void updateDirectionFromVoltages()
{
const float diff = v1 - v2;
const float absDiff = absf(diff);
// 1) Neutral region: HOLD
if (absDiff <= T_hold) {
return;
}
// 2) Strong region: allow direction change
if (absDiff >= T_enter) {
direction = (diff > 0.0f) ? (byte)2 : (byte)3;
return;
}
// 3) Deadband between T_hold and T_enter: HOLD
return;
}
// -----------------------------------------------------------------------------
// 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("VdiffThreshold: ");
Serial.print(VdiffThreshold, 3);
Serial.print(" V | ");
Serial.print("T_hold: ");
Serial.print(T_hold, 3);
Serial.print(" V | ");
Serial.print("T_enter: ");
Serial.print(T_enter, 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 Optocoupler Average Test (Arduino Pro Mini 5V/16MHz) ===");
Serial.print("AverageRepeat: ");
Serial.println(AverageRepeat);
Serial.print("THOLD_MULT: ");
Serial.print(THOLD_MULT, 2);
Serial.print(" TENTER_MULT: ");
Serial.println(TENTER_MULT, 2);
}
serialPrintAll();
}
void loop() {
measureAveragedVoltages();
updateDirectionFromVoltages();
applyDirectionOutputs();
serialPrintAll();
delay(300);
}