基于平头哥RSIC-V RVB2601的网络收音机设计(2)
<p style="list-style-type:none">1、<span style="font-size:10.5pt"><span style="font-family:等线"><span style="font-family:宋体">概述</span></span></span></p><p style="text-align:justify; text-indent:21pt"><span style="font-size:10.5pt"><span style="font-family:等线"><span style="font-family:宋体">一般收音机主要使用过天线接收到电磁波,然后对电磁波进行放大</span><span lang="EN-US" style="font-family:Wingdings">à</span><span style="font-family:宋体">滤波</span><span lang="EN-US" style="font-family:Wingdings">à</span><span style="font-family:宋体">混频</span><span lang="EN-US" style="font-family:Wingdings">à</span><span style="font-family:宋体">中频</span><span lang="EN-US" style="font-family:Wingdings">à</span><span style="font-family:宋体">解调</span><span lang="EN-US" style="font-family:Wingdings">à</span><span style="font-family:宋体">播放这样的流程。整个收音机的数据来源主要来自于空气中的电磁波,电磁波信号质量的强弱直接决定了音质的好坏。</span></span></span></p>
<p style="text-align:justify; text-indent:21pt"><span style="font-size:10.5pt"><span style="font-family:等线"><span style="font-family:宋体">而网络收音机则是通过网络向特定的服务器下载音乐,然后播放,相比于普通收音机具有音质好,易操作的特点等。</span></span></span></p>
<p align="center" style="text-align:center; text-indent:0cm"></p>
<p align="center" style="text-align:center; text-indent:0cm"><span style="font-size:10.5pt"><span style="font-family:等线"><span style="font-size:7.5pt"><span style="font-family:宋体">图</span></span><span lang="EN-US" style="font-size:7.5pt"><span style="font-family:"AxMath",serif">1</span></span> <span style="font-size:7.5pt"><span style="font-family:宋体">网络收音机原理</span></span></span></span></p>
<p style="text-align:justify; text-indent:21pt"><span style="font-size:10.5pt"><span style="font-family:等线"><span style="font-family:宋体">通过对图</span><span lang="EN-US" style="font-family:"AxMath",serif">1</span><span style="font-family:宋体">的分析可以发现,网络收音机最重要的地方是数据的来源。作为网络收音机主主流的数据来源是蜻蜓</span><span lang="EN-US" style="font-family:"Cambria",serif">FM</span><span style="font-family:宋体">,但是在实际操作过程中发现蜻蜓</span><span lang="EN-US" style="font-family:"Cambria",serif">FM</span><span style="font-family:宋体">的接口比较麻烦,最后选择网易云音乐的接口作为网络收音机的数据来源。</span></span></span></p>
<p style="text-align:justify; text-indent:21pt"><span style="font-size:10.5pt"><span style="font-family:等线"><span style="font-family:宋体">网易云音乐接口的</span><span lang="EN-US" style="font-family:"Cambria",serif">API</span><span style="font-family:宋体">地址为:</span><span lang="EN-US" style="font-family:"Cambria",serif">https://neteasecloudmusicapi.vercel.app/#/?id=neteasecloudmusicapi</span></span></span></p>
<p style="text-align:justify; text-indent:21pt"><span style="font-size:10.5pt"><span style="font-family:等线"><span style="font-family:宋体">通过接口可以实现几乎所有的音乐播放器功能,介于</span><span lang="EN-US" style="font-family:"AxMath",serif">RVB2601</span><span style="font-family:宋体">的资源比较紧张,在实现网络连接的同时还需要实现对</span><span lang="EN-US" style="font-family:"AxMath",serif">mp3</span><span style="font-family:宋体">的解码,</span><span lang="EN-US" style="font-family:"AxMath",serif">OLED</span><span style="font-family:宋体">显示和按键操作等功能,因此本文主要实现根据音乐名称查找音乐,当然也可以根据歌手名称来查找音乐。</span></span></span></p>
<p style="text-align:justify; text-indent:21pt"><span style="font-size:10.5pt"><span style="font-family:等线"><span style="font-family:宋体">网易云音乐查找功能主要通过搜索标签里面的</span><span lang="EN-US" style="font-family:"AxMath",serif">GET</span><span style="font-family:宋体">请求实现。</span></span></span></p>
<p align="center" style="text-align:center; text-indent:0cm"></p>
<p> </p>
<p align="center" style="text-align:center; text-indent:0cm"><span style="font-size:10.5pt"><span style="font-family:等线"><span style="font-size:7.5pt"><span style="font-family:宋体">图</span></span><span lang="EN-US" style="font-size:7.5pt"><span style="font-family:"AxMath",serif">2</span></span> <span style="font-size:7.5pt"><span style="font-family:宋体">网易云音乐查找接口</span></span></span></span></p>
<p style="text-align:justify; text-indent:21pt"><span style="font-size:10.5pt"><span style="font-family:等线"><span style="font-family:宋体">通过接口的描述可以知道,如果我们要搜索刘德华的音乐,同时每次只返回</span><span lang="EN-US" style="font-family:"AxMath",serif">3</span><span style="font-family:宋体">条结果</span><span lang="EN-US" style="font-family:"AxMath",serif">(</span><span style="font-family:宋体">网易云音乐接口默认每次返回</span><span lang="EN-US" style="font-family:"AxMath",serif">30</span><span style="font-family:宋体">条结果,这样的数据量大概是</span><span lang="EN-US" style="font-family:"AxMath",serif">400k</span><span style="font-family:宋体">,单片机的内存受不了</span><span lang="EN-US" style="font-family:"AxMath",serif">)</span><span style="font-family:宋体">,另外</span><span lang="EN-US" style="font-family:"AxMath",serif">RVB</span><span style="font-family:宋体">内部没有中文字库,因此所有的字符都需要使用英文来表示,而刘德华可以用拼音</span><span lang="EN-US" style="font-family:"AxMath",serif">liudehua</span><span style="font-family:宋体">来表示,最终</span><span lang="EN-US" style="font-family:"AxMath",serif">GET</span><span style="font-family:宋体">请求的</span><span lang="EN-US" style="font-family:"AxMath",serif">url</span><span style="font-family:宋体">为</span></span></span></p>
<p style="text-align:justify; text-indent:21pt"><span style="font-size:10.5pt"><span style="font-family:等线"><span lang="EN-US" style="font-family:"AxMath",serif">http://cloud-music.pl-fe.cn/search?limit=3&keywords=liudehua&offset=10</span></span></span></p>
<p style="text-align:justify; text-indent:21pt"><span style="font-size:10.5pt"><span style="font-family:等线"><span style="font-family:宋体">使用单片机通过对上面的</span><span lang="EN-US" style="font-family:"AxMath",serif">url</span><span style="font-family:宋体">完成</span><span lang="EN-US" style="font-family:"AxMath",serif">GET</span><span style="font-family:宋体">请求后,会返回一个</span><span lang="EN-US" style="font-family:"AxMath",serif">JSON</span><span style="font-family:宋体">,下面是浏览器的测试结果</span></span></span></p>
<p align="center" style="text-align:center; text-indent:0cm"></p>
<p align="center" style="text-align:center; text-indent:0cm"></p>
<p align="center" style="text-align:center; text-indent:0cm"><span style="font-size:10.5pt"><span style="font-family:等线"><span style="font-size:7.5pt"><span style="font-family:宋体">图</span></span><span lang="EN-US" style="font-size:7.5pt"><span style="font-family:"AxMath",serif">3</span></span> <span style="font-size:7.5pt"><span style="font-family:宋体">通过接口返回的音乐</span></span><span lang="EN-US" style="font-size:7.5pt"><span style="font-family:"Cambria",serif">id</span></span><span style="font-size:7.5pt"><span style="font-family:宋体">和详情的</span></span><span lang="EN-US" style="font-size:7.5pt"><span style="font-family:"Cambria",serif">json</span></span></span></span></p>
<p style="text-align:justify; text-indent:21pt"><span style="font-size:10.5pt"><span style="font-family:等线"><span style="font-family:宋体">在返回的</span><span lang="EN-US" style="font-family:"AxMath",serif">json</span><span style="font-family:宋体">数据里面,</span><span lang="EN-US" style="font-family:"AxMath",serif">json</span><span style="font-family:宋体">的头是</span><span lang="EN-US" style="font-family:"AxMath",serif">result</span><span style="font-family:宋体">,每一首音乐后面都会有一个</span><span lang="EN-US" style="font-family:"AxMath",serif">id</span><span style="font-family:宋体">,然后通过这个</span><span lang="EN-US" style="font-family:"AxMath",serif">id</span><span style="font-family:宋体">就可以在网易云音乐的曲库中查找到一个音乐的</span><span lang="EN-US" style="font-family:"AxMath",serif">mp3</span><span style="font-family:宋体">链接,而通过</span><span lang="EN-US" style="font-family:"AxMath",serif">id</span><span style="font-family:宋体">查找音乐的</span><span lang="EN-US" style="font-family:"AxMath",serif">url</span><span style="font-family:宋体">为</span></span></span></p>
<p style="text-align:justify; text-indent:21pt"><span style="font-size:10.5pt"><span style="font-family:等线"><span lang="EN-US" style="font-family:"AxMath",serif">http://music.163.com/api/song/enhance/player/url?id=554191989&ids=%5B554191989%5D&br=3200000</span></span></span></p>
<p style="text-align:justify; text-indent:21pt"><span style="font-size:10.5pt"><span style="font-family:等线"><span style="font-family:宋体">其中</span><span lang="EN-US" style="font-family:"AxMath",serif">ids</span><span style="font-family:宋体">后面的</span><span lang="EN-US" style="font-family:"AxMath",serif">%5B</span><span style="font-family:宋体">与</span><span lang="EN-US" style="font-family:"AxMath",serif">%5D</span><span style="font-family:宋体">是固定的,</span><span lang="EN-US" style="font-family:"AxMath",serif">br</span><span style="font-family:宋体">也是固定的。这样在获取每一首音乐的时候就转化为通过</span><span lang="EN-US" style="font-family:"AxMath",serif">search</span><span style="font-family:宋体">接口查找曲目的</span><span lang="EN-US" style="font-family:"AxMath",serif">id</span><span style="font-family:宋体">,再通过上面的</span><span lang="EN-US" style="font-family:"AxMath",serif">url</span><span style="font-family:宋体">结合</span><span lang="EN-US" style="font-family:"AxMath",serif">id</span><span style="font-family:宋体">通过</span><span lang="EN-US" style="font-family:"AxMath",serif">GET</span><span style="font-family:宋体">请求得到一个包含真实音乐链接的</span><span lang="EN-US" style="font-family:"AxMath",serif">json</span><span style="font-family:宋体">,</span><span lang="EN-US" style="font-family:"AxMath",serif">json</span><span style="font-family:宋体">内容如下</span></span></span><br />
</p>
<p style="text-indent: 21pt; text-align: center;"> </p>
<p style="text-align:justify; text-indent:21pt"></p>
<p align="center" style="text-align:center; text-indent:0cm"><span style="font-size:10.5pt"><span style="font-family:等线"><span style="font-size:7.5pt"><span style="font-family:宋体">图</span></span><span lang="EN-US" style="font-size:7.5pt"><span style="font-family:"AxMath",serif">4</span></span> <span style="font-size:7.5pt"><span style="font-family:宋体">通过</span></span><span lang="EN-US" style="font-size:7.5pt"><span style="font-family:"Cambria",serif">get</span></span><span style="font-size:7.5pt"><span style="font-family:宋体">请求包含真实音乐信息的</span></span><span lang="EN-US" style="font-size:7.5pt"><span style="font-family:"Cambria",serif">json</span></span></span></span></p>
<p style="text-align:justify; text-indent:21pt"><span style="font-size:10.5pt"><span style="font-family:等线"><span style="font-family:宋体">然后这个</span><span lang="EN-US" style="font-family:"AxMath",serif">json</span><span style="font-family:宋体">里面的</span><span lang="EN-US" style="font-family:"AxMath",serif">url</span><span style="font-family:宋体">就是真实的音乐,再把这个</span><span lang="EN-US" style="font-family:"AxMath",serif">url</span><span style="font-family:宋体">通过</span><span lang="EN-US" style="font-family:"AxMath",serif">mp3</span><span style="font-family:宋体">播放即可,下面就是如何通过单片机来完成这一过程。</span></span></span></p>
<p style="list-style-type:none">2、<span style="font-size:10.5pt"><span style="font-family:等线"><span style="font-family:宋体">在单片机中完成</span><span lang="EN-US" style="font-family:"AxMath",serif">GET</span><span style="font-family:宋体">请求和</span><span lang="EN-US" style="font-family:"AxMath",serif">JSON</span><span style="font-family:宋体">解析</span></span></span></p>
<p style="text-align:justify; text-indent:21pt"><span style="font-size:10.5pt"><span style="font-family:等线"><span style="font-family:宋体">由于单片机的资源比较紧张,对于资源能省则省。通过跟踪例程中通过命令行播放音乐的函数调用发现例程中已经有一部分</span><span lang="EN-US" style="font-family:"AxMath",serif">GET</span><span style="font-family:宋体">请求的功能,因此准备复用其中的一部分功能。</span></span></span></p>
<p style="text-align:justify; text-indent:21pt"><span style="font-size:10.5pt"><span style="font-family:等线"><span style="font-family:宋体">原来的请求是通过下面的流程完成的</span></span></span><br />
</p>
<p align="center" style="text-align:center; text-indent:0cm"><span style="font-size:10.5pt"><span style="font-family:等线"><span style="font-size:7.5pt"><span style="font-family:宋体">图</span></span><span lang="EN-US" style="font-size:7.5pt"><span style="font-family:"AxMath",serif">5</span></span> <span style="font-size:7.5pt"><span style="font-family:宋体">原来的</span></span><span lang="EN-US" style="font-size:7.5pt"><span style="font-family:"Cambria",serif">get</span></span><span style="font-size:7.5pt"><span style="font-family:宋体">请求过程</span></span></span></span></p>
<p style="text-align:justify; text-indent:21pt"><span style="font-size:10.5pt"><span style="font-family:等线"><span style="font-family:宋体">通过分析可以发现,原始的请求通过层层调用,最终在</span><span lang="EN-US" style="font-family:"AxMath",serif">_read_resp_hdr(,,)</span><span style="font-family:宋体">中接收到数据,由于</span><span lang="EN-US" style="font-family:"AxMath",serif">_read_resp_hdr</span><span style="font-family:宋体">中只接收了响应头,因此没有办法接收到完整的</span><span lang="EN-US" style="font-family:"AxMath",serif">json</span><span style="font-family:宋体">段,需要对此进行改进修改。</span></span></span></p>
<p style="text-align:justify; text-indent:21pt"><span style="font-size:10.5pt"><span style="font-family:等线"><span style="font-family:宋体">根据上述的流程,下面开始构建</span><span lang="EN-US" style="font-family:"AxMath",serif">get</span><span style="font-family:宋体">请求</span><span lang="EN-US" style="font-family:"AxMath",serif">json</span><span style="font-family:宋体">的函数。</span></span></span></p>
<p style="text-align:justify; text-indent:21pt"><span style="font-size:10.5pt"><span style="font-family:等线"><span style="font-family:宋体">首先由于响应的</span><span lang="EN-US" style="font-family:"AxMath",serif">json</span><span style="font-family:宋体">比较大,返回</span><span lang="EN-US" style="font-family:"AxMath",serif">3</span><span style="font-family:宋体">个搜索结果都需要将近</span><span lang="EN-US" style="font-family:"AxMath",serif">3k</span><span style="font-family:宋体">的空间,本身给函数的堆空间又比较小,因此在</span><span lang="EN-US" style="font-family:"AxMath",serif">.c</span><span style="font-family:宋体">中定义一个全局数组</span><span lang="EN-US" style="font-family:"AxMath",serif">char dbuf</span></span></span></p>
<p style="text-align:justify; text-indent:21pt"></p>
<p style="text-align:justify; text-indent:21pt"><span style="font-size:10.5pt"><span style="font-family:等线"><span style="font-family:宋体">这个数组就是</span><span lang="EN-US" style="font-family:"AxMath",serif">json</span><span style="font-family:宋体">的缓存数组,第一步对其空间进行清零,然后再使用</span><span lang="EN-US" style="font-family:"AxMath",serif">strcat</span><span style="font-family:宋体">拼接</span><span lang="EN-US" style="font-family:"AxMath",serif">url</span><span style="font-family:宋体">链接,然后调用自己编写的</span><span lang="EN-US" style="font-family:"AxMath",serif">wjson_get(wsession_t *, const char *, int,char *)</span><span style="font-family:宋体">函数,</span><span lang="EN-US" style="font-family:"AxMath",serif">wsession_t *</span><span style="font-family:宋体">类型的指针通过调用</span><span lang="EN-US" style="font-family:"AxMath",serif">wsession_create()</span><span style="font-family:宋体">为其分配内存,不过这里有一个疑问,</span><span lang="EN-US" style="font-family:"AxMath",serif">CH2601</span><span style="font-family:宋体">应该没有</span><span lang="EN-US" style="font-family:"AxMath",serif">MMU</span><span style="font-family:宋体">单元,如果这样重复分配几次内存估计后面出现许多问题。</span></span></span></p>
<p style="text-align:justify; text-indent:21pt"><span style="font-size:10.5pt"><span style="font-family:等线"><span style="font-family:宋体">在</span><span lang="EN-US" style="font-family:"AxMath",serif">wjson_get(,,,)</span><span style="font-family:宋体">中再调用</span><span lang="EN-US" style="font-family:"AxMath",serif">rc = resp_json_menu(session, 3000,dbuf);</span><span style="font-family:宋体">获取</span><span lang="EN-US" style="font-family:"AxMath",serif">json</span><span style="font-family:宋体">,整个原理和前面的过程大同小异,</span><span lang="EN-US" style="font-family:"AxMath",serif">resp_json_menu(,,,)</span><span style="font-family:宋体">再调用</span><span lang="EN-US" style="font-family:"AxMath",serif"> rc = _read_resp_player_menu(session, dbuf, timeout_ms);</span><span style="font-family:宋体">然后在</span><span lang="EN-US" style="font-family:"AxMath",serif">_read_resp_player_menu(,,)</span><span style="font-family:宋体">里面完成对</span><span lang="EN-US" style="font-family:"AxMath",serif">json</span><span style="font-family:宋体">的接收。</span></span></span></p>
<p style="text-align:justify; text-indent:21pt"><span style="font-size:10.5pt"><span style="font-family:等线"><span style="font-family:宋体">与原始接收响应头有所区别的地方是,这里判断响应中有</span><span lang="EN-US" style="font-family:"AxMath",serif">{</span><span style="font-family:宋体">就表示</span><span lang="EN-US" style="font-family:"AxMath",serif">JSON</span><span style="font-family:宋体">数据开始了,尽管有许多问题和隐患,但是通过对多次网易云接口响应的数据来看,这样设计是可以的,同时也符合能省则省的原则</span></span></span>。</p>
<p style="text-align:justify; text-indent:21pt"></p>
<p style="text-align:justify; text-indent:21pt"><span style="font-size:10.5pt"><span style="font-family: 宋体;">这样收到</span><span lang="EN-US" style="font-family: AxMath, serif;">json</span><span style="font-family: 宋体;">数据之后需要从里面解析出歌曲名称和</span><span lang="EN-US" style="font-family: AxMath, serif;">id</span><span style="font-family: 宋体;">,最简单的思路是使用</span><span lang="EN-US" style="font-family: AxMath, serif;">cjson</span><span style="font-family: 宋体;">来完成,实际发现一旦使用</span><span lang="EN-US" style="font-family: AxMath, serif;">cjson</span><span style="font-family: 宋体;">整个程序的内存就爆掉了,本身资源就比较紧张,决定还是自己手动拆解</span><span lang="EN-US" style="font-family: AxMath, serif;">json</span><span style="font-family: 宋体;">,从里面拿到曲目名称和</span><span lang="EN-US" style="font-family: AxMath, serif;">id</span><span lang="EN-US" style=""><font face="宋体">。</font></span></span></p>
<pre style="text-indent:21.0pt">
<span style="font-size:12pt"><span style="font-family:宋体">通过分析可以发现,曲目的<span lang="EN-US" style="font-family:"AxMath",serif">id</span>和名称都是在<span lang="EN-US" style="color:black">[{"id"</span><span style="color:black">或者},{"id"后面,因此重点比对这段字符,具体的比对过程是通过一个指针ch,ch每次只移动1位,然后再一次抓取ch后面7位字符进行比对,如果发现是上面的两个固定字符串那么铁定就是歌曲的id和名称了</span></span></span></pre>
<p style="text-align:justify; text-indent:21pt"><span style="font-size:10.5pt"><span style="font-family:等线"><span style="color:black">这样拿到id和名称之后,再通过向</span><span lang="EN-US" style="font-family:"AxMath",serif"><a href="http://music.163.com/api/song/enhance/player/url?id=id&ids=%5Bid%5D&br=3200000" style="color:#0563c1; text-decoration:underline">http://music.163.com/api/song/enhance/player/url?id=id&ids=%5Bid%5D&br=3200000</a></span><span style="font-family:宋体">请求就可以得到歌曲的播放链接</span></span></span></p>
<p style="text-align:justify; text-indent:21pt"><span style="font-size:10.5pt"><span style="font-family:等线"><span lang="EN-US" style="font-family:"AxMath",serif">json</span><span style="font-family:宋体">解析过程如下</span></span></span></p>
<pre style="text-indent:21.0pt">
</pre>
<p style="text-align:justify; text-indent:21pt"><span style="font-size:10.5pt"><span style="font-family:等线"><span style="font-family:宋体">最后就完成了对网易云音乐的数据请求,网络收音机的核心部分就完成了,整个函数调用可以概括为</span></span></span><br />
</p>
<p align="center" style="text-align:center; text-indent:0cm"><span style="font-size:10.5pt"><span style="font-family:等线"><span style="font-size:7.5pt"><span style="font-family:宋体">图</span></span><span lang="EN-US" style="font-size:7.5pt"><span style="font-family:"AxMath",serif">6</span></span><span lang="EN-US" style="font-size:7.5pt"><span style="font-family:"Cambria",serif"> get</span></span><span style="font-size:7.5pt"><span style="font-family:宋体">请求</span></span><span lang="EN-US" style="font-size:7.5pt"><span style="font-family:"Cambria",serif">id</span></span><span style="font-size:7.5pt"><span style="font-family:宋体">和曲目名称过程概括</span></span></span></span></p>
<p style="list-style-type:none"><span style="font-size:10.5pt">3、<span style="font-family: 宋体;">总结</span></span></p>
<p style="text-align:justify; text-indent:21pt"><span style="font-size:10.5pt"><span style="font-family:等线"><span lang="EN-US" style="font-family:"AxMath",serif">json</span><span style="font-family:宋体">一般都使用</span><span lang="EN-US" style="font-family:"AxMath",serif">cjson</span><span style="font-family:宋体">进行处理,但是网易响应过来的</span><span lang="EN-US" style="font-family:"AxMath",serif">json</span><span style="font-family:宋体">太长了,没办法用专门的软件处理,使用这样非正常的手段实属无奈之举。</span></span></span></p>
<p style="text-align:justify; text-indent:21pt"><span style="font-size:10.5pt"><span style="font-family:等线"><span style="font-family:宋体">另外响应过来的数据中还有相当的一部分没有使用,如果屏幕能够显示完成是可以使用那一部分数据的。同时也发现播放音乐的核心就是</span><span lang="EN-US" style="font-family:"AxMath",serif">id</span><span style="font-family:宋体">,拿到</span><span lang="EN-US" style="font-family:"AxMath",serif">id</span><span style="font-family:宋体">之后再请求数据即可。</span></span></span></p>
高糊图片 墨文@ 发表于 2022-3-20 21:28
高糊图片
<p>我反馈下技术</p>
<p>你用了网络功能之后还能使用lvgl作为显示吗?我这边显示SRAM溢出了</p>
hehung 发表于 2022-3-21 11:29
你用了网络功能之后还能使用lvgl作为显示吗?我这边显示SRAM溢出了
<p>我没有用lvgl了,使用打点阵的方式显示文字。</p>
墨文@ 发表于 2022-3-21 13:16
我没有用lvgl了,使用打点阵的方式显示文字。
<p>好的,我也打算这么做,不然SRAM不够用呀<img height="28" src="https://bbs.eeworld.com.cn/static/editor/plugins/hkemoji/sticker/facebook/lying-face_1f925.png" width="28" /></p>
<p>今天有个网友和我说json解析的事儿,感觉资源不够</p>
<p>我先把你这个帖子分享过去,不知道有没有帮助</p>
<p>你的帖子,还需同步到平头哥社区一份,<a href="https://bbs.eeworld.com.cn/thread-1197314-1-1.html" target="_blank">>>点此查看如何同步</a>。</p>
页:
[1]