【STM32F4系列】【HAL库】【自制库】RDA5807M收音机芯片驱动
目录
概述
电路
通信
读写时序
芯片寄存器
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收音机芯片驱动相关推荐
- STM32F4系列HAL库配置定时器实验——输入捕获
STM32F4系列HAL库配置定时器实验--输入捕获 输入捕获简单讲解 输入捕获模式可以用来测量脉冲宽度或者测量频率.我们以测量周期和频率为例,用一个简图来说明输入捕获的原理 假定定时器工作在向上计数 ...
- STM32F4系列 HAL Flash 读写
前言 注意:F0F1系列和F4系列的Flash读写操作不相同 一.STM32CubeMX怎么查看芯片的Flash分布? 二.擦除F4系列Flash 本例程使用的是F411CEU6的型号芯片 1.擦除F ...
- 【STM32F4系列】【HAL库】【自制库】WS2812(软件部分)(PWM+DMA)
文章目录 相关链接 协议 外设设置 硬件PWM 分析 HAL设置 DMA 分析 HAL设置 方案设计 代码实现 解码函数 开始发送和复位 发送函数 波形 成品 相关链接 硬件介绍(PCB设计方案) 模 ...
- STM32CubeMX | STM32 F1系列HAL库低功耗STOP和STANDBY模式唤醒(RTC时钟唤醒+外部中断唤醒示例)
STM32CubeMX | STM32 F1系列HAL库低功耗STOP和STANDBY模式唤醒(RTC时钟唤醒+外部中断唤醒示例) 目录 STM32CubeMX | STM32 F1系列HAL库低功耗 ...
- STM32F1系列HAL库配置系统时钟
STM32F1系列HAL库配置系统时钟 其实一开始对于时钟我也是知之甚少,在MSP432中我就一直忽视时钟配置,其实也是在STM32学习时落下的病根,现在趁有空补一下. 时钟简单讲解 对于时钟系统,在 ...
- STM32系列(HAL库)——F103C8T6通过MFRC522、RFID射频卡、门禁卡模块读取卡片ID(二)
本文继上一篇:STM32系列(HAL库)--F103C8T6通过MFRC522.RFID射频卡.门禁卡模块读取卡片ID 本文介绍在运用RC522模块时,运用链表结构存储数据的操作 Let's go! ...
- STM32中STD、HAL、LL库比较
ST为开发者提供了标准外设库(STD库).HAL库.LL库 三种.前两者都是常用的库,后面的LL库是ST新添加的,随HAL源码包一起提供,目前支持的芯片也偏少. 标准外设库(Standard Peri ...
- DW1000开发笔记(三)基于STM32 HAL库裸机工程移植DW1000官方驱动
系列文章 DW1000开发笔记(一)DW1000芯片概览 DW1000开发笔记(二)使用STM32硬件SPI+STM32cubeMX+HAL库测试DW1000通信 一.官方驱动 Decawave官方提 ...
- Python数据分析学习系列 十三 Python建模库介绍
Python数据分析学习系列 十三 Python建模库介绍 资料转自(GitHub地址):https://github.com/wesm/pydata-book 有需要的朋友可以自行去github下载 ...
最新文章
- OpenCV+python:模糊操作
- 测试django_如何像专业人士一样测试Django Signals
- map的key可以试一个数组吗?_【自考】数据结构第三章,数组,期末不挂科指南,第5篇...
- FluorineFx + Flex视频聊天室案例开发----客户端
- 智能合约重构社会契约 (5)比特犬模型实现智能合约
- 分类变量 哑变量矩阵 指标矩阵_不懂数据集重排序?分类变量转换苦难?4种python方法,不再难!...
- 计算机新入学教案,计算机应用 新教案(1-6周).doc
- HbuilderX、Hbuilder编辑器如何使用手机调试app
- 计算机系统中字word的描述性定义是,计算机基础练习题1
- 使用HTML5中的Canves标签制作时钟特效
- 我最看不惯的几个公众号
- linux五笔输入法制作_五笔98输入法制做--for Linux ibus
- 中英文1:2等宽字体
- 2020滑铁卢大学计算机科学学费,滑铁卢大学专业
- 在计算机上OF键开机键,电脑开机时出现英文字母串需要按回车键才能继
- MYSQL选修课的心得体会_选修课心得体会
- 2017北京区域赛 G - Liaoning Ship’s Voyage【计算几何+bfs】
- 01-交换机级联实验
- 纯CSS实现多行文本溢出显示省略号(兼容不同浏览器)
- buu crypto 变异凯撒