Fortgeschrittenes XBee Walkie-Talkie mit Arduino, DAC und Audioverstärkern
Komponenten und Zubehör
| Komponente | Menge | Hinweis |
|---|---|---|
| Goldilocks Analogue | 1 | Prototyp; funktional nachbaubar mit: MCP4822 DAC, Mikrofonverstärker, Kopfhörerverstärker + Arduino Uno |
| MAX9744 (Kopfhörerverstärker) | 1 | |
| MAX9814 (Mikrofonverstärker) | 1 | |
| MCP4921 DAC | 1 | |
| Arduino UNO | 1 | |
| Arduino Wireless Shield (XBee) | 1 |
Über dieses Projekt
Ich baue einen fortschrittlichen Arduino-Klon basierend auf dem AVR ATmega1284p mit besonderen Features: 12-Bit-DAC (MCP4822), Kopfhörerverstärker, 2× SPI-Speicher (SRAM, EEPROM), SD-Karte. Da Arduino keine integrierte DAC-Fähigkeit hat, gibt es wenige Anwendungen für analoge Signale. Ein Walkie-Talkie ist ein Beispiel für die Kombination digitaler und analoger Technik.
Die eigentliche Walkie-Talkie-Funktionalität ist nur wenige Codezeilen, basiert aber auf: analoger Eingangsabtastung, analoger Ausgabe via SPI an MCP4822 DAC, Sample-Timing-Routinen, XBee-Digitalfunkplattform. Schauen wir uns die Ebenen an.
XBee-Funk
Verwendet: XBee Pro S2B, Punkt-zu-Punkt konfiguriert. Einer als Coordinator, der andere als Router. Konfigurationsanleitungen im Netz.
Konfiguration: Maximale Inter-Zeichen-Zeit vor Paketversand → Pakete nur bei Vollständigkeit (84 Bytes) gesendet. Maximiert Datendurchsatz. Rohrate: 250 kbit/s, effektive Nutzdatenrate: ~32 kbit/s. Begrenzt Abtastrate und Sprachqualität.
Mit 8-Bit-Samples: ~3 kHz Abtastrate erzeugt gerade so viel Daten wie übertragbar ohne Kompression. Kompression für späteres Projekt.
XBees im AT-Modus → transparenter Serial-Pipe. Einfachste Verbindung zweier Geräte per Digitalfunk. Erlaubte Kabel-Tests vor Funk-Tests.
Empfangene Pakete in Ringpuffer (bis 255 Bytes, XBee-Paketgröße 84 Bytes) gespeichert, konstant wiedergegeben. Zu sendende Samples auf Tx-Leitung, gepuffert, bei vollem Paket versendet.
Abtastrate
Bitbudget: 8 Bit × 3.000 Hz = 24 kbit/s → funktioniert gut. 4 kHz zu nah am theoretischen Maximum, funktioniert schlecht.
Sample-Verarbeitung
„Ping“ auf Ausgang misst Interrupt-Dauer (gelb). Interrupt-Verarbeitung sehr kurz im Verhältnis zur Sample-Periode. Datenkompression möglich.
Im Sampling-Interrupt zwei Hauptaufgaben: Audioausgabe via DAC (Sample ablegen), ADC auslesen (Sample erfassen) → USART-Puffer. Erledigt in audioCodec_dsp, aufgerufen aus Timer-Interrupt.
AVR 8-Bit Timer0 erzeugt regelmäßige Sample-Intervalle per Interrupt. MCU-Takt als binäres Vielfaches Standard-Audiofrequenzen → präzise Raten mit 8-Bit-Timer + Prescaler 64. Für 44,1 kHz: 16-Bit Timer1.
ATmega1284p ADC im Free-Run-Modus, auf 192 kHz getaktet (nahe Max-Spec, aber innerhalb für 8-Bit). Interrupt: 14 µs bei 333 µs Periode → viel Zeit für UI/weiteres Audio-Processing.
SPI-Transaktion
Auf Goldilocks Analogue Prototyp 2: Standard-SPI-Bus. Spätere Prototypen nutzen Master-SPI-Mode am USART1 des ATmega1284p (Double-Buffering, schneller, normaler SPI frei für SD/Speicher). Für Walkie-Talkie (keine Aufzeichnung) unproblematisch.
Zusammenfassung
Mit wenigen Tools und Codezeilen: digital verschlüsseltes Walkie-Talkie, verständliche (nicht HiFi) Sprache. Keine CB-Funker mithören!
Test: Mikrofoneingang (MAX9814) am Goldilocks Analogue. Prototyp 4 wird Mikrofonverstärkung integrieren für Voice-Changer, Vokalsynthese etc.
ATmega1284p bei 24,576 MHz (statt 20 MHz) – ermöglicht präzise Audiofrequenzen von 48 kHz bis 1,5 kHz. Mehr Taktzyklen pro Sample für Synthese.
Code auf SourceForge: AVR freeRTOS. Dank an Shuyang (SeeedStudio) für OPL & Komponenten.
Code
audioCodec_dsp – Kern-DSP-Funktion
void audioCodec_dsp(uint16_t *ch_A, uint16_t *ch_B) {
int16_t xn;
uint8_t cn;
/*----- Audio Rx -----*/
if (ringBuffer_IsEmpty(&(xSerialPort.xRxedChars))) {
cn = 0x80 ^ 0x55; // A-Law Nullsignal
} else if (ringBuffer_GetCount(&(xSerialPort.xRxedChars)) > (portSERIAL_BUFFER_RX >> 1)) {
cn = ringBuffer_Pop(&(xSerialPort.xRxedChars)); // zwei Samples holen, erstes verwerfen
cn = ringBuffer_Pop(&(xSerialPort.xRxedChars));
} else {
cn = ringBuffer_Pop(&(xSerialPort.xRxedChars));
}
alaw_expand1(&cn, &xn); // A-Law dekomprimieren
*ch_A = *ch_B = (uint16_t)(xn + 0x7fff); // auf positive Werte shiften, auf A & B Kanal
/*----- Audio Tx -----*/
AudioCodec_ADC(&mod7_value.u16); // 10-bit linksbündig
xn = mod7_value.u16 - 0x7fe0; // auf 0 zentrieren
IIRFilter(&tx_filter, &xn); // TX-Filter
alaw_compress1(&xn, &cn); // A-Law komprimieren
xSerialPutChar(&xSerialPort, cn); // senden
}
Timer0-Interrupt (Sample-Rate)
ISR(TIMER0_COMPA_vect) __attribute__((hot, flatten));
ISR(TIMER0_COMPA_vect) {
#if defined(DEBUG_PING)
PORTD |= _BV(PORTD7); // Ping Start (gelb)
#endif
DAC_out(ch_A_ptr, ch_B_ptr); // DAC zuerst für Jitter-Reduktion
if (audioHandler != NULL) audioHandler(ch_A_ptr, ch_B_ptr);
#if defined(DEBUG_PING)
PORTD &= ~_BV(PORTD7); // Ping Ende
#endif
}
DAC_out – SPI an MCP4822
void DAC_out(const uint16_t *ch_A, const uint16_t *ch_B) {
DAC_command_t write;
if (ch_A != NULL) {
write.value.u16 = (*ch_A) >> 4;
write.value.u8[1] |= CH_A_OUT;
} else {
write.value.u8[1] = CH_A_OFF;
}
SPI_PORT_SS_DAC &= ~SPI_BIT_SS_DAC; // SS low
SPDR = write.value.u8[1];
while (!(SPSR & _BV(SPIF)));
SPDR = write.value.u8[0];
if (ch_B != NULL) {
write.value.u16 = (*ch_B) >> 4;
write.value.u8[1] |= CH_B_OUT;
} else {
write.value.u8[1] = CH_B_OFF;
}
while (!(SPSR & _BV(SPIF)));
SPI_PORT_SS_DAC |= SPI_BIT_SS_DAC; // SS high, latch
SPI_PORT_SS_DAC &= ~SPI_BIT_SS_DAC; // SS low für Kanal B
SPDR = write.value.u8[1];
while (!(SPSR & _BV(SPIF)));
SPDR = write.value.u8[0];
while (!(SPSR & _BV(SPIF)));
SPI_PORT_SS_DAC |= SPI_BIT_SS_DAC; // SS high, latch
}
Repository: AVR freeRTOS auf SourceForge (DAC.h, Analogue-Testfiles). Nicht das verlinkte GitHub-Repo nutzen!
Schaltpläne
Fritzing-Schaltplan nutzt MCP4725 (I²C) statt MCP4822 (SPI) – falscher Breakout in Bibliothek. Nur Einrichtungsrichtung gezeichnet (Rx/Tx gekreuzt). XBee-Boards ersetzen die zwei Drähte zwischen Rx/Tx. Jedes Funksystem mit ausreichender Datenrate funktioniert.
Zusatz: DAC-Ausgang & Kopfhörerverstärker. Mikrofonverstärker kommt in Prototyp 4.
Herstellungsprozess
- Wichtige Überlegungen für Hochvolumen-Swiss-Drehen
- CNC-Prototyping-Leitfaden: Präzision, Geschwindigkeit und kosteneffiziente Produktion
- Experten-Wellenfertigung: Präzisionsprozesse & kundenspezifische Lösungen
- Edelstahl-Passivierung: Korrosionsbeständigkeit & Leistung steigern
- Analoge Sensoren am Raspberry Pi mit nur einem GPIO-Pin auslesen
- MCP3008 ADC zum Auslesen analoger Sensoren mit Raspberry Pi nutzen
- Hochpräzise Wellenformgenerierung mit DAC-basiertem Custom PCB
- Smart Irrigation Controller mit Windows 10 IoT, Raspberry Pi und XBee Feuchtesensoren
- Warum analoge Messungen die Anlagenleistung antreiben
- Fortgeschrittene geschirmte Kabel für Signalleitungen: Praktische Anschlusstechniken (Teil 2)