aitendo のDSP ラジオ モジュール BK1088 は、I2Cで制御できる AM FM SW ラジオです。このモジュールを使い実用性のあるFMラジオを作成しました。BK1088 は、I2Cで制御しますが、そのデータの並び順が特殊で I2C EEPROM とは異なります。具体的には、R/W ビットが2バイト目にあります。操作対象のRegADDを1ビット左にシフトし、LSBにR/Wビットを付加して送信します。
| EEPROM | | Start | | ChipADD + W | | ADD | | ADD | | DATA | | Stop | | ||
| BK1088 | | Start | | ChipADD | | RegADD + W | | DATA | | DATA | | Stop | |
BK1088 で、ラジオ局を受信するには、BK1088内部のレジスタに適切な値を書き込む必要があります。また、受信する周波数の変更や、出力音量の変更も、定められたレジスタの内容を書き換えることで実現できます。ICの働きを理解するために、FM放送を受信するだけの BK_Simple と、実用的なポータブルFMラジオである BK_FM の2種類のプログラムを作成しました。8ピンPIC12F1822 を使った同じ実用的なBK1088FMラジオも公開しています。
BK_Simple プログラムは、放送大学 77.1MHz を受信設定するだけのプログラムです。 BK1088の初期化、I2Cデータ書込み だけで、それ以外の機能は付加してありません。どのように、DSP モジュールをコントロールするのか理解しやすいでしょう。出力する音量を制御するには、Bk1088 の05 レジスタのLSB 5ビット(bit4 - bit0)に希望する値を書き込みます。受信周波数を変更するには、Bk1088 の 03 レジスタに、バンドの最少周波数とステップ周波数から計算した周波数セット値をセットします。セット後、同じ 03 レジスタ のMSB (TuneBit)を「1」にセットします。ソースリストと見比べてください。なお、上記回路図に示されている PushSW は、使用していません。
/*********************************************************************
* DSP RADIO BK1088
* 受信バンド:FM
* 音量:vol (0x00-0x1F)に設定
* 受信周波数:inFreq に設定する
* PIC18F14K50 MPLAB X IDE with XC8 Ver1.32
* Copyright (c) 2014 iwamoto All Rights Reserved
* *******************************************************************/
#include <xc.h>
//********************************************************************
// vol : reg 05に設定する音量値 ( 0 - 31 )
// inFreq : reg 03に設定する値 ( freq - mimFreq ) / StepFreq
// 77.1MHzの場合 ( 77.1x100 - 7600 ) / 10
//*********************************************************************
#define vol 22 // 音量 0 - 31
#define inFreq (7710 - 7600) / 10 // 放送大学 11
//#define inFreq (8000 - 7600) / 10 // FM東京 40
//#define inFreq (8470 - 7600) / 10 // FM横浜 87
//******************* コンフィグレーション ****************************
#pragma config FOSC = IRC // 内部クロック
#pragma config USBDIV = OFF, CPUDIV = NOCLKDIV
#pragma config IESO = OFF, FCMEN = OFF, PLLEN = ON
#pragma config BORV = 30, BOREN = OFF, PWRTEN = OFF
#pragma config WDTPS = 32768, WDTEN = OFF
#pragma config MCLRE = OFF, HFOFST = OFF, XINST = OFF
#pragma config BBSIZ = OFF, LVP = OFF, STVREN = ON
#pragma config CP1 = OFF, CP0 = OFF, CPD = OFF, CPB = OFF
#pragma config WRT1 = OFF, WRT0 = OFF, WRTB = OFF, WRTC = OFF
#pragma config EBTR1 = OFF, EBTR0 = OFF, EBTRB = OFF
//
//******************* 定義 *******************************************
#define _XTAL_FREQ 4000000
#define i2cStart() SSPCON2bits.SEN=1;while(SSPCON2bits.SEN)
#define i2cStop() SSPCON2bits.PEN=1;while(SSPCON2bits.PEN)
//******************* プロトタイプ ***********************************
void delay_ms (int ms);
void i2cintl(void);
void Bk1088_Write(unsigned int, unsigned int);
void i2cTxData(char data);
// ******************* main ******************************************
void main() {
OSCCON = 0b01010010; // 内部クロック4Mhz
PORTA = 0x00; PORTB = 0x00; PORTC = 0x00;
TRISA = 0xFF; TRISB = 0xFF; TRISC = 0xFF; //Port すべて入力
ANSEL = 0x00; ANSELH = 0x00; //すべてデジタル
// I2C初期化 SCLK=100KHz ------------------------------------------
i2cintl();
// DSP初期化 受信バンド:FM 音量:1A -----------------------------
Bk1088_Write(0x02, 0x6281); // power config
Bk1088_Write(0x03, inFreq); // channel
Bk1088_Write(0x05, 0x3740 + vol); // system config2
Bk1088_Write(0x06, 0x0930); // system config3
Bk1088_Write(0x07, 0x0901); // test1
Bk1088_Write(0x14, 0x878E); // boot config 5
Bk1088_Write(0x1A, 0x0001); // boot config 11
Bk1088_Write(0x1B, 0x48D4); // analog config 1
Bk1088_Write(0x1D, 0x0200); // analog config 3
Bk1088_Write(0x1E, 0x80AA); //
Bk1088_Write(0x20, 0x0EF7); //
Bk1088_Write(0x26, 0x8400); //
Bk1088_Write(0x03, inFreq | 0x8000); // TUNEビットを立てる
delay_ms(500); // 安定するまで遅延
Bk1088_Write(0x02,0x0281); // mute off 音を出す
while (1);
}
//********************************************************************
// mS 単位の遅延
//********************************************************************
void delay_ms (int ms){
while(ms-- > 0)__delay_ms(1);
}
//********************************************************************
// SSPを I2C Master mode、SCL 100kHz @ 4MHz に設定
//********************************************************************
void i2cintl(void){
SSPCON1 = 0b00001000; // I2C Master modeにする
SSPCON2 = 0x00; // PowerOn初期値にする
SSPSTAT = 0b10000000; // スルーレート制御はOff
SSPADD = 9; // クロックの設定 100k@4MHz
SSPCON1bits.SSPEN = 1; // SSP 有効にする bit5
}
//********************************************************************
// Bk1088_のレジスタに書き込む
//********************************************************************
void Bk1088_Write(unsigned int add, unsigned int data) {
i2cStart(); // 送信開始
i2cTxData(0x80); // Chipアドレス送信
i2cTxData(add << 1); // RegAdd + Write
i2cTxData(data >> 8); // Register data MSB
i2cTxData(data & 0xff); // Register data LSB
i2cStop(); // 送信終了
__delay_us(500);
}
//********************************************************************
// SSPBUF に1文字保存し送信終了を待つ
//********************************************************************
void i2cTxData(char data){
PIR1bits.SSPIF = 0; // 終了フラグクリア
SSPBUF = data; // データセット
while(!PIR1bits.SSPIF); // 送信終了待ち
}
BK_FM プログラムは、BK_Simple を基本に、PushSW を3ケ追加し、音量の増減、受信FM局の変更 を可能にしました。受信局は、東京地区で受信できる周波数jを書き込んであります。ほかの地区では、プログラム11行目の presetFreq を地元FM局に周波数に変更してPICに書き込んでください。 音量や、受信局を変更すると変更内容をPIC内のEEPROMに書き込んでいます。このため、電源をOFFしても、その設定は保存され、次に電源をONとしたとき前の状態が再現されます。さらに、選局ボタン(station) を長押しすると、常に homeSt でプログラム上に指定した局が受信するようプログラムされています。 また、変更動作が完了すると、省電力と雑音防止を兼ねPICはスリープ状態になり、クロックも停止します。PushSWのどれかを押すことでPICはスリープが解除され、ボタンの処理を再開します。
/*********************************************************************
* DSP RADIO BK1088
* 受信バンド:FM
* 音量:受信局は EEPROM に保存され、電源OFF時でも失われない
* 選局を長押しすると、ホーム局 stHome に戻る
* 受信周波数:presetFreq に設定する
*
* PIC18F14K50 MPLAB X IDE with XC8 Ver1.32
* Copyright (c) 2014 iwamoto All Rights Reserved
* *******************************************************************/
#define presetFreq 7610,7710,7810,8000,8130,8250,8470,0
#define long_ms 1000 // 長押し時間 ms
#define homeSt 1 // 長押しで選局する局番号
#define minFreq 7600 // 最低周波数
#define maxFreq 9000 // 最高周波数
#define stepFreq 10 // ステップ周波数
#define SWs (PORTA|0b11000111) // SW 3ケの状態
#define VolUp !PORTAbits.RA5 // SW 音量 大
#define Voldn !PORTAbits.RA4 // SW 音量 大
#define station !PORTAbits.RA3 // SW 選局
#include <xc.h>
//******************* コンフィグレーション ****************************
#pragma config FOSC = IRC // 内部クロック
#pragma config USBDIV = OFF, CPUDIV = NOCLKDIV
#pragma config IESO = OFF, FCMEN = OFF, PLLEN = ON
#pragma config BORV = 30, BOREN = OFF, PWRTEN = OFF
#pragma config WDTPS = 32768, WDTEN = OFF
#pragma config MCLRE = OFF, HFOFST = OFF, XINST = OFF
#pragma config BBSIZ = OFF, LVP = OFF, STVREN = ON
#pragma config CP1 = OFF, CP0 = OFF, CPD = OFF, CPB = OFF
#pragma config WRT1 = OFF, WRT0 = OFF, WRTB = OFF, WRTC = OFF
#pragma config EBTR1 = OFF, EBTR0 = OFF, EBTRB = OFF
//
//******************* 定義 *******************************************
#define _XTAL_FREQ 4000000
#define i2cStart() SSPCON2bits.SEN=1;while(SSPCON2bits.SEN)
#define i2cStop() SSPCON2bits.PEN=1;while(SSPCON2bits.PEN)
//******************* プロトタイプ ***********************************
void delay_ms (int);
void i2cintl(void);
void Bk1088_Write(unsigned int, unsigned int);
void i2cTxData(char);
void Freq_set(int);
/* ********** EEROM に設定する 初期周波数番号 *********** */
__EEPROM_DATA(1,22,0,0,0,0,0,0); //0番地:局、1番地:音量
// ******************* main ******************************************
void main() {
int FM_FREQ[] = {presetFreq}; // 周波数プリセット
char st; // 受信中の局番号
signed char vol; // 音量
int SwTime; // SW を押している時間
char dummy; // 作業変数
OSCCON = 0b01010010; // 内部クロック4Mhz
PORTA = 0x00; PORTB = 0x00; PORTC = 0x00; // 全ポート 0
TRISA = 0xFF; TRISB = 0xFF; TRISC = 0xFF; // PortC すべて入力
ANSEL = 0x00; ANSELH = 0x00; // すべてデジタル
WPUA = 0xFF; WPUB = 0xFF; // 弱プルアップするピンを選択
INTCON2bits.nRABPU = 0; // 弱プルアップ有効
IOCA = 0b00111000; // PORTA 状態変化割り込み
INTCONbits.RABIE = 1;
// I2C初期化 SCLK=100KHz ------------------------------------------
i2cintl();
// DSP初期化 受信バンド:FM 音量:22 -----------------------------
st = eeprom_read(0); // 起動時受信局番号
vol = eeprom_read(1); // 起動時音量
Bk1088_Write(0x02, 0x6281); // power config
Bk1088_Write(0x05, 0x3740 + vol); // system config2
Bk1088_Write(0x06, 0x0930); // system config3
Bk1088_Write(0x07, 0x0901); // test1
Bk1088_Write(0x14, 0x878E); // boot config 5
Bk1088_Write(0x1A, 0x0001); // boot config 11
Bk1088_Write(0x1B, 0x48D4); // analog config 1
Bk1088_Write(0x1D, 0x0200); // analog config 3
Bk1088_Write(0x1E, 0x80AA); //
Bk1088_Write(0x20, 0x0EF7); //
Bk1088_Write(0x26, 0x8400); //
delay_ms(500); // 遅延
Freq_set(FM_FREQ[st]); // 指定する局の周波数をセット
Bk1088_Write(0x02,0x0281); // mute off 音を出す
//********************************************************************
while(1){
while(SWs == 0xFF); // SW が押されるのを待つ
delay_ms(5); // チャタリング防止
if(station){ // -------- 局を変更 ------------------------
st++; // 局番号を更新する
if(FM_FREQ[st]==0)st=0; // 局番号の範囲確認
Freq_set(FM_FREQ[st]); // 指定する局の周波数をセット
eeprom_write(0, st); // EEPROM 0番地 書込み
}
if(VolUp){ // -------- 音量 大 ------------------------
vol++; // 音量を上げる
if(vol > 28)vol = 28; // 上限の確認
Bk1088_Write(0x05,0x3740 + vol); // 音量をセット
eeprom_write(1, vol); // EEPROM 1番地 書込み
}
if(Voldn){ // -------- 音量 小 ----------------
vol--; // 音量を上げる
if(vol < 0)vol = 0; // 下限の確認
Bk1088_Write(0x05,0x3740 + vol); // 音量をセット
eeprom_write(1, vol); // EEPROM 1番地 書込み
}
SwTime = 0;
while(SWs != 0xFF){ // SW が押されているなら
delay_ms(1); // 離れるのを待つ
if(!station)continue; // 選局 SW なら以下を実施
if(SwTime < long_ms){ // 長押しより 短いなら
SwTime++; // 長押し時間を増やす
}else if(SwTime == long_ms){ // 長押し指定時間なら
SwTime++; // 長押し時間を増やし
st = homeSt; // ホーム局を
Freq_set(FM_FREQ[homeSt]); // 選局する
eeprom_write(0, st); // EEPROM 0番地 書込み
} // SW が離れるのを待つ
}
delay_ms(5); // チャタリング防止
dummy=PORTA; // 状態変化割込み準備
INTCONbits.RABIF = 0; // 状態変化割込み準備
NOP();
SLEEP(); // SW が押されるまでスリープ
NOP();
}
}
//********************************************************************
// mS 単位の遅延
//********************************************************************
void delay_ms (int ms){
while(ms-- > 0)__delay_ms(1);
}
//********************************************************************
// SSPを I2C Master mode、SCL 100kHz @ 4MHz に設定
//********************************************************************
void i2cintl(void){
SSPCON1 = 0b00001000; // I2C Master modeにする
SSPCON2 = 0x00; // PowerOn初期値にする
SSPSTAT = 0b10000000; // スルーレート制御はOff
SSPADD = 9; // クロックの設定 100k@4MHz
SSPCON1bits.SSPEN = 1; // SSP 有効にする bit5
}
//********************************************************************
// Bk1088_のレジスタに書き込む
//********************************************************************
void Bk1088_Write(unsigned int add, unsigned int data) {
i2cStart(); // 送信開始
i2cTxData(0x80); // Chipアドレス送信
i2cTxData(add << 1); // RegAdd + Write
i2cTxData(data >> 8); // Register data MSB
i2cTxData(data & 0xff); // Register data LSB
i2cStop(); // 送信終了
__delay_us(500);
}
//********************************************************************
// SSPBUF に1文字保存し送信終了を待つ
//********************************************************************
void i2cTxData(char data){
PIR1bits.SSPIF = 0; // 終了フラグクリア
SSPBUF = data; // データセット
while(!PIR1bits.SSPIF); // 送信終了待ち
}
//*****************************************************************/
// 新しい周波数をセットする
// 引数は、freq
//*****************************************************************/
void Freq_set(int freq){
signed int reg_val;
reg_val=(freq - minFreq)/stepFreq;
Bk1088_Write(0x0003, reg_val); // 周波数セット
Bk1088_Write(0x0003, reg_val | 0x8000); // TUNEビットを立てる
}