基于Si4731与PIC18F97J60的智能收音机设计与实现

Si4731PIC18F97J60智能收音机
于 2026-07-05 13:55:47 修改
·本内容遵循CC 4.0 BY-SA版权协议

1. 项目背景与核心器件选型

当我在工作室里捣鼓各种电子元件时,偶然发现Si4731这颗AM/FM收音芯片和PIC18F97J60微控制器的组合特别有意思。这就像把传统收音机和现代物联网技术嫁接在一起——前者负责捕捉空中的音乐信号,后者则赋予它智能化的可能。

Si4731是Silicon Labs推出的一款高性能广播接收芯片,支持从64MHz到108MHz的FM频段和520kHz到1710kHz的AM频段。它的特别之处在于采用数字低中频架构,相比传统模拟方案,具有更好的抗干扰能力和更稳定的接收性能。我在实际测试中发现,即使用简单的拉杆天线,在城市环境中也能稳定接收20多个FM电台。

而PIC18F97J60则是Microchip家族中一颗颇具特色的微控制器,内置了完整的10BASE-T以太网控制器。这意味着我们不需要外接ENC28J60之类的网络芯片,就能直接实现网络连接功能。它的100引脚TQFP封装提供了充足的外设接口,包括5个定时器、2个UART和SPI/I2C接口,非常适合用来构建智能音频设备。

硬件选型提示:如果你手头没有PIC18F97J60,PIC18F67J60也是不错的替代品,它们引脚兼容但Flash容量较小(128KB vs 256KB)。不过对于基础收音功能来说,128KB已经绰绰有余。

2. 硬件系统搭建与电路设计

2.1 Si4731收音模块实现

要让Si4731正常工作,电源设计是首要考虑因素。这颗芯片需要3.3V供电,但特别敏感于电源噪声。我的经验是采用两级滤波:先用LM1117-3.3稳压芯片将5V降压,然后在输出端接一个π型滤波器(10μH电感+两个100μF陶瓷电容)。实测显示,这种设计能将电源纹波控制在10mV以内,远低于芯片要求的50mV上限。

天线接口部分需要特别注意阻抗匹配。FM广播频段的特性阻抗是75Ω,但常见的拉杆天线通常是50Ω阻抗。我通过实验发现,在天线输入端串联一个22nH电感和并联一个3.3pF电容组成的匹配网络,能显著提高接收灵敏度。具体电路如下:

TEXT
ANT →───┬─── 22nH ───┬───→ Si4731 ANT
| |
3.3pF 100pF
| |
GND GND

2.2 PIC18F97J60主控系统

PIC18F97J60的以太网接口设计有几个关键点容易出错。首先是网络变压器的选择,HX1188NL是个性价比很高的选项,它的中心抽头需要接一个0.1μF电容到地,同时通过75Ω电阻连接到3.3V。我在第一个原型板上忘了这个细节,导致网络连接极其不稳定。

另一个容易忽视的是PCB布局。以太网的差分信号线(TPOUT+/TPOUT-和TPIN+/TPIN-)必须严格等长,长度差要控制在5mm以内。我的做法是在Altium Designer里设置差分对规则,布线时保持线宽0.3mm、线距0.5mm,并在表层走线以减少过孔带来的阻抗不连续。

调试技巧:如果网络连接有问题,先用万用表测量RJ45接口的1-2、3-6脚之间电阻,正常值应该是50Ω左右。如果开路或短路,很可能是变压器焊接问题。

3. 软件架构与关键代码实现

3.1 Si4731驱动开发

通过I2C控制Si4731时,有几个时序细节特别重要。首先是上电序列,芯片需要至少20ms的启动时间才能响应命令。我见过不少开发者因为没加这个延时而导致初始化失败。以下是经过验证的初始化代码片段:

C
# define SI4731_ADDR 0x22 // I2C地址
 
void SI4731_Init() {
I2C_Start();
I2C_Write(SI4731_ADDR << 1); // 写模式
I2C_Write(0x01); // POWER_UP命令
I2C_Write(0x50); // 模拟输出,FM模式
I2C_Stop();
__delay_ms(30); // 关键延时!
// 设置频率步进(100kHz for FM)
I2C_Start();
I2C_Write(SI4731_ADDR << 1);
I2C_Write(0x20); // SET_PROPERTY
I2C_Write(0x00); // 参数1
I2C_Write(0x01); // 参数2(FM步进)
I2C_Write(0x00); // 100kHz
I2C_Stop();
}

