嵌入式
返回首页

使用RDA5807构建一个Arduino FM收音机

2022-08-22 来源:elecfans

  今天几乎每个人都用手机听音乐、新闻、播客等。但不久前,我们都依靠当地的 FM 收音机来获取最新的新闻和歌曲,慢慢地这些收音机正在失去人气,但在互联网的紧急情况下停电后,收音机在向用户传输信息方面发挥了重要作用。无线电信号始终存在于空中(由电台广播),我们所需要的只是一个FM 接收器电路来捕获这些无线电信号并将它们转换为音频信号。


  在本教程中,我们将构建一个Arduino FM 接收器,并将其添加到我们的项目库中。我们将使用带有 Arduino 的 RDA5807 FM 接收器 IC并对其进行编程,播放任何可由用户使用电位计调谐的 FM 广播电台。我们还将使用音频放大器和电路来控制我们的Arduino FM 收音机的输出音量,听起来很有趣吧?那么,让我们开始吧。


  调频收音机一般工作

  无线电台将电信号转换为无线电信号,这些信号在通过天线传输之前必须进行调制。有两种方法可以调制信号,即 AM 和 FM。顾名思义,幅度调制 (AM)在发送信号之前调制幅度,而在频率调制 (FM)中,在通过天线发送之前调制信号的频率。在无线电台,他们使用频率调制来调制信号,然后传输数据。现在,我们只需要构建一个可以调谐到特定频率并接收这些信号的接收器,然后将这些电信号转换为音频信号。我们将使用本项目中的RDA5807 FM 接收模块,简化了我们的电路。


  所需组件

  Arduino纳米

  RDA5807接收器

  音频放大器

  连接线

  底池 – 100K

  性能板


  RDA5807 接收器

  RDA5807是一款单芯片FM 立体声收音机调谐器模块,具有完全集成的合成器。模块支持全球50-115MHz频段、音量控制和静音、可编程去加重(50/75us)、接收信号强度指示和信噪比、32.768KHz晶振、数字自动增益控制等。下图为RDA5807M 调谐器的框图。

poYBAGL_MkeACcu-AAFTa8JIeWI082.png

  它具有数字低中频架构,并集成了支持 FM 广播频段(50 至 115 MHz)的低噪声放大器 (LNA)、可编程增益控制 (PGA)、高分辨率模数转换器和高保真数模转换器 (DAC)。限幅器可防止过载并限制相邻信道产生的互调产物的数量。PGA 放大混频器输出信号,然后使用 ADC 进行数字化。DSP 内核管理频道选择、FM 解调、立体声 MPX 解码器和输出音频信号。该IC 的RDA5807 引脚图如下所示。

poYBAGL_MkOAentFAAFRJmuH_N0484.png

  该模块工作在1.8 – 3.3V 的电源上。当进入休眠状态并选择控制接口时,VIO 上电时模块会自行复位,也支持通过 02H 地址的 0 到 1 的 bit1 触发软复位。模块使用I2C 通信与 MCU 通信,接口以启动条件、命令字节和数据字节开始。RDA5807 有 13 个 16 位寄存器,每个寄存器执行一个特定的功能。寄存器地址以 00H 开始,分配给芯片 ID,以 0FH 结束。在所有 13 个寄存器中,一些位被保留,而一些位是 R/W。每个寄存器根据分配给它们的位执行诸如改变音量、改变通道等任务。

  将模块连接到电路时,我们不能直接使用模块,因为引脚是封闭的。所以,我使用了一个穿孔板和一些公插针,并将模块的每个插针焊接到每个公插针上,如下图所示。

poYBAGL_Mj-AYzU7AAPIrYwbHYs284.png

  音频放大器

  音频放大器是一种电子设备,可将低功率电子音频信号放大到足以驱动扬声器或耳机的水平。我们使用 LM386 构建了一个简单的音频放大器,相同的电路如下所示,您也可以查看链接以了解有关此电路的更多信息,也可以查看其他音频放大器电路。

