고급 예제

다양한 도구들을 가지고 마음껏 응용해보세요.

FM 라디오 송/수신 모듈

2014-10-06 16:30:55

개요

이번 예제에서는 라디오 송신/수신 모듈에 대해서 알아보고
이를 이용하여 미니 방송국을 만들어 보겠습니다.



실습에 앞서 라디오의 원리를 살펴보면

방송국측의 마이크로폰으로부터 음성에 비례한 파형의 전압이 발생되는데

이때 음파의 주파수는 주파수가 낮아서(20-20,000[Hz]),

이 음파신호를 방송에 알맞게 높은 주파수(100[kHz]이상)의 파형에 실어서 송신을 해야 합니다.

여기서 음성이나 영상신호를 실어주는 고주파의 전파를 ‘반송파’라고 합니다.

따라서, 이 ‘반송파’에 ‘음성신호’를 실어 송출하면,

‘라디오’에서 이를 수신받아 ‘음성신호’를 스피커로 출력하게 됩니다.

 


이 반송파에 음성신호를 싣는 것을 변조라고 하며,

변조하는 방법에 따라 AM변조와 FM변조로 나뉘게 됩니다.

AM방송에서의 AM변조란 진폰변조를 말하며, 반송파의 진폭을 음성신호로 바꾸어 주는 것입니다.
 

예를들어 강한 음성일 때는 반송파의 진폭을 크게, 약한 음성일 때는 진폭을 작게 하는 것입니다.

한편, FM방송에서의 FM변조란 주파수변조로서, 반송파의 주파수를 음성신호로 바꾸어 주는 방법입니다.

FM에서는 반송파의 진폭은 항상 일정하고 음성신호의 강약을 주파수의 변화(고저)로 바꾸어 반송파에 실어 보내게 됩니다.

변조된 반송파는 증폭기로 증폭되어 안테나를 통해서 공중에 전파로 방출됩니다.

 

라디오에서는 안테나로 이 전파를 받게 되는데, 음성신호를 끄집어내는 부분과 음성신호를

증폭해서 스피커를 울리는 부분으로 구성됩니다.

전파(변조된 반송파)로부터 본래의 음성신호를 끄집어내는 조작을 ‘복조’또는 ‘검파’라고 합니다.

출처 : 라디오의 원리 - 선광 네이버 블로그




이번 실습에는 FM 송출 모듈을 사용하는데요,
이 모듈의 경우 70-108Mhz의 '초단파'대역폭을 지닙니다.
AM에 비해 수신감도는 낮지만, 고음질의 방송을 할 수 있습니다.



송출 모듈와 연결된 5110LCD 와 가변저항을 통해 대역폭을 설정하고 확인할수 있습니다.



FM 수신 모듈입니다.
시리얼 모니터를 통해 수신받을 주파수를 설정하면, 
스피커를 통해 해당 주파수의 음성신호가 스피커를 통해 출력됩니다.

그럼 본격적으로 실습을 통해 
아두이노 방송국을 만들어 보겠습니다.

 

 

부품목록

NO 부품명 수량 상세설명
1 오렌지 보드 2 아두이노호환보드 by KocoaFAB
2 브레드보드 1 브레드보드
3 10kΩ 가변저항  2 가변저항
4 점퍼 케이블 18 점퍼 케이블 M-F : 4개  M-M : 14개
5 노키아 5110  LCD 1 LCD
6 FM Trasmitter (FM 송신기) 1 Elechouse
7 FM Receiver (FM 수신기) 1 Elechouse
8 스피커 1 스피커 혹은 이어폰
부품명 오렌지 보드 브레드보드 점퍼케이블 10kΩ 가변저항 노키아 5110  LCD
파트 x2 x1 x18  x2 x1
부품명 FM Trasmitter (FM 송신기) FM Receiver(FM 수신기) 스피커
파트 x1 x1 x1

하드웨어 Making

회로도

송신 모듈 ( FM Transmitter)




수신 모듈 ( FM Receiver)

브레드보드 레이아웃

송신 모듈 ( FM Transmitter)

수신 모듈 ( FM Receiver)



각각의 단자에는 안테나를 설치할수 있는 핀이 있습니다.
안테나는 동봉되어 있지 않지만,
강선이나 점퍼케이블을 연결하면 안테나의 기능을 합니다.

 

소프트웨어 Coding

아래의 링크를 통해 본 예제에 필요한 라이브러리를 다운받고 설치합니다.
라이브러리 다운받기

다운받은 파일을 압축 해제하면, 총 4개의 라이브러리 폴더가 있습니다.

  • FMTX(FM송신 라이브러리)
  • FMRX(FM수신 라이브러리)
  • u8glib(LCD통합 라이브러리)
  • SoftI2C(I2C 라이브러리)

라이브러리 폴더를 Document(내문서)>Arduino>Libraries의 경로에 설치합니다.

1. FM Transmitter 모듈 스케치
아래의 코드를 송신모듈과 연결된 아두이노에 업로드 합니다.

