目录
概述
RDA5807M是一个FM收音芯片,可以支持76MHz-108MHz宽频带
高度集成化,仅需很少的外围元件即可使用
而且价格十分低廉,大量购买只需1元左右(立创商城截图)
电路
工作电压和逻辑电平均为3.3V标准,可以直连3.3V单片机(可以直连stm32)
只需要一个滤波电容,外部晶振及I2C的上拉电阻即可使用
外接天线可以使用拉杆天线也可以使用10cm左右的导线代替
输出可以直接接喇叭(5W以下),也可以接功放
通信
RDA5807M使用的是I2C通信,传送门
读写寄存器有两种方式,连续读写寄存器和单独读写寄存器(数据手册上只有连续读写方式,实测单独读写可以使用)
为编程方便这里选用单独读写寄存器的方式
读写时序
读写过程和标准I2C的有一点区别,协议的其他部分与标准I2C完全相同
芯片寄存器
0x00
寄存器 | 字节 | 名称 | 功能 | 默认值 |
0x00 | 15:0 | CHIPID[7:0] | 芯片ID | 0x5804 |
0x02
寄存器 | 字节 | 名称 | 功能 | 默认值 |
0x02 | 15 | DHIZ | 音频输出高阻 | 0 |
0:高阻 1:正常 | ||||
14 | DMUTE | 静音 | 0 | |
0:静音 1:正常 | ||||
13 | MONO | 单声道 | 0 | |
0:立体声 1:单声道 | ||||
12 | BASS | 增强低音 | 0 | |
0;禁用 1:启用 | ||||
11 | RCLK NON-CALIBRATE MODE | 晶振启用 | 0 | |
0:总是启用 1:仅FM工作时启用 | ||||
10 | RCLK DIRECT INPUT MODE | 晶振直接输入模式 | 0 | |
0:正常 1:直接输入模式 | ||||
9 | SEEKUP | 向上搜索 | 0 | |
0:向下搜索 1:向上搜索 | ||||
8 | SEEK | 搜索启用 | 0 | |
0:停止搜索 1:启用搜索 | ||||
7 | SKMODE | 搜索模式 | 0 | |
0:到达边界处从另一边界开始搜索 1:到达边界处停止搜索 | ||||
6:4 | CLK_MODE[2:0] | 晶振频率 | 000 | |
000:32.768KHz 001:12MHz 101:24MHz 010:12MHz 110:26MHz 011:19.2MHz 111:38.4MHz | ||||
3 | RDS_EN | RDS/RBDS启用 | 0 | |
0:不启用 1:启用 | ||||
2 | NEW_METHOD | 使用新技术提高信号质量(数据手册原话) | 0 | |
1 | SOFT_RESET | 软件复位 | 0 | |
0:正常 1:复位 | ||||
0 | ENABLE | 上电启用 | 0 | |
0:不启用 1:启用 |
0x03
寄存器 | 字节 | 名称 | 功能 | 默认值 |
0x03 | 15:6 | CHAN | 信道(用于选择频率) | 0x00 |
BAND的起始频率+信道值*SPACE (全换成MHz位单位) | ||||
5 | DIRECT MODE | 测试模式(手册原话) | 0 | |
4 | TUNE | 调谐 | 0 | |
0:禁用 1:启用 | ||||
3:2 | BAND | 波段 | 00 | |
00:87-108 01:76-91 10:76-108 11:65-76或50-65 (根据0x07寄存器的bit9选择) | ||||
1:0 | SPACE | 频率的间隔 | 00 | |
00:100kHz 01:200kHz 10:50kHz 11:25kHz |
0x04
寄存器 | 字节 | 名称 | 功能 | 默认值 |
0x04 | 15 | RSVD | 保留字(无功能) | 0 |
14 | STCIEN | 搜索和调谐中断使能 | 0 | |
0:禁用 1:启用 (中断是GPIO2的低脉冲) | ||||
13 | RBDS | RBDS/RDS功能 | 0 | |
0:仅使用RDS 1:RBDS启用 | ||||
12 | RDS_FIFO_EN | RDS先进先出功能 | 0 | |
0:禁用 1“启用 | ||||
11 | DE | 去重 | 0 | |
0:75us 1:50us | ||||
10 | RDS_FIFO_CLR | 清除RDS先进先出 | 1 | |
1:清除 | ||||
9 | SOFTMUTE_EN | 软件静音使能 | 0 | |
0:关闭软件静音 1:开启软件静音 | ||||
8 | AFCD | AFC失能 | 0 | |
0:AFC启用 1:AFK禁用 | ||||
7 | Rsvd | 被读取时为0 | 0 | |
6 | I2S_ENABLE | I2C使能 | 0 | |
0:关闭 1:打开 | ||||
5:4 | GPIO3[1:0] | GPIO3 | 00 | |
00:高阻 01:单声道/立体声指示 10:低电平 11:高电平 | ||||
3:2 | GPIO2[1:0] | GPIO2 | 00 | |
00:高阻 01:中断 10:低电平 11:高电平 | ||||
1:0 | GPIO1[1:0] | GPIO1 | 00 | |
00:高阻 01:保留 10:低电平 11:高电平 |
0x05
寄存器 | 字节 | 名称 | 功能 | 默认值 |
0x05 | 15 | INT _MODE | 中断模式 | 1 |
0:5ms中断 1:最后一次中断,直到读取了0x0C寄存器 | ||||
14:13 | Seek_mode | 搜索模式 | 00 | |
00:默认 10:添加RSSI模式 | ||||
12 | RSVD | 保留 | 0 | |
11:8 | SEEKTH[3:0] | SNK阈值 | 1000 | |
7:6 | LNA_PORT_SEL[1:0] | 低噪声放大器输入端口选择 | 10 | |
00:无输入 01:LNAN 10:LNAP 11:双输入 | ||||
5:4 | LNA_ICSEL_BIT[1:0] | 低噪声放大器工作电流 | 00 | |
00:1.8mA 01:2.1mA 10:2.5mA 11:3.0mA | ||||
3:0 | VOLUME[3:0] | 音量 | 1011 | |
0-15等级 |
0x06
寄存器 | 字节 | 名称 | 功能 | 默认值 |
0x06 | 15 | RSVD | 保留 | 0 |
14:13 | OPEN_MODE[1:0] | 保留寄存器模式 | 00 | |
11:打开寄存器后写入 其他:仅打开寄存器后读取功能 | ||||
12 | slave_master | I2S主从 | 0 | |
0:主机 1:从机 | ||||
11 | ws_lr | Ws与l/r通道的关系 | 0 | |
0:ws=0 ->r, ws=1 ->l 1:ws=0 ->l, ws=1 ->r | ||||
10 | sclk_i_edge | SCLK边沿 | 0 | |
0:正常 1:反相 | ||||
9 | data_signed | I2S数据符号 | 0 | |
0:无符号16bit 1:有符号16bit | ||||
8 | WS_I_EDGE | |||
0:正常 1:反相 | ||||
7:4 | I2S_SW_CNT[4:0] | 波特率 | ||
只有主机模式有用 | 1000: WS_STEP_48 0111: WS_STEP:44.1kbps; 0110: WS_STEP:32kbps; 0101: WS_STEP:24kbps; 0100: WS_STEP:22.05kbps; 0011: WS_STEP:16kbps; 0010: WS_STEP:12kbps; 0001: WS_STEP:11.025kbps; 0000: WS_STEP:8kbps; | |||
3 | SW_O_EDGE | Ws输出 | 0 | |
0:禁用 1:启用 | ||||
2 | SCLK_O_EDGE | SCLK输出 | 0 | |
0:禁用 1:启用 | ||||
1 | L_DELY | 左声道延迟 | 0 | |
0:不延迟 1:延迟1T | ||||
0 | R_DELY | 右声道延迟 | 0 | |
0:不延迟 1:延迟1T |
0x07
寄存器 | 字节 | 名称 | 功能 | 默认值 |
0x07 | 15 | RSVD | 保留 | 0 |
14:10 | TH_SOFRBLEND[5:0] | 噪声软混合设置阈值,单位2dB | 10000 | |
9 | 65M_50M MODE | 选择频率段 | 1 | |
在0x30[3:2]=11时有效 0 :50~76 MHz. 1: 65~76 MHz | ||||
8 | RSVD | 保留 | 0 | |
7:2 | SEEK_TH_OLD | 旧搜索模式的搜索阈值, 0x05[14:13]=10时有效 | ||
1 | SOFTBLEND_EN | Softblend启用 | 1 | |
0:禁用 1:启用 | ||||
0 | FREQ_MODE | 频率模式 | 0 | |
0:传统模式 1:直接写出频率(0x08) |
0x08
寄存器 | 字节 | 名称 | 功能 | 默认值 |
0x08 | 15:0 | freq_direct[15:0] | 频率 | 0x0000 |
0x07[0]=1时有效 |
0x0A
寄存器 | 字节 | 名称 | 功能 | 默认值 |
0x0A | 15 | RDSR | RDS就绪 | 0 |
0:没有准备就绪 1:准备就绪 | ||||
14 | STC | 调谐搜索完成 | 0 | |
0:未完成 1:完成 | ||||
13 | SF | 搜索失败 | 0 | |
0:成功 1:失败 | ||||
12 | RDSS | RDS同步 | 0 | |
0:RDS解码器未同步(默认) 1:RDS解码器已同步 仅在RDS详细模式下可用 | ||||
11 | BLK_E | 0 | ||
当RDS启用时 0:没有找到Block E 1:找到Block E | ||||
10 | ST | 立体声指示 | 1 | |
0:单声道 1:立体声 | ||||
9:0 | READCHAN[9:0] | 信道值 | 0x00 |
0x0B
寄存器 | 字节 | 名称 | 功能 | 默认值 |
0x0B | 15:9 | RSSI[6:0] | 信号强度 | 0 |
0-127 | ||||
8 | FM TRUE | 电台指示 | 0 | |
0:不是电台 1:是电台 | ||||
7 | FM_READY | 软件搜索 | 0 | |
0:没有就绪 1:就绪 | ||||
6:5 | RSVD | 保留 | ||
4 | ABCD_E | 0x0c,0x0d,0x0e,0x0f功能 | 0 | |
0:ABCD 1:E | ||||
3:2 | BLERA[1:0] | 纠错级别 | ||
00:0需要更正的错误 01:需要纠正的1~2个错误 10:需要纠正的3-5个错误 11:6+错误或校验字错误,无法纠正。 | ||||
1:0 | BLERB[1:0] | 纠错级别 | ||
00:0需要更正的错误 01:需要纠正的1~2个错误 10:需要纠正的3-5个错误 11:6+错误或校验字错误,无法纠正。 |
其余寄存器
寄存器 | 字节 | 名称 | 功能 | 默认值 |
0x0C | 15:0 | RDSA[15:0] | BLOCK A ( 在RDS模式) 或BLOCK E (0x0B[4]=1) | 0x5803 |
0x0D | 15:0 | RDSB[15:0] | BLOCK B ( 在RDS模式) 或BLOCK E (0x0B[4]=1) | 0x5804 |
0x0E | 15:0 | RDSC[15:0] | BLOCK C ( 在RDS模式) 或BLOCK E (0x0B[4]=1) | 0x5808 |
0x0F | 15:0 | RDSD[15:0] | BLOCK D ( 在RDS模式) 或BLOCK E (0x0B[4]=1) | 0x5804 |
其他的请查看芯片手册,本文会在用到的地方给出寄存器的截图和解释
数据手册https://www.findic.com/doc/browser/me6Bn61ve?doc_id=78581521#locale=zh-CN
HAL库初始化
使用硬件I2C或软件I2C进行操作
硬件I2C
硬件I2C,使用默认设置即可
7bit地址长度,从器件地址无需填写
软件I2C
开漏输出,上不上拉取决于外电路
代码
I2C通信
RDA5807M的寄存器地址是8bit
而其内容是16bit数据,也就是说调用HAL库函数时需要使用读取和写入2字节数据
RDA5807M要求先发送(写),接受(读),16bit的高8位,再发送或接受低8位
每个字节中先发送高位再发送低位(标准I2C)
硬件I2C
单独读写寄存器的从器件地址是0x22(写),0x23(读),硬件i2C的HAL库函数时不需要管最后一位,函数会自动根据读写操作这位,也就是可以读和写均放入0x22
读取寄存器
1.首先创建一个缓冲区
uint8_t Buf[2] = {0};
2.调用硬件I2C读取寄存器函数,从指定位置读取2字节数据
HAL_I2C_Mem_Read(&RDA6807M_I2C_Handle, 0x22, Address, I2C_MEMADD_SIZE_8BIT, Buf, 2, 0xffff);
3.将数据进行拼接并返回数据
return ((Buf[0] << 8) | Buf[1]);
写入寄存器
1.首先创建一个缓冲区
uint8_t Buf[2] = {0};
2.将数据分割写入缓冲区
Buf[0] = (Data & 0xff00) >> 8; Buf[1] = Data & 0x00ff;
3.调用硬件I2C将数据写入寄存器
HAL_I2C_Mem_Write(&RDA6807M_I2C_Handle, 0x22, Address, I2C_MEMADD_SIZE_8BIT, Buf, 2, 0xffff);
软件I2C
协议方面请看,传送门
这里用到的是读写寄存器的模拟I2C,直接给出源码
#define I2C_Group_SCL GPIOB // I2C的时钟GPIO组号
#define I2C_SCL GPIO_PIN_6 // I2C时钟的GPIO端口号
#define I2C_Group_SDA GPIOB // I2C的数据GPIO组号
#define I2C_SDA GPIO_PIN_7 // I2C数据的GPIO端口号
#define I2C_Write_SCL(x) HAL_GPIO_WritePin(I2C_Group_SCL, I2C_SCL, x)
#define I2C_Write_SDA(x) HAL_GPIO_WritePin(I2C_Group_SDA, I2C_SDA, x)
#define I2C_Read_SCL() HAL_GPIO_ReadPin(I2C_Group_SCL, I2C_SCL)
#define I2C_Read_SDA() HAL_GPIO_ReadPin(I2C_Group_SDA, I2C_SDA)
/**
* @brief 一段延迟
* @param 无
* @return 无
* @author HZ12138
* @date 2022-07-27 08:53:30
*/
void I2C_Delay()
{
int z = 0xff;
while (z--)
;
}
/**
* @brief 产生I2C起始信号
* @param 无
* @return 无
* @author HZ12138
* @date 2022-07-27 08:54:48
*/
void I2C_Start(void)
{
I2C_Write_SDA(GPIO_PIN_SET); //需在SCL之前设定
I2C_Write_SCL(GPIO_PIN_SET); // SCL->高
I2C_Delay(); //延时
I2C_Write_SDA(GPIO_PIN_RESET); // SDA由1->0,产生开始信号
I2C_Delay(); //延时
I2C_Write_SCL(GPIO_PIN_RESET); // SCL->低
}
/**
* @brief 产生I2C结束信号
* @param 无
* @return 无
* @author HZ12138
* @date 2022-07-27 08:57:03
*/
void I2C_End(void)
{
I2C_Write_SDA(GPIO_PIN_RESET); //在SCL之前拉低
I2C_Write_SCL(GPIO_PIN_SET); // SCL->高
I2C_Delay(); //延时
I2C_Write_SDA(GPIO_PIN_SET); // SDA由0->1,产生结束信号
I2C_Delay(); //延时
}
/**
* @brief 发送应答码
* @param ack:0 应答 1 不应达
* @return 无
* @author HZ12138
* @date 2022-07-27 09:03:38
*/
void IIC_Send_ACK(uint8_t ack)
{
if (ack == 1)
I2C_Write_SDA(GPIO_PIN_SET); //产生应答电平
else
I2C_Write_SDA(GPIO_PIN_RESET);
I2C_Delay();
I2C_Write_SCL(GPIO_PIN_SET); //发送应答信号
I2C_Delay(); //延时至少4us
I2C_Write_SCL(GPIO_PIN_RESET); //整个期间保持应答信号
}
/**
* @brief 接受应答码
* @param 无
* @return 应答码 0 应答 1 不应达
* @author HZ12138
* @date 2022-07-27 09:04:28
*/
uint8_t IIC_Get_ACK(void)
{
uint8_t ret; //用来接收返回值
I2C_Write_SDA(GPIO_PIN_SET); //电阻上拉,进入读
I2C_Delay();
I2C_Write_SCL(GPIO_PIN_SET); //进入应答检测
I2C_Delay(); //至少延时4us
ret = I2C_Read_SDA(); //保存应答信号
I2C_Write_SCL(GPIO_PIN_RESET);
return ret;
}
/**
* @brief I2C写1Byte
* @param dat:1Byte数据
* @return 应答结果 0 应答 1 不应达
* @author HZ12138
* @date 2022-07-27 09:05:14
*/
uint8_t I2C_SendByte(uint8_t dat)
{
uint8_t ack;
for (int i = 0; i < 8; i++)
{
// 高在前低在后
if (dat & 0x80)
I2C_Write_SDA(GPIO_PIN_SET);
else
I2C_Write_SDA(GPIO_PIN_RESET);
I2C_Delay();
I2C_Write_SCL(GPIO_PIN_SET);
I2C_Delay(); //延时至少4us
I2C_Write_SCL(GPIO_PIN_RESET);
dat <<= 1; //低位向高位移动
}
ack = IIC_Get_ACK();
return ack;
}
/**
* @brief I2C读取1Byte数据
* @param ack:应答 0 应答 1 不应达
* @return 接受到的数据
* @author HZ12138
* @date 2022-07-27 09:06:13
*/
uint8_t I2C_ReadByte(uint8_t ack)
{
uint8_t ret = 0;
// OLED_Read_SDA() 设置输入方向
I2C_Write_SDA(GPIO_PIN_SET);
for (int i = 0; i < 8; i++)
{
ret <<= 1;
I2C_Write_SCL(GPIO_PIN_SET);
I2C_Delay();
// 高在前低在后
if (I2C_Read_SDA())
{
ret++;
}
I2C_Write_SCL(GPIO_PIN_RESET);
I2C_Delay();
}
IIC_Send_ACK(ack);
return ret;
}
读写寄存器代码
头文件中使用宏定义来区分使用硬件还是软件
#ifdef RDA5807_Hardware_I2C
extern I2C_HandleTypeDef hi2c1;
#define RDA6807M_I2C_Handle hi2c1
#endif
#ifdef RDA5807_Software_I2C
#define I2C_Group_SCL GPIOB // I2C的时钟GPIO组号
#define I2C_SCL GPIO_PIN_6 // I2C时钟的GPIO端口号
#define I2C_Group_SDA GPIOB // I2C的数据GPIO组号
#define I2C_SDA GPIO_PIN_7 // I2C数据的GPIO端口号
#define I2C_Write_SCL(x) HAL_GPIO_WritePin(I2C_Group_SCL, I2C_SCL, x)
#define I2C_Write_SDA(x) HAL_GPIO_WritePin(I2C_Group_SDA, I2C_SDA, x)
#define I2C_Read_SCL() HAL_GPIO_ReadPin(I2C_Group_SCL, I2C_SCL)
#define I2C_Read_SDA() HAL_GPIO_ReadPin(I2C_Group_SDA, I2C_SDA)
#endif
根据需要写入下方两个宏定义之一
#define RDA5807_Software_I2C
#define RDA5807_Hardware_I2C
读写寄存器
/**
* @brief 写寄存器
* @param Address:寄存器地址
* @param Data:数据
* @return 无
* @author HZ12138
* @date 2022-07-21 21:57:40
*/
void RDA5807M_Write_Reg(uint8_t Address, uint16_t Data)
{
uint8_t Buf[2] = {0};
Buf[0] = (Data & 0xff00) >> 8; //高位
Buf[1] = Data & 0x00ff; //低位
#ifdef RDA5807_Hardware_I2C
HAL_I2C_Mem_Write(&RDA6807M_I2C_Handle, 0x22, Address, I2C_MEMADD_SIZE_8uint8_t, Buf, 2, 0xffff);
#endif
#ifdef RDA5807_Software_I2C
I2C_Start();
I2C_SendByte(0x22);
I2C_SendByte(Address);
I2C_SendByte(Buf[0]);
I2C_SendByte(Buf[1]);
I2C_End();
#endif
}
/**
* @brief 读寄存器
* @param Address:寄存器地址
* @return 读取的数据
* @author HZ12138
* @date 2022-07-21 21:58:33
*/
uint16_t RDA5807M_Read_Reg(uint8_t Address)
{
uint8_t Buf[2] = {0};
#ifdef RDA5807_Hardware_I2C
HAL_I2C_Mem_Read(&RDA6807M_I2C_Handle, 0x22, Address, I2C_MEMADD_SIZE_8uint8_t, Buf, 2, 0xffff);
#endif
#ifdef RDA5807_Software_I2C
I2C_Start();
I2C_SendByte(0x22);
I2C_SendByte(Address);
I2C_Start();
I2C_SendByte(0x23);
Buf[0] = I2C_ReadByte(0);
Buf[1] = I2C_ReadByte(1);
I2C_End();
#endif
return ((Buf[0] << 8) | Buf[1]);
}
一定要注意软件I2C读寄存器时的应答与起始信号
软件复位
将0x02[1]设置为1即可,注意复位后要加延迟
/**
* @brief 复位
* @param 无
* @return 无
* @author HZ12138
* @date 2022-07-24 00:11:54
*/
void RDA5807M_Reast(void)
{
RDA5807M_Write_Reg(0x02, 0x0002); //复位
HAL_Delay(50);
}
初始化
各种寄存器的设置,先进行软件复位,之后再进行设置,这里的值根据寄存器定义写出的常用值
/**
* @brief 初始化
* @param 无
* @return 无
* @author HZ12138
* @date 2022-07-21 22:00:48
*/
void RDA5807M_init(void)
{
RDA5807M_Write_Reg(0x02, 0x0002); //复位
HAL_Delay(50);
RDA5807M_Write_Reg(0x02, 0xc001);
HAL_Delay(600);
RDA5807M_Write_Reg(0x03, 0x0018);
RDA5807M_Write_Reg(0x04, 0x0400);
RDA5807M_Write_Reg(0x05, 0x86ad);
RDA5807M_Write_Reg(0x06, 0x8000);
RDA5807M_Write_Reg(0x07, 0x5F1A);
}
设置频率间隔
操作寄存器0x03[1:0]位即可
宏定义 和代码
/** @defgroup 频率间隔选择组
* @{
*/
#define RDA6807M_Freq_Space_100kHz 1
#define RDA6807M_Freq_Space_200kHz 2
#define RDA6807M_Freq_Space_50KHz 3
#define RDA6807M_Freq_Space_25KHz 4
/**
* @}
*/
/**
* @brief 设置频率间隔
* @param SPACE:间隔,从频率间隔选择组宏定义里选取,如RDA6807M_Freq_Space_100kHz
* @return 无
* @author HZ12138
* @date 2022-07-23 16:01:05
*/
void RDA5807M_Set_FreqSpace(uint8_t SPACE)
{
uint16_t zj;
zj = RDA5807M_Read_Reg(0x03);
if (SPACE == RDA6807M_Freq_Space_100kHz)
{ /*0x03[1:0]=00*/
zj &= ~(1 << 1);
zj &= ~(1 << 0);
}
else if (SPACE == RDA6807M_Freq_Space_200kHz)
{ /*0x03[1:0]=01*/
zj &= ~(1 << 1);
zj |= 1 << 0;
}
else if (SPACE == RDA6807M_Freq_Space_50KHz)
{ /*0x03[1:0]=10*/
zj |= 1 << 1;
zj &= ~(1 << 0);
}
else if (SPACE == RDA6807M_Freq_Space_25KHz)
{ /*0x03[1:0]=11*/
zj |= 1 << 1;
zj |= 1 << 0;
}
RDA5807M_Write_Reg(0x03, zj);
}
设置波段
操作寄存器0x03[3:2]和0x07[9]位即可
宏定义 和代码
/** @defgroup 频率段选择组
* @{
*/
#define RDA6807M_Freq_Range_87_108 1
#define RDA6807M_Freq_Range_76_91 2
#define RDA6807M_Freq_Range_76_108 3
#define RDA6807M_Freq_Range_65_76 4
#define RDA6807M_Freq_Range_50_76 5
/**
* @}
*/
/**
* @brief 设置频率段
* @param Range:频率段,来自频率段选择组的宏定义,如RDA6807M_Freq_Range_76_108
* @return 无
* @author HZ12138
* @date 2022-07-23 11:16:42
*/
void RDA5807M_Set_FreqRange(uint8_t Range)
{
uint16_t zj;
zj = RDA5807M_Read_Reg(0x03);
if (Range == RDA6807M_Freq_Range_87_108)
{ /*0x03[3:2]=00 0x07[9]=x*/
zj &= ~(1 << 3);
zj &= ~(1 << 2);
RDA5807M_Write_Reg(0x02, zj);
}
else if (Range == RDA6807M_Freq_Range_76_91)
{ /*0x03[3:2]=01 0x07[9]=x*/
zj &= ~(1 << 3);
zj |= 1 << 2;
RDA5807M_Write_Reg(0x02, zj);
}
else if (Range == RDA6807M_Freq_Range_76_108)
{ /*0x03[3:2]=10 0x07[9]=x*/
zj |= 1 << 3;
zj &= ~(1 << 2);
RDA5807M_Write_Reg(0x02, zj);
}
else if (Range == RDA6807M_Freq_Range_65_76)
{ /*0x03[3:2]=11 0x07[9]=1*/
zj |= 1 << 2;
zj |= 1 << 3;
RDA5807M_Write_Reg(0x02, zj);
zj = RDA5807M_Read_Reg(0x07);
zj |= 1 << 9;
RDA5807M_Write_Reg(0x07, zj);
}
else if (Range == RDA6807M_Freq_Range_50_76)
{ /*0x03[3:2]=11 0x07[9]=0*/
zj |= 1 << 2;
zj |= 1 << 3;
RDA5807M_Write_Reg(0x02, zj);
zj = RDA5807M_Read_Reg(0x07);
zj &= ~(1 << 9);
RDA5807M_Write_Reg(0x07, zj);
}
}
读取芯片ID
读取0x00寄存器的值即可,RDA5807M的芯片ID为0x5804
/**
* @brief 读取芯片ID
* @param 无
* @return 芯片ID
* @author HZ12138
* @date 2022-07-21 23:53:58
*/
uint16_t RDA5807M_Read_ID(void)
{
return RDA5807M_Read_Reg(0x00);
}
频率值和信道值转换
信道值是在正常的设置情况下读取和写入频率时所使用的
信道值 = ( 频率值 - 频率段的起始值 ) / 频率间隔
频率值 = ( 频率间隔 * 信道值 ) + 频率段的起始值
于此相关的寄存器是
0x03[3:2] 波段选择
0x03[1:0] 频率间隔选择
0x03[15:6] 设置信道值
0x0A[9:0] 读取信道值
为了方便操作,我们将频率值*100进行操作(106.7MHz=>10670)
将信道值转换为频率值
频率值 = ( 频率间隔 * 信道值 ) + 频率段的起始值
读取之前提到的寄存器的值并根据其将输入的信道值转换为频率值
/**
* @brief 将信道值转为频率
* @param Chan:信道值
* @return 频率(以MHz为单位*100)(如108MHz=>10800)
* @author HZ12138
* @date 2022-07-21 22:03:01
*/
uint16_t RDA5807M_ChanToFreq(uint16_t Chan)
{
uint16_t Start = 0; //频率开始
uint16_t End = 0; //频率结束
uint16_t Space = 0; //频率间隔
uint16_t zj = 0;
zj = (RDA5807M_Read_Reg(0x03) & 0x000C) >> 2; // 0x03的3,2位(波段)
if (zj == 0 /*0b00*/)
{
Start = 8700;
End = 10800;
}
else if (zj == 1 /*0b01*/)
{
Start = 7600;
End = 9100;
}
else if (zj == 2 /*0b10*/)
{
Start = 7600;
End = 10800;
}
else if (zj == 3 /*0b11*/)
{
if ((RDA5807M_Read_Reg(0x07) >> 9) & 0x01)
{
Start = 6500;
End = 7600;
}
else
{
Start = 5000;
End = 7600;
}
}
else
return 0;
zj = (RDA5807M_Read_Reg(0x03) & 0x0003);
if (zj == 0 /*0b00*/)
Space = 10;
else if (zj == 1 /*0b01*/)
Space = 5;
else if (zj == 2 /*0b10*/)
Space = 20;
else if (zj == 3 /*0b11*/)
Space = 80;
else
return 0;
zj = Start + Chan * Space;
if (zj > End)
return 0;
if (zj < Start)
return 0;
return zj;
}
将频率值转换为信道值
信道值 = ( 频率值 - 频率段的起始值 ) / 频率间隔
读取之前提到的寄存器的值并根据其将输入的频率值转换为信道值
/**
* @brief 将频率转为信道值
* @param Freq:频率(以MHz为单位*100)(如108MHz=>10800)
* @return 转换为的信道值
* @author HZ12138
* @date 2022-07-21 22:01:08
*/
uint16_t RDA5807M_FreqToChan(uint16_t Freq)
{
uint16_t Start = 0; //频率开始
uint16_t End = 0; //频率结束
uint16_t Space = 0; //频率间隔
uint16_t zj = 0;
zj = (RDA5807M_Read_Reg(0x03) & 0x000C) >> 2; // 0x03的3,2位(波段)
if (zj == 0 /*0b00*/)
{
Start = 8700;
End = 10800;
}
else if (zj == 1 /*0b01*/)
{
Start = 7600;
End = 9100;
}
else if (zj == 2 /*0b10*/)
{
Start = 7600;
End = 10800;
}
else if (zj == 3 /*0b11*/)
{
if ((RDA5807M_Read_Reg(0x07) >> 9) & 0x01)
{
Start = 6500;
End = 7600;
}
else
{
Start = 5000;
End = 7600;
}
}
else
return 0;
zj = (RDA5807M_Read_Reg(0x03) & 0x0003);
if (zj == 0 /*0b00*/)
Space = 10;
else if (zj == 1 /*0b01*/)
Space = 5;
else if (zj == 2 /*0b10*/)
Space = 20;
else if (zj == 3 /*0b11*/)
Space = 40;
else
return 0;
if (Freq < Start)
return 0;
if (Freq > End)
return 0;
return ((Freq - Start) / Space);
}
频率
设置频率
先将频率值转化为信道值,在写入信道值,并启用调谐
使用位操作写入
为了方便操作,我们将频率值*100进行操作(106.7MHz=>10670)
0x03[4]=1 启动调谐
/**
* @brief 设置频率值
* @param Freq:频率(以MHz为单位*100)(如108MHz=>10800)
* @return 无
* @author HZ12138
* @date 2022-07-21 22:06:22
*/
void RDA5807M_Set_Freq(uint16_t Freq)
{
uint16_t Chan = RDA5807M_FreqToChan(Freq); //先转化为信道值
uint16_t zj = RDA5807M_Read_Reg(0x03);
zj &= 0x003F; //清空信道值
zj |= (Chan & 0x03FF) << 6; //写入信道值
zj |= (1) << 4; //调频启用
RDA5807M_Write_Reg(0x03, zj);
RDA5807M_Write_Reg(0x03, zj); //需要写入两次,咱也不知道为啥
}
读取当前频率
读取0x0A[9:0]为信道值,将其转化为频率值即可
为了方便操作,我们将频率值*100进行操作(106.7MHz=>10670)
/**
* @brief 读取当前频率
* @param 无
* @return 频率(以MHz为单位*100)(如108MHz=>10800)
* @author HZ12138
* @date 2022-07-21 22:05:43
*/
uint16_t RDA5807M_Read_Freq(void)
{
uint16_t Chan = 0;
Chan = RDA5807M_Read_Reg(0x0A) & 0x03FF;
return RDA5807M_ChanToFreq(Chan);
}
声音输出
设置音量
设置0x05[3:0]的值,取值范围为0-15(只是个等级编号,0不是没有声音)
/**
* @brief 设置音量
* @param Val:音量值(0-15)
* @return 无
* @author HZ12138
* @date 2022-07-21 22:20:20
*/
void RDA5807M_Set_Volume(uint8_t Val)
{
uint16_t zj;
zj = RDA5807M_Read_Reg(0x05);
zj &= 0xFFF0;
zj |= (Val & 0x0F);
RDA5807M_Write_Reg(0x05, zj);
}
设置静音
设置0x02[14]的值,0是静音
/**
* @brief 设置静音
* @param Bool:1是静音,0是解除静音
* @return 无
* @author HZ12138
* @date 2022-07-21 23:13:30
*/
void RDA5807M_SetMutea(uint8_t Bool)
{
uint16_t zj;
zj = RDA5807M_Read_Reg(0x02);
if (Bool)
{
zj &= ~(1 << 14);
}
else
{
zj |= 1 << 14;
}
RDA5807M_Write_Reg(0x02, zj);
}
设置输出高阻
设置0x02[15]的值,0是高阻
/**
* @brief 将输出设为空闲状态(喇叭高阻)
* @param Bool:1是空闲,0是解除空闲
* @return 无
* @author HZ12138
* @date 2022-07-21 23:39:07
*/
void RDA5807M_Set_Output_Idle(uint8_t Bool)
{
uint16_t zj;
zj = RDA5807M_Read_Reg(0x02);
if (Bool)
{
zj &= ~(1 << 15);
}
else
{
zj |= 1 << 15;
}
RDA5807M_Write_Reg(0x02, zj);
}
读取信号强度
读取0x0B[15:9]的数据即可
取值范围是0-127
/**
* @brief 获取当前频率的信号强度
* @param 无
* @return 信号强度(0-127)
* @author HZ12138
* @date 2022-07-21 23:47:17
*/
uint8_t RDA5807M_Read_Signal_Intensity(void)
{
uint16_t zj;
zj = RDA5807M_Read_Reg(0x0B);
zj >>= 9;
return (uint8_t)zj;
}
判断本频率是不是电台
芯片内部的功能,我们只是读取而已
原理是电台的信号强度是大于噪声的,我们将信号强度高于某个阈值的叫做电台
但是这个功能有BUG,每次调谐(频率设置)过后才会进行一次检测
也就是说如果进行了移动导致收不到电台信号或者电台消失(出现)则会出现判断失效
/**
* @brief 判断当前频率是否为电台
* @param 无
* @return 返回1则是电台,0则不是电台
* @author HZ12138
* @date 2022-07-21 22:22:30
*/
uint8_t RDA5807M_Radio_Instructions(void)
{
uint16_t zj;
zj = RDA5807M_Read_Reg(0x0B);
zj >>= 8;
zj &= 1;
return zj;
}
电台搜索
本内容是调用芯片的搜索电台功能
搜索下一个电台
首先设置禁用调谐
之后将寄存器0x03设置为向上搜索,达到最高频率截止,并开启搜索
进入一个循环,直到搜索完成0x0A[14]=1
最后将当前频率设置为播放频率(冗余操作,不写有时候出问题)
/**
* @brief 向上搜索下一个电台(搜索完成后会设置当前频率为搜到的频率)
* @param 无
* @return 无
* @author HZ12138
* @date 2022-07-21 22:11:22
*/
void RDA5807M_Search_Freq_TurnUp(void)
{
uint16_t zj;
zj = RDA5807M_Read_Reg(0x03);
zj &= ~(1 << 4); //禁用调谐
RDA5807M_Write_Reg(0x03, zj);
zj = RDA5807M_Read_Reg(0x02);
zj |= 1 << 9; //向上搜索
zj |= 1 << 8; //开启搜索
zj |= 1 << 7; //到达最高频率停止
RDA5807M_Write_Reg(0x02, zj);
while ((RDA5807M_Read_Reg(0x0A) & 0x4000) == 0) //等待搜索完成
{
HAL_Delay(1);
}
RDA5807M_Set_Freq(RDA5807M_Read_Freq()); //将搜索到频率设置为播放频率
}
搜索全部电台
注意:整个搜索过程需要耗费2-3秒,不用再中断里调用
将当前频率设置为起始值
每次向上搜索电台并将其保存下来,直到达到最大
判断最后频率是判断其是否为电台
uint16_t RDA5807M_RadioStadion_Freq[RDA5807M_N] = {0}; //查找到的电台
/**
* @brief 搜索所有电台
* @param 无
* @return 搜到的电台数量
* @author HZ12138
* @date 2022-07-21 22:12:33
*/
uint16_t RDA5807M_Search_ALL_Freq(void)
{
uint16_t i = 0;
uint16_t zj = 0;
uint16_t Start, End;
zj = (RDA5807M_Read_Reg(0x03) & 0x000C) >> 2; // 0x03的3,2位(波段)
if (zj == 0 /*0b00*/)
{
Start = 8700;
End = 10800;
}
else if (zj == 1 /*0b01*/)
{
Start = 7600;
End = 9100;
}
else if (zj == 2 /*0b10*/)
{
Start = 7600;
End = 10800;
}
else if (zj == 3 /*0b11*/)
{
if ((RDA5807M_Read_Reg(0x07) >> 9) & 0x01)
{
Start = 6500;
End = 7600;
}
else
{
Start = 5000;
End = 7600;
}
}
else
return 0;
RDA5807M_Set_Freq(Start);
HAL_Delay(100);
while (RDA5807M_Read_Freq() != End)
{
RDA5807M_Search_Freq_TurnUp();
HAL_Delay(10);
RDA5807M_RadioStadion_Freq[i] = RDA5807M_Read_Freq();
i++;
}
HAL_Delay(100);
if (!RDA5807M_Radio_Instructions())
RDA5807M_RadioStadion_Freq[--i] = 0;
return i;
}
成品
百度网盘https://pan.baidu.com/s/1vr6KlJgScMLcwAz4It--fA?pwd=lnbe%C2%A0GitHubhttps://github.com/HZ1213825/HAL_STM32F4_RDA5807M/tree/master