poYBAGL_MjuABBYnAADuUfVkoSs290.png

  Arduino FM接收器电路图

  我们使用了两个电位器来调整 FM 波段和控制音频放大器的音量。要改变音量,您可以改变连接在 LM386 的第 1 和第 8 引脚之间的电位器或连接在 LM386 的引脚 3 之间的电位器。下图显示了Arduino FM Radio 的完整电路图。

poYBAGL_MjaAK3R0AAKNGjqZtkI869.png

  我对放大器做了一些改动。我没有在放大器中使用两个电位器,而是只使用了一个。我把用来改变增益的电位器换成了一个电阻。所以现在我们的项目有两个电位器,一个用来调节,一个用来改变音量。用于调谐通道的电位器与 Arduino nano 相连。锅的中心引脚连接到Arduino nano的A0引脚,其余两个引脚中的一个连接到5V,另一个连接到GND。另一个电位器用于控制收音机的音量,连接方式如上图所示。

  Arduino 的引脚 A4 和 A5 连接到 RDA5807M 的 SDA 和 SCL 引脚。请记住,接收器模块仅适用于 3.3V。因此,将 Nano 的 3v3 引脚连接到接收器模块的 VCC 引脚。建立连接后,我的设置看起来像这样

pYYBAGL_MjOAT4xjAAZmeDXFBig356.png

  Arduino FM收音机代码说明

  该代码将初始化接收器模块,然后将频道设置为预设频率。当 nano 在 A0 引脚上读取的值发生变化(通过改变电位器)时,频率会发生变化,从而改变通道。完整的代码在页面末尾给出。

  我们通过添加与 RDA5807 通信所需的线库来开始我们的程序。然后,在变量“通道”中,我们设置通道的值。每当收音机启动时,它都会自动调到该频道。

 

#includeuint16_t 通道 = 187;

 

接下来,我们将向 RDA5807 IC 上的每个寄存器加载字节以设置我们的初始配置。此时,我们正在重置接收器。

 

uint8_t 引导配置 [] = {
  /* 寄存器 0x02 */
  0b11000001,
  0b00000011,
  /* 寄存器 0x03 */
  0b00000000,
  0b00000000,
  /* 寄存器 0x04 */
  0b00001010,
  0b00000000,
  /* 寄存器 0x05 */
  0b10001000,
  0b00001111,
  /* 寄存器 0x06 */
  0b00000000,   
  0b00000000,
  /* 寄存器 0x07 */
  0b01000010,
  0b00000010,
};

 

重置设备后,我们可以调整设备。为了调谐通道,我们只需要编程前 4 个字节。这部分代码会将频道更改为所需的频率。在 I2C 中,我们首先开始传输,写入或读取数据,然后结束传输。在这个接收器IC中,我们不必指定地址,因为数据表清楚地说明了I2C接口有一个固定的起始寄存器,即0x02h用于写操作,0x0Ah用于读操作。

 

uint8_t tune_config[] = {
  /* 寄存器 0x02 */
  0b11000000,
   0b00000001,
   /* 寄存器 0x03 */
   (频道 >> 2),
   ((频道 & 0b11) << 6 ) | 0b00010000
};

 

在设置中,我们初始化引导配置(重置),然后通过将调谐配置字节写入 RDA5807M 来调谐到一个通道。

 

无效设置()
{
  序列号.开始(9600);  pinMode(A0,输入);
  /* 连接到 RDA5807M FM 调谐器:*/
  Wire.begin();
  Wire.beginTransmission(RDA5807M_ADDRESS);
  Wire.write(boot_config, BOOT_CONFIG_LEN);
  Wire.endTransmission();
  Wire.beginTransmission(RDA5807M_ADDRESS);
  Wire.write(tune_config, TUNE_CONFIG_LEN);
  Wire.endTransmission();
}

 

当使用pot调整频率时,我遇到了一个问题。A0 引脚读取的值不是恒定的。有一个噪声与所需的值结合在一起。我在 A0 和 GND 之间使用了一个 0.1uF 的陶瓷电容器,虽然噪声已经降到最低,但它并没有达到预期的水平。因此,我不得不对代码进行一些更改。起初,我记下了受噪音影响的读数。我发现噪声的最大值是10。所以我编写了这样的程序,如果同一引脚的新值与旧值之间的差异大于10,它只会考虑新值然后调到想要的频道。

 

