Construye una Radio FM Estilo Retro con Módulo TEA5767 - Guía DIY Paso a Paso
Componentes y Suministros
| Componente | Descripción | Cantidad |
|---|---|---|
| Arduino Nano R3 | Microcontrolador principal | 1 |
| Módulo Radio FM TEA5767 | Chip sintonizador FM Philips | 1 |
| Medidores analógicos de radio antigua | Indicadores aguja: señal y frecuencia | 2 |
| Pantalla LCD Adafruit 16x2 Blanco/Azul | Escala de frecuencia visual | 1 |
| Potenciómetro estéreo 10k logarítmico | Control de volumen | 1 |
| Módulo amplificador Clase D 2x3W | Amplificación audio estéreo | 1 |
| Altavoz 3W, 4 ohm (2 vías) | Altavoz principal agudos/graves | 2 |
| Altavoz 0.25W, 8 ohm | Altavoz agudos separado | 2 |
| Encoder Rotativo con Pulsador | Sintonía y cambio modo auto/manual | 1 |
| Pulsador SparkFun 12mm | td>Teclas memoria predefinidas4 | |
| Condensador 1µF | Filtro paso alto para tweeters | 2 |
| LED (genérico) | Indicadores: estéreo, auto/manual | 3 |
Aplicaciones y Servicios Online
- Arduino IDE - Entorno de desarrollo
Sobre el Proyecto
Basado en el código de Rodolfo Broco Manin (RodLophus en GitHub) que incluye una bonita escala analógica en LCD 16x2. He modificado su código añadiendo:
- Dos medidores analógicos de aguja para nivel de señal y frecuencia
- LED "Estéreo" y LED "Auto/Búsqueda Manual"
- Cuatro teclas de memoria con frecuencias predefinidas en código (aspecto retro/antiguo)
Las salidas de audio del TEA5767, vía potenciómetro estéreo, conectan al amplificador Clase D 2x3W (suficiente potencia). A la salida del amplificador van dos altavoces de 2 vías. El tweeter (agudos) se separa del woofer (graves-medios) con condensador 1µF. Los medidores analógicos son de una radio antigua averiada, pero puede usarse cualquier medidor; la desviación completa de la aguja se ajusta con potenciómetros multivuelta (trimmers).
El dispositivo se alimenta con dos baterías de litio en serie a través de un regulador 7805, proporcionando 5V estabilizados.
Librería TEA5767 para Arduino: GitHub TEA5767
Diagrama de circuito y código a continuación.
Nota: La aguja del medidor de frecuencia se actualiza escalonadamente cada 1MHz (limitación de la librería). Si alguien logra movimiento suave, se agradecería la solución. Recepción excelente en emisoras locales fuertes; en débiles hay interrupciones estéreo/mono frecuentes. Próxima actualización: interruptores "estéreo/mono" y "mute".
Todo el conjunto va en caja apropiada con antena telescópica: receptor FM estéreo completo con look retro.
Código
/* Sintonizador radio simple con Arduino Leonardo y módulo Philips TEA5767 (versión Arduino Uno)
Notas:
- TEA5767 voltaje máx 5V. Asegurar que Arduino no suministre >5V
- TEA5767 no actualiza indicador nivel señal en lectura; solo en cambio de emisora
- Si hay glitches en encoder/pulsador, usar red snubber:
Pin Arduino >----+----/\/\/\/---------> Pin Encoder/Interruptor
| 100Ohm resistor
-----
47nF cap
| ---
GND
Conexiones:
- Encoder (con pulsador en eje):
Pulsador -> Arduino pin 2
Encoder pin A -> Arduino pin 3
Encoder pin B -> Arduino pin 4
- LCD:
D7 -> pin 8, D6 -> pin 9, D5 -> pin 10, D4 -> pin 11
RS -> pin 13, RW -> GND, E -> pin 12
VO -> resistencia 2k2 a GND (contraste)
- Módulo TEA5767 (vista superior):
+-10--9--8--7--6-+
| +------+ ++ |
| | TEA | || |
| | 5767 | || |
| +------+ ++ |
+--1--2--3--4--5-+
1 -> Arduino SDA
2 -> Arduino SCL
3 -> GND
5 -> +5V
6 -> GND
7 -> Audio out (canal derecho)
8 -> Audio out (canal izquierdo)
10 -> Antena
*/
#include <LiquidCrystal.h>
#include <Wire.h>
#include <TEA5767.h>
#define ENCODER_SW 2
#define ENCODER_A 3
#define ENCODER_B 4
#define button_freq1 A0
#define button_freq2 A1
#define button_freq3 A2
#define button_freq4 A3
#define SCALE_CLEAR 5
#define STEREO_CHAR_S 6
#define STEREO_CHAR_T 7
#define ST_AUTO 0
#define ST_STEREO 1
#define ST_GO_UP 2
#define ST_GO_DOWN 3
#define ST_SEARCH 4
const int LED = 0;
int analogsignal = 0;
int analogscale = 0;
int stereoled = 0;
TEA5767 Radio;
float frequency = 88;
byte status = 0;
LiquidCrystal lcd(13, 12, 11, 10, 9, 8);
void updateScale() {
int lcdBase = (frequency - 88) * 4;
if(lcdBase > 79) lcdBase = 79;
int lcdMajor = lcdBase / 5;
int lcdMinor = lcdBase % 5;
if(lcdMajor > 0) {
lcd.setCursor(lcdMajor - 1, 0);
lcd.write(SCALE_CLEAR);
} else lcd.setCursor(lcdMajor, 0);
lcd.write(lcdMinor);
if(lcdMajor < 15) lcd.write(SCALE_CLEAR);
}
void isrEncoder() {
delay(50);
if(digitalRead(ENCODER_B) == HIGH) bitWrite(status, ST_GO_UP, 1);
else bitWrite(status, ST_GO_DOWN, 1);
}
void isrSwitch() {
delay(50);
if(bitRead(status, ST_AUTO)) bitWrite(status, ST_AUTO, 0);
else bitWrite(status, ST_AUTO, 1);
}
void setup() {
Serial.end();
pinMode(button_freq1, INPUT); digitalWrite(button_freq1, LOW);
pinMode(button_freq2, INPUT); digitalWrite(button_freq2, LOW);
pinMode(button_freq3, INPUT); digitalWrite(button_freq3, LOW);
pinMode(button_freq4, INPUT); digitalWrite(button_freq4, LOW);
pinMode(LED, OUTPUT);
pinMode(6, OUTPUT); pinMode(7, OUTPUT); pinMode(5, OUTPUT);
int i;
byte needleChar[8];
byte stereoChar1[8] = { 0b01111, 0b11000, 0b11011, 0b11101, 0b11110, 0b11000, 0b01111, 0b00000 };
lcd.createChar(STEREO_CHAR_S, stereoChar1);
byte stereoChar2[8] = { 0b11110, 0b00011, 0b10111, 0b10111, 0b10111, 0b10111, 0b11110, 0b00000 };
lcd.createChar(STEREO_CHAR_T, stereoChar2);
byte scaleChar[8] = { 0b00000, 0b00000, 0b00000, 0b00000, 0b00000, 0b00100, 0b10101, 0b10101 };
lcd.createChar(SCALE_CLEAR, scaleChar);
for(int j = 0; j < 5; j++) {
for(i = 0; i < 8; i++) needleChar[i] = scaleChar[i] | (0b10000 >> j);
lcd.createChar(j, needleChar);
}
lcd.begin(16, 2);
lcd.clear();
for(i = 0; i < 16; i++) lcd.write(SCALE_CLEAR);
pinMode(ENCODER_SW, INPUT); digitalWrite(ENCODER_SW, HIGH);
pinMode(ENCODER_A, INPUT); digitalWrite(ENCODER_A, HIGH);
pinMode(ENCODER_B, INPUT); digitalWrite(ENCODER_B, HIGH);
attachInterrupt(0, isrSwitch, RISING);
attachInterrupt(1, isrEncoder, RISING);
Wire.begin();
Radio.init();
Radio.set_frequency(frequency);
}
void loop() {
unsigned char buf[5];
int stereo, signalLevel, searchDirection, i = 0;
lcd.setCursor(12, 1);
lcd.write(bitRead(status, ST_AUTO) ? 'A' : 'M');
if(bitRead(status, ST_AUTO)) digitalWrite(LED, LOW);
else digitalWrite(LED, HIGH);
if (Radio.read_status(buf) == 1) {
frequency = floor(Radio.frequency_available(buf) / 100000 + .5) / 10;
stereo = Radio.stereo(buf);
signalLevel = (Radio.signal_level(buf) * 100) / 15;
analogsignal = map(signalLevel, 0, 100, 0, 255);
analogscale = map(frequency, 88, 114, 0, 255);
stereoled = map(stereo, 0.7, 1, 0, 255);
analogWrite(5, analogsignal); // Medidor señal
analogWrite(6, analogscale); // Medidor frecuencia
analogWrite(7, stereoled); // LED estéreo
updateScale();
lcd.setCursor(0, 1);
lcd.write(183); // Carácter antena
if(signalLevel < 100) lcd.write(' ');
lcd.print(signalLevel); lcd.write('%');
lcd.setCursor(6, 1);
if(frequency < 100) lcd.write(' ');
lcd.print(frequency, 1);
lcd.setCursor(14, 1);
if(stereo) {
lcd.write(STEREO_CHAR_S);
lcd.write(STEREO_CHAR_T);
} else lcd.print(" ");
}
if(bitRead(status, ST_SEARCH)) {
if(Radio.process_search(buf, searchDirection) == 1) {
bitWrite(status, ST_SEARCH, 0);
}
}
// Teclas memoria predefinidas
if(digitalRead(button_freq2) == HIGH) { // 94.8 MHz
if(frequency > 94.8) { frequency = 94.8; Radio.set_frequency(frequency); bitWrite(status, ST_GO_DOWN, 0); }
else { frequency = 94.8; Radio.set_frequency(frequency); bitWrite(status, ST_GO_UP, 0); }
precrtajScale();
}
if(digitalRead(button_freq1) == HIGH) { // 92.0 MHz
if(frequency > 92) { frequency = 92; Radio.set_frequency(frequency); bitWrite(status, ST_GO_DOWN, 0); }
else { frequency = 92; Radio.set_frequency(frequency); bitWrite(status, ST_GO_UP, 0); }
precrtajScale();
}
if(digitalRead(button_freq3) == HIGH) { // 97.0 MHz
if(frequency > 97) { frequency = 97; Radio.set_frequency(frequency); bitWrite(status, ST_GO_DOWN, 0); }
else { frequency = 97; Radio.set_frequency(frequency); bitWrite(status, ST_GO_UP, 0); }
precrtajScale();
}
if(digitalRead(button_freq4) == HIGH) { // 101.2 MHz
if(frequency > 101.2) { frequency = 101.2; Radio.set_frequency(frequency); bitWrite(status, ST_GO_DOWN, 0); }
else { frequency = 101.2; Radio.set_frequency(frequency); bitWrite(status, ST_GO_UP, 0); }
precrtajScale();
}
// Encoder horario (+)
if(bitRead(status, ST_GO_UP)) {
if(bitRead(status, ST_AUTO) && !bitRead(status, ST_SEARCH)) {
bitWrite(status, ST_SEARCH, 1);
searchDirection = TEA5767_SEARCH_DIR_UP;
Radio.search_up(buf);
delay(50);
} else {
if(frequency < 108) { frequency += 0.1; Radio.set_frequency(frequency); }
}
bitWrite(status, ST_GO_UP, 0);
}
// Encoder antihorario (-)
if(bitRead(status, ST_GO_DOWN)) {
if(bitRead(status, ST_AUTO) && !bitRead(status, ST_SEARCH)) {
bitWrite(status, ST_SEARCH, 1);
searchDirection = TEA5767_SEARCH_DIR_DOWN;
Radio.search_down(buf);
delay(50);
} else {
if(frequency > 88) { frequency -= 0.1; Radio.set_frequency(frequency); }
}
bitWrite(status, ST_GO_DOWN, 0);
}
}
void precrtajScale() {
int i;
lcd.clear();
for(i = 0; i < 16; i++) lcd.write(SCALE_CLEAR);
}
Esquemáticos
Proceso de manufactura
- Construya un termostato inteligente tipo NEST con Node‑RED en Raspberry Pi
- Construya una API robusta de temperatura y sensores en Raspberry Pi usando el módulo GY‑91
- Construya un Detector de Llanto de Bebé Económico con Raspberry Pi – Guía DIY
- Construye un reloj Numitron retro con Arduino: Simple, fiable y eficiente energéticamente
- Captura Gotas de Agua en Acción con Arduino Nano: Fotografía de Alta Velocidad DIY
- Construye un Skateboard VR Casero con Arduino, Google Cardboard y Bluetooth
- Construye una radio FM a prueba de agua para la ducha con Arduino Nano, RDA5807, LCD Nokia y PAM8403
- Conectar Arduino Mega a módulo GPS NEO‑6M: Guía paso a paso
- Construye un voltímetro DIY con Arduino y pantalla Nokia 5110 – Guía paso a paso
- Elecciones de diseño Bluetooth Mesh: Módulo vs. Dispositivo discreto
- Importación de Módulos en Python: Guía Práctica con Ejemplos