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

21 篇文章 11 订阅
20 篇文章 33 订阅

目录

概述

 电路

通信

读写时序

芯片寄存器

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

00032.768KHz

00112MHz

10124MHz

01012MHz

11026MHz

01119.2MHz

11138.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

0087-108

0176-91

1076-108

1165-7650-65

(根据0x07寄存器的bit9选择)

1:0

SPACE

频率的间隔

00

00100kHz

01200kHz

1050kHz

1125kHz

0x04

寄存器

字节

名称

功能

默认值

0x04

15

RSVD

保留字(无功能)

0

14

STCIEN

搜索和调谐中断使能

0

0:禁用

1:启用

(中断是GPIO2的低脉冲)

13

RBDS

RBDS/RDS功能

0

0:仅使用RDS

1RBDS启用

12

RDS_FIFO_EN

RDS先进先出功能

0

0:禁用

1“启用

11

DE

去重

0

075us

150us

10

RDS_FIFO_CLR

清除RDS先进先出

1

1:清除

9

SOFTMUTE_EN

软件静音使能

0

0:关闭软件静音

1:开启软件静音

8

AFCD

AFC失能

0

0AFC启用

1AFK禁用

7

Rsvd

被读取时为0

0

6

I2S_ENABLE

I2C使能

0

0:关闭

1:打开

5:4

GPIO3[1:0]

GPIO3

00

00:高

01:单声/立体声指示

10:低电平

11:高电平

32

GPIO2[1:0]

GPIO2

00

00:高

01:中断

10:低电平

11:高电平

10

GPIO1[1:0]

GPIO1

00

00:高

01:保留

10:低电平

11:高电平

0x05

寄存器

字节

名称

功能

默认值

0x05

15

INT _MODE

中断模式

1

05ms中断

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:无输入

01LNAN

10LNAP

11:双输入

5:4

LNA_ICSEL_BIT[1:0]

低噪声放大器工作电流

00

001.8mA

012.1mA

102.5mA

113.0mA

30

VOLUME[3:0]

音量

1011

0-15等级

0x06

寄存器

字节

名称

功能

默认值

0x06

15

RSVD

保留

0

1413

OPEN_MODE[1:0]

保留寄存器模式

00

11:打开寄存器后写入

其他:仅打开寄存器后读取功能

12

slave_master

I2S主从

0

0:主机

1:从

11

ws_lr

Wsl/r通道的关系

0

0ws=0 ->r, ws=1 ->l

1ws=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_STEP44.1kbps;

0110: WS_STEP32kbps;

 0101: WS_STEP24kbps;

0100: WS_STEP22.05kbps;

0011: WS_STEP16kbps;

0010: WS_STEP12kbps;

0001: WS_STEP11.025kbps;

 0000: WS_STEP8kbps;

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

150

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

0RDS解码器未同步(默认)

1RDS解码器已同步

仅在RDS详细模式下可用

11

BLK_E

0

RDS启用时

0:没有找到Block E

1:找到Block E

10

ST

立体声指示

1

0:单声道

1:立体声

90

READCHAN[9:0]

信道值

0x00

0x0B

寄存器

字节

名称

功能

默认值

0x0B

159

RSSI[6:0]

信号强度

0

0-127

8

FM TRUE

电台指示

0

0:不是电台

1:是电台

7

FM_READY

软件搜索

0

0:没有就绪

1:就绪

65

RSVD

保留

4

ABCD_E

0x0c,0x0d,0x0e,0x0f功能

0

0ABCD

1E

3:2

BLERA[1:0]

纠错级别

000需要更正的错误

01:需要纠正的1~2个错误

10:需要纠正的3-5个错误

116+错误或校验字错误,无法纠正。

1:0

BLERB[1:0]

纠错级别

000需要更正的错误

01:需要纠正的1~2个错误

10:需要纠正的3-5个错误

116+错误或校验字错误,无法纠正。

其余寄存器

寄存器

字节

名称

功能

默认值

0x0C

150

RDSA[15:0]

BLOCK A ( RDS模式) BLOCK E (0x0B[4]=1)

0x5803

0x0D

150

RDSB[15:0]

BLOCK B ( RDS模式) BLOCK E (0x0B[4]=1)

0x5804

0x0E

150

RDSC[15:0]

BLOCK C ( RDS模式) BLOCK E (0x0B[4]=1)

0x5808

0x0F

150

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

STM32F4xx HAL库是针对STM32F4系列微控制器的一套软件,是ST公司提供的一种高级抽象层级(HAL)软件。该致力于简化STM32F4系列微控制器的驱动和操作,使开发人员可以更加轻松地使用STM32微控制器。 STM32F4xx HAL库提供了丰富的功能和接口,包括GPIO(通用输入输出),UART(通用异步收发器),SPI(串行外设接口),I2C(I²C总线接口),定时器,ADC(模数转换器)等。通过这些功能和接口,开发人员可以实现各种应用,如串行通信、数据采集、外设控制等。 HAL库详解主要包括以下几个方面: 1. 初始化和配置:HAL库提供了一系列函数来初始化和配置微控制器的各个模块。开发人员只需设置相应的参数并调用相应的函数即可完成初始化和配置工作。 2. 中断处理:HAL库提供了用于中断处理的函数,并且简化了中断的使用。开发人员可以使用HAL库提供的函数注册中断处理函数,并可以方便地配置中断触发条件和优先级。 3. 外设驱动HAL库提供了各种外设的驱动函数,使开发人员可以方便地配置和操作外设。开发人员只需简单地调用相应的函数即可实现对外设的控制。 4. 时钟管理:HAL库提供了函数用于设置各个模块的时钟。开发人员可根据需求调整时钟频率和分频系数,从而优化系统性能。 5. 低功耗模式:HAL库支持低功耗模式,可以帮助开发人员优化系统功耗。通过调用相应的函数,开发人员可以将系统进入低功耗模式,并在必要时唤醒系统。 总之,STM32F4xx HAL库是一套强大而灵活的软件,它简化了STM32F4系列微控制器的驱动和操作。通过HAL库,开发人员可以更加轻松地进行嵌入式系统开发,提高开发效率并降低开发成本。
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值