//This program is distributed in the hope that it will be useful,
//but WITHOUT ANY WARRANTY; without even the implied warranty of
//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//You should have received a copy of the GNU General Public License
// along with this program. If not, see http://www.gnu.org/licenses/
//Name :Mohannad Rawashdeh .
//Date "13/5/2013 3:00pm

// 이 코드에서는  GLCD 12864 ST7920 Controller를 사용합니다.
// 아두이노 핀  #D11,D12,D13 을 사용합니다., SPI 시리얼 인터페이스를 사용합니다.
// 출처 :  http://www.genotronex.com/

#include "U8glib.h" //통합 LCD 라이브러리를 불러옵니다.
#include "FMTX.h" // FMTX 라이브러리를 불러옵니다.

U8GLIB_PCD8544 u8g(13, 11, 10, 9, 8);    //  SCK = 13, MOSI = 11, CS = 10, A0 = 9, Reset = 8에 연결합니다.
int channel=0;
float fm_freq = 90;  // 기본 주파수를 90으로 설정합니다.
int reading=0;
int last_reading=0;
int Current_reading=0;
int mapping_reading=000;

void setup(void){
  
pinMode(A0,INPUT);// 가변저항을 아날로그 0번에 연결하고 입력으로 설정합니다.
Serial.begin(9600);// 시리얼 통신을 시작합니다.
fmtx_init(fm_freq, USA); // 국가를 설정 할 수 있습니다만 사실상 무의미 합니다.
u8g.setRot180();
u8g.setColorIndex(1); // LCD의 픽셀을 켭니다.
//..........................................
u8g.firstPage();  
  do{
    set_screen(1);
  }
  while(u8g.nextPage() );
  delay(1000);
 //....................
  u8g.firstPage();  
  do{
    set_screen(0);
  }
  while(u8g.nextPage() );
  delay(1000);
   Clear();
   //..........
   
    u8g.firstPage();  
  do{
    intro();
  }
  while(u8g.nextPage() );
  delay(2500);
   u8g.firstPage();  
  do{
    intro2();
  }
  while(u8g.nextPage() );
  delay(2500);
  Clear();

//..........................................
}
// 가변저항의 값을 주파수 채널값으로 맵핑합니다.
void Analog_pin_read(){
   channel=mapping_reading;
   Current_reading=channel;
   fmtx_set_freq(channel);
   
}

void set_screen(int i){
 u8g.setColorIndex(i); // pixel on !
 for (int x_axis=0;x_axis<84;x_axis++){
 for (int y_axis=0;y_axis<44;y_axis++){
 u8g.drawPixel(x_axis,y_axis);
 }
 }
}

void Clear(void){
  u8g .setFont(u8g_font_04b_03);
  u8g.setFontRefHeightExtendedText();
  u8g.setDefaultForegroundColor();
  u8g.setFontPosTop(); 
}
void intro(void){
  u8g.setColorIndex(1);
  u8g.drawFrame(0,0,83,47);
  u8g .setFont(u8g_font_osr18);
  u8g.drawStr( 5, 25, "FM Tx ");
  u8g .setFont(u8g_font_tpss);
  u8g.drawStr( 5, 40, " System");
}
void intro2(void){
  u8g.setColorIndex(1);
  u8g.drawFrame(0,0,83,47);
  u8g .setFont(u8g_font_04b_03);
  u8g.drawStr( 2, 7, "Build Your FM station! ");
  u8g.drawStr( 2, 15, "Change the Freq");
  u8g.drawStr( 2, 26, "From Poten"); 
  u8g.drawStr( 2, 38, "www.genotronex.com");
}
//주파수 값이 변하면 LCD에 해당 주파수를 표기합니다.
void number(int value){
  u8g.setColorIndex(1);
  u8g.drawFrame(0,0,83,47);
  u8g .setFont(u8g_font_unifont);
  u8g.drawStr( 5, 15, "Frequency ");
  u8g .setFont(u8g_font_osr18);
  u8g.setPrintPos(10,45);
  u8g.println(value,DEC);
  u8g .setFont(u8g_font_unifont);
  u8g.drawStr( 45, 38, "MHz ");
}

void loop(){  
  reading=analogRead(A0);   
  mapping_reading=map(reading,0,1023,90,100);
  mapping_reading=constrain(mapping_reading,90,100);
  if( mapping_reading!= Current_reading){
  Clear();
  Analog_pin_read();
u8g.firstPage();  
  do{
  number(channel);
  }
  while(u8g.nextPage() );
  delay(100);
  }
}
 


2. FM Receiver(FM 수신 모듈) 
아래의 코드를 수신모듈과 연결된 아두이노에 업로드 합니다.

 

/**
  @file    fmrx_demo.ino
  @author  www.elechouse.com
  @brief   example of FMRX_MODULE
  
   '1' 을 입력하면 상위 채널의 주파수를 찾습니다. , '2'를 입력하면 하위 채널의 주파수를 찾습니다.
 '3'을 입력하면 볼륨(소리의 크기)를 증가시킵니다., '4' 를 입력하면 볼륨을 감소시킵니다.
  
@section  HISTORY
  
  V1.0 initial version
  
    Copyright (c) 2012 www.elechouse.com  All right reserved.
*/

