Walkie-Talkie avanzado con XBee, Arduino, DAC y amplificadores de audio
Componentes y materiales
| Componente | Cantidad | Notas |
|---|---|---|
| Goldilocks Analogue | 1 | Prototipo; funcionalidad replicable con MCP4822 DAC, amplificador micrófono, amplificador auriculares y Arduino Uno |
| MAX9744 | 1 | Amplificador de audio |
| MAX9814 | 1 | Amplificador de micrófono |
| MCP4921 DAC | 1 | |
| Arduino UNO | 1 | |
| Shield inalámbrico Arduino (XBee) | 1 |
Sobre el proyecto
Estoy construyendo un clon avanzado de Arduino basado en el MCU AVR ATmega1284p con características especiales: DAC 12 bits MCP4822, amplificador de auriculares, 2x memoria SPI (SRAM, EEPROM) y tarjeta SD. Hay muchas aplicaciones reales para salidas analógicas, pero como Arduino no tiene DAC integrado, hay pocas aplicaciones publicadas. Un Walkie-Talkie es un ejemplo de uso de digital y analógico junto para un proyecto simple pero muy útil.
La funcionalidad real del Walkie-Talkie son solo unas líneas de código, pero se basa en: entrada analógica (muestreo), salida analógica en bus SPI al DAC MCP4822, rutinas de temporización de muestreo y plataforma de radio digital XBee.
Radio XBee
Uso radios XBee Pro S2B configuradas punto a punto. Una como Coordinador, otra como Router. Configuradas para esperar el tiempo máximo entre caracteres antes de enviar paquete (paquetes de 84 bytes), maximizando rendimiento. Throughput bruto 250 kbit/s, pero tasa real de datos de usuario ~32 kbit/s. Esto afecta la tasa de muestreo y calidad de voz.
Con muestras de 8 bits, ~3 kHz genera datos transmitibles sin compresión. La compresión queda para otro proyecto.
Las radios XBee en modo AT actúan como tubería serie transparente entre extremos. Es la forma más simple de conectar dos dispositivos por radio digital y permitió pruebas simples con cable antes de verificar la radio.
En el analizador lógico se ven paquetes XBee llegando en línea Rx (morado). Datos recibidos se guardan en buffer circular y se reproducen a tasa constante. Buffer de recepción hasta 255 bytes (paquete XBee 84 bytes).
Muestras a transmitir salen por Tx (azul), bufferizadas antes de transmisión. XBee las bufferiza hasta 0xFF periodos entre símbolos y solo transmite paquete cuando está lleno.
Tasa de muestreo
Presupuesto de bits: 8 bits x 3000 Hz = 24 kbit/s. Funciona bien. 4 kHz está muy cerca del máximo teórico y no funciona eficazmente.
Se ve llegada de paquete comenzando con 0x7E y 0x7C en Rx. Ambos, amplificador micrófono y salida DAC, están sesgados en 0x7F(FF), indicando niveles de señal muy bajos. Tasa de muestreo 3000 Hz.
Procesamiento de muestras
Puse un "ping" en una salida para capturar cuándo se procesa la interrupción de muestreo (amarillo). El tiempo en la interrupción es muy pequeño relativo al total. Posible implementar compresión de datos.
Durante la interrupción de muestreo: generar salida de audio poniendo muestra en DAC, y leer ADC para capturar muestra de audio y transmitirla al buffer USART. Hecho por función audioCodec_dsp llamada desde interrupción de timer.
Uso timer0 de 8 bits para intervalos regulares de muestreo. Con frecuencia MCU múltiplo binario de frecuencias de audio estándar, se generan tasas precisas con prescaler 64. Para frecuencias impares (44.1 kHz), timer1 de 16 bits da precisión sin prescaler.
ADC del ATmega1284p en modo free-run, escalado a 192 kHz (cerca del máximo para ADC, pero dentro de especificación para 8 bits). La interrupción toma 14 µs, muy corto comparado con 333 µs por período de muestra. Tiempo suficiente para UI u otro procesamiento.
Transacción SPI
Al detalle final, vemos la transacción SPI real para salida de muestra entrante al DAC MCP4822.
En Goldilocks Analogue Prototipo 2 uso bus SPI estándar. Prototipos posteriores usan modo Master SPI en USART1 del ATmega1284p, acelerando SPI por doble buffer y liberando bus SPI normal para SD o memoria SPI simultánea. En Walkie-Talkie no hay captura de audio, así que no hay desventaja usando bus SPI normal.
Conclusión
Con herramientas preexistentes y pocas líneas de código, es posible construir rápidamente un walkie-talkie digitalmente cifrado, capaz de comunicar voz (entendible, no alta calidad). ¡Y ningún camionero de CB va a escuchar las conversaciones familiares!
Fue prueba de añadir entrada de micrófono basada en MAX9814 a Goldilocks Analogue. Revisaré Prototipo 3 añadiendo circuito de amplificación de micrófono para aplicaciones necesitando entrada de audio: walkie-talkie, cambiadores de voz, sintetizadores musicales vocales.
Ejecuto ATmega1284p a 24.576 MHz (vs 20 MHz estándar). Esta frecuencia permite reproducción precisa de muestras de audio desde 48 kHz hasta 4 kHz (o incluso 1.5 kHz). Los ciclos extra de reloj por período de muestra son bienvenidos para síntesis musical.
Código en Sourceforge AVR freeRTOS. Mención a Shuyang en SeeedStudio cuyo OPL es genial y fuente de muchos componentes y PCBs.
Código
Función audioCodec_dsp
void audioCodec_dsp(uint16_t *ch_A, uint16_t *ch_B) {
int16_t xn;
uint8_t cn;
/*----- Audio Rx -----*/
if(ringBuffer_IsEmpty((ringBuffer_t*)&(xSerialPort.xRxedChars))) {
cn = 0x80 ^ 0x55; // señal A-Law nula en salida
} else if (ringBuffer_GetCount(&(xSerialPort.xRxedChars)) > (portSERIAL_BUFFER_RX>>1)) {
cn = ringBuffer_Pop((ringBuffer_t*)&(xSerialPort.xRxedChars));
cn = ringBuffer_Pop((ringBuffer_t*)&(xSerialPort.xRxedChars)); // descartar primera
} else {
cn = ringBuffer_Pop((ringBuffer_t*)&(xSerialPort.xRxedChars));
}
alaw_expand1(&cn, &xn);
*ch_A = *ch_B = (uint16_t)(xn + 0x7fff); // mover señal a valores positivos
/*----- Audio Tx -----*/
AudioCodec_ADC(&mod7_value.u16); // muestra 10 bits left-justified
xn = mod7_value.u16 - 0x7fe0; // centrar muestra a 0
IIRFilter(&tx_filter, &xn); // filtrar muestra transmitida
alaw_compress1(&xn, &cn); // comprimir A-Law
xSerialPutChar(&xSerialPort, cn); // transmitir muestra
}
ISR Timer0
ISR(TIMER0_COMPA_vect) __attribute__ ((hot, flatten));
ISR(TIMER0_COMPA_vect) {
#if defined(DEBUG_PING)
PORTD |= _BV(PORTD7); // Ping línea IO (amarillo)
#endif
DAC_out(ch_A_ptr, ch_B_ptr); // transferencia datos a MCP4822 - primero para regularidad
if (audioHandler != NULL) audioHandler(ch_A_ptr, ch_B_ptr); // handler global
#if defined(DEBUG_PING)
PORTD &= ~_BV(PORTD7);
#endif
}
Salida DAC
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;
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;
SPI_PORT_SS_DAC &= ~SPI_BIT_SS_DAC;
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;
}
Repositorio AVR freeRTOS
Sourceforge AVR freeRTOS - Repositorio del puerto AVR de freeRTOS, incluyendo DAC.h y archivos de prueba analógica. No usar el GitHub enlazado; ir a Sourceforge para código más reciente.
Esquemáticos
No es absolutamente correcto: usa DAC MCP4725 (I2C) no MCP4822 (SPI), Fritzing no tenía la breakout correcta de Adafruit. Solo dibujado en una dirección (excepto Rx/Tx interconectados). Las placas XBee simplemente reemplazan los dos cables que conectan Rx y Tx. Cualquier radio con suficiente ancho de banda funcionaría.
Esquemáticos para salida DAC y amplificador de auriculares. Amplificador de entrada de micrófono se añadirá en prototipo 4.
Proceso de manufactura
- Consideraciones Clave para el Mecanizado Suizo de Alto Volumen
- Guía de Prototipado CNC: Precisión, Velocidad y Producción Rentable
- Fabricación Experta de Ejes: Procesos de Precisión y Soluciones Personalizadas
- Pasivado de Acero Inoxidable: Mejora de la Resistencia a la Corrosión y Rendimiento
- Medición de Sensores Analógicos en Raspberry Pi con un Solo Pin GPIO
- Usar ADC MCP3008 para leer sensores analógicos con Raspberry Pi
- Generación de formas de onda de alta precisión con PCB personalizado basado en DAC
- Controlador de Riego Inteligente con Windows 10 IoT, Raspberry Pi y Sensores de Humedad XBee
- Dibuja Gráficos Personalizados en tu Osciloscopio con un DAC R-2R y Arduino
- Cables apantallados avanzados para circuitos de señal: técnicas prácticas de conexión (Parte 2)
- Por qué las mediciones analógicas impulsan el rendimiento de la planta