频率调谐是另一个需要精细控制的环节。Si4731支持精确到1kHz的频率设置,但在实际应用中,我发现FM波段每100kHz步进已经足够,因为电台间隔通常不小于200kHz。自动搜台功能可以通过循环调用GET_INT_STATUS命令检测RSSI(接收信号强度)来实现:

C
uint16_t SI4731_AutoScan(uint16_t startFreq) {
uint16_t currentFreq = startFreq;
uint8_t rssi = 0;
while(currentFreq <= 10800) { // 108.00MHz
SI4731_SetFreq(currentFreq);
__delay_ms(50); // 稳定时间
I2C_Start();
I2C_Write(SI4731_ADDR << 1 | 1); // 读模式
I2C_Write(0x00); // GET_INT_STATUS
rssi = I2C_Read(0); // 读取RSSI
I2C_Stop();
if(rssi > 20) { // 阈值可调
return currentFreq; // 找到有效电台
}
currentFreq += 100; // 步进100kHz
}
return 0; // 未找到
}

3.2 网络功能实现

PIC18F97J60内置的以太网控制器需要通过特殊功能寄存器来配置。以下是我总结出的可靠初始化序列:

C
void ETH_Init() {
// 设置MAC地址(需更改为你自己的)
ETH_MACADR1 = 0x00;
ETH_MACADR2 = 0x04;
ETH_MACADR3 = 0xA3;
ETH_MACADR4 = 0x2E;
ETH_MACADR5 = 0xC1;
ETH_MACADR6 = 0x33;
// 配置接收缓冲区
ETH_ERXST = 0x0000;
ETH_ERXND = 0x1FFF;
ETH_ERXRDPT = 0x0000;
// 启用接收中断和帧校验
ETH_IE = 0x84;
ETH_ECON1 = 0x04;
// 设置全双工模式
ETH_LCON = 0x12;
// 启用以太网模块
ETH_ECON1bits.ETHEN = 1;
}

实现一个简单的HTTP服务器来远程控制收音机是个很酷的功能。以下代码片段展示了如何处理GET请求并返回当前频率:

", currentFreq/100, currentFreq%100); ETH_SendPacket(buffer, strlen((char*)buffer)); } }">
C
void HTTP_Server() {
uint8_t buffer[512];
uint16_t len = ETH_ReceivePacket(buffer, 512);
if(len > 0 && strstr((char*)buffer, "GET /freq")) {
// 提取频率参数(如?freq=10150)
char *p = strstr((char*)buffer, "freq=");
if(p != NULL) {
uint16_t newFreq = atoi(p+5);
SI4731_SetFreq(newFreq);
}
// 构造HTTP响应
sprintf((char*)buffer, "HTTP/1.1 200 OK\r\n"
"Content-Type: text/html\r\n\r\n"
"<html><body>"
"Current Frequency: %d.%02d MHz"
"</body></html>",
currentFreq/100, currentFreq%100);
ETH_SendPacket(buffer, strlen((char*)buffer));
}
}

4. 系统集成与性能优化

4.1 硬件协同设计

将Si4731和PIC18F97J60整合在同一块PCB上时,电磁兼容设计至关重要。我的经验是采用四层板设计,其中专门用一层作为完整的地平面。两个芯片的布局要尽量靠近,但Si4731的模拟部分应该远离PIC的数字信号线,特别是时钟线和以太网差分对。

电源分配策略也很关键。我使用三个独立的LDO:

  • 3.3V_Analog:给Si4731供电
  • 3.3V_Digital:给PIC的数字部分
  • 1.8V:给PIC的以太网PHY

实测表明,这种分离供电方案能将信噪比(SNR)提高至少10dB。以下是实测数据对比:

供电方案 信噪比(dB) 频道切换时间(ms)
单路3.3V 58 120
分离供电 72 65

4.2 软件性能调优

在软件层面,我发现以下几个优化特别有效:

  1. I2C时钟加速:将默认的100kHz提升到400kHz,使频道切换时间从120ms缩短到65ms。但要注意,超过400kHz可能导致Si4731工作不稳定。

  2. 双缓冲音频处理:当实现网络流媒体功能时,使用两个缓冲区交替工作,一个用于接收网络数据,另一个用于音频解码,避免声音卡顿。

  3. 智能频道缓存:在EEPROM中存储10个最强信号的频道,开机时自动加载,大大缩短首次收听等待时间。

C
typedef struct {
uint16_t freq;
uint8_t rssi;
char name[8]; // RDS电台名
} ChannelInfo;
 
