FM Radio using Arduino. DIY

Programming, Tutorial, Coding, New Design, and/or any project for your Arduino and Raspberry Pi can post your topic /suggestion here.
User avatar
Dohangout
Admin
Admin
Contact:
Location: Philippines
Posts: 198
Joined: Sat Apr 23, 2016 10:32 pm

FM Radio using Arduino. DIY

Mon Mar 30, 2020 6:06 pm

Radios are losing popularity but in emergencies when the internet is down, radios place an important role to transmit information to the users. Radio signals are always present in the air (which are broadcasted by the stations), and all we need is an FM receiver circuit to catch those radio signals and transfer them to audio signals.
RDA5807M-Tuner-Cicuit-Diagram.jpg
RDA5807M-Tuner-Cicuit-Diagram.jpg (53.17 KiB) Viewed 852 times
In this tutorial we are going to construct an Arduino FM Receiver, and add it to our project arsenal. We will use the RDA5807 FM Receiver IC with Arduino and program it so, play any FM radio station which can be tuned by the user with a potentiometer. We will also use an Audio Amplifier along with the circuit to control the output volume of our Arduino FM Radio.

Components Required
- Arduino Nano
- RDA5807 receiver
- Audio Amplifier
- Connecting wires
- Pot – 100K
- Perf Board

It has digital low-IF architecture and integrates a low noise amplifier (LNA), which supports the FM broadcast band (50 to 115 MHz), a programmable gain control(PGA), a high-resolution analog-to-digital converter, and a high fidelity digital-to-analog converters (DACs). The limiter prevents overloading and limits the number of intermodulation products created by adjacent channels. The PGA amplifies the mixer output signal and then digitized with ADCs. The DSP core manages the channel selection, FM demodulation, stereo MPX decoder, and output audio signal. The RDA5807 pinout diagram for the IC is given below.
RDA5807-Pinout.png
RDA5807-Pinout.png (37.48 KiB) Viewed 852 times
The module works on the power supply of 1.8 – 3.3V. When coming to rest and control interface selected, the module resets itself when VIO is Power up, and also supports soft reset by the trigger of bit1 from 0 to 1 of 02H address. The module uses I2C communication to communicate with the MCU, and the interface begins with starts condition, a command byte, and data bytes. The RDA5807 has 13 16-bit registers, each performing a particular function. The register addresses start with 00H, which is allotted to chip ID and ends with 0FH. In all 13 registers, some bits are reserved while some are R/W. Each register performs tasks like varying volume, changing channels, etc depending upon the bits assigned to them.

Audio Amplifier
An audio amplifier is an electronic device, which amplifies low-power electronic audio signals to a level where it is high enough for driving loudspeakers or headphones. We have built a simple audio amplifier using LM386, the circuit for the same is shown below and you can also check the link to learn more about this circuit, also check other audio amplifier circuits.
Audio-Amplifier-Circuit-Diagram.png
Audio-Amplifier-Circuit-Diagram.png (28.06 KiB) Viewed 852 times
Arduino FM Receiver Circuit Diagram
We used two potentiometers for tuning the FM band and controlling the volume of the audio amplifier. To change the volume you can either vary the pot, which is connected in between 1 and 8th pin of LM386 or the pot, which is connected at pin 3 of the LM386. The below pic shows the complete circuit diagram for Arduino FM Radio.
Arduino-Based-FM-Radio-using-RDA5807-Circuit-Diagram.png
I did little changes in the amplifier. Instead of using two potentiometers in the amplifier, I used only one. I interchanged the pot, which is used to change the Gain, with a resistor. So now our project has two potentiometers one to tune, and one to change the volume. The potentiometer, which is used to tune the channel is connected with the Arduino nano. The center pin of the pot is connected to the A0 pin of the Arduino nano, and either of the remaining two pins is connected to the 5V and the other is connected to the GND. Another pot is used to control the volume of the radio and is connected as shown in the above fig.

The pin A4 and A5 of the Arduino are connected to SDA and SCL pin of the RDA5807M. keep in mind that the receiver module works only on 3.3V. So, connect the 3v3 pin of the Nano to the VCC pin of the receiver module.

The code will initialize the receiver module and then sets the channel with the preset frequency. When the value read by the nano at the A0 pin changes (by changing pot) the frequency changes which in turn changes the channel. The full code is given at the end of the page.

We begin our program by adding the required wire library for communicating with RDA5807. Then, in the variable “channel” we set the value of the channel. Whenever the radio starts it will get tuned to this channel automatically.

