mirror of
https://github.com/erik-toth/audio-synth.git
synced 2025-12-06 14:00:02 +00:00
Compare commits
5 Commits
latest-saf
...
f86db9c917
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f86db9c917 | ||
| b106859252 | |||
| dac90a977b | |||
| ce4e6cb536 | |||
|
|
ae7b6f6114 |
Binary file not shown.
File diff suppressed because one or more lines are too long
BIN
dev/analog/ETOTH-Amp_LM386/History/Amp_LM386.~(143).SchDoc.Zip
Normal file
BIN
dev/analog/ETOTH-Amp_LM386/History/Amp_LM386.~(143).SchDoc.Zip
Normal file
Binary file not shown.
BIN
dev/analog/ETOTH-Amp_LM386/History/Amp_LM386.~(144).SchDoc.Zip
Normal file
BIN
dev/analog/ETOTH-Amp_LM386/History/Amp_LM386.~(144).SchDoc.Zip
Normal file
Binary file not shown.
BIN
dev/analog/ETOTH-Amp_LM386/History/Amp_LM386.~(145).SchDoc.Zip
Normal file
BIN
dev/analog/ETOTH-Amp_LM386/History/Amp_LM386.~(145).SchDoc.Zip
Normal file
Binary file not shown.
BIN
dev/analog/ETOTH-Amp_LM386/History/Amp_LM386.~(146).SchDoc.Zip
Normal file
BIN
dev/analog/ETOTH-Amp_LM386/History/Amp_LM386.~(146).SchDoc.Zip
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1,18 +1,18 @@
|
|||||||
ETOTH-Amp_LM386
|
ETOTH-Amp_LM386
|
||||||
*SPICE Netlist generated by Advanced Sim server on 25.11.2025 22:45:08
|
*SPICE Netlist generated by Advanced Sim server on 28.11.2025 11:11:11
|
||||||
.options MixedSimGenerated
|
.options MixedSimGenerated
|
||||||
|
|
||||||
*Schematic Netlist:
|
*Schematic Netlist:
|
||||||
CCblock NetCblock_1 OUT 220uF
|
CC_DCBLOCK_IN IN NetC_DCBLOCK_IN_2 10uF
|
||||||
CCblock1 NetCblock1_1 NetCblock1_2 10nF
|
CC_DCBLOCK_OUT NetC_DCBLOCK_OUT_1 OUT 220uF
|
||||||
XIC1A NetIC1_1 0 NetCblock1_2 0 NetCblock_1 VAP NetIC1_7 NetIC1_8 lm386
|
XIC1A NetIC1_1 0 NetIC1_3 0 NetC_DCBLOCK_OUT_1 VAP NetIC1_7 NetIC1_8 lm386
|
||||||
XIC1B NetIC1_1 0 NetCblock1_2 0 NetCblock_1 VAP NetIC1_7 NetIC1_8 lm386
|
XIC1B NetIC1_1 0 NetIC1_3 0 NetC_DCBLOCK_OUT_1 VAP NetIC1_7 NetIC1_8 lm386
|
||||||
LL_Speaker 0 NetL_Speaker_2 0.1mH
|
LL_Speaker 0 NetL_Speaker_2 0.1mH
|
||||||
RR_POTA 0 NetR_POT_2 {10k * {POS}}
|
RR_POTA 0 NetR_POT_2 {10k * {POS}}
|
||||||
RR_POTB NetR_POT_2 IN {10k - (10k * {POS})}
|
RR_POTB NetR_POT_2 NetC_DCBLOCK_IN_2 {10k - (10k * {POS})}
|
||||||
RR_Speaker NetL_Speaker_2 OUT 8R
|
RR_Speaker NetL_Speaker_2 OUT 8R
|
||||||
RR_static1 NetCblock1_1 NetR_POT_2 100k
|
RR_static1 NetIC1_3 NetR_POT_2 100k
|
||||||
RR_static2 0 NetCblock1_1 10k
|
RR_static2 0 NetIC1_3 10k
|
||||||
VU_q VAP 0 10V
|
VU_q VAP 0 10V
|
||||||
VUin IN 0 DC 0 SIN(5 2 220 0 0 0) AC 1 0
|
VUin IN 0 DC 0 SIN(5 2 220 0 0 0) AC 1 0
|
||||||
|
|
||||||
|
|||||||
@@ -7,4 +7,4 @@ From : Project [ETOTH-Amp_LM386.PrjPcb]
|
|||||||
Files Generated : 1
|
Files Generated : 1
|
||||||
Documents Printed : 0
|
Documents Printed : 0
|
||||||
|
|
||||||
Finished Output Generation At 22:41:52 On 25.11.2025
|
Finished Output Generation At 11:00:20 On 28.11.2025
|
||||||
|
|||||||
Binary file not shown.
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -7,4 +7,4 @@ From : Project [TRI-SQR-VCO_OTA_SS.PrjPcb]
|
|||||||
Files Generated : 1
|
Files Generated : 1
|
||||||
Documents Printed : 0
|
Documents Printed : 0
|
||||||
|
|
||||||
Finished Output Generation At 21:27:47 On 23.10.2025
|
Finished Output Generation At 12:23:27 On 28.11.2025
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
TRI-SQR-VCO_OTA_SS
|
TRI-SQR-VCO_OTA_SS
|
||||||
*SPICE Netlist generated by Advanced Sim server on 18.11.2025 14:07:43
|
*SPICE Netlist generated by Advanced Sim server on 28.11.2025 12:29:53
|
||||||
.options MixedSimGenerated
|
.options MixedSimGenerated
|
||||||
|
|
||||||
*Schematic Netlist:
|
*Schematic Netlist:
|
||||||
@@ -29,6 +29,8 @@ RR_A 0 U_SQR_OTA 3.63k
|
|||||||
RR_CV NetR_CV_1 NetIC2_9 59.941k
|
RR_CV NetR_CV_1 NetIC2_9 59.941k
|
||||||
RR_E NetC_an_2 NetR_E_2 10k
|
RR_E NetC_an_2 NetR_E_2 10k
|
||||||
RR_lambda_T NetIC2_9 U_C 1.1k
|
RR_lambda_T NetIC2_9 U_C 1.1k
|
||||||
|
RR_offset_1 NetR_CV_1 GND 10k
|
||||||
|
RR_offset_2 VAP NetR_CV_1 10k
|
||||||
RR_PWM_a GND NetIC3_6 15k
|
RR_PWM_a GND NetIC3_6 15k
|
||||||
RR_PWM_b NetIC3_6 VAP 10k
|
RR_PWM_b NetIC3_6 VAP 10k
|
||||||
RR_PWM_c U_PWM NetIC3_7 1k
|
RR_PWM_c U_PWM NetIC3_7 1k
|
||||||
@@ -55,15 +57,17 @@ VU_var NetR_CV_1 0 1
|
|||||||
.PLOT TRAN {v(U_TRI)} =PLOT(2) =AXIS(1) =NAME(U_TRI) =UNITS(V)
|
.PLOT TRAN {v(U_TRI)} =PLOT(2) =AXIS(1) =NAME(U_TRI) =UNITS(V)
|
||||||
.PLOT TRAN {v(U_SAW)} =PLOT(3) =AXIS(1) =NAME(U_SAW) =UNITS(V)
|
.PLOT TRAN {v(U_SAW)} =PLOT(3) =AXIS(1) =NAME(U_SAW) =UNITS(V)
|
||||||
.PLOT TRAN {v(U_PWM)} =PLOT(4) =AXIS(1) =NAME(U_PWM) =UNITS(V)
|
.PLOT TRAN {v(U_PWM)} =PLOT(4) =AXIS(1) =NAME(U_PWM) =UNITS(V)
|
||||||
.PLOT TRAN {i(U_mess)} =PLOT(5) =AXIS(1) =NAME(I_GND) =UNITS(A)
|
.PLOT TRAN {v(U_C)} =PLOT(5) =AXIS(1) =NAME(U_C) =UNITS(V)
|
||||||
.PLOT TRAN {v(U_in)} =PLOT(2) =AXIS(1) =NAME(U_in) =UNITS(V)
|
|
||||||
|
|
||||||
.OPTIONS ABSTOL=1e-10 RELTOL=1e-2 VNTOL=1e-4 METHOD=GEAR MAXORD=2
|
.OPTIONS ABSTOL=1e-10 RELTOL=1e-2 VNTOL=1e-4 METHOD=GEAR MAXORD=2
|
||||||
*Selected Circuit Analyses:
|
*Selected Circuit Analyses:
|
||||||
.TRAN 25u 20m 5m 25u UIC
|
.TRAN 25u 20m 5m 25u UIC
|
||||||
|
.CONTROL
|
||||||
|
SWEEP R_offset_2 LIST 10k 20k 30k
|
||||||
|
.ENDC
|
||||||
|
|
||||||
*Global Parameters:
|
*Global Parameters:
|
||||||
.PARAM POS=0
|
.PARAM POS={0}
|
||||||
|
|
||||||
*Models and Subcircuits:
|
*Models and Subcircuits:
|
||||||
* A dual opamp ngspice model
|
* A dual opamp ngspice model
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Binary file not shown.
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
1
dev/digital/ESP32-S3/ESP32-S3.Harness
Normal file
1
dev/digital/ESP32-S3/ESP32-S3.Harness
Normal file
@@ -0,0 +1 @@
|
|||||||
|
SB=SB1.R,SB1.P,SB2.R,SB2.P
|
||||||
Binary file not shown.
BIN
dev/digital/ESP32-S3/History/ESP32-S3.~(20).SchDoc.Zip
Normal file
BIN
dev/digital/ESP32-S3/History/ESP32-S3.~(20).SchDoc.Zip
Normal file
Binary file not shown.
BIN
dev/digital/ESP32-S3/History/ESP32-S3.~(21).SchDoc.Zip
Normal file
BIN
dev/digital/ESP32-S3/History/ESP32-S3.~(21).SchDoc.Zip
Normal file
Binary file not shown.
BIN
dev/digital/ESP32-S3/History/ESP32-S3.~(22).SchDoc.Zip
Normal file
BIN
dev/digital/ESP32-S3/History/ESP32-S3.~(22).SchDoc.Zip
Normal file
Binary file not shown.
File diff suppressed because one or more lines are too long
456
dev/digital/Firmware_TEST/README.md
Normal file
456
dev/digital/Firmware_TEST/README.md
Normal file
@@ -0,0 +1,456 @@
|
|||||||
|
# Firmware
|
||||||
|
|
||||||
|
## Inhaltsverzeichnis
|
||||||
|
|
||||||
|
1. [Projektübersicht](#projektübersicht)
|
||||||
|
2. [Systemarchitektur](#systemarchitektur)
|
||||||
|
3. [Komponenten](#komponenten)
|
||||||
|
4. [Speicheranalyse](#speicheranalyse)
|
||||||
|
5. [Installation](#installation)
|
||||||
|
6. [Verwendung](#verwendung)
|
||||||
|
7. [Hauptablauf](#hauptablauf)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Projektübersicht
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
- ✅ **Dual-Channel CV-Sequencer** - 2 unabhängige Control Voltage Ausgänge
|
||||||
|
- ✅ **4×3 Tastaturmatrix** - Echtzeit-Tasten-Eingabe mit Entprellung
|
||||||
|
- ✅ **Recording & Playback** - Speichere Sequenzen bis 30 Sekunden
|
||||||
|
- ✅ **Loop-Funktion** - Endlose Wiederholung oder Einmaledition
|
||||||
|
- ✅ **Live-Modus** - Direkte Tastatur-zu-CV Ausgabe
|
||||||
|
- ✅ **Multi-Key Support** - Bis zu 10 gleichzeitig aktive Tasten
|
||||||
|
|
||||||
|
### Hardware
|
||||||
|
|
||||||
|
| Komponente | Modell | Funktion |
|
||||||
|
|-----------|--------|---------|
|
||||||
|
| Microcontroller | ESP32 | Hauptprozessor |
|
||||||
|
| DAC | MCP4728 | 4-Kanal 12-Bit DAC |
|
||||||
|
| I2C Bus | - | Kommunikation MCU ↔ DAC |
|
||||||
|
| Tastatur | 4×3 Matrix | Benutzereingabe |
|
||||||
|
| Buttons | 4× Push-Buttons | Record/Play Steuerung |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Systemarchitektur
|
||||||
|
|
||||||
|
### 3-Schicht-Modell
|
||||||
|
|
||||||
|
```
|
||||||
|
┌─────────────────────────────────────────────────────┐
|
||||||
|
│ INPUT LAYER (📥) │
|
||||||
|
├──────────────────────┬──────────────────────────────┤
|
||||||
|
│ Keyboard Matrix │ Sequencer Buttons │
|
||||||
|
│ (4×3 Tasten) │ (Record/Play × 2) │
|
||||||
|
└──────────────┬───────┴──────────────┬───────────────┘
|
||||||
|
│ │
|
||||||
|
┌──────────────▼─────────────────────▼───────────────┐
|
||||||
|
│ PROCESSING LAYER (⚙️) │
|
||||||
|
├──────────────────────┬──────────────────────────────┤
|
||||||
|
│ Keyboard Klasse │ SequencerBlock (2×) │
|
||||||
|
│ (Queue-Management) │ (Recording & Playback) │
|
||||||
|
└──────────────┬───────┴──────────────┬───────────────┘
|
||||||
|
│ │
|
||||||
|
┌──────────────▼─────────────────────▼───────────────┐
|
||||||
|
│ OUTPUT LAYER (📤) │
|
||||||
|
├──────────────────────┬──────────────────────────────┤
|
||||||
|
│ CV Klasse (DAC) │ CV Ausgänge │
|
||||||
|
│ MCP4728 I2C │ (A=Ch1, B=Ch2) │
|
||||||
|
└──────────────┬───────┴──────────────┬───────────────┘
|
||||||
|
│ │
|
||||||
|
└──────────────┬───────┘
|
||||||
|
▼
|
||||||
|
Externe Synthesizer / Module
|
||||||
|
```
|
||||||
|
|
||||||
|
### Datenfluss
|
||||||
|
|
||||||
|
```
|
||||||
|
TASTATUR → KEYBOARD → SEQUENCER/LIVE → DAC → CV AUSGÄNGE
|
||||||
|
↑
|
||||||
|
BUTTONS
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Komponenten
|
||||||
|
|
||||||
|
### 1. Keyboard Klasse
|
||||||
|
|
||||||
|
**Funktion:** Verwaltet die 4×3 Matrix-Tastatur mit Entprellung
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
class Keyboard {
|
||||||
|
public:
|
||||||
|
Keyboard(uint8_t nRows, uint8_t nCols, uint8_t *pinsRow, uint8_t *pinsCol);
|
||||||
|
void begin();
|
||||||
|
void update();
|
||||||
|
int getQueueLength();
|
||||||
|
Key getQueue(uint8_t index);
|
||||||
|
// ...
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
**Merkmale:**
|
||||||
|
- Debounce-Zeit: 20ms
|
||||||
|
- Max. 10 gleichzeitig aktive Tasten
|
||||||
|
- FIFO-Queue für Tastenreihenfolge
|
||||||
|
- Rückmeldung als `Key(row, col)` Struktur
|
||||||
|
|
||||||
|
### 2. CV Klasse
|
||||||
|
|
||||||
|
**Funktion:** Verwaltet DAC-Ausgänge über I2C (MCP4728)
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
class CV {
|
||||||
|
public:
|
||||||
|
CV(Adafruit_MCP4728 *dac, TwoWire *wire, uint8_t nCV,
|
||||||
|
MCP4728_channel_t *cvChannelMap, uint16_t *keyToVoltage,
|
||||||
|
uint8_t row, uint8_t col);
|
||||||
|
bool begin(uint8_t pinSDA, uint8_t pinSCL);
|
||||||
|
void setVoltage(uint8_t cvIndex, Key k);
|
||||||
|
void setVoltage(uint8_t cvIndex, uint16_t mV);
|
||||||
|
void clearAll();
|
||||||
|
// ...
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
**Merkmale:**
|
||||||
|
- 2 CV-Kanäle (A, B)
|
||||||
|
- I2C-Kommunikation (Pins 15, 16)
|
||||||
|
- Voltage-Mapping von Tasten
|
||||||
|
- Range: 0-4096mV (12-Bit)
|
||||||
|
|
||||||
|
### 3. SequencerBlock Klasse
|
||||||
|
|
||||||
|
**Funktion:** Speichert und spielt Sequenzen auf 2 Kanälen
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
class SequencerBlock {
|
||||||
|
public:
|
||||||
|
SequencerBlock(uint16_t maxDurationMS, uint16_t minStepDurationMS);
|
||||||
|
|
||||||
|
// Recording
|
||||||
|
void startRecord();
|
||||||
|
void stopRecord();
|
||||||
|
void addStep(uint16_t voltage_ch1, uint16_t voltage_ch2);
|
||||||
|
|
||||||
|
// Playback
|
||||||
|
void startPlay();
|
||||||
|
void stopPlay();
|
||||||
|
void update(); // Must be called regularly
|
||||||
|
void setLoop(bool loop);
|
||||||
|
|
||||||
|
// Status
|
||||||
|
uint8_t getStepCount();
|
||||||
|
uint16_t getCurrentVoltageCh1();
|
||||||
|
uint16_t getCurrentVoltageCh2();
|
||||||
|
// ...
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
**Merkmale:**
|
||||||
|
- Max. 128 Steps pro Sequenz
|
||||||
|
- Max. 30 Sekunden Aufnahmetime
|
||||||
|
- Dual-Channel Recording
|
||||||
|
- Loop-Funktion
|
||||||
|
- Automatisches Time-Limit
|
||||||
|
|
||||||
|
### 4. Button-Verarbeitung
|
||||||
|
|
||||||
|
**3-Mode Play-Button-System:**
|
||||||
|
|
||||||
|
| Click | Aktion | Zustand |
|
||||||
|
|-------|--------|---------|
|
||||||
|
| 1x | Play (keine Loop) | Spielt einmalig ab |
|
||||||
|
| 2x | Loop aktivieren | Endlosschleife |
|
||||||
|
| 3x | Stop | Stoppt Wiedergabe |
|
||||||
|
|
||||||
|
**Record-Button:** Toggle zwischen Recording starten/stoppen
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Speicheranalyse
|
||||||
|
```bash
|
||||||
|
RAM: [= ] 6.5% (used 21176 bytes from 327680 bytes)
|
||||||
|
Flash: [= ] 8.5% (used 283165 bytes from 3342336 bytes)
|
||||||
|
```
|
||||||
|
### RAM-Verbrauch
|
||||||
|
|
||||||
|
| Komponente | Größe | Menge | Gesamt | Notizen |
|
||||||
|
|-----------|-------|-------|--------|---------|
|
||||||
|
| SequencerBlock #1 | ~550 B | 1x | 550 B | 128 Steps × 6 Bytes + Variablen |
|
||||||
|
| SequencerBlock #2 | ~550 B | 1x | 550 B | 128 Steps × 6 Bytes + Variablen |
|
||||||
|
| Keyboard Objekt | ~130 B | 1x | 130 B | 8×8 Bool Arrays + Pointer |
|
||||||
|
| CV Objekt | ~50 B | 1x | 50 B | DAC-Pointer + Config |
|
||||||
|
| keyToVoltage Array | 24 B | 1x | 24 B | 12 Keys × uint16_t |
|
||||||
|
| Button States | ~50 B | 1x | 50 B | 4 Buttons × ~12 Bytes |
|
||||||
|
| Lokale Variablen | ~100 B | 1x | 100 B | Loop-Variablen |
|
||||||
|
| **GESAMT (Schätzung)** | - | - | **~1.5 KB** | - |
|
||||||
|
|
||||||
|
### Flash-Verbrauch
|
||||||
|
|
||||||
|
| Komponente | Größe |
|
||||||
|
|-----------|-------|
|
||||||
|
| Arduino/Wire Libraries | ~150 KB |
|
||||||
|
| Adafruit_MCP4728 | ~20 KB |
|
||||||
|
| Firmware Code | ~80 KB |
|
||||||
|
| Bootloader | ~60 KB |
|
||||||
|
| **GESAMT (Schätzung)** | **~310 KB** |
|
||||||
|
|
||||||
|
|
||||||
|
### Sequenzen-Speicher Detail
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
struct DualVoltageDurationPair {
|
||||||
|
uint16_t voltage_ch1; // 2 Bytes
|
||||||
|
uint16_t voltage_ch2; // 2 Bytes
|
||||||
|
uint16_t duration; // 2 Bytes
|
||||||
|
}; // = 6 Bytes pro Step
|
||||||
|
|
||||||
|
// Berechnung:
|
||||||
|
// - N_MAX_SEQUENCE_STEPS = 128
|
||||||
|
// - 128 Steps × 6 Bytes = 768 Bytes pro Sequenz
|
||||||
|
// - 2 Sequenzer = 1536 Bytes (1.5 KB)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Optimierungspotential
|
||||||
|
|
||||||
|
| Feature | Größenänderung | Status |
|
||||||
|
|---------|-----------------|--------|
|
||||||
|
| 256 Steps statt 128 | +768 B | ✅ Problemlos möglich |
|
||||||
|
| 60s statt 30s Limit | 0 B | ✅ Kostenloses Upgrade |
|
||||||
|
| 4 Sequenzer statt 2 | +3.3 KB | ✅ Problemlos möglich |
|
||||||
|
| 8×8 Tastatur statt 4×3 | ~ +30 B | ✅ Kaum Mehraufwand |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Verwendung
|
||||||
|
|
||||||
|
### Grundlegende Konfiguration
|
||||||
|
|
||||||
|
`include/FIRMWARE_DEF.h`:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
#define N_KEYBOARD_ROW 4 // Keyboard Reihen
|
||||||
|
#define N_KEYBOARD_COL 3 // Keyboard Spalten
|
||||||
|
#define N_CV_GATES 2 // CV-Ausgänge
|
||||||
|
#define N_SB 2 // Sequencer
|
||||||
|
|
||||||
|
// I2C Pins
|
||||||
|
#define PIN_SDA 15
|
||||||
|
#define PIN_SCL 16
|
||||||
|
|
||||||
|
// Keyboard Pins (Reihen)
|
||||||
|
#define PIN_K_R0 7
|
||||||
|
#define PIN_K_R1 8
|
||||||
|
#define PIN_K_R2 9
|
||||||
|
#define PIN_K_R3 10
|
||||||
|
|
||||||
|
// Keyboard Pins (Spalten)
|
||||||
|
#define PIN_K_C0 1
|
||||||
|
#define PIN_K_C1 2
|
||||||
|
#define PIN_K_C2 4
|
||||||
|
```
|
||||||
|
|
||||||
|
### Spannung-Mapping
|
||||||
|
|
||||||
|
`src/main.cpp`:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
// Voltage für jede Tastaturposition (in 1/12V = 83mV Schritten = 1 Halbtonschritt)
|
||||||
|
uint16_t keyToVoltage[N_KEYBOARD_ROW*N_KEYBOARD_COL] = {
|
||||||
|
1*83, 5*83, 9*83, // Row 0: C, E, G
|
||||||
|
2*83, 6*83, 10*83, // Row 1: D, F, A
|
||||||
|
3*83, 7*83, 11*83, // Row 2: E, G, B
|
||||||
|
4*83, 8*83, 12*83 // Row 3: F, A, C (Oktave)
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Hauptablauf
|
||||||
|
|
||||||
|
### Main Loop Flowchart
|
||||||
|
|
||||||
|
```
|
||||||
|
START
|
||||||
|
↓
|
||||||
|
SETUP (Initialisierung)
|
||||||
|
↓
|
||||||
|
┌─── MAIN LOOP ───────────────────────┐
|
||||||
|
│ │
|
||||||
|
├─ Keyboard Update │
|
||||||
|
│ (Tasten auslesen) │
|
||||||
|
│ │
|
||||||
|
├─ Button Handler │
|
||||||
|
│ (Record/Play Buttons) │
|
||||||
|
│ │
|
||||||
|
├─ Sequencer Update │
|
||||||
|
│ (sb1 & sb2 Playback) │
|
||||||
|
│ │
|
||||||
|
├─ Spannungen bestimmen │
|
||||||
|
│ voltage_ch1 = Queue[0] │
|
||||||
|
│ voltage_ch2 = Queue[1] │
|
||||||
|
│ │
|
||||||
|
├─ Recording Check │
|
||||||
|
│ IF Recording: addStep() │
|
||||||
|
│ │
|
||||||
|
├─ Output Priority │
|
||||||
|
│ IF sb1.playing() → Output SEQ1 │
|
||||||
|
│ ELSE IF sb2.playing() → Output SEQ2│
|
||||||
|
│ ELSE → Output Live │
|
||||||
|
│ │
|
||||||
|
├─ Time-Limit Check │
|
||||||
|
│ IF Limit reached: Stop Record │
|
||||||
|
│ │
|
||||||
|
├─ Delay 10ms │
|
||||||
|
│ │
|
||||||
|
└─────────────────────────────────────┘
|
||||||
|
↓
|
||||||
|
[Loop zurück]
|
||||||
|
```
|
||||||
|
|
||||||
|
### State Machine
|
||||||
|
|
||||||
|
| State | Beschreibung | Aktion |
|
||||||
|
|-------|-------------|--------|
|
||||||
|
| **IDLE** | Leerlauf | Liest Tasten, gibt Live-Spannungen aus |
|
||||||
|
| **REC** | Recording aktiv | Speichert Sequenzen, überwacht Zeit-Limits |
|
||||||
|
| **PLAY** | Playback aktiv | Gibt Sequenzen aus, verwaltet Step-Übergänge |
|
||||||
|
| **LOOP** | Endlosschleife | Wiederholt Sequenz nahtlos |
|
||||||
|
|
||||||
|
### Ausgabe-Prioritätssystem
|
||||||
|
|
||||||
|
```
|
||||||
|
1. Sequencer 1 Playing?
|
||||||
|
├─ JA → Gebe SEQ1 Voltages aus (höchste Priorität)
|
||||||
|
└─ NEIN ↓
|
||||||
|
|
||||||
|
2. Sequencer 2 Playing?
|
||||||
|
├─ JA → Gebe SEQ2 Voltages aus (zweite Priorität)
|
||||||
|
└─ NEIN ↓
|
||||||
|
|
||||||
|
3. Live Input
|
||||||
|
└─ Gebe Tasten-Voltages aus (Standard)
|
||||||
|
```
|
||||||
|
|
||||||
|
Dies ermöglicht nahtlose Übergänge und verhindert Konflikte.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Code-Beispiele
|
||||||
|
|
||||||
|
### Beispiel 1: Live-Modus (main.cpp.1)
|
||||||
|
|
||||||
|
Direkte Tastatur-zu-CV Verbindung ohne Sequencer:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
void loop() {
|
||||||
|
keyboard.update();
|
||||||
|
|
||||||
|
int n = keyboard.getQueueLength();
|
||||||
|
|
||||||
|
if(n > 0) {
|
||||||
|
for(int i = 0; (i < N_CV_GATES) && (i < n); i++) {
|
||||||
|
Key k = keyboard.getQueue(i);
|
||||||
|
cv.setVoltage(i, k); // Taste direkt auf CV ausgeben
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
cv.clearAll(); // Keine Taste → 0V
|
||||||
|
}
|
||||||
|
|
||||||
|
delay(50);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Beispiel 2: Dual-Channel Sequencer (main.cpp)
|
||||||
|
|
||||||
|
Vollständiger Sequencer mit 2 unabhängigen Kanälen:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
void loop() {
|
||||||
|
keyboard.update();
|
||||||
|
handleSequencerButtons();
|
||||||
|
|
||||||
|
sb1.update();
|
||||||
|
sb2.update();
|
||||||
|
|
||||||
|
// ... Voltage determination ...
|
||||||
|
|
||||||
|
// Recording
|
||||||
|
if(sb1.isRecording()) {
|
||||||
|
sb1.addStep(voltage_ch1, voltage_ch2);
|
||||||
|
}
|
||||||
|
if(sb2.isRecording()) {
|
||||||
|
sb2.addStep(voltage_ch1, voltage_ch2);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Output mit Priorität
|
||||||
|
if(sb1.isPlaying()) {
|
||||||
|
cv.setVoltage(0, sb1.getCurrentVoltageCh1());
|
||||||
|
cv.setVoltage(1, sb1.getCurrentVoltageCh2());
|
||||||
|
}
|
||||||
|
else if(sb2.isPlaying()) {
|
||||||
|
cv.setVoltage(0, sb2.getCurrentVoltageCh1());
|
||||||
|
cv.setVoltage(1, sb2.getCurrentVoltageCh2());
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
cv.setVoltage(0, voltage_ch1);
|
||||||
|
cv.setVoltage(1, voltage_ch2);
|
||||||
|
}
|
||||||
|
|
||||||
|
delay(10);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Dateistruktur
|
||||||
|
|
||||||
|
```
|
||||||
|
project/
|
||||||
|
├── include/
|
||||||
|
│ ├── FIRMWARE.h # Klassen-Definitionen
|
||||||
|
│ └── FIRMWARE_DEF.h # Konstanten & Pin-Definitionen
|
||||||
|
│
|
||||||
|
└── src/
|
||||||
|
├── main.cpp # Dual-Channel Sequencer Beispiel
|
||||||
|
├── main.cpp.1 # Live-Modus Beispiel
|
||||||
|
├── main.cpp.2 # Dual-Channel ohne Sequencer
|
||||||
|
└── FIRMWARE.cpp # Implementierungen
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Technische Spezifikationen
|
||||||
|
|
||||||
|
### Timings
|
||||||
|
|
||||||
|
| Parameter | Wert | Funktion |
|
||||||
|
|-----------|------|----------|
|
||||||
|
| Keyboard Debounce | 20ms | Anti-Prellen Verzögerung |
|
||||||
|
| Button Debounce | 50ms | Button Anti-Prellen |
|
||||||
|
| Main Loop Delay | 10ms | Update-Rate |
|
||||||
|
| Max Recording | 30s | Zeit-Limit pro Sequenz |
|
||||||
|
| Min Step Duration | 50ms | Minimale Step-Länge |
|
||||||
|
|
||||||
|
### Voltage-Mapping
|
||||||
|
|
||||||
|
Verwendet gleichmäßige 83mV Schritte (1/12 Oktave):
|
||||||
|
|
||||||
|
```
|
||||||
|
Key (1,0) = 1 × 83mV = 83mV (C)
|
||||||
|
Key (1,1) = 5 × 83mV = 415mV (E)
|
||||||
|
Key (1,2) = 9 × 83mV = 747mV (G)
|
||||||
|
... etc
|
||||||
|
Key (4,2) = 12 × 83mV = 996mV (C')
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**Zuletzt aktualisiert:** 2025-11-30
|
||||||
@@ -26,9 +26,10 @@ struct Key
|
|||||||
int col;
|
int col;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct voltageDurationPair
|
struct DualVoltageDurationPair
|
||||||
{
|
{
|
||||||
uint16_t voltage;
|
uint16_t voltage_ch1;
|
||||||
|
uint16_t voltage_ch2;
|
||||||
uint16_t duration;
|
uint16_t duration;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -93,12 +94,12 @@ class CV
|
|||||||
class SequencerBlock
|
class SequencerBlock
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
SequencerBlock(uint16_t maxDurationMS, uint16_t timeoutMS);
|
SequencerBlock(uint16_t maxDurationMS, uint16_t minStepDurationMS);
|
||||||
|
|
||||||
// Aufnahme-Funktionen
|
// Aufnahme-Funktionen
|
||||||
void startRecord();
|
void startRecord();
|
||||||
void stopRecord();
|
void stopRecord();
|
||||||
void addStep(uint16_t voltage);
|
void addStep(uint16_t voltage_ch1, uint16_t voltage_ch2);
|
||||||
bool isRecording();
|
bool isRecording();
|
||||||
|
|
||||||
// Wiedergabe-Funktionen
|
// Wiedergabe-Funktionen
|
||||||
@@ -114,18 +115,19 @@ class SequencerBlock
|
|||||||
// Status-Abfragen
|
// Status-Abfragen
|
||||||
bool timeLimitReached();
|
bool timeLimitReached();
|
||||||
uint8_t getStepCount();
|
uint8_t getStepCount();
|
||||||
uint16_t getCurrentVoltage();
|
uint16_t getCurrentVoltageCh1();
|
||||||
|
uint16_t getCurrentVoltageCh2();
|
||||||
uint16_t getTotalDuration();
|
uint16_t getTotalDuration();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Sequenz-Speicher
|
// Sequenz-Speicher
|
||||||
voltageDurationPair _sequence[N_MAX_SEQUENCE_STEPS];
|
DualVoltageDurationPair _sequence[N_MAX_SEQUENCE_STEPS];
|
||||||
uint8_t _stepCount;
|
uint8_t _stepCount;
|
||||||
uint8_t _currentStep;
|
uint8_t _currentStep;
|
||||||
|
|
||||||
// Zeitverwaltung
|
// Zeitverwaltung
|
||||||
uint16_t _maxDurationMS;
|
uint16_t _maxDurationMS;
|
||||||
uint16_t _timeoutMS;
|
uint16_t _minStepDurationMS;
|
||||||
unsigned long _recordStartTime;
|
unsigned long _recordStartTime;
|
||||||
unsigned long _lastStepTime;
|
unsigned long _lastStepTime;
|
||||||
unsigned long _playStartTime;
|
unsigned long _playStartTime;
|
||||||
@@ -136,8 +138,9 @@ class SequencerBlock
|
|||||||
bool _isPlaying;
|
bool _isPlaying;
|
||||||
bool _loop;
|
bool _loop;
|
||||||
|
|
||||||
// Letzte aufgenommene Spannung
|
// Letzte aufgenommene Spannungen
|
||||||
uint16_t _lastVoltage;
|
uint16_t _lastVoltageCh1;
|
||||||
|
uint16_t _lastVoltageCh2;
|
||||||
|
|
||||||
// Hilfsfunktionen
|
// Hilfsfunktionen
|
||||||
void _finishCurrentStep();
|
void _finishCurrentStep();
|
||||||
|
|||||||
@@ -25,15 +25,15 @@
|
|||||||
#define PIN_K_R1 8
|
#define PIN_K_R1 8
|
||||||
#define PIN_K_R2 9
|
#define PIN_K_R2 9
|
||||||
#define PIN_K_R3 10
|
#define PIN_K_R3 10
|
||||||
#define PIN_K_R4 // NOT IN USE
|
#define PIN_K_R4 // 11 NOT IN USE
|
||||||
#define PIN_K_C0 1
|
#define PIN_K_C0 1
|
||||||
#define PIN_K_C1 2
|
#define PIN_K_C1 2
|
||||||
#define PIN_K_C2 4
|
#define PIN_K_C2 4
|
||||||
#define PIN_K_C3 // NOT IN USE
|
#define PIN_K_C3 // 5 NOT IN USE
|
||||||
#define PIN_K_C4 // NOT IN USE
|
#define PIN_K_C4 // 6 NOT IN USE
|
||||||
// SEQUENCER BUTTON PINS
|
// SEQUENCER BUTTON PINS
|
||||||
#define PIN_SB_1_REC 0
|
#define PIN_SB_1_REC 37 // 33 not available on dev board
|
||||||
#define PIN_SB_1_PLAY 0
|
#define PIN_SB_1_PLAY 38 // 34 not available on dev board
|
||||||
#define PIN_SB_2_REC 0
|
#define PIN_SB_2_REC 35
|
||||||
#define PIN_SB_2_PLAY 0
|
#define PIN_SB_2_PLAY 36
|
||||||
#endif
|
#endif
|
||||||
@@ -177,15 +177,6 @@ void Keyboard::_removeActiveKey(uint8_t row, uint8_t col)
|
|||||||
|
|
||||||
// ==================== CV ====================
|
// ==================== CV ====================
|
||||||
|
|
||||||
/*!
|
|
||||||
* @param dac Adafruit_MCP4728 object
|
|
||||||
* @param wire TwoWire object
|
|
||||||
* @param nCV Number of CV-Gates
|
|
||||||
* @param cvChannelMap Maps CV-Gate-Index to a MCP4728 output-channel
|
|
||||||
* @param keyToVoltage One dimensional array of size row times col
|
|
||||||
* @param row Keyboard matrix rows
|
|
||||||
* @param col Keyboard matrix cols
|
|
||||||
*/
|
|
||||||
CV::CV(Adafruit_MCP4728 *dac, TwoWire *wire, uint8_t nCV, MCP4728_channel_t *cvChannelMap, uint16_t *keyToVoltage, uint8_t row, uint8_t col)
|
CV::CV(Adafruit_MCP4728 *dac, TwoWire *wire, uint8_t nCV, MCP4728_channel_t *cvChannelMap, uint16_t *keyToVoltage, uint8_t row, uint8_t col)
|
||||||
{
|
{
|
||||||
_dac = dac;
|
_dac = dac;
|
||||||
@@ -242,31 +233,27 @@ uint8_t CV::_getKeyToVoltageIndex(Key k)
|
|||||||
|
|
||||||
// ==================== SequencerBlock ====================
|
// ==================== SequencerBlock ====================
|
||||||
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* @param maxDurationMS maximum loop duration of recording in milliseconds
|
* @param maxDurationMS maximum loop duration of recording in milliseconds
|
||||||
* @param timeoutMS stops recording after timeout in milliseconds
|
* @param minStepDurationMS minimum duration for a step to be recorded (prevents ultra-short steps)
|
||||||
* @brief TODO
|
|
||||||
*/
|
*/
|
||||||
SequencerBlock::SequencerBlock(uint16_t maxDurationMS, uint16_t timeoutMS)
|
SequencerBlock::SequencerBlock(uint16_t maxDurationMS, uint16_t minStepDurationMS)
|
||||||
{
|
{
|
||||||
_maxDurationMS = maxDurationMS;
|
_maxDurationMS = maxDurationMS;
|
||||||
_timeoutMS = timeoutMS;
|
_minStepDurationMS = minStepDurationMS;
|
||||||
_stepCount = 0;
|
_stepCount = 0;
|
||||||
_currentStep = 0;
|
_currentStep = 0;
|
||||||
_isRecording = false;
|
_isRecording = false;
|
||||||
_isPlaying = false;
|
_isPlaying = false;
|
||||||
_loop = false;
|
_loop = false;
|
||||||
_lastVoltage = 0;
|
_lastVoltageCh1 = 0;
|
||||||
|
_lastVoltageCh2 = 0;
|
||||||
_recordStartTime = 0;
|
_recordStartTime = 0;
|
||||||
_lastStepTime = 0;
|
_lastStepTime = 0;
|
||||||
_playStartTime = 0;
|
_playStartTime = 0;
|
||||||
_stepStartTime = 0;
|
_stepStartTime = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
|
||||||
* @brief starts sequence block recording
|
|
||||||
*/
|
|
||||||
void SequencerBlock::startRecord()
|
void SequencerBlock::startRecord()
|
||||||
{
|
{
|
||||||
if(_isPlaying) stopPlay();
|
if(_isPlaying) stopPlay();
|
||||||
@@ -275,12 +262,10 @@ void SequencerBlock::startRecord()
|
|||||||
_isRecording = true;
|
_isRecording = true;
|
||||||
_recordStartTime = millis();
|
_recordStartTime = millis();
|
||||||
_lastStepTime = _recordStartTime;
|
_lastStepTime = _recordStartTime;
|
||||||
_lastVoltage = 0;
|
_lastVoltageCh1 = 0xFFFF; // Ungültiger Wert zum Triggern des ersten Steps
|
||||||
|
_lastVoltageCh2 = 0xFFFF;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
|
||||||
* @brief stops sequence block recording and saves it
|
|
||||||
*/
|
|
||||||
void SequencerBlock::stopRecord()
|
void SequencerBlock::stopRecord()
|
||||||
{
|
{
|
||||||
if(!_isRecording) return;
|
if(!_isRecording) return;
|
||||||
@@ -289,36 +274,44 @@ void SequencerBlock::stopRecord()
|
|||||||
_isRecording = false;
|
_isRecording = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
void SequencerBlock::addStep(uint16_t voltage_ch1, uint16_t voltage_ch2)
|
||||||
* @brief adds step to sequencer block
|
|
||||||
* @param voltage voltage step for CV-Gate in millivolts
|
|
||||||
*/
|
|
||||||
void SequencerBlock::addStep(uint16_t voltage)
|
|
||||||
{
|
{
|
||||||
if(!_isRecording) return;
|
if(!_isRecording) return;
|
||||||
if(!_canAddStep()) return;
|
if(timeLimitReached())
|
||||||
|
{
|
||||||
|
stopRecord();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
unsigned long now = millis();
|
unsigned long now = millis();
|
||||||
|
|
||||||
// Wenn sich die Spannung geändert hat, vorherigen Schritt abschließen
|
// Hat sich die Spannung geändert?
|
||||||
if(voltage != _lastVoltage && _stepCount > 0)
|
bool voltageChanged = (voltage_ch1 != _lastVoltageCh1) || (voltage_ch2 != _lastVoltageCh2);
|
||||||
{
|
|
||||||
_finishCurrentStep();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Neuen Schritt beginnen oder vorhandenen aktualisieren
|
if(voltageChanged)
|
||||||
if(voltage != _lastVoltage || _stepCount == 0)
|
|
||||||
{
|
{
|
||||||
|
// Vorherigen Step abschließen (wenn vorhanden)
|
||||||
|
if(_stepCount > 0)
|
||||||
|
{
|
||||||
|
_finishCurrentStep();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Neuen Step beginnen
|
||||||
if(_canAddStep())
|
if(_canAddStep())
|
||||||
{
|
{
|
||||||
_sequence[_stepCount].voltage = voltage;
|
_sequence[_stepCount].voltage_ch1 = voltage_ch1;
|
||||||
|
_sequence[_stepCount].voltage_ch2 = voltage_ch2;
|
||||||
_sequence[_stepCount].duration = 0;
|
_sequence[_stepCount].duration = 0;
|
||||||
|
_stepCount++;
|
||||||
|
|
||||||
_lastStepTime = now;
|
_lastStepTime = now;
|
||||||
_lastVoltage = voltage;
|
_lastVoltageCh1 = voltage_ch1;
|
||||||
|
_lastVoltageCh2 = voltage_ch2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
// Gleiche Spannung - Duration des aktuellen Steps aktualisieren
|
||||||
if(_stepCount > 0)
|
if(_stepCount > 0)
|
||||||
{
|
{
|
||||||
_sequence[_stepCount - 1].duration = now - _lastStepTime;
|
_sequence[_stepCount - 1].duration = now - _lastStepTime;
|
||||||
@@ -326,18 +319,11 @@ void SequencerBlock::addStep(uint16_t voltage)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
|
||||||
* @brief checks if sequencer block is recording
|
|
||||||
* @return true or false
|
|
||||||
*/
|
|
||||||
bool SequencerBlock::isRecording()
|
bool SequencerBlock::isRecording()
|
||||||
{
|
{
|
||||||
return _isRecording;
|
return _isRecording;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
|
||||||
* @brief starts playing sequencer block
|
|
||||||
*/
|
|
||||||
void SequencerBlock::startPlay()
|
void SequencerBlock::startPlay()
|
||||||
{
|
{
|
||||||
if(_stepCount == 0) return;
|
if(_stepCount == 0) return;
|
||||||
@@ -349,19 +335,12 @@ void SequencerBlock::startPlay()
|
|||||||
_stepStartTime = _playStartTime;
|
_stepStartTime = _playStartTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
|
||||||
* @brief stops playing sequencer block
|
|
||||||
*/
|
|
||||||
void SequencerBlock::stopPlay()
|
void SequencerBlock::stopPlay()
|
||||||
{
|
{
|
||||||
_isPlaying = false;
|
_isPlaying = false;
|
||||||
_currentStep = 0;
|
_currentStep = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
|
||||||
* @brief updates sequencer block
|
|
||||||
* @attention Has to be called every cycle!
|
|
||||||
*/
|
|
||||||
void SequencerBlock::update()
|
void SequencerBlock::update()
|
||||||
{
|
{
|
||||||
if(!_isPlaying || _stepCount == 0) return;
|
if(!_isPlaying || _stepCount == 0) return;
|
||||||
@@ -395,44 +374,31 @@ void SequencerBlock::update()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
|
||||||
* @brief checks if sequencer block is playing
|
|
||||||
* @return true or false
|
|
||||||
*/
|
|
||||||
bool SequencerBlock::isPlaying()
|
bool SequencerBlock::isPlaying()
|
||||||
{
|
{
|
||||||
return _isPlaying;
|
return _isPlaying;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
|
||||||
* @brief clears recording of sequencer block
|
|
||||||
*/
|
|
||||||
void SequencerBlock::clear()
|
void SequencerBlock::clear()
|
||||||
{
|
{
|
||||||
_stepCount = 0;
|
_stepCount = 0;
|
||||||
_currentStep = 0;
|
_currentStep = 0;
|
||||||
_lastVoltage = 0;
|
_lastVoltageCh1 = 0;
|
||||||
|
_lastVoltageCh2 = 0;
|
||||||
|
|
||||||
for(uint8_t i = 0; i < N_MAX_SEQUENCE_STEPS; i++)
|
for(uint8_t i = 0; i < N_MAX_SEQUENCE_STEPS; i++)
|
||||||
{
|
{
|
||||||
_sequence[i].voltage = 0;
|
_sequence[i].voltage_ch1 = 0;
|
||||||
|
_sequence[i].voltage_ch2 = 0;
|
||||||
_sequence[i].duration = 0;
|
_sequence[i].duration = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
|
||||||
* @brief sets configuation for looping over the recording
|
|
||||||
* @param loop if set to true, saved recording gets played in a loop
|
|
||||||
*/
|
|
||||||
void SequencerBlock::setLoop(bool loop)
|
void SequencerBlock::setLoop(bool loop)
|
||||||
{
|
{
|
||||||
_loop = loop;
|
_loop = loop;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
|
||||||
* @brief checks if the recording time limit has been reached
|
|
||||||
* @return true of false
|
|
||||||
*/
|
|
||||||
bool SequencerBlock::timeLimitReached()
|
bool SequencerBlock::timeLimitReached()
|
||||||
{
|
{
|
||||||
if(!_isRecording) return false;
|
if(!_isRecording) return false;
|
||||||
@@ -443,31 +409,27 @@ bool SequencerBlock::timeLimitReached()
|
|||||||
return (elapsed >= _maxDurationMS);
|
return (elapsed >= _maxDurationMS);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
|
||||||
* @brief returns the currently recoreded steps
|
|
||||||
* @return uint8_t between 0 and 128
|
|
||||||
*/
|
|
||||||
uint8_t SequencerBlock::getStepCount()
|
uint8_t SequencerBlock::getStepCount()
|
||||||
{
|
{
|
||||||
return _stepCount;
|
return _stepCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
uint16_t SequencerBlock::getCurrentVoltageCh1()
|
||||||
* @brief if sequencer is playing, returns the current voltage level
|
|
||||||
* @return uint16_t voltage range for CV
|
|
||||||
*/
|
|
||||||
uint16_t SequencerBlock::getCurrentVoltage()
|
|
||||||
{
|
{
|
||||||
if(!_isPlaying || _stepCount == 0) return 0;
|
if(!_isPlaying || _stepCount == 0) return 0;
|
||||||
if(_currentStep >= _stepCount) return 0;
|
if(_currentStep >= _stepCount) return 0;
|
||||||
|
|
||||||
return _sequence[_currentStep].voltage;
|
return _sequence[_currentStep].voltage_ch1;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t SequencerBlock::getCurrentVoltageCh2()
|
||||||
|
{
|
||||||
|
if(!_isPlaying || _stepCount == 0) return 0;
|
||||||
|
if(_currentStep >= _stepCount) return 0;
|
||||||
|
|
||||||
|
return _sequence[_currentStep].voltage_ch2;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
|
||||||
* @brief gets the length of the recording in the block
|
|
||||||
* @return uint16_t time in milliseconds
|
|
||||||
*/
|
|
||||||
uint16_t SequencerBlock::getTotalDuration()
|
uint16_t SequencerBlock::getTotalDuration()
|
||||||
{
|
{
|
||||||
uint16_t total = 0;
|
uint16_t total = 0;
|
||||||
@@ -483,12 +445,17 @@ void SequencerBlock::_finishCurrentStep()
|
|||||||
if(_stepCount == 0) return;
|
if(_stepCount == 0) return;
|
||||||
|
|
||||||
unsigned long now = millis();
|
unsigned long now = millis();
|
||||||
_sequence[_stepCount - 1].duration = now - _lastStepTime;
|
uint16_t duration = now - _lastStepTime;
|
||||||
|
|
||||||
// Timeout prüfen - wenn zu lange keine Änderung, Schritt nicht hinzufügen
|
// Nur Steps mit ausreichender Dauer speichern
|
||||||
if(_sequence[_stepCount - 1].duration < _timeoutMS)
|
if(duration >= _minStepDurationMS)
|
||||||
{
|
{
|
||||||
_stepCount++;
|
_sequence[_stepCount - 1].duration = duration;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Step war zu kurz, verwerfen
|
||||||
|
_stepCount--;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,19 +1,11 @@
|
|||||||
/*
|
/*
|
||||||
* Example Code Three
|
* Example Code Three - Dual Channel Sequencer
|
||||||
* with Sequencer
|
|
||||||
*
|
|
||||||
* Bedienung:
|
|
||||||
* - Keyboard-Tasten: CV-Ausgabe direkt oder Recording
|
|
||||||
* - PIN_SB_1_REC: Sequencer 1 Record Start/Stop
|
|
||||||
* - PIN_SB_1_PLAY: Sequencer 1 Play/Stop
|
|
||||||
* - PIN_SB_2_REC: Sequencer 2 Record Start/Stop
|
|
||||||
* - PIN_SB_2_PLAY: Sequencer 2 Play/Stop
|
|
||||||
*/
|
*/
|
||||||
#include "FIRMWARE_DEF.h"
|
#include "FIRMWARE_DEF.h"
|
||||||
#include "FIRMWARE.h"
|
#include "FIRMWARE.h"
|
||||||
|
|
||||||
static byte pins_keyboard_row[N_KEYBOARD_ROW] = {PIN_K_R0, PIN_K_R1, PIN_K_R2, PIN_K_R3};
|
byte pins_keyboard_row[N_KEYBOARD_ROW] = {PIN_K_R0, PIN_K_R1, PIN_K_R2, PIN_K_R3};
|
||||||
static byte pins_keyboard_col[N_KEYBOARD_COL] = {PIN_K_C0, PIN_K_C1, PIN_K_C2};
|
byte pins_keyboard_col[N_KEYBOARD_COL] = {PIN_K_C0, PIN_K_C1, PIN_K_C2};
|
||||||
|
|
||||||
Keyboard keyboard(N_KEYBOARD_ROW, N_KEYBOARD_COL, pins_keyboard_row, pins_keyboard_col);
|
Keyboard keyboard(N_KEYBOARD_ROW, N_KEYBOARD_COL, pins_keyboard_row, pins_keyboard_col);
|
||||||
|
|
||||||
@@ -28,8 +20,9 @@ uint16_t keyToVoltage[N_KEYBOARD_ROW*N_KEYBOARD_COL] = { /* 83mV = 1/12V */
|
|||||||
|
|
||||||
CV cv(&MCP4728, &Wire, N_CV_GATES, cvMap, keyToVoltage, N_KEYBOARD_ROW, N_KEYBOARD_COL);
|
CV cv(&MCP4728, &Wire, N_CV_GATES, cvMap, keyToVoltage, N_KEYBOARD_ROW, N_KEYBOARD_COL);
|
||||||
|
|
||||||
SequencerBlock sb1(30000, 250); // 30 Sekunden max, 250ms Timeout
|
// Sequencer mit 30s max, 50ms Mindest-Step-Dauer
|
||||||
SequencerBlock sb2(30000, 250);
|
SequencerBlock sb1(30000, 50);
|
||||||
|
SequencerBlock sb2(30000, 50);
|
||||||
|
|
||||||
// Button States
|
// Button States
|
||||||
struct ButtonState {
|
struct ButtonState {
|
||||||
@@ -45,10 +38,9 @@ ButtonState btn_sb2_play;
|
|||||||
|
|
||||||
const unsigned long DEBOUNCE_DELAY = 50;
|
const unsigned long DEBOUNCE_DELAY = 50;
|
||||||
|
|
||||||
// Hilfsfunktion zum Lesen eines Buttons mit Debouncing
|
|
||||||
bool readButton(byte pin, ButtonState &state)
|
bool readButton(byte pin, ButtonState &state)
|
||||||
{
|
{
|
||||||
bool reading = digitalRead(pin) == LOW; // LOW = gedrückt (mit Pull-Up)
|
bool reading = digitalRead(pin) == HIGH;
|
||||||
bool buttonPressed = false;
|
bool buttonPressed = false;
|
||||||
|
|
||||||
if(reading != state.last)
|
if(reading != state.last)
|
||||||
@@ -61,7 +53,7 @@ bool readButton(byte pin, ButtonState &state)
|
|||||||
if(reading != state.current)
|
if(reading != state.current)
|
||||||
{
|
{
|
||||||
state.current = reading;
|
state.current = reading;
|
||||||
if(state.current == true) // Button wurde gerade gedrückt
|
if(state.current == true)
|
||||||
{
|
{
|
||||||
buttonPressed = true;
|
buttonPressed = true;
|
||||||
}
|
}
|
||||||
@@ -74,10 +66,10 @@ bool readButton(byte pin, ButtonState &state)
|
|||||||
|
|
||||||
void initButtons()
|
void initButtons()
|
||||||
{
|
{
|
||||||
pinMode(PIN_SB_1_REC, INPUT_PULLUP);
|
pinMode(PIN_SB_1_REC, INPUT_PULLDOWN);
|
||||||
pinMode(PIN_SB_1_PLAY, INPUT_PULLUP);
|
pinMode(PIN_SB_1_PLAY, INPUT_PULLDOWN);
|
||||||
pinMode(PIN_SB_2_REC, INPUT_PULLUP);
|
pinMode(PIN_SB_2_REC, INPUT_PULLDOWN);
|
||||||
pinMode(PIN_SB_2_PLAY, INPUT_PULLUP);
|
pinMode(PIN_SB_2_PLAY, INPUT_PULLDOWN);
|
||||||
|
|
||||||
btn_sb1_rec.current = false;
|
btn_sb1_rec.current = false;
|
||||||
btn_sb1_rec.last = false;
|
btn_sb1_rec.last = false;
|
||||||
@@ -111,23 +103,54 @@ void handleSequencerButtons()
|
|||||||
{
|
{
|
||||||
if(sb1.isPlaying()) sb1.stopPlay();
|
if(sb1.isPlaying()) sb1.stopPlay();
|
||||||
sb1.startRecord();
|
sb1.startRecord();
|
||||||
Serial.printf("\n\r[SEQ1] Recording started...");
|
Serial.printf("\n\r[SEQ1] Recording started (2 channels)...");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sequencer 1 Play Button
|
// Sequencer 1 Play Button - 3 Modi: Play / Loop / Stop
|
||||||
if(readButton(PIN_SB_1_PLAY, btn_sb1_play))
|
if(readButton(PIN_SB_1_PLAY, btn_sb1_play))
|
||||||
{
|
{
|
||||||
if(sb1.isPlaying())
|
if(!sb1.isPlaying())
|
||||||
{
|
{
|
||||||
sb1.stopPlay();
|
// Nicht am Spielen -> Starte Playback (ohne Loop)
|
||||||
Serial.printf("\n\r[SEQ1] Playback stopped");
|
if(sb1.isRecording()) sb1.stopRecord();
|
||||||
|
sb1.setLoop(false);
|
||||||
|
sb1.startPlay();
|
||||||
|
Serial.printf("\n\r[SEQ1] Playback started (single)\n\r\tSteps: %i, Duartion: %ims", sb1.getStepCount(), sb1.getTotalDuration());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if(sb1.isRecording()) sb1.stopRecord();
|
// Am Spielen -> Prüfe Loop-Status
|
||||||
sb1.startPlay();
|
if(!sb1.isPlaying()) // Falls schon gestoppt
|
||||||
Serial.printf("\n\r[SEQ1] Playback started");
|
{
|
||||||
|
// Starte neu
|
||||||
|
sb1.setLoop(false);
|
||||||
|
sb1.startPlay();
|
||||||
|
Serial.printf("\n\r[SEQ1] Playback started (single)");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Ist am Spielen - ermittle ob Loop aktiv ist
|
||||||
|
// Wir testen das indirekt: Wenn ein Sequencer am Ende angekommen ist
|
||||||
|
// und noch spielt, dann muss Loop aktiv sein
|
||||||
|
// Alternative: Wir tracken den Loop-Status selbst
|
||||||
|
static bool seq1_loop_active = false;
|
||||||
|
|
||||||
|
if(!seq1_loop_active)
|
||||||
|
{
|
||||||
|
// 2. Klick: Loop aktivieren
|
||||||
|
sb1.setLoop(true);
|
||||||
|
seq1_loop_active = true;
|
||||||
|
Serial.printf("\n\r[SEQ1] Loop activated");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// 3. Klick: Stop
|
||||||
|
sb1.stopPlay();
|
||||||
|
seq1_loop_active = false;
|
||||||
|
Serial.printf("\n\r[SEQ1] Playback stopped");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -144,23 +167,40 @@ void handleSequencerButtons()
|
|||||||
{
|
{
|
||||||
if(sb2.isPlaying()) sb2.stopPlay();
|
if(sb2.isPlaying()) sb2.stopPlay();
|
||||||
sb2.startRecord();
|
sb2.startRecord();
|
||||||
Serial.printf("\n\r[SEQ2] Recording started...");
|
Serial.printf("\n\r[SEQ2] Recording started (2 channels)...");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sequencer 2 Play Button
|
// Sequencer 2 Play Button - 3 Modi: Play / Loop / Stop
|
||||||
if(readButton(PIN_SB_2_PLAY, btn_sb2_play))
|
if(readButton(PIN_SB_2_PLAY, btn_sb2_play))
|
||||||
{
|
{
|
||||||
if(sb2.isPlaying())
|
static bool seq2_loop_active = false;
|
||||||
|
|
||||||
|
if(!sb2.isPlaying())
|
||||||
{
|
{
|
||||||
sb2.stopPlay();
|
// Nicht am Spielen -> Starte Playback (ohne Loop)
|
||||||
Serial.printf("\n\r[SEQ2] Playback stopped");
|
if(sb2.isRecording()) sb2.stopRecord();
|
||||||
|
sb2.setLoop(false);
|
||||||
|
seq2_loop_active = false;
|
||||||
|
sb2.startPlay();
|
||||||
|
Serial.printf("\n\r[SEQ2] Playback started (single)");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if(sb2.isRecording()) sb2.stopRecord();
|
if(!seq2_loop_active)
|
||||||
sb2.startPlay();
|
{
|
||||||
Serial.printf("\n\r[SEQ2] Playback started");
|
// 2. Klick: Loop aktivieren
|
||||||
|
sb2.setLoop(true);
|
||||||
|
seq2_loop_active = true;
|
||||||
|
Serial.printf("\n\r[SEQ2] Loop activated");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// 3. Klick: Stop
|
||||||
|
sb2.stopPlay();
|
||||||
|
seq2_loop_active = false;
|
||||||
|
Serial.printf("\n\r[SEQ2] Playback stopped");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -175,13 +215,16 @@ void setup()
|
|||||||
sb1.setLoop(false);
|
sb1.setLoop(false);
|
||||||
sb2.setLoop(false);
|
sb2.setLoop(false);
|
||||||
|
|
||||||
Serial.printf("\n\r=== Sequencer System Started ===");
|
Serial.printf("\n\r=== Dual-Channel Sequencer System Started ===");
|
||||||
Serial.printf("\n\rControls:");
|
Serial.printf("\n\rControls:");
|
||||||
Serial.printf("\n\r PIN_SB_1_REC: SEQ1 Record Start/Stop");
|
Serial.printf("\n\r PIN_SB_1_REC: SEQ1 Record Start/Stop (CH1+CH2)");
|
||||||
Serial.printf("\n\r PIN_SB_1_PLAY: SEQ1 Play/Stop");
|
Serial.printf("\n\r PIN_SB_1_PLAY: SEQ1 Play Mode Toggle:");
|
||||||
Serial.printf("\n\r PIN_SB_2_REC: SEQ2 Record Start/Stop");
|
Serial.printf("\n\r 1st click: Play once");
|
||||||
Serial.printf("\n\r PIN_SB_2_PLAY: SEQ2 Play/Stop");
|
Serial.printf("\n\r 2nd click: Loop mode");
|
||||||
Serial.printf("\n\r================================\n\r");
|
Serial.printf("\n\r 3rd click: Stop");
|
||||||
|
Serial.printf("\n\r PIN_SB_2_REC: SEQ2 Record Start/Stop (CH1+CH2)");
|
||||||
|
Serial.printf("\n\r PIN_SB_2_PLAY: SEQ2 Play Mode (same as SEQ1)");
|
||||||
|
Serial.printf("\n\r==============================================\n\r");
|
||||||
}
|
}
|
||||||
|
|
||||||
void loop()
|
void loop()
|
||||||
@@ -195,71 +238,54 @@ void loop()
|
|||||||
|
|
||||||
int n = keyboard.getQueueLength();
|
int n = keyboard.getQueueLength();
|
||||||
|
|
||||||
// Keyboard-Tasten verarbeiten
|
// Aktuelle Spannungen für beide Kanäle ermitteln
|
||||||
|
uint16_t voltage_ch1 = 0;
|
||||||
|
uint16_t voltage_ch2 = 0;
|
||||||
|
|
||||||
if(n > 0)
|
if(n > 0)
|
||||||
{
|
{
|
||||||
// Alle Keyboard-Tasten für CV-Ausgabe verwenden
|
Key k1 = keyboard.getQueue(0);
|
||||||
int cvIndex = 0;
|
if(!isNotKey(k1))
|
||||||
for(int i = 0; i < n && cvIndex < N_CV_GATES; i++)
|
|
||||||
{
|
{
|
||||||
Key k = keyboard.getQueue(i);
|
voltage_ch1 = keyToVoltage[k1.row * N_KEYBOARD_COL + k1.col];
|
||||||
if(!isNotKey(k))
|
|
||||||
{
|
|
||||||
uint16_t voltage = keyToVoltage[k.row * N_KEYBOARD_COL + k.col];
|
|
||||||
|
|
||||||
// Bei Recording: Spannung aufnehmen
|
|
||||||
if(sb1.isRecording())
|
|
||||||
{
|
|
||||||
sb1.addStep(voltage);
|
|
||||||
}
|
|
||||||
if(sb2.isRecording())
|
|
||||||
{
|
|
||||||
sb2.addStep(voltage);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Live-Ausgabe nur wenn nicht gerade wiedergegeben wird
|
|
||||||
if(!sb1.isPlaying() && !sb2.isPlaying())
|
|
||||||
{
|
|
||||||
cv.setVoltage(cvIndex++, k);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Restliche CV-Ausgänge auf 0 setzen wenn live gespielt wird
|
if(n > 1)
|
||||||
if(!sb1.isPlaying() && !sb2.isPlaying())
|
{
|
||||||
|
Key k2 = keyboard.getQueue(1);
|
||||||
|
if(!isNotKey(k2))
|
||||||
{
|
{
|
||||||
for(int i = cvIndex; i < N_CV_GATES; i++)
|
voltage_ch2 = keyToVoltage[k2.row * N_KEYBOARD_COL + k2.col];
|
||||||
{
|
|
||||||
cv.setVoltage(i, 0);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Bei Recording: Beide Kanäle aufnehmen
|
||||||
|
if(sb1.isRecording())
|
||||||
|
{
|
||||||
|
sb1.addStep(voltage_ch1, voltage_ch2);
|
||||||
|
}
|
||||||
|
if(sb2.isRecording())
|
||||||
|
{
|
||||||
|
sb2.addStep(voltage_ch1, voltage_ch2);
|
||||||
|
}
|
||||||
|
|
||||||
|
// CV-Ausgabe: Priorität hat Sequencer-Wiedergabe
|
||||||
|
if(sb1.isPlaying())
|
||||||
|
{
|
||||||
|
cv.setVoltage(0, sb1.getCurrentVoltageCh1());
|
||||||
|
cv.setVoltage(1, sb1.getCurrentVoltageCh2());
|
||||||
|
}
|
||||||
|
else if(sb2.isPlaying())
|
||||||
|
{
|
||||||
|
cv.setVoltage(0, sb2.getCurrentVoltageCh1());
|
||||||
|
cv.setVoltage(1, sb2.getCurrentVoltageCh2());
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Keine Tasten gedrückt
|
// Live-Ausgabe wenn kein Sequencer spielt
|
||||||
if(sb1.isRecording())
|
cv.setVoltage(0, voltage_ch1);
|
||||||
{
|
cv.setVoltage(1, voltage_ch2);
|
||||||
sb1.addStep(0);
|
|
||||||
}
|
|
||||||
if(sb2.isRecording())
|
|
||||||
{
|
|
||||||
sb2.addStep(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!sb1.isPlaying() && !sb2.isPlaying())
|
|
||||||
{
|
|
||||||
cv.clearAll();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Sequencer-Wiedergabe auf CV-Ausgänge
|
|
||||||
if(sb1.isPlaying())
|
|
||||||
{
|
|
||||||
cv.setVoltage(0, sb1.getCurrentVoltage());
|
|
||||||
}
|
|
||||||
if(sb2.isPlaying())
|
|
||||||
{
|
|
||||||
cv.setVoltage(1, sb2.getCurrentVoltage());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Time-Limit Warnung
|
// Time-Limit Warnung
|
||||||
@@ -267,12 +293,16 @@ void loop()
|
|||||||
{
|
{
|
||||||
sb1.stopRecord();
|
sb1.stopRecord();
|
||||||
Serial.printf("\n\r[SEQ1] Time limit reached! Recording stopped.");
|
Serial.printf("\n\r[SEQ1] Time limit reached! Recording stopped.");
|
||||||
|
Serial.printf("\n\r[SEQ1] Final: Steps: %i, Duration: %ims",
|
||||||
|
sb1.getStepCount(), sb1.getTotalDuration());
|
||||||
}
|
}
|
||||||
if(sb2.isRecording() && sb2.timeLimitReached())
|
if(sb2.isRecording() && sb2.timeLimitReached())
|
||||||
{
|
{
|
||||||
sb2.stopRecord();
|
sb2.stopRecord();
|
||||||
Serial.printf("\n\r[SEQ2] Time limit reached! Recording stopped.");
|
Serial.printf("\n\r[SEQ2] Time limit reached! Recording stopped.");
|
||||||
|
Serial.printf("\n\r[SEQ2] Final: Steps: %i, Duration: %ims",
|
||||||
|
sb2.getStepCount(), sb2.getTotalDuration());
|
||||||
}
|
}
|
||||||
|
|
||||||
delay(10); // Kürzeres Delay für bessere Sequencer-Auflösung
|
delay(10);
|
||||||
}
|
}
|
||||||
@@ -54,7 +54,7 @@ Die eigentliche __Diplomarbeit__ und die dazugehörigen (finalen) Fertigungsunte
|
|||||||
## TO-DO Liste
|
## TO-DO Liste
|
||||||
- [x] Literaturrechreche
|
- [x] Literaturrechreche
|
||||||
- [x] Schaltungsentwurf
|
- [x] Schaltungsentwurf
|
||||||
- [ ] Simulationen
|
- [x] Simulationen
|
||||||
- [ ] Gesamt System zusammengeführt
|
- [ ] Gesamt System zusammengeführt
|
||||||
- [ ] Prototyp entwickeln und bestellen (Deadline: Bis Weihnachtsferien)
|
- [ ] Prototyp entwickeln und bestellen (Deadline: Bis Weihnachtsferien)
|
||||||
- [ ] Start Diplomarbeit dokumentieren
|
- [ ] Start Diplomarbeit dokumentieren
|
||||||
|
|||||||
1
lab/VCF/Aufbau_Steckbrett.brd
Normal file
1
lab/VCF/Aufbau_Steckbrett.brd
Normal file
File diff suppressed because one or more lines are too long
BIN
lab/VCF/Aufbau_Steckbrett.png
Normal file
BIN
lab/VCF/Aufbau_Steckbrett.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 99 KiB |
BIN
lab/VCF/TEK0000.JPG
Normal file
BIN
lab/VCF/TEK0000.JPG
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 181 KiB |
BIN
lab/VCF/TEK0001.JPG
Normal file
BIN
lab/VCF/TEK0001.JPG
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 159 KiB |
BIN
lab/VCF/VCF.xlsx
Normal file
BIN
lab/VCF/VCF.xlsx
Normal file
Binary file not shown.
Reference in New Issue
Block a user