目录

概述

电路

通信

读写时序

芯片寄存器

0x00

0x02

0x03

0x04

0x05

0x06

0x07

0x08

0x0A

0x0B

其余寄存器

HAL库初始化

硬件I2C

软件I2C

代码

I2C通信

硬件I2C

软件I2C

读写寄存器代码

软件复位

初始化

设置频率间隔

设置波段

读取芯片ID

频率值和信道值转换

将信道值转换为频率值

将频率值转换为信道值

频率

设置频率

读取当前频率

声音输出

设置音量

设置静音

设置输出高阻

读取信号强度

判断本频率是不是电台

电台搜索

搜索下一个电台

搜索全部电台

成品


概述

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); //产生应答电平elseI2C_Write_SDA(GPIO_PIN_RESET);I2C_Delay();I2C_Write_SCL(GPIO_PIN_SET);   //发送应答信号I2C_Delay();                   //延时至少4usI2C_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();                 //至少延时4usret = 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);elseI2C_Write_SDA(GPIO_PIN_RESET);I2C_Delay();I2C_Write_SCL(GPIO_PIN_SET);I2C_Delay(); //延时至少4usI2C_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_I2CHAL_I2C_Mem_Write(&RDA6807M_I2C_Handle, 0x22, Address, I2C_MEMADD_SIZE_8uint8_t, Buf, 2, 0xffff);
#endif
#ifdef RDA5807_Software_I2CI2C_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_I2CHAL_I2C_Mem_Read(&RDA6807M_I2C_Handle, 0x22, Address, I2C_MEMADD_SIZE_8uint8_t, Buf, 2, 0xffff);
#endif
#ifdef RDA5807_Software_I2CI2C_Start();I2C_SendByte(0x22);I2C_SendByte(Address);I2C_Start();I2C_SendByte(0x23);Buf[0] = I2C_ReadByte(0);Buf[1] = I2C_ReadByte(1);I2C_End();
#endifreturn ((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;}}elsereturn 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;elsereturn 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;}}elsereturn 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;elsereturn 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;}}elsereturn 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

【STM32F4系列】【HAL库】【自制库】RDA5807M收音机芯片驱动相关推荐

  1. STM32F4系列HAL库配置定时器实验——输入捕获

    STM32F4系列HAL库配置定时器实验--输入捕获 输入捕获简单讲解 输入捕获模式可以用来测量脉冲宽度或者测量频率.我们以测量周期和频率为例,用一个简图来说明输入捕获的原理 假定定时器工作在向上计数 ...

  2. STM32F4系列 HAL Flash 读写

    前言 注意:F0F1系列和F4系列的Flash读写操作不相同 一.STM32CubeMX怎么查看芯片的Flash分布? 二.擦除F4系列Flash 本例程使用的是F411CEU6的型号芯片 1.擦除F ...

  3. 【STM32F4系列】【HAL库】【自制库】WS2812(软件部分)(PWM+DMA)

    文章目录 相关链接 协议 外设设置 硬件PWM 分析 HAL设置 DMA 分析 HAL设置 方案设计 代码实现 解码函数 开始发送和复位 发送函数 波形 成品 相关链接 硬件介绍(PCB设计方案) 模 ...

  4. STM32CubeMX | STM32 F1系列HAL库低功耗STOP和STANDBY模式唤醒(RTC时钟唤醒+外部中断唤醒示例)

    STM32CubeMX | STM32 F1系列HAL库低功耗STOP和STANDBY模式唤醒(RTC时钟唤醒+外部中断唤醒示例) 目录 STM32CubeMX | STM32 F1系列HAL库低功耗 ...

  5. STM32F1系列HAL库配置系统时钟

    STM32F1系列HAL库配置系统时钟 其实一开始对于时钟我也是知之甚少,在MSP432中我就一直忽视时钟配置,其实也是在STM32学习时落下的病根,现在趁有空补一下. 时钟简单讲解 对于时钟系统,在 ...

  6. STM32系列(HAL库)——F103C8T6通过MFRC522、RFID射频卡、门禁卡模块读取卡片ID(二)

    本文继上一篇:STM32系列(HAL库)--F103C8T6通过MFRC522.RFID射频卡.门禁卡模块读取卡片ID 本文介绍在运用RC522模块时,运用链表结构存储数据的操作 Let's go! ...

  7. STM32中STD、HAL、LL库比较

    ST为开发者提供了标准外设库(STD库).HAL库.LL库 三种.前两者都是常用的库,后面的LL库是ST新添加的,随HAL源码包一起提供,目前支持的芯片也偏少. 标准外设库(Standard Peri ...

  8. DW1000开发笔记(三)基于STM32 HAL库裸机工程移植DW1000官方驱动

    系列文章 DW1000开发笔记(一)DW1000芯片概览 DW1000开发笔记(二)使用STM32硬件SPI+STM32cubeMX+HAL库测试DW1000通信 一.官方驱动 Decawave官方提 ...

  9. Python数据分析学习系列 十三 Python建模库介绍

    Python数据分析学习系列 十三 Python建模库介绍 资料转自(GitHub地址):https://github.com/wesm/pydata-book 有需要的朋友可以自行去github下载 ...

最新文章

  1. OpenCV+python:模糊操作
  2. 测试django_如何像专业人士一样测试Django Signals
  3. map的key可以试一个数组吗?_【自考】数据结构第三章,数组,期末不挂科指南,第5篇...
  4. FluorineFx + Flex视频聊天室案例开发----客户端
  5. 智能合约重构社会契约 (5)比特犬模型实现智能合约
  6. 分类变量 哑变量矩阵 指标矩阵_不懂数据集重排序?分类变量转换苦难?4种python方法,不再难!...
  7. 计算机新入学教案,计算机应用 新教案(1-6周).doc
  8. HbuilderX、Hbuilder编辑器如何使用手机调试app
  9. 计算机系统中字word的描述性定义是,计算机基础练习题1
  10. 使用HTML5中的Canves标签制作时钟特效
  11. 我最看不惯的几个公众号
  12. linux五笔输入法制作_五笔98输入法制做--for Linux ibus
  13. 中英文1:2等宽字体
  14. 2020滑铁卢大学计算机科学学费,滑铁卢大学专业
  15. 在计算机上OF键开机键,电脑开机时出现英文字母串需要按回车键才能继
  16. MYSQL选修课的心得体会_选修课心得体会
  17. 2017北京区域赛 G - Liaoning Ship’s Voyage【计算几何+bfs】
  18. 01-交换机级联实验
  19. 纯CSS实现多行文本溢出显示省略号(兼容不同浏览器)
  20. buu crypto 变异凯撒

热门文章

  1. 如何调用Revit API实现风道末端与风管连接?
  2. 新冠病毒爆发如何预防?用Python模拟病毒应对策略(附代码)
  3. phpcms之管理栏目添加单网页遇到的英文名称已经存在的问题
  4. python进程管理讲解_python之supervisor进程管理工具
  5. 服务器架设了网站还能架设游戏吗,云服务器可以架设游戏吗
  6. 前端模块化 AMD 详解
  7. MySQL不建议使用UUID作为主键的原因
  8. 一站式解决方案,华为云CDN这波双十一很强!
  9. C语言程序设计(第4版)谭浩强著—学习笔记chapter one 程序设计与C语言
  10. MyBatis中万能的Map和模糊查询