无效循环()
{
  int channel1 =187 ,avg=0, newA;
  静态int oldA = 0;
  整数结果 = 0;
  newA = 模拟读取(A0);
  如果 ((newA - oldA) > 10 || (oldA - newA) > 10){
   序列号.println(newA);
  如果(新A!=旧A){
     通道 = 通道 1+(newA/10);
    我的改变频道(频道);
    旧A=新A;
  }
}
}//循环结束

 

该函数用于设置tune_config数组的字节,然后使用 I2C 协议将数据传输到 RDA5807M IC。

 

void myChangeChannel(int channel){ /* 如果没有返回则为 void else int */
   tune_config[2] = (频道 >> 2);
   tune_config[3] = ((频道 & 0b11) << 6) | 0b00010000;
      Wire.begin();
      Wire.beginTransmission(RDA5807M_ADDRESS);
      Wire.write(tune_config, TUNE_CONFIG_LEN);
      Wire.endTransmission();
  }

 

  Arduino FM 收音机的工作原理

  当模块上电时,我们的代码重置 RDA5807-M IC 并将其设置为用户所需的通道(注意:此频率被视为频率将增加的基本频率)。通过更改电位器(连接到 A0),Arduino Nano 读取的值会发生变化。如果新旧值之差大于 10,我们的代码会考虑这个新值。通道根据新值与旧值的变化而变化。增加或减少音量取决于电位器,它连接在引脚 3 和 GND 之间。

pYYBAGL_MiuAKiqpAAfiQ-QERTA667.png

#include  

    /* 选择我们想要调谐到的频率*

     选择所需频率的频道 

     */ 

uint16_t channel = 187; 

    /* 

     * 假设频段从 87.0MHz 开始(根据以下设置)

     * 通道间隔为 100kHz(0.1MHz)(根据以下设置)

     * 然后可以按如下方式得出通道:

     *   

     * 通道 =(<以 MHz 为单位的所需频率> - 87.0) / 0.1  

     * 

     * 等同于:

     * <10 x 所需频率 (MHz)> - 870 

     */ 

#define RDA5807M_ADDRESS 0b0010000 // 0x10 

#define BOOT_CONFIG_LEN 12 

#define TUNE_CONFIG_LEN 4 

/* 

 * 这些字节设置了我们的初始配置

 * 在这个阶段我们不会费心去调到一个频道。

 * 但改为启动重置。

 */ 

