aitendoのFMラジオモジュールをPICで動かす。

最小構成で電池駆動にする。機能も最小とし、操作はプリセットした受信周波数を切り替えるボタンのみ。

FullSizeRender

■回路図
MiniFMradio
※ SDA, SCL線はラジオモジュール内でプルアップされている。

■PICについて
PIC16F1503は安価で入手可能。I2C通信ポートが使える。低電圧で動作。EEPROMは搭載していない。

■PICのプログラム
FMラジオモジュールのチップ(RDA1508M)に、放送受信に必要な設定を書き込むとラジオが起動する。後はスリープモードへ移行させ、メインプログラムは終了。
周波数切り替えの押しボタンが押されるとハードウェア割り込みにより受信周波数の設定を変更して、周波数の数値をチップに書き込む関数を起動する。

/*
// Project Name: FM_Radio_16F1503
// Date: 2021.10.24
// Target PIC:  PIC16F1503
// Compiler: XC8 (ver.2.32)
//
*/

/************************************
 File name:  main.c
 ************************************/

// CONFIG1
#pragma config FOSC = INTOSC    // Oscillator Selection Bits (INTOSC oscillator: I/O function on CLKIN pin)
#pragma config WDTE = OFF       // Watchdog Timer Enable (WDT disabled)
#pragma config PWRTE = ON       // Power-up Timer Enable (PWRT enabled)
#pragma config MCLRE = OFF      // MCLR Pin Function Select (MCLR/VPP pin function is digital input)
#pragma config CP = OFF         // Flash Program Memory Code Protection (Program memory code protection is disabled)
#pragma config BOREN = ON       // Brown-out Reset Enable (Brown-out Reset enabled)
#pragma config CLKOUTEN = OFF   // Clock Out Enable (CLKOUT function is disabled. I/O or oscillator function on the CLKOUT pin)

// CONFIG2
#pragma config WRT = OFF        // Flash Memory Self-Write Protection (Write protection off)
#pragma config STVREN = ON      // Stack Overflow/Underflow Reset Enable (Stack Overflow or Underflow will cause a Reset)
#pragma config BORV = LO        // Brown-out Reset Voltage Selection (Brown-out Reset Voltage (Vbor), low trip point selected.)
#pragma config LPBOR = OFF      // Low-Power Brown Out Reset (Low-Power BOR is disabled)
#pragma config LVP = OFF        // Low-Voltage Programming Enable (High-voltage on MCLR/VPP must be used for programming)

#include <xc.h>
#define _XTAL_FREQ 4000000
#define SW1 PORTAbits.RA5 //ch切り替えスイッチ(押すと 0, 離すと 1)

// RDA5708M register 02H setting
#define DHIZ    1
#define DMUTE   1
#define MONO    1
#define BASS    1
#define SEEKUP  0
#define SEEK    0
#define SKMODE      0
#define CLK_MODE    0b000
#define RDS_EN      0
#define NEW_METHOD  0
#define SOFT_RESET  0
#define ENABLE      1

// RDA5708M register 04H setting
#define DE      0
#define AFC     1

// RDA5708M register 05H setting
#define INT_MODE    1
#define SEEKTH      0b1000
#define bit7        1


//***プロトタイプ宣言*****************************************************
void i2cTxData(char);
void configCmd(void);
void SleepIn(void);
void i2cStart(void);
void i2cStop(void);
void reset(void);
void send(unsigned char, unsigned char, unsigned char);
void Freqset(void);

//変数宣言と初期設定
char VOLUME=0x15; /音量設定の初期値
int freq[] = {8000, 8130, 8250, 9050, 9160, 9300};

char ch=0;
int RcvFreq = 8000; /受信周波数の初期値
unsigned char num = sizeof freq / sizeof freq[0]; //////////// Main ////////////////////////////////// void main(void){ OSCCON = 0b01101000; // 4MHz __delay_ms(100); ANSELA = 0x0; // PortAをデジタルI/Oにする ANSELC = 0x0; // PortCをデジタルI/Oにする TRISA = 0b11100011; // RA0, RA1, RA5 をINPUTに TRISC = 0b11000011; // RC0(SCL)とRC1(SDA)をINPUTに SSPCON1 = 0x28; // I2Cマスター SSPSTAT = 0x00; SSPADD = 0x24; // I2C周波数100KHz for 4MHz WPUA = 0b00100000; // RA5 をプルアップ // 16F1503の PortCはプルアップ設定できない OPTION_REGbits.nWPUEN=0; //0 = Weak pull-ups are enabled by individual WPUx latch values __delay_ms(1000); reset(); __delay_ms(100); configCmd(); INTCONbits.IOCIE=1; //IOC(状態変化割り込み)Enable IOCAPbits.IOCAP5=1; //Port RA5(=SW1)ボタン割り込み INTCONbits.GIE=1; //INTグローバルEnable while(1){ SleepIn(); } } ///////////// Main ここまで ///////////////////////////// void i2cStart(void){ SEN = 1; // Start condition while(SEN); // Start condition } void i2cStop(void){ //i2c STOP SSP1IF = 0; // クリア PEN = 1; // Stop condition while(PEN); // Stop condition } void i2cTxData(char data){ SSP1IF = 0; // SSPBUF = data; // while(!SSP1IF); // } void send(unsigned char ch,unsigned char i,unsigned char j){ i2cStart(); i2cTxData(0x22); // スレーブアドレス 0010001+0 i2cTxData(ch); // channel i2cTxData(i); // upper i2cTxData(j); // lower i2cStop(); } void reset(void) { send(0x02,0x00,0x01); /ミュート状態にする } void configCmd(void){ unsigned char upper, lower; //02Hレジスタへの書き込み upper = 0; upper += DHIZ << 7; upper += DMUTE << 6; upper += MONO << 5; upper += BASS << 4; upper += SEEKUP<< 1; upper += SEEK; lower = 0; lower += SKMODE << 7; lower += CLK_MODE << 4; lower += RDS_EN << 3; lower += NEW_METHOD << 2; lower += SOFT_RESET << 1; lower += ENABLE; send(0x02, upper, lower); //send(0x02,0xf0,0x01); __delay_ms(100); //03Hレジスタへの書き込み Freqset(); //04Hレジスタへの書き込み upper = 0; upper += DE << 4; upper += AFC; lower = 0; send(0x04, upper, lower); //send(0x04,0x04,0x00); //05Hレジスタへの書き込み upper = 0; upper += INT_MODE << 7; upper += SEEKTH; lower = 0; lower += bit7 << 7; lower += VOLUME; send(0x05, upper, lower); //send(0x05,0x88,0x80+VOLUME); } void Freqset(void){ signed int reg_val; reg_val = (RcvFreq - 7600)/10; send(0x03, reg_val >> 2, (reg_val << 6) + 0x18); __delay_ms(100); } void SleepIn(void){ IOCAPbits.IOCAP5=1; //RA5(=SW1)ボタン割り込みON SLEEP(); } void __interrupt() isr(void) { if(IOCAFbits.IOCAF5){ //RA5(=SW1)による割り込みフラグ ch = (++ch >= num)? 0 : ch; RcvFreq = freq[ch]; //受信周波数の設定 Freqset(); IOCAFbits.IOCAF5=0; //割り込みフラグをクリア } } //end of the program


■参考にした情報