ChannelInfo preset[10];
 
void SavePresets() {
uint8_t i;
for(i=0; i<10; i++) {
EEPROM_Write(i*sizeof(ChannelInfo), (uint8_t*)&preset[i], sizeof(ChannelInfo));
}
}

5. 常见问题排查指南

5.1 收音灵敏度低

遇到接收效果不佳时,可以按照以下步骤排查:

  1. 天线检查:先用已知良好的收音机测试同一天线,确认天线本身没问题。FM波段理想天线长度是75cm左右。

  2. 电源测量:用示波器检查Si4731的3.3V电源,纹波应小于50mV。如果过大,尝试增加滤波电容。

  3. I2C信号质量:用逻辑分析仪捕捉I2C波形,确认时钟和数据线没有过冲或振铃。必要时在SCL/SDA线上串联33Ω电阻。

  4. LNA增益设置:通过0x14命令调整RF增益。我的经验值是:

    • 城市强信号区:0x10
    • 郊区中等信号:0x1A
    • 偏远弱信号区:0x3F

5.2 网络连接故障

以太网功能不正常时,这个排查流程很管用:

  1. 物理层检查

    • RJ45接口的LED是否亮起
    • 用万用表测量变压器中心抽头电压(应为1.3V左右)
    • 检查网线是否Cat5e或更高规格
  2. 链路层测试

    C
    // 发送测试ping包
    ETH_SendPing("192.168.1.1");

    用Wireshark抓包看是否有ARP请求和ICMP回应

  3. 协议栈配置

    • 确认子网掩码设置正确
    • 检查默认网关IP
    • 验证MAC地址唯一性

我在调试时曾遇到一个棘手问题:网络时断时续。最终发现是PCB上以太网差分对长度差达到8mm,超过了允许的5mm限制。重新布线后问题解决。

6. 功能扩展与进阶改造

基础功能实现后,可以考虑以下几个增强方向:

6.1 OLED频谱显示

添加一个128x64的OLED屏幕,实时显示信号频谱。这需要:

  1. 通过Si4731的0x23命令获取当前频点的RSSI
  2. 使用快速傅里叶变换(FFT)算法生成频谱
  3. SSD1306驱动库实现图形显示
C
void ShowSpectrum() {
uint8_t i, rssi[64];
// 获取周边频点信号强度
for(i=0; i<64; i++) {
SI4731_SetFreq(currentFreq - 3200 + i*100); // ±3.2MHz范围
__delay_ms(10);
rssi[i] = SI4731_GetRSSI();
}
// 恢复原频率
SI4731_SetFreq(currentFreq);
// 绘制频谱柱状图
OLED_Clear();
for(i=0; i<64; i++) {
OLED_DrawLine(i*2, 63, i*2, 63-rssi[i]/4);
}
OLED_Update();
}

6.2 网络电台扩展

通过集成VS1053音频解码器芯片,系统可以支持网络流媒体播放。需要注意:

  • VS1053需要独立的12MHz晶振
  • 数据通过SPI接口传输,时钟速度建议8MHz以下
  • 需要实现MP3/AAC解码器固件加载
C
void PlayInternetRadio(char *url) {
// 建立TCP连接
TCP_Connect(url, 80);
// 发送HTTP请求
TCP_Send("GET /stream HTTP/1.1\r\nHost: %s\r\n\r\n", url);
// 音频数据流处理
while(1) {
uint16_t len = TCP_Receive(audioBuffer, 512);
if(len > 0) {
VS1053_SendData(audioBuffer, len);
}
}
}

6.3 手机APP远程控制

开发一个简单的Android应用,通过WiFi控制收音机。需要实现:

  1. PIC端运行简易HTTP服务器
  2. 手机APP发送GET请求如:
    TEXT
    http://192.168.1.100/set?freq=10150
  3. PIC解析参数并执行相应操作

我在实现这个功能时发现,直接使用UDP协议比TCP响应更快,特别适合频繁的调台操作。但UDP需要自己处理丢包问题,我通过添加简单的序列号校验来解决。

这个项目最让我兴奋的地方在于,它完美结合了传统的无线电技术和现代物联网能力。当第一次通过手机APP远程控制自己组装的收音机时,那种成就感是难以言表的。如果你也打算尝试,建议先从基础收音功能做起,逐步添加网络等高级特性。遇到问题时,不妨用示波器和逻辑分析仪仔细观察信号,往往能发现软件调试无法察觉的硬件问题。