uint8_t boot_config[] = { 

  /* register 0x02 */ 

  0b11000001, 

    /*  

     * DHIZ audio output high-z disable 

     * 1 = normal operaTIon 

     * 

     * DMUTE mute disable  

     * 1 = normal operaTIon 

     * 

     * MONO mono select 

     * 0 = stereo 

     * 

     * BASS 低音增强

     * 0 = 禁用

     * 

     * RCLK 非校准模式 

     * 0 = 始终提供 RCLK 

     *

     * RCLK 直接输入模式 

     * 0 = ??? 不确定这是做什么的

     * 

     * SEEKUP 

     * 0 = 向下搜索

     * 

     * SEEK 

     * 0 = 禁用/停止搜索(即不搜索)

     */ 

  0b00000011, 

    /*  

     * SKMODE 搜索模式:  

     * 0 = 向上换行或下限和继续搜索

     * 

     * CLK_MODE 时钟模式

     * 000 = 32.768kHZ 时钟速率(匹配模块上的手表晶体)  

     * 

     * RDS_EN 无线电数据系统启用

     * 0 = 禁用无线电数据系统

     * 

     * NEW_METHOD 使用新的解调方法进行改进灵敏度

     * 0 = 可能已禁用 

     * 

     * SOFT_RESET 

     * 1 = 执行重置

     * 

     * ENABLE 上电启用:  

     * 1 = 启用

     */  

  /* 寄存器 0x03 */ 

    /* 在此阶段不要费心调谐到频道*/ 

  0b00000000 ,  

    /*  

     * CHAN 通道选择总共 10 的 8 个最高有效位

     * 0000 0000 = 此时不要对通道进行编程

     */ 

  0b00000000, 

    /*  

     * CHAN 总共 10 的两个最低有效位 

     * 00 = don '此时无需费心对频道进行编程

     * 

     * DIRECT MODE 仅在测试时使用

     * 0 = 可能禁用

     * 

     * TUNE 开始调谐操作 

     * 0 = 禁用(即不调谐到所选频道)

     * 

     * BAND 波段选择

     * 00 = 选择 87-108MHz 波段

     * 

     * SPACE 频道间隔

     * 00 = 选择间隔通道之间 100kHz 

     */     

  /* 寄存器 0x04 */ 

  0b00001010,  

    /*  

     * 保留 15 

     * 0 

     * 

     * 大概保留 14 

     * 0 

     * 

     * 保留 13:12 

     * 00 

     * 

     * DE 去加重: 

     * 1 = 澳大利亚使用的 50us 去加重

     * 

     * 保留

     * 0 

     * 

     * SOFTMUTE_EN 

     * 1 = 启用软静音

     * 

     * AFCD AFC 禁用

     * 0 = AFC 启用

     */ 

  0b00000000,  

    /*  

     * 位 7-0 未指定,所以假设所有的 0 

     * 0000 0000 

     */   

  /* 寄存器 0x05 */ 

  0b10001000,  

    /*  

     * INT_MODE 

     * 1 = 中断最后直到读取 reg 0x0C 

     * 

     * 保留 14:12  

     * 000 

     * 

     * SEEKTH 寻道信噪比阈值

     * 1000 = 建议的默认值

     */    

  0b00001111,  

    /*  

     * 大概保留 7:6 

     * 00 

     * 

     * 保留 5:4 

     * 00 

     * 

     * 音量

     * 1111 = 最大音量

     */  

  /* 寄存器 0x06 */ 

  0b00000000,  

    /*  

     * 保留 15 

     * 0 

     * 

     * OPEN_MODE 打开保留寄存器模式

     * 00 = 建议的默认值

     * 

     * 未指定位 12:8,因此假设全为 0 

     * 00000 

     */    

  0b00000000,  

    /* 

     * 位 7:0 未指定,因此假设全为 0 

     * 00000000 

     */     

  /* 寄存器 0x07 */ 

  0b01000010,  

    /*  

     * 保留 15  

     * 0 

     * 

     * TH_SOFRBLEND 噪声软混合设置阈值

     * 10000 = 使用默认值

     * 

     * 65M_50M MODE  

     * 1 = 仅适用于 0b11 的 BAND 设置,因此这里也可以使用 0 

     * 

     * RESERVED 8 

     * 0 

     */       

  0b00000010,  

    /*    

     * SEEK_TH_OLD 旧搜索模式的搜索阈值

     * 000000 

     *

     * SOFTBLEND_EN 软混合启用

     * 1 = 使用默认值

     * 

     * FREQ_MODE 

     * 0 = 使用默认值

     */   

}; 

/* 复位后,我们可以调整设备

 * 我们只需要编程前 4 个字节就可以做到这一点

 */ 

uint8_t tune_config[] = { 

  /* register 0x02 */ 

  0b11000000,  

    /*  

     * DHIZ audio output high-z disable 

     * 1 = 正常运行

     * 

     * DMUTE 静音禁用 

     * 1 = 正常运行

     * 

     * MONO 单声道选择

     * 0 = 单声道

     * 

     * BASS 低音增强

     * 0 = 禁用

     * 

     * RCLK 非校准模式 

     * 0 = 始终提供RCLK 

     * 

     * RCLK 直接输入模式 

     * 0 = ??? 不确定这是做什么的

     * 

     * SEEKUP 

     * 0 = 向下搜索

     * 

     * SEEK 

     * 0 = 禁用/停止搜索(即不搜索)

     */    

   0b00000001,  

    /*  

     * SKMODE 搜索模式:  

     * 0 = 向上换行或下限和继续寻求

     * 

     * CLK_MODE 时钟模式

     * 000 = 32.768kHZ 时钟速率(匹配模块上的手表晶体)  

     *

     * RDS_EN 无线电数据系统启用

     * 0 = 禁用无线电数据系统

     * 

     * NEW_METHOD 使用新的解调方法来提高灵敏度

     * 0 = 可能已禁用 

     * 

     * SOFT_RESET 

     * 0 = 这次不要重置

     * 

     * 启用上电启用:  

     * 1 = 启用

     */  

   /* 寄存器 0x03 */ 

   /* 这是我们设置要调谐到的频率的位置 */ 

   (channel >> 2),  

    /* CHAN channel select 8 most Significant bits of 10 */ 

   ((channel & 0b11) << 6) | 0b00010000 

    /*  

     * CHAN 总共 10 的两个最低有效位 

     * 

     * DIRECT MODE 仅在测试时使用

     * 0 = 可能禁用

     * 

     * TUNE 开始调谐操作 

     * 1 = 启用(即调谐到所选频道)

     * 

     * BAND 波段选择

     * 00 = 选择 87-108MHz 波段

     * 

     * SPACE 频道间隔

     * 00 = 选择通道之间的 100kHz 间隔

     */   

}; 

无效设置()

{

  序列.开始(9600);

  pinMode(A0,输入);

  Wire.begin(); 

  Wire.beginTransmission(RDA5807M_ADDRESS); 

  Wire.write(boot_config, BOOT_CONFIG_LEN); 

  Wire.endTransmission();

  Wire.beginTransmission(RDA5807M_ADDRESS); 

  Wire.write(tune_config, TUNE_CONFIG_LEN); 

  Wire.endTransmission(); 

}//设置结束

void loop() 

  int channel1 =90,newA; 

  静态int oldA = 0; // 将 oldA 设置为 HIGH 

  int result = 0; 

  newA = 模拟读取(A0);

  if ((newA - oldA) > 10 || (oldA - newA) > 10){ 

    Serial.println(newA); 

    if(newA!= oldA){

      通道 = 通道 1+(newA/10); 

      我的改变频道(频道);

      旧A=新A;

      } 

  uint16_t 频率 = 频道+870;

  uint16_t num1 = (频率/1000) % 10; 

  uint16_t num2 = (频率/100) % 10;

  uint16_t num3 = (频率/10) % 10; 

  uint16_t num4 = 频率 % 10; 

  序列号.print(num1); 

  序列号.print(num2); 

  序列号.print(num3); 

  序列号.print(num4); 

  Serial.print('--'); 

  Serial.println(通道+870); 

}//loop end 

/* 

 * 改变radio RDA5807频道的函数

 * 示例:channel = 191  

 */ 

void myChangeChannel(int channel){ /* 如果没有返回则为void else int */ 

  /* 

   * 首先将新频道写入tune_config海量

   */ 

   tune_config[2] = (频道 >> 2); 

   tune_config[3] = ((频道 & 0b11) << 6) | 0b00010000; 

      Wire.begin();

      Wire.beginTransmission(RDA5807M_ADDRESS); 

      Wire.write(tune_config, TUNE_CONFIG_LEN); 

      Wire.endTransmission(); 

  }


进入嵌入式查看更多内容>>
相关视频
  • PX4固件二次开发课程

  • RISC-V嵌入式系统开发

  • NuttX Workshop 2024

  • 自己动手写操作系统

  • SOC系统级芯片设计实验

  • 自己动手做一台计算机

精选电路图
  • 单稳态控制电路设计与分析

  • IGBT模块通过控制门极阻断过电流

  • 开关电源的基本组成及工作原理

  • 比较常见的功率整流器和滤波电路

  • 基于CA3193的热电偶放大器电路

  • 基于TDA1554的立体声放大器电路

    相关电子头条文章