/** 라이브러리를 불러와 포함시킵니다.*/
#include <FMRX.h>
float channel;
void setup(void)
{
  Serial.begin(9600);
  Serial.print("FM-RX Demo By Elechosue\r\n");
  
  /** I2C 통신 설정 */
  i2c_init();
  
  fmrx_power();
  fmrx_read_reg(fmrx_reg_r);
  Serial.print("FMRX Module Power up.\r\n");

  /**볼륨 설정 */
  fmrx_set_volume(10);
  Serial.println("Volume Set");
  
  /** 수신 감도 설정, 범위:0-127*/
  fmrx_set_rssi(15);
  
  /** 
    대역폭에 따른 국가 채널 설정:
    BAND_EU:       87-108MHz, Europe
    BAND_US:       87-108MHz, USA
    BAND_JP:       76-91MHz, JAPAN
    BAND_JP_WIDE:  76-108MHz, JAPAN wide
  */
  fmrx_select_band(BAND_EU);
  
  channel=fmrx_seek(SEEK_DOWN);
  Serial.println("Initial seek.");
  Serial.print("Channel:");
  Serial.print(channel, 2);
  Serial.println("MHz");
}

void loop(void)
{
  static u8 vol=10;
  if(Serial.available()>0){
    switch(Serial.read()){
      case '1':
        Serial.println("Wait...");
        channel = fmrx_seek(SEEK_DOWN);
        Serial.println("Seek down.");
        Serial.print("Channel:");
        Serial.print(channel, 2);
        Serial.println("MHz");
        break;
      case '2':
        Serial.println("Wait...");
        channel = fmrx_seek(SEEK_UP);
        Serial.println("Seek up.");
        Serial.print("Channel:");
        Serial.print(channel, 2);
        Serial.println("MHz");
        break;
      case '3':
        Serial.println("Wait...");
        if(vol < 0x0F){
          vol++;
        }
        fmrx_set_volume(vol);
        Serial.print("Volume+:");
        Serial.println(vol);
        break;
      case '4':
        Serial.println("Wait...");
        if(vol > 0){
          vol--;
        }
        fmrx_set_volume(vol);
        Serial.print("Volume-:");
        Serial.println(vol);
        break;
   /** 새로운 채널을 찾으면 설정을 검사합니다. 입력 데이터는  '&' 와 4자리수의 숫자로 입력되어야 합니다, 처음 3개의 숫자는 정수이며 단위는
    (Unit: MHz)입니다., 마지막 4번째 숫자는 소수입니다. 채널은 76MHz 과 108Mhz 사이 값이여야 합니다.
  */
        case '&':
        u8 i,buf[4];
         float ch;
         i=0;
         delay(30);
         while(Serial.available()&&i<4){
           buf[i]=Serial.read();
           if (buf[i]<= '9' && buf[i]>= '0') { 
           i++;}
           else{
           i=0;
           break;
           }
         }
         if (i==4){
           ch = (buf[0]-'0')*100+(buf[1]-'0')*10+(buf[2]-'0')*1+0.1*(buf[3]-'0');
           Serial.println(fmrx_set_freq(ch),2);
         }else{
           Serial.println("Input Error.");
         }
         /** dummy read for useless character */
         while(Serial.available()){
           Serial.read();
         }
         break;
    }
  }
}


스케치 설명

 

 

 

void loop(void)
{
  static u8 vol=10;
  if(Serial.available()>0){
    switch(Serial.read()){
      case '1':
        Serial.println("Wait...");
        channel = fmrx_seek(SEEK_DOWN);
        Serial.println("Seek down.");
        Serial.print("Channel:");
        Serial.print(channel, 2);
        Serial.println("MHz");
        break;
      case '2':
        Serial.println("Wait...");
        channel = fmrx_seek(SEEK_UP);
        Serial.println("Seek up.");
        Serial.print("Channel:");
        Serial.print(channel, 2);
        Serial.println("MHz");
        break;
      case '3':
        Serial.println("Wait...");
        if(vol < 0x0F){
          vol++;
        }
        fmrx_set_volume(vol);
        Serial.print("Volume+:");
        Serial.println(vol);
        break;
      case '4':
        Serial.println("Wait...");
        if(vol > 0){
          vol--;
        }
        fmrx_set_volume(vol);
        Serial.print("Volume-:");
        Serial.println(vol);
        break;


시리얼 모니터상에 1,2,3,4를 입력했을때 수행할 작업을 설정하고 동작 상태를 시리얼 모니터상에 다시 출력합니다.

 

 

 

 

 

 

 

 

 

 

kocoafabeditor

항상 진취적이고, 새로운 것을 추구하는 코코아팹 에디터입니다!

라디오송신,라디오수신, 아두이노, 오렌지보드

체르니 2016-04-21 22:18:58

얀녕하세요. 혹시 송신부 모듈의 전원을, 굳이 외부배터리로 사용한 이유가 궁금합니다