Working of Arduino FM Radio
When the module is powered up, our code resets the RDA5807-M IC and sets it to a channel of the user desired (Note: this frequency is taken as the base frequency upon which the frequency will be incremented). By changing the potentiometer (connected to A0), the values read by the Arduino Nano changes. If the difference between the new and old value is greater than 10, our code will consider this new value. The channel is changed depending upon the change in the new value from the old value. Increasing or decreasing the volume depends on the potentiometer, which is connected in between the pin 3 and GND.

At the end of the construction and coding, you will be having your own FM Radio. The complete working of the FM Radio can be found in the video linked at the bottom of this page. Hope you enjoyed the project and learned something useful. Please share and don't hit and run.

The Code

Code: Select all

#include <Wire.h>
    /* Select the frequency we want to tune to by way
     * of selecting the channel for the desired frequency 
     */
uint16_t channel = 187; 
    /*
     * assuming band starts at 87.0MHz (per settings below)
     * and channel spacing of 100kHz (0.1MHz) (per settings below)
     * then channel can be derived as follows:
     *  
     * channel = (<desired freq in MHz> - 87.0) / 0.1 
     *
     * which is the same as:
     * <10 x desired freq in MHz> - 870
     */
#define RDA5807M_ADDRESS  0b0010000 // 0x10
#define BOOT_CONFIG_LEN 12
#define TUNE_CONFIG_LEN 4
/* 
 *  These bytes set our initial configuration
 *  We don't bother to tune to a channel at this stage.
 *  But instead initiate a reset.
 */
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 bass boost
     * 0 = disabled
     *
     * RCLK NON-CALIBRATE MODE 
     * 0 = RCLK is always supplied
     *
     * RCLK DIRECT INPUT MODE 
     * 0 = ??? not certain what this does
     *
     * SEEKUP
     * 0 = seek in down direction
     *
     * SEEK
     * 0 = disable / stop seek (i.e. don't seek)
     */
  0b00000011,
    /* 
     * SKMODE seek mode: 
     * 0 = wrap at upper or lower band limit and continue seeking
     *
     * CLK_MODE clock mode
     *  000 = 32.768kHZ clock rate (match the watch crystal on the module) 
     *
     * RDS_EN radio data system enable
     * 0 = disable radio data system
     *
     * NEW_METHOD use new demodulate method for improved sensitivity
     * 0 = presumably disabled 
     *
     * SOFT_RESET
     * 1 = perform a reset
     *
     * ENABLE power up enable: 
     * 1 = enabled
     */ 
  /* register 0x03 */
    /* Don't bother to tune to a channel at this stage*/
  0b00000000, 
    /* 
     * CHAN channel select 8 most significant bits of 10 in total
     * 0000 0000 = don't bother to program a channel at this time
     */
  0b00000000,
    /* 
     * CHAN two least significant bits of 10 in total 
     * 00 = don't bother to program a channel at this time
     *
     * DIRECT MODE used only when test
     * 0 = presumably disabled
     *
     * TUNE commence tune operation 
     * 0 = disable (i.e. don't tune to selected channel)
     *
     * BAND band select
     * 00 = select the 87-108MHz band
     *
     * SPACE channel spacing
     * 00 = select spacing of 100kHz between channels
     */    
  /* register 0x04 */
  0b00001010, 
    /* 
     * RESERVED 15
     * 0
     *
     * PRESUMABLY RESERVED 14
     * 0
     *
     * RESERVED 13:12
     * 00
     *
     * DE de-emphasis: 
     * 1 = 50us de-emphasis as used in Australia
     *
     * RESERVED
     * 0
     *
     * SOFTMUTE_EN
     * 1 = soft mute enabled
     *
     * AFCD AFC disable
     * 0 = AFC enabled
     */
  0b00000000, 
    /* 
     *  Bits 7-0 are not specified, so assume all 0's
     * 0000 0000
     */  
  /* register 0x05 */
  0b10001000, 
    /* 
     * INT_MODE
     * 1 = interrupt last until read reg 0x0C
     *
     * RESERVED 14:12 
     * 000
     *
     * SEEK seek signal to noise ratio threshold
     * 1000 = suggested default
     */   
  0b00001111, 
    /* 
     * PRESUMABLY RESERVED 7:6
     * 00
     *
     * RESERVED 5:4
     * 00
     *
     * VOLUME
     * 1111 = loudest volume
     */ 
  /* register 0x06 */
  0b00000000, 
    /* 
     * RESERVED 15
     * 0
     *
     * OPEN_MODE open reserved registers mode
     * 00 = suggested default
     *
     * Bits 12:8 are not specified, so assume all 0's
     * 00000
     */   
  0b00000000, 
    /* 
     *  Bits 7:0 are not specified, so assume all 0's
     *  00000000
     */    
  /* register 0x07 */
  0b01000010, 
    /* 
     *  RESERVED 15 
     * 0
     *
     * TH_SOFRBLEND threshold for noise soft blend setting
     * 10000 = using default value
     *
     * 65M_50M MODE 
     * 1 = only applies to BAND setting of 0b11, so could probably use 0 here too
     *
     * RESERVED 8
     * 0
     */      
  0b00000010, 
    /*   
     *  SEEK_TH_OLD seek threshold for old seek mode
     * 000000
     *
     * SOFTBLEND_EN soft blend enable
     * 1 = using default value
     *
     * FREQ_MODE
     * 0 = using default value
     */  
};
/* After reset, we can tune the device
 * We only need program the first 4 bytes in order to do this
 */
uint8_t tune_config[] = {
  /* register 0x02 */
  0b11000000, 
    /* 
     * DHIZ audio output high-z disable
     * 1 = normal operation
     *
     * DMUTE mute disable 
     * 1 = normal operation
     *
     * MONO mono select
     * 0 = mono
     *
     * BASS bass boost
     * 0 = disabled
     *
     * RCLK NON-CALIBRATE MODE 
     * 0 = RCLK is always supplied
     *
     * RCLK DIRECT INPUT MODE 
     * 0 = ??? not certain what this does
     *
     * SEEKUP
     * 0 = seek in down direction
     *
     * SEEK
     * 0 = disable / stop seek (i.e. don't seek)
     */   
   0b00000001, 
    /* 
     * SKMODE seek mode: 
     * 0 = wrap at upper or lower band limit and continue seeking
     *
     * CLK_MODE clock mode
     * 000 = 32.768kHZ clock rate (match the watch crystal on the module) 
     *
     * RDS_EN radio data system enable
     * 0 = disable radio data system
     *
     * NEW_METHOD use new demodulate method for improved sensitivity
     * 0 = presumably disabled 
     *
     * SOFT_RESET
     * 0 = don't reset this time around
     *
     * ENABLE power up enable: 
     * 1 = enabled
     */ 
   /* register 0x03 */
   /* Here's where we set the frequency we want to tune to */
   (channel >> 2), 
    /* CHAN channel select 8 most significant bits of 10 in total   */
   ((channel & 0b11) << 6 ) | 0b00010000
    /* 
     *  CHAN two least significant bits of 10 in total 
     *
     * DIRECT MODE used only when test
     * 0 = presumably disabled
     *
     * TUNE commence tune operation 
     * 1 = enable (i.e. tune to selected channel)
     *
     * BAND band select
     * 00 = select the 87-108MHz band
     *
     * SPACE channel spacing
     * 00 = select spacing of 100kHz between channels
     */  
};
void setup()
{
  Serial.begin(9600);
  pinMode(A0,INPUT);
  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(); 
}//setup end
void loop()
{
  int channel1 =90,newA;
  static int oldA = 0; // set the oldA as HIGH
  int result = 0;
  newA = analogRead(A0);
  if ((newA - oldA) > 10 || (oldA - newA) > 10){
    Serial.println(newA);
    if(newA!= oldA){
      channel = channel1+(newA/10);
      myChangeChannel(channel);
      oldA=newA;
      }
}
  uint16_t frequency = channel+870;
  uint16_t num1 = (frequency / 1000) % 10;
  uint16_t num2 = (frequency / 100) % 10;
  uint16_t num3 = (frequency / 10) % 10;
  uint16_t num4 = frequency % 10;
  Serial.print(num1);
  Serial.print(num2);
  Serial.print(num3);
  Serial.print(num4);
  Serial.print("--");
  Serial.println(channel+870); 
}//loop end
/*
 * Function to change channel on radio RDA5807
 * Example: channel = 191 
 */
void myChangeChannel(int channel){ /* void if nothing is returned else int */
  /*
   * first write new channel to tune_config massive
   */
   tune_config[2] = (channel >> 2); 
   tune_config[3] = ((channel & 0b11) << 6 ) | 0b00010000;
      Wire.begin();
      Wire.beginTransmission(RDA5807M_ADDRESS);
      Wire.write(tune_config, TUNE_CONFIG_LEN);
      Wire.endTransmission();
  }
The Code:


Return to “ARDUINO AND RASPBERRY PI”

Links