功能

1.调台
  刻度盘调台(快捷键:左右键100Khz微调)
  频道列表下拉框选台(快捷键:上下键)

2.搜台
  搜索全部频道并保存到频道列表,可选择是否还保留原有的频道
  搜索上一个可用的频道
  搜索下一个可用的频道

3.频道列表
  频道列表保存在注册表
  全部搜台自动保存和单一频道手动添加删除
  可编辑的频道名称,频道名称永久有效,不会因频道删除而消失

4.其他
  音量调节、开机/休眠,休眠恢复后回到原频道及音量
  可设置开机默认频道音量及频道搜索灵敏度阀值

硬件
  stm32F103C8T6最小板+RDA8705M

开发工具
  VS2010 C#(引用控件 LibUsbDotNet,IrisSkin)
  Keil uVision5(ST-link v2仿真)

之前都是用AVR单片机,USB就用了AVRUSB模拟的USB,简单的LED控制等都没问题。后来用AVRUSB做了个电话来电弹屏显示姓名部门的东东,需要USB一直在线就发觉AVRUSB会无原因的失去响应(单片机还活着,就是USB没有数据发到PC),还有中断传输也会不固定的丢失最后一帧数据。一直找不到原因只能怀疑洞洞板干扰了,这些问题后来也只能靠软件来解决了。

接触STM32很大的原因就是他内置了全速USB,看了例程中有声卡的代码,就想着把输出改成输入再加上收音机模块不就可以做个USB收音机了吗?说干就干。

第一步,先调通STM32 Speaker声卡例程,精简了代码,把不相干宏定义及其他硬件代码都删除,上电后都正常但一播放就报错,网上找了一遍后发现要把采样率从22k改到22.5k,可能发布时是用在winXP上是支持的,WIN7非标频率就报错了。第一步还算顺利(废话,官方代码还能有什么问题),基本上是在边改边学STM32。

第二步,把STM32声卡从播放改成录音(先用正弦波表模拟),先要修改USB描述符,没方向网上找,过程不说了,最后是对照着USB官网音频类文档最后的USB Microphone例子一点一点改的。

上电后能识别、录音设备中也有了,说明描述符修改OK。为了方便将采样率设到16k(关键不知道22k每帧怎么分配),从最简单的8位单声道开始,直接定义了个16字节正弦波表,每次EP1_IN的时候将这些数据发送出去模拟麦克风数据,这样如果正常应该能听到1Khz的声波。接下来就改程序了,思路很简单,所有与EP1同步端口相关的设置都反一反,out变in,rx变tx,下载上电后没声音,用Bus Hound看了下,每个同步都报错。仿真调试也没用,因为就是进不了EP1_IN中断。

接下来又是到处找到处改一直试,断断续续弄了一个多月没结果。最后只能单步执行并查手册检查寄存器,马上找到原因 ,原来改这行时SetEPRxStatus(ENDP1, EP_RX_VALID)时只把参数的RX改到了TX,而函数名却没有改,等于没有启用发送。改好后喇叭中终于发出‘嘟’的声音了。一大半的时间都花在这上面还好最后搞定了。

第三步,搞定FM模块和ADC;FM模块我买了两种:TEA5767和RDA5807,测收音机代码时因RDA5807能直接推动耳机所以就一直就用RDA5807了。RDA5807的信号很好,不接天线都能收到很多台,不过底噪较大且与音量无关,不知道5767能否好点?R

DA5807用了网上现成的代码,上电后程序中直接调到信号最好的频道。ADC端口连接FM左声道,在每次定时器16K的中断中读取ADC数据并手动开启下一次转换,EP1_IN时用ADC数据代替正弦波表模拟数据,现在插入usb就能听到广播了,音质还是可以的,只是没有上位机不能控制调台。本来还考虑处理USB的断流和溢出问题,后来看了下什么都不做好像也没什么问题的。

第四步,上位机程序开发。windows开发只会C#,USB库用了LibUsbDotNet,好处是不用开发驱动,也很简单几句代码就可以了。上位机基本控制(调台、音量、开关、收音机状态回传)都通过EP0的控制传输,在usb_prop.c中增加相应代码处理就可以了。这样有了上位机的操作最基本的USB收音机就算做好了。

不过搜索频道时有了问题,全部频道搜索大概要十多秒才能完成,用控制传输早就超时了,所以只能再增加中断传输端口了,搜到一个台就发送一个数据,同时也能在上位机中显示搜索状态。USB原有的2个接口都是标准音频类的,我也不确定加了中断端口是否会有影响,就再开第3个接口吧(用到输入输出2个端点,其实1个输入端点就可以了,为代码验证搜台就都用了中断端点,因同步端点将来要增加缓存,将同步端口改到了EP2,EP1用作中断端口),命名为Usb Radio Control。

原来audio标准类是不需要驱动,现在加了个普通接口就需要驱动程序了(如改成HID类也可以是无驱的),很简单用LibUsbDotNet的USB InfWizard生成就可以了。USB开发其实是比较复杂的,USB协议、描述符、PC驱动,上位机等等,最大的问题是电脑驱动和上位机,好像还都需要用C++,我觉得一大半的单片机学习者都没有经验的,想象下你做了个USB控制LED这样最简单的单片机程序却没有上位机测试时该何等的尴尬?这里强烈推荐下LibUsbDotNet,有.net经验的(C#,VB)都能很快上手,而在这个程序中也演示了控制传输和中断传输的使用方法。

最后,原想着要优化代码,将采样率和采样位数增加到32k/16bit,改成立体声,USB的断流和溢出问题也应该处理下。不过后来看到个有趣的东东,这些就都还没有动。看RDA5807手册时发现支持RDS(radio broadcast data system),就是电台可以在广播的同时发送一些数据如电台名称、节目名词、交通状况等,试了下上海有两个电台支持,读取RDA5807的RDS数据简单分析后能读到电台名称和时间还有‘高德欢迎你’的文本。

电台名称和时间这些没太大意思,有高德就代表有路况信息,公司有辆新昊锐,内置的导航没有网络支持也能显示实时路况,当时不知道是什么原理,现在知道就是RDS-TMC。试着找资料解析TMC数据。TMC的报文由方向、范围、事件、位置等组成。

方向和范围很简单,事件也有字典解释比如拥堵几公里、修路等到底发生了什么情况,但位置信息只有编码方式却没找到对应的数据库解析,没有位置数据库TMC也就解析不了具体发生在那里了,不知道是否有人研究过这个东西能提供下了。

资料下载链接:http://pan.baidu.com/s/1nvm1ahr