126 lines
7.4 KiB
Markdown
126 lines
7.4 KiB
Markdown
# Rotary Encoder — Setpoint Control Wiring
|
||
|
||
Adds an EC11-class incremental rotary encoder to the kttl controller so the
|
||
temperature **setpoint** can be dialled in live, and so the encoder's
|
||
**push-switch** acts as the on-switch (identical to the board's B1 button).
|
||
|
||
Target board: **STM32F4-Discovery (STM32F411VE)**. Firmware: `src/main.rs`
|
||
(`SetpointKnob`, TIM1 in encoder mode).
|
||
|
||
---
|
||
|
||
## 1. Pin assignment
|
||
|
||
| Encoder leg | Discovery pin | Function | Extra parts |
|
||
|-----------------|------------------|---------------------------|-----------------------------|
|
||
| **A** (CLK) | **PE9** (TIM1_CH1) | quadrature channel A | 10 kΩ → 3V, 100 nF → GND |
|
||
| **B** (DT) | **PE11** (TIM1_CH2) | quadrature channel B | 10 kΩ → 3V, 100 nF → GND |
|
||
| **C** (common) | **GND** | rotary common | — |
|
||
| **SW1** | **3V** | push-switch leg | — |
|
||
| **SW2** | **PA0** | push-switch leg (‖ B1) | — |
|
||
| mount ×2 | **GND** | shield / mechanical | optional |
|
||
|
||
> **Use 3V, not 5V.** The STM32F411 is a 3.3 V part; the pull-ups set the logic
|
||
> high level seen by the pins, and the switch drives PA0 directly. 3V matches
|
||
> the MCU and the existing B1 button exactly — no level shifting.
|
||
|
||
---
|
||
|
||
## 2. Schematic
|
||
|
||
```
|
||
STM32F4-Discovery Rotary encoder (EC11, 7-leg)
|
||
┌──────────────┐
|
||
│ 3V ●───────────┬───────────┬──────────────┐
|
||
│ │ │ │ │
|
||
│ │ ┌┴┐ ┌┴┐ │
|
||
│ │ 10k │ │ 10k │ │ │ (pull-ups
|
||
│ │ └┬┘ └┬┘ │ to 3V)
|
||
│ │ │ │ │
|
||
│ PE9 (CH1) ●─┼───────────┼────────────● A (CLK) │
|
||
│ │ │ │ │
|
||
│ │ 100n═╪═ 100n═╪═ │
|
||
│ │ │ │ │
|
||
│ PE11 (CH2) ●─┼───────────●────────────┼──● B (DT) │
|
||
│ │ │ │
|
||
│ │ ● C (common)──┼──┐
|
||
│ │ │ │
|
||
│ │ SW1 ●────────────────┘ │
|
||
│ PA0 ●───────────────────┐ │ (push-switch) │
|
||
│ │ │ ● SW2 ─────────────┼──┐
|
||
│ GND ●──────┬─────────────┼─────────────────────┘ │
|
||
│ │ │ │ mount legs ●●─────────┘
|
||
└──────────────┘ │ │ (to GND, shield)
|
||
│ │
|
||
┌──────┴──────┐ │ B1 (on-board) also sits
|
||
│ both 100n │ │ 3V ↔ PA0 — encoder SW is
|
||
│ caps → GND │ └─ in PARALLEL with it.
|
||
└─────────────┘
|
||
```
|
||
|
||
---
|
||
|
||
## 3. Breadboard view
|
||
|
||
```
|
||
3V rail ●━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━● ← jumper from Discovery 3V
|
||
GND rail ●━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━● ← jumper from Discovery GND
|
||
┌──────────────────────────────────────────────────┐
|
||
│ [10k] [10k] encoder straddles trench │
|
||
│ │ │ │ │ ┌──────────────────────┐ │
|
||
3V ──┴─┘ └──┬──┘ └──┬──────┤ A C B │ SW1 SW2 ├─┐ │
|
||
│ │ │ └──┼────┼────┼───┼────┼──┘ │ │
|
||
│ [100n] [100n] │ GND │ 3V PA0 │ │
|
||
│ │ │ │ │ │ │
|
||
GND ─┴─────┴───────┴───────────┘ │ │ │
|
||
│ │ │ │
|
||
│ A → PE9 B → PE11 SW2 → PA0 │ │
|
||
└──────────────────────────────────────────────────┘
|
||
(jumper) (jumper) (jumper, ‖ B1)
|
||
```
|
||
|
||
Power both breadboard rails from the Discovery's **3V** and **GND** pins; tap
|
||
everything else off those rails.
|
||
|
||
---
|
||
|
||
## 4. Why the resistors and caps
|
||
|
||
- **10 kΩ pull-ups (A→3V, B→3V):** *required.* This HAL's QEI driver puts the
|
||
pins in alternate-function mode without enabling the internal pull-ups, so the
|
||
channels would float. With the encoder common tied to GND, the lines idle high
|
||
and each detent pulls them low.
|
||
- **100 nF caps (A→GND, B→GND):** *recommended.* Each forms an RC low-pass with
|
||
its 10 kΩ pull-up, τ = R·C = 10 kΩ · 100 nF = **1 ms** — long enough to absorb
|
||
the ~1–5 ms of mechanical contact bounce, short enough that no hand-turned knob
|
||
outruns it. Combined with the STM32 inputs' Schmitt-trigger hysteresis, this
|
||
turns each bounced click into one clean edge. The cap's closure surge also
|
||
provides wetting current to keep the low-current (~0.3 mA) contacts reliable.
|
||
|
||
---
|
||
|
||
## 5. Behaviour (firmware)
|
||
|
||
- **TIM1 encoder mode** counts quadrature edges (×4). EC11s emit one full cycle
|
||
per detent → **4 counter steps per detent** (`COUNTS_PER_DETENT`).
|
||
- Each detent moves the setpoint by **`SETPOINT_STEP_C` (1 °C)**, clamped to
|
||
**`[SETPOINT_MIN_C, SETPOINT_MAX_C]` = [25, 100] °C**. Power-on default is
|
||
**`SETPOINT_DEFAULT_C` = 25 °C**.
|
||
- The encoder is sampled every `POLL_MS` (20 ms) in the main poll loops (normal
|
||
and fault), so the setpoint tracks smoothly and the per-second status log
|
||
prints the live value.
|
||
- **Push-switch:** wired in parallel with B1 (3V ↔ PA0). Pressing the knob is
|
||
electrically identical to the board button and is handled by the existing PA0
|
||
polling — no extra code.
|
||
|
||
---
|
||
|
||
## 6. Alternatives
|
||
|
||
- **Drop the caps:** enable TIM1's built-in digital input filter (sample-count
|
||
debounce) in firmware instead. The RC filter is simpler and also gives wetting
|
||
current + on-wire noise rejection, so it's preferred for a breadboard build.
|
||
- **KY-040 module:** has onboard pull-ups — power it from **3.3 V** (not 5 V) so
|
||
CLK/DT/SW idle at a level the MCU pins accept; the external 10 kΩ/100 nF here
|
||
can then be omitted.
|