RDA5820是北京锐迪科推出的一款集成度非常高的立体声FM收发芯片。该芯片具有以下特点:
l FM发射和接收一体
l 支持65Mhz~115Mhz的全球FM接收频段,收发天线共用。
l 支持IIC/SPI接口
l 支持32.768K晶振
l 数字音量及自动AGC控制
l 支持立体声/单声道切换,带软件静音功能
l 支持I2S接口(输入/输出)
l 内置LDO,使用电压范围宽(2.7~5.5V)
l 高功率32欧负载音频输出、可直接驱动耳机
l 集成度高、功耗低、尺寸小(4mm*4mm QFN封装)、应用简单
RDA5820应用范围很宽,在很多手机、MP3、MP4甚至平板电脑上都有应用。RDA5820的引脚图如图40.1.1所示:
图40.1.1 RDA5820引脚图 RDA5820支持2种通信模式,SPI和IIC,在战舰STM32开发板上面,使用的是RDA5820的IIC模式。通过将图40.1.1的MODE脚接GND,RDA5820即进入IIC模式,此时SCLK充当IIC的SCL,SDIO充当IIC的SDA。RDA5820的IIC地址为0X11(不包含最低位),对应读为0X23,写为0X20。
模式设置
RDA5820的模式设置通过40H(寄存器地址0X40)寄存器的CHIP_FUNC[3:0]位来设置,RDA5820可以工作在RX模式、TX模式、PA模式和DAC模式等,本章我们只介绍RX模式和TX模式。
通过设置CHIP_FUNC[3:0]=0即可定义当前工作模式为FM接收模式。在该模式下,我们即可实现FM收音机功能。
通过设置CHIP_FUNC[3:0]=1即可定义当前工作模式为FM发送模式。在该模式下,我们即可实现FM电台的功能。
频点设置
软件可以通过配置03H(寄存器地址0X30)寄存器来选择FM频道。搜台(Seek)的步进长度(100KHz、200KHz或50KHz)由SPACE[1:0] 来选择,频道由CHAN[9:0]来选择,频率范围(76MHz~91MHz、87MHz~108MHz或76MHz~108MHz 或用户自定义65MHz~115MHz 范围内频段)由BAND[1:0]来选择。自定义的频段由寄存器53H(chan_bottom)和54H(chan_top)来设置,单位为100KHz,即定义65MHz~76MHz,可设置BAND[1:0]=3(用户自定义频段),并且设置chan_bottom=0x028A,chan_top=0x02f8。
频点计算方法如下(该公式也适用于FM频点的读取):
FMfreq=SPACE*CHAN+FMBTM
其中FMfreq即我们需要的FM频率(Mhz),SPACE为我们设置的步进长度(Khz),CHAN是我们设置的频点值,FMBTM则是我们在BAND里面所选频段的最低频率,当BAND=0的实惠,FMBTM=87Mhz;BAND=1的时候,FMBTM=76Mhz;BAND=2的时候,FMBTM=CHAN_BOTTOM*0.1Mhz。
例如,我们要设置FM频率为93.0Mhz,假设BAND=0,SPACE=100Khz。那么我们只需要设置CHAN=60即可。
频点设置部分,FM接收和FM发送是共用的,对两者都适用。
关于RDA5820,我们就介绍到这,详细的使用说明,请大家参考《RDA5820编程指南》和RDA5820的数据手册。
本章实验功能简介:开机默认设置FM为接收模式,设置接收频率为93.6Mhz,我们插上耳机就能听到该频率的电台。通过KEY0和KEY2,我们可以调节FM频率(发送/接收),在FM接收模式下,KEY1用于自动搜台,在FM发送模式下,KEY1无效。通过WK_UP按键切换RDA5820的工作模式(FM发送/FM接收)。在FM发送模式下,我们可以通过在多功能端口(P3)的AIN排针上面输入音频信号,就可以在收音机里面听到该音频。同时用DS0提示程序正在运行。
所要用到的硬件资源如下:
1) 指示灯DS0
2) KEY0、KEY1、KEY2和WK_UP等四个按键
3) TFTLCD模块
4) 串口(USMART使用)
5) RDA5820
6) 74HC4052
7) TDA1308
前面4个我们就不介绍了,RDA5820与STM32的连接电路如图40.2.1所示:
图40.2.1 RDA5820与STM32的连接图 这里RDA5820和之前介绍的24C02共用IIC总线,他们都是接在STM32的PB10和PB11两个脚上,上图中OUTL和OUTR接在RDA5820的LIN和RIN,OUTR和OUTL是来自音频选择器(74HC4052)的输出端,作为FM发送时的音源输入。另外RADIO_L和RADIO_R则是FM收音的音频输出,他们接在音频选择器的一对输入上面。
音频选择器(74HC4052)和耳机驱动(TDA1308)的连接电路如图40.2.2所示:
图40.2.2 音频选择器与耳机驱动连接电路图 战舰STM32开发板选择74HC4052来做音频选择器,74HC4052是一个4-2模拟选择器,可以实现4组立体声音源的切换,战舰STM32开发板有3路音源输出:FM收音机、MP3(VS1053)输出、PWM DAC输出,我们通过74HC4052实现这3路音源的切换。图中ASEL_A和ASEL_B是其控制信号,分别连接在STM32的PD7和PB7上,用于控制音源切换。OUTL和OUTR是74HC4052的输出端,被分为两路,一路接到FM发射的音频输入端,另外一路接到耳机驱动的输入端(A_OUTR和A_OUTL)。
TDA1308是一款性能十分优异(秒杀TDA2822、TDA7050等)的AB类数字音频专用耳放IC,战舰STM32搭载这颗耳机驱动,其MP3播放的音质可以打败市面上很多中低端MP3播放器。A_OUTR和A_OUTL是来自74HC4052的输出信号,作为TDA1308的输入端,经过TDA1308驱动后,输出到耳机插座。
硬件上,我们不需要做其他变动,只需找个耳机插到开发板的耳机插口,将开发板板载的天线拉出来,然后下载本章的实验例程,就可以听广播了。
打开上一章的工程,首先在HARDWARE文件夹下新建RDA5820和AUDIOSEL两个文件夹。在RDA5820文件夹下新建rda5820.c和rda5820.h两个文件。然后,在AUDIOSEL文件夹里面新建audiosel.c和audiosel.h两个文件。并将这个两个文件夹加入头文件包含路径。
打rda5820.c,输入如下代码:
#include "rda5820.h"
#include "delay.h"
//初始化
//0,初始化成功;
//其他,初始化失败.
u8 RDA5820_Init(void)
{
u16 id;
IIC_Init(); //初始化IIC口
id=RDA5820_RD_Reg(RDA5820_R00); //读取ID =0X5805
if(id==0X5805) //读取ID正确
{
RDA5820_WR_Reg(RDA5820_R02,0x0002); //软复位
delay_ms(50);
RDA5820_WR_Reg(RDA5820_R02,0xC001); //立体声,上电
delay_ms(600); //等待时钟稳定
RDA5820_WR_Reg(RDA5820_R05,0X884F);
//搜索强度8,LNAN,1.8mA,VOL最大
RDA5820_WR_Reg(0X07,0X7800);
RDA5820_WR_Reg(0X13,0X0008);
RDA5820_WR_Reg(0X15,0x1420); //VCO设置 0x17A0/0x1420
RDA5820_WR_Reg(0X16,0XC000);
RDA5820_WR_Reg(0X1C,0X3126);
RDA5820_WR_Reg(0X22,0X9C24); //fm_true
RDA5820_WR_Reg(0X47,0XF660) ; //tx rds
}else return 1;//初始化失败
return 0;
}
//写RDA5820寄存器
void RDA5820_WR_Reg(u8 addr,u16 val)
{
IIC_Start();
IIC_Send_Byte(RDA5820_WRITE); IIC_Wait_Ack(); //发送写命令
IIC_Send_Byte(addr); IIC_Wait_Ack(); //发送地址
IIC_Send_Byte(val>>8); IIC_Wait_Ack(); //发送高字节
IIC_Send_Byte(val&0XFF); IIC_Wait_Ack(); //发送低字节
IIC_Stop(); //产生一个停止条件
}
//读RDA5820寄存器
u16 RDA5820_RD_Reg(u8 addr)
{
u16 res;
IIC_Start();
IIC_Send_Byte(RDA5820_WRITE); IIC_Wait_Ack(); //发送写命令
IIC_Send_Byte(addr); IIC_Wait_Ack(); //发送地址
IIC_Start();
IIC_Send_Byte(RDA5820_READ); IIC_Wait_Ack(); //发送读命令
res=IIC_Read_Byte(1); //读高字节,发送ACK
res<<=8;
res|=IIC_Read_Byte(0); //读低字节,发送NACK
IIC_Stop(); //产生一个停止条件
return res; //返回读到的数据
}
//设置RDA5820为RX模式
void RDA5820_RX_Mode(void)
{
u16 temp;
temp=RDA5820_RD_Reg(0X40); //读取0X40的内容
temp&=0xfff0; //RX 模式
RDA5820_WR_Reg(0X40,temp) ; //FM RX模式
}
//设置RDA5820为TX模式
void RDA5820_TX_Mode(void)
{
u16 temp;
temp=RDA5820_RD_Reg(0X40); //读取0X40的内容
temp&=0xfff0;
temp|=0x0001; //TX 模式
RDA5820_WR_Reg(0X40,temp) ; //FM TM 模式
}
//得到信号强度
//返回值范围:0~127
u8 RDA5820_Rssi_Get(void)
{
u16 temp;
temp=RDA5820_RD_Reg(0X0B); //读取0X0B的内容
return temp>>9; //返回信号强度
}
//设置音量ok
//vol:0~15;
void RDA5820_Vol_Set(u8 vol)
{
u16 temp;
temp=RDA5820_RD_Reg(0X05); //读取0X05的内容
temp&=0XFFF0;
temp|=vol&0X0F;
RDA5820_WR_Reg(0X05,temp) ; //设置音量
}
//静音设置
//mute:0,不静音;1,静音
void RDA5820_Mute_Set(u8 mute)
{
u16 temp;
temp=RDA5820_RD_Reg(0X02); //读取0X02的内容
if(mute)temp|=1<<14;
else temp&=~(1<<14);
RDA5820_WR_Reg(0X02,temp) ; //设置MUTE
}
//设置灵敏度
//rssi:0~127;
void RDA5820_Rssi_Set(u8 rssi)
{
u16 temp;
temp=RDA5820_RD_Reg(0X05); //读取0X05的内容
temp&=0X80FF;
temp|=(u16)rssi<<8;
RDA5820_WR_Reg(0X05,temp) ; //设置RSSI
}
//设置TX发送功率
//gain:0~63
void RDA5820_TxPAG_Set(u8 gain)
{
u16 temp;
temp=RDA5820_RD_Reg(0X42); //读取0X42的内容
temp&=0XFFC0;
temp|=gain; //GAIN
RDA5820_WR_Reg(0X42,temp) ; //设置PA的功率
}
//设置TX 输入信号增益
//gain:0~7
void RDA5820_TxPGA_Set(u8 gain)
{
u16 temp;
temp=RDA5820_RD_Reg(0X42); //读取0X42的内容
temp&=0XF8FF;
temp|=gain<<8; //GAIN
RDA5820_WR_Reg(0X42,temp) ; //设置PGA
}
//设置RDA5820的工作频段
//band:0,87~108Mhz;1,76~91Mhz;2,76~108Mhz;3,用户自定义(53H~54H)
void RDA5820_Band_Set(u8 band)
{
u16 temp;
temp=RDA5820_RD_Reg(0X03); //读取0X03的内容
temp&=0XFFF3;
temp|=band<<2;
RDA5820_WR_Reg(0X03,temp) ; //设置BAND
}
//设置RDA5820的步进频率
//band:0,100Khz;1,200Khz;3,50Khz;3,保留
void RDA5820_Space_Set(u8 spc)
{
u16 temp;
temp=RDA5820_RD_Reg(0X03); //读取0X03的内容
temp&=0XFFFC;
temp|=spc;
RDA5820_WR_Reg(0X03,temp) ; //设置BAND
}
//设置RDA5820的频率
//freq:频率值(单位为10Khz),比如10805,表示108.05Mhz
void RDA5820_Freq_Set(u16 freq)
{
u16 temp;
u8 spc=0,band=0;
u16 fbtm,chan;
temp=RDA5820_RD_Reg(0X03); //读取0X03的内容
temp&=0X001F;
band=(temp>>2)&0x03; //得到频带
spc=temp&0x03; //得到分辨率
if(spc==0)spc=10;
else if(spc==1)spc=20;
else spc=5;
if(band==0)fbtm=8700;
else if(band==1||band==2)fbtm=7600;
else
{
fbtm=RDA5820_RD_Reg(0X53);//得到bottom频率
fbtm*=10;
}
if(freq<fbtm)return;
chan=(freq-fbtm)/spc; //得到CHAN应该写入的值
chan&=0X3FF; //取低10位
temp|=chan<<6;
temp|=1<<4; //TONE ENABLE
RDA5820_WR_Reg(0X03,temp) ; //设置频率
delay_ms(20); //等待20ms
while((RDA5820_RD_Reg(0X0B)&(1<<7))==0);//等待FM_READY
}
//得到当前频率
//返回值:频率值(单位10Khz)
u16 RDA5820_Freq_Get(void)
{
u16 temp;
u8 spc=0,band=0;
u16 fbtm,chan;
temp=RDA5820_RD_Reg(0X03); //读取0X03的内容
chan=temp>>6;
band=(temp>>2)&0x03; //得到频带
spc=temp&0x03; //得到分辨率
if(spc==0)spc=10;
else if(spc==1)spc=20;
else spc=5;
if(band==0)fbtm=8700;
else if(band==1||band==2)fbtm=7600;
else
{
fbtm=RDA5820_RD_Reg(0X53);//得到bottom频率
fbtm*=10;
}
temp=fbtm+chan*spc;
return temp;//返回频率值
}
本部分代码我们就不细说了,都是一些寄存器配置,比较简单。保存rda5820.c文件,并加入到HARDWARE组下,然后打开rda5820.h,在该文件里面输入如下代码:
#ifndef __RDA5820_H
#define __RDA5820_H
#include "sys.h"
#include "myiic.h"
#define RDA5820_R00 0X00 //读出16个位的ID =0X5820
……此处省略部分寄存器定义
#define RDA5820_R64 0X64 //RDS_RXMOD[4:3](FIFO模式[10]或者寄存器模式[11]) #define RDA5820_READ 0X23 //读RDA5820
#define RDA5820_WRITE 0X22 //写RDA5820
u8 RDA5820_Init(void); //初始化
void RDA5820_WR_Reg(u8 addr,u16 val); //写RDA5820寄存器
u16 RDA5820_RD_Reg(u8 addr); //读RDA5820寄存器
void RDA5820_RX_Mode(void); //设置RDA5820为RX模式
void RDA5820_TX_Mode(void); //设置RDA5820为TX模式
u8 RDA5820_Rssi_Get(void);
void RDA5820_Mute_Set(u8 mute);
void RDA5820_Rssi_Set(u8 rssi);
void RDA5820_Vol_Set(u8 vol);
void RDA5820_TxPAG_Set(u8 gain);
void RDA5820_TxPGA_Set(u8 gain);
void RDA5820_Band_Set(u8 band);
void RDA5820_Space_Set(u8 spc);
void RDA5820_Freq_Set(u16 freq);
u16 RDA5820_Freq_Get(void);
#endif
此部分代码省略了部分寄存器的定义,大家可以在战舰STM32开发板的光盘找到本实验的源码查看。保存此部分代码,然后打开audiosel.c文件,在该文件里面输入如下代码:
#include "audiosel.h"
//声音初始化
void Audiosel_Init(void)
{
RCC->APB2ENR|=1<<3; //使能PORTB时钟
RCC->APB2ENR|=1<<5; //使能PORTD时钟
GPIOB->CRL&=0X0FFFFFFF;
GPIOB->CRL|=0X30000000;//PB.7 推挽输出
GPIOD->CRL&=0X0FFFFFFF;
GPIOD->CRL|=0X30000000;//PD.7 推挽输出
}
//设置4052的选择通道
//声音通道选择
//0 //MP3通道
//1 //收音机通道
//2 //PWM音频通道
//3 //无声
void Audiosel_Set(u8 ch)
{
AUDIO_SELA=ch&0X01;
AUDIO_SELB=(ch>>1)&0X01;
}
此部分代码很简单,用来控制74HC4052,保存audiosel.c文件,并将其加入到HARDWARE组下。然后,打开audiosel.h,并输入如下代码:
#ifndef __AUDIOSEL_H
#define __AUDIOSEL_H
#include "sys.h"
//74HC4052控制设置端口
#define AUDIO_SELB PBout(7)
#define AUDIO_SELA PDout(7)
//声音通道选择
#define AUDIO_MP3 0 //MP3通道
#define AUDIO_RADIO 1 //收音机通道
#define AUDIO_PWM 2 //PWM音频通道
#define AUDIO_NONE 3 //无声
void Audiosel_Init(void); //初始化函数
void Audiosel_Set(u8 ch); //设置函数
#endif
保存audiosel.h,最后,打开test.c文件,修改代码如下:
void RDA5820_Show_Msg(void)
{
u8 rssi;
u16 freq;
freq=RDA5820_Freq_Get(); //读取设置到的频率值
LCD_ShowNum(100,210,freq/100,3,16); //显示频率整数部分
LCD_ShowNum(132,210,(freq%100)/10,1,16); //显示频率小数部分
rssi=RDA5820_Rssi_Get(); //得到信号强度
LCD_ShowNum(100,230,rssi,2,16); //显示信号强度
}
int main(void)
{
u8 key,rssi;
u16 freqset=0;
u8 i=0;
u8 mode=0; //接收模式
Stm32_Clock_Init(9); //系统时钟设置
uart_init(72,9600); //串口初始化为9600
delay_init(72); //延时初始化
LED_Init(); //初始化与LED连接的硬件接口
LCD_Init(); ///初始化LCD
usmart_dev.init(72); //初始化USMART
KEY_Init(); //按键初始化
Audiosel_Init();
Audiosel_Set(AUDIO_RADIO);
RDA5820_Init();
POINT_COLOR=RED;//设置字体为红色
LCD_ShowString(60,50,200,16,16,"WarShip STM32");
LCD_ShowString(60,70,200,16,16,"RDA5820 TEST");
LCD_ShowString(60,90,200,16,16,"ATOM@ALIENTEK");
LCD_ShowString(60,110,200,16,16,"2012/9/14");
LCD_ShowString(60,130,200,16,16,"KEY0:Freq+ KEY2:Freq-");
LCD_ShowString(60,150,200,16,16,"KEY1:Auto Search(RX)");
LCD_ShowString(60,170,200,16,16,"KEY_UP:Mode Set");
POINT_COLOR=BLUE;
//显示提示信息
POINT_COLOR=BLUE;//设置字体为蓝色
LCD_ShowString(60,190,200,16,16,"Mode:FM RX");
LCD_ShowString(60,210,200,16,16,"Freq: 93.6Mhz");
LCD_ShowString(60,230,200,16,16,"Rssi:");
RDA5820_Band_Set(0); //设置频段为87~108Mhz
RDA5820_Space_Set(0); //设置步进为100Khz
RDA5820_TxPGA_Set(3); //信号增益设置为3
RDA5820_TxPAG_Set(63); //发射功率为最大.
RDA5820_RX_Mode(); //设置为接收模式
freqset=9360; //默认为93.6Mhz
RDA5820_Freq_Set(freqset); //设置频率
while(1)
{
key=KEY_Scan(0);//不支持连按
switch(key)
{
case 0: break;//无任何按键按下
case KEY_UP://切换模式
mode=!mode;
if(mode)
{
Audiosel_Set(AUDIO_PWM); //设置到PWM 音频通道
RDA5820_TX_Mode(); //发送模式
RDA5820_Freq_Set(freqset); //设置频率
LCD_ShowString(100,190,200,16,16,"FM TX");
}else
{
Audiosel_Set(AUDIO_RADIO); //设置到收音机声道
RDA5820_RX_Mode(); //接收模式
RDA5820_Freq_Set(freqset); //设置频率
LCD_ShowString(100,190,200,16,16,"FM RX");
}
break;
case KEY_DOWN://自动搜索下一个电台.
if(mode==0)//仅在接收模式有效
{
while(1)
{
if(freqset<10800)freqset+=10; //频率增加100Khz
else freqset=8700; //回到起点
RDA5820_Freq_Set(freqset); //设置频率
delay_ms(10); //等待调频信号稳定
if(RDA5820_RD_Reg(0X0B)&(1<<8))//是一个有效电台.
{
RDA5820_Show_Msg();break; //显示信息
}
RDA5820_Show_Msg(); //显示信息
key=KEY_Scan(0);//不支持连按
if(key)break; //在搜台期间有按键按下,则跳出搜台.
}
}
break;
case KEY_LEFT://频率减
if(freqset>8700)freqset-=10; //频率减少100Khz
else freqset=10800; //越界处理
RDA5820_Freq_Set(freqset); //设置频率
RDA5820_Show_Msg();//显示信息
break;
case KEY_RIGHT://频率增
if(freqset<10800)freqset+=10; //频率增加100Khz
else freqset=8700; //越界处理
RDA5820_Freq_Set(freqset); //设置频率
RDA5820_Show_Msg();//显示信息
break;
}
i++;
delay_ms(10);
if(i==200)//每两秒左右检测一次信号强度等信息.
{
i=0;
rssi=RDA5820_Rssi_Get(); //得到信号强度
LCD_ShowNum(100,230,rssi,2,16); //显示信号强度
}
if((i%20)==0)LED0=!LED0;//DS0闪烁,提示程序运行
}
}
此部分代码除了mian函数,还有一个RDA5820_Show_Msg函数,该函数用于显示当前FM频率和信号强度等信息。main函数我面就不多介绍了。本章,我面可以利用USMART来设置RDA5820的各项参数,方便大家快速掌握。在usmart_nametab里面,我面加入如下五个函数:
(void*)RDA5820_Rssi_Set,"void RDA5820_Rssi_Set(u8 rssi)",
(void*)RDA5820_Band_Set,"void RDA5820_Band_Set(u8 band)",
(void*)RDA5820_Freq_Set,"void RDA5820_Freq_Set(u16 freq)",
(void*)RDA5820_Vol_Set,"void RDA5820_Vol_Set(u8 vol)",
(void*)RDA5820_TxPGA_Set,"void RDA5820_TxPGA_Set(u8 gain)",
这样,我面就可以在串口调用这些函数,从而修改RDA5820的配置。至此,我们的软件设计部分就结束了。
在代码编译成功之后,我们通过下载代码到ALIENTEK战舰STM32开发板上,得到如图40.4.1所示界面:
图40.4.1 程序运行效果图 此时,我们就可以在耳机上面听到广播了(注意,将开发板自带的天线拉出来,可以提高接收能力),通过KEY0和KEY1,调节频率,也可以通过按KEY1自动搜索下一个电台(PS:如果收不到台,说明你住的地方信号不好,跑到窗户边或者室外,一般就可以收到电台了)。
通过WK_UP按键,可以切换工作模式,例如:切换到FM TX模式,就可以通过单独的收音机(或者另外一块战舰STM32开发板)接收到开发板发出的FM信号了,此时在多功能接口P3的AIN端输入音频信号,就可以在收音机端接收这个音频信号了。
本章还可以通过USMART设置RDA5820的相关参数,感兴趣的朋友可以动手试试。