描述
<h3 style="line-height:1.8;">* 1、项目功能介绍</h3>
<hr>
<p>随着时代的发展,大众日常娱乐更加青睐各种视频节目。但是无论如何,FM 广播有着接收成本低廉,分散的注意力有限(迄今为止我只听说过针对司机朋友的交通广播,并未见过针对司机的交通视频)等等优势,因此 FM 广播永远不会消失。</p>
<p>同样的,自己制作一个 FM 收音机也是电子爱好者踏入无线电领域的必经之路。</p>
<p>这次,使用国产 WCH 出品的 CH32V305 ,配合 RDA5807 制作一个 USB FM 收音机。</p>
<p style="line-height:1.8;"> </p>
<h3 style="line-height:1.8;">*2、项目属性</h3>
<hr>
<p>原创项目,首次公开</p>
<p style="line-height:1.8;"> </p>
<h3 style="line-height:1.8;">* 3、开源协议</h3>
<hr>
<p>GPL 3.0 开源协议</p>
<p style="line-height:1.8;"> </p>
<p style="line-height:1.8;"><strong><span style="color:#0093e6;">请在竞赛阶段填写 ↓</span></strong></p>
<p style="line-height:1.8;"> </p>
<h3 style="line-height:1.8;">*4、硬件部分</h3>
<hr>
<p>硬件上选择 RDA5807 作为 FM 接收和处理芯片,是上海锐迪科(RDA)推出的一款高集成度单芯片FM收音解决方案。这款芯片支持两种工作模式:全自动收音机模式和单片机控制模式。二者通过上电时引脚的 Strapping 来区分。全自动收音机模式下,上电之后就是一个收音机,通过引脚即可实现选台自动搜索等等功能;单片机控制模式下是通过外部的单片机使用 I2C 接口进行控制,这样可以更加灵活,比如,在外界屏幕上显示当前的频率等等。此外,这个芯片可以通过模拟输出接收的音频,还可以使用 I2S 接口进行输出。I2S 是纯数字型号,最大限度的避免干扰。</p>
<p>为了控制RDA5807, 这里选择 CH32V305 作为主控。它是一款支持USB High Speed 的单片机,为了更好的压缩体积,选择QFN28封装的CH32V305GBU6型号。这种封装在保证体积的情况下,提供了足够多的引脚便于实现功能。这个芯片通过I2C 总线控制 RDA5807, 然后通过I2S 接收音频信号,再通过代码将自身模拟为一个 USB 麦克风设备,这样就能将收到的 FM 广播传输到电脑中。</p>
<p>需要注意RDA5807 的Pin6 是工作模式选择,上电拉低意味着单片机控制模式。</p>
<p>此外,RDA5807 的GPIO0/1/2 分别对应 I2S WS/SD/SCK 功能。</p>
<p>为了尽量的提升音质,设计上预留了LP5907MFX-3.3作为 5V转3.3V,但是实际测试下来国产的XC6206P332MR 已经足够。</p>
<p><img src="//image.lceda.cn/pullimage/r5S9cD3sVIJCA8mJ5TdLCBnxaZ3r6CGLTa15bouK.png" alt="r5S9cD3sVIJCA8mJ5TdLCBnxaZ3r6CGLTa15bouK.png"></p>
<p>为了尽可能保证接收效果,避免干扰,PCB 使用4层板, I2S 信号位于中间层,上下的铜箔层保证I2S 不会干扰 模拟接收。</p>
<p><img src="//image.lceda.cn/pullimage/4FZHXCUlSA3Wnu95GEB7qt4JvZCMGG3k9l1Ppbmg.png" alt="4FZHXCUlSA3Wnu95GEB7qt4JvZCMGG3k9l1Ppbmg.png"></p>
<p> </p>
<p>外壳同样是立创EDA 设计,上下结构通过螺丝进行固定</p>
<p style="line-height:1.8;"><img src="//image.lceda.cn/pullimage/A5OXugmur7JwK5hZGV97d7zUTYo2MMgq9GmsAgo7.png" alt="A5OXugmur7JwK5hZGV97d7zUTYo2MMgq9GmsAgo7.png"></p>
<h3 style="line-height:1.8;">*5、软件部分</h3>
<hr>
<p>软件包括两部分:固件的设计和应用程序的设计</p>
<p>第一部分:固件设计</p>
<p>代码是基于官方的Ch372 例子修改而来,关键代码首先是描述符部分,该设备实现了 <strong>UAC 1.0 </strong><strong>麦克风 + HID</strong> 的复合设备。其中的麦克风是用于设备将FM 音频传递给主机, HID 负责应用程序将命令发送给设备</p>
<p><strong>High Speed USB </strong><strong>带有3 </strong><strong>个接口:</strong></p>
<p><strong>Interface 0 — </strong><strong>音频控制</strong></p>
<ul>
<li>拓扑链:Input Terminal (ID=4, Microphone) → Feature Unit (ID=5, 支持静音) → Output Terminal (ID=6, USB Streaming)</li>
<li>无端点</li>
</ul>
<p><strong>Interface 1 — </strong><strong>音频流传输</strong></p>
<ul>
<li>Alternate 0:零带宽(无端点,空闲状态)</li>
<li>Alternate 1:激活流,<strong>EP3 IN</strong><strong>(ISO</strong><strong>)</strong><ul>
<li>格式:PCM Type I,<strong>双声道,</strong><strong>16-bit</strong><strong>,48 kHz</strong></li>
<li>最大包大小:196 字节(48+1 样本补偿用于速率匹配)</li>
<li>HS 模式:bmAttributes = 0x05(Isochronous | Async)</li>
</ul></li>
</ul>
<p><strong>Interface 2 — HID</strong><strong>接口</strong></p>
<ul>
<li>EP1 IN + EP1 OUT,均为 Interrupt,包大小 64 字节,间隔 1ms</li>
<li>HID Report 为 Vendor Defined(Usage Page 0xFF00),64 字节 IN / 64 字节 OUT,用于自定义控制命令</li>
</ul>
<p>这样设置之后,插入Windows主机就会出现麦克风设备和一个自定的 HID设备。</p>
<p><img src="//image.lceda.cn/pullimage/ATsxJmTfC1wvG8cwgFCzMUNOvUbAc2YT55xTDdoo.png" alt="ATsxJmTfC1wvG8cwgFCzMUNOvUbAc2YT55xTDdoo.png"></p>
<p> </p>
<p>接下来,在USBHS_Device_Endp_Init() 函数中设置端点属性,特别是 USBHSD->ENDP_TYPE = USBHS_UEP3_T_TYPE; 指定表示 <strong>EP3 </strong><strong>的 TX </strong><strong>方向(IN</strong><strong>)设置为 ISO </strong><strong>同步传输类型</strong>。之后的处理就和常见的 Bulk 之类没有太大区别了。</p>
<p>需要注意的是,对于音频USB设备,缓冲是必不可少的设计。整体架构是一个 <strong>I2S DMA </strong><strong>双缓冲 → </strong><strong>环形缓冲区 → USB ISO </strong><strong>端点</strong> 的三级流水线,用于吸收 I2S 采样时钟与 USB SOF 时钟之间的频率漂移。</p>
<p><strong>第一级:I2S DMA </strong><strong>双缓冲(硬件层)</strong></p>
<p>I2S2_Rx[2 × (192/2)] = I2S2_Rx[192 个 uint16]</p>
<p>├── 前半([0..95]) — 一个 ISO 包 (192 字节)</p>
<p>└── 后半([96..191]) — 一个 ISO 包 (192 字节)</p>
<p>DMA1_Channel4 以<strong>循环模式</strong>将 SPI2/I2S 的 RX FIFO 不停搬运到 I2S2_Rx:</p>
<ul>
<li><strong>HT</strong><strong>(半传输中断标志)置位</strong>:前半已满,DMA 正在写后半 → 主循环安全拷贝前半</li>
<li><strong>TC</strong><strong>(传输完成标志)置位</strong>:后半已满,DMA 正在写前半 → 主循环安全拷贝后半</li>
</ul>
<p>这是经典的<strong>乒乓缓冲</strong>,保证 DMA 写和 CPU 读不冲突。</p>
<p><strong>第二级:字节环形缓冲区(软件层)</strong></p>
<p>USBHS_EP3_Buf[RINGBUFFERNUMBER × 192] = 1920 字节 (10 包)</p>
<p>三个变量管理:</p>
<table>
<tr>
<td>
<p><strong>变量</strong></p>
</td>
<td>
<p><strong>含义</strong></p>
</td>
</tr>
<tr>
<td>
<p><a target="_blank">tail</a></p>
</td>
<td>
<p>写指针(I2S 写入位置)</p>
</td>
</tr>
<tr>
<td>
<p><a target="_blank">head</a></p>
</td>
<td>
<p>读指针(USB 消费位置)</p>
</td>
</tr>
<tr>
<td>
<p><a target="_blank">counter</a></p>
</td>
<td>
<p>当前字节数(填充量)</p>
</td>
</tr>
</table>
<p>目标填充水位 AUDIO_CENTER = 960 字节(5 包),两侧各留 5 包的漂移余量。</p>
<p><strong>第三级:USB </strong><strong>速率自适应(流控层)</strong></p>
<p>每次 EP3 的 TX_CTRL 变为 NAK(表示上一包已发出,可准备下一包)时,主循环判断:</p>
<p>未预填充 (audio_primed=0):</p>
<p> → 发静音包,等待 counter ≥ 960 字节后置 primed=1</p>
<p> </p>
<p>预填充完成 (audio_primed=1):</p>
<p> counter > 960+4 → 发 49 个采样帧(196 字节) ← buffer 偏高,多发</p>
<p> counter < 960-4 → 发 47 个采样帧(188 字节) ← buffer 偏低,少发</p>
<p> 否则 → 发 48 个采样帧(192 字节) ← 正常</p>
<p> 若 counter < nbytes(欠载)→ 发静音,重回预填充阶段</p>
<p>是 <strong>异步 ISO </strong><strong>的软件速率匹配</strong>(Async Isochronous),通过每包加减一帧(±4 字节)来平滑 I2S 实际采样率(约 47872 Hz,受 144MHz 时钟精度限制)与 USB 主机消费速率(48000 Hz)之间的差异,避免产生周期性爆音。</p>
<p><strong>整体数据流</strong></p>
<p>RDA5807 (I2S slave)</p>
<p> │ Philips I2S / 16bit / 48k / Stereo</p>
<p> ▼</p>
<p>SPI2 DATAR ──DMA1_Ch4 循环──▶ I2S2_Rx[192](双缓冲)</p>
<p> │ HT/TC 标志,主循环轮询</p>
<p> ▼</p>
<p> RingWrite() ──▶ USBHS_EP3_Buf[1920](环形缓冲)</p>
<p> │ 速率自适应,主循环</p>
<p> ▼</p>
<p> EP3_Tx[200](临时包缓冲)</p>
<p> │ DMA 地址写入寄存器</p>
<p> ▼</p>
<p> USBHSD UEP3 ISO IN ──▶ USB Host</p>
<p>固件定义了三个命令通过 USB HID 发送:每次发送 64Bytes,第一个字节为 ‘T表示后面是要设置的频率,为字符串格式,比如:要求设置频率为107Mhz,那么发送给设备的命令是 “T:10700”;此外,设计上通过 RDA5807 接收FM 信号,额外定义一个读取命令 ‘R’ , 后面跟着要读取的寄存器,比如,要读取 RDA5807 的 0x2 寄存器,发送的 HID 命令是:“R2”, 返回16Bits的寄存器值;还有一个写入取命令 ‘R’,比如,要对RDA5807 的 0x2 寄存器写入 34,发送的 HID 命令是:“W2=34”</p>
<p>烧录上述固件后,可以将设备设置为“监听”模式,这样设备的声音可以通过扬声器不停的播放出来,然后使用 HID 工具直接发送命令这样即可方便的进行调试。</p>
<p>之后,开始Window下应用程序的设计。</p>
<p>选择使用 C# .net 4.8 ,这个版本Windows10/11 内置直接支持,无需额外安装库。同时可以将用到的库都打包在同一个 EXE 中便于分发使用。</p>
<p><img src="//image.lceda.cn/pullimage/Y7VtZciSiVngRQAEbsp29G0aCK4aMybtIGRWAvFT.png" alt="Y7VtZciSiVngRQAEbsp29G0aCK4aMybtIGRWAvFT.png"></p>
<p>代码基本流程是</p>
<ol>
<li><strong>构造 RadioDeviceController</strong> → 通过 HidSharp 库按 VID=0x1A84, PID=0xFE09 搜索 USB 设备并打开 HID 流</li>
<li><strong>加载配置</strong> → 从 radio_config.json 读取预设电台和扫描结果</li>
<li><strong>枚举录音设备</strong> → AudioPlayer.GetAllRecordingDeviceNames() 列出可用的 USB 音频输入设备</li>
<li><strong>检查麦克风权限</strong> → 无设备则弹窗警告</li>
</ol>
<p>然后等待用户操作</p>
<p> </p>
<h3 style="line-height:1.8;">*6、BOM清单</h3>
<hr>
<p style="line-height:1.8;"><span style="color:#95a5a6;font-size:14px;">请输入内容…</span></p>
<p style="line-height:1.8;"> </p>
<p style="line-height:1.8;"><span style="color:#95a5a6;font-size:14px;">注:项目涉及的BOM清单。在<span style="text-decoration:underline;"><a href="https://lceda.cn/editor" target="_blank">嘉立创EDA</a> </span>生成/上传设计文件后,BOM将自动生成至项目详情;建议包括型号、品牌、名称、封装、采购渠道、用途等内容。具体内容和形式应以表达清楚项目构成为准。 </span></p>
<p style="line-height:1.8;"> </p>
<h3 style="line-height:1.8;">*7、大赛LOGO验证</h3>
<hr>
<p style="line-height:1.8;"> </p>
<p style="line-height:1.8;"><img src="//image.lceda.cn/pullimage/ySMVQ5ukNA15ABpnaqyR4oAPPMbC2T3xiWAtp0lC.png" alt="ySMVQ5ukNA15ABpnaqyR4oAPPMbC2T3xiWAtp0lC.png"></p>
<p style="line-height:1.8;"> </p>
<h3 style="line-height:1.8;">* 8、演示您的项目并录制成视频上传</h3>
<hr>
<p style="line-height:1.8;"> </p>
<p style="line-height:1.8;"><span style="color:#95a5a6;font-size:14px;">视频要求:请横屏拍摄,分辨率不低于1280×720,格式Mp4/Mov,单个视频大小限50M内;</span></p>
<p style="line-height:1.8;"><span style="color:#95a5a6;font-size:14px;">视频标题:立创电赛:{项目名称}-{视频模块名称};如立创电赛:《自动驾驶》-团队介绍。</span></p>
<p style="line-height:1.8;"><span style="color:#95a5a6;font-size:14px;">视频冲榜:项目制作过程中,可随时录制视频上传至B站、小红书、视频号、抖音号,<a style="text-decoration:underline;" href="https://doc.weixin.qq.com/smartsheet/form/1_wpmhMpBwAAfrKELBBSNdSqJrorjTQE8Q_600d71" target="_blank">冲榜人气奖励 ></a>,优秀项目可获得立创官方全域曝光机会;</span></p>
<p style="line-height:1.8;"> </p>
<p style="line-height:1.8;"><span style="font-size:14px;"><a style="text-decoration:underline;" href="/posts/b2b65ad17ac34080a318a5ab47a632c2" target="_blank">前往查看更多详情 ></a></span></p>
<p style="line-height:1.8;"> </p>
评论(0)