---
---
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内部のレジスタに適切な値を書き込む必要があります。また、受信する周波数の変更や、出力音量の変更も、定められたレジスタの内容を書き換えることで実現できます。実用的なポータブルFMラジオとして使える BK_FM プログラムを作成しました。PIC18F14K50 で作成したものを、PIC12F1822 に移植しました。乾電池2本をつないだ3v電源でも動作可能で、感度も音質も十分に実用になります。FMラジオが、これだけ少ない部品で完成するとは、DSPの潜在能力はもっともっと大きいのでしょう。
<プログラム>
/*********************************************************************
* DSP RADIO BK1088
* 受信バンド:FM
* 音量:受信局は EEPROM に保存され、電源OFF時でも失われない
* 選局を長押しすると、ホーム局 stHome に戻る
* 受信周波数:presetFreq に設定する
*
* PIC12F1822 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 = INTOSC, WDTE = OFF, PWRTE = OFF, MCLRE = OFF, CP = OFF
#pragma config CPD = OFF, BOREN = ON, CLKOUTEN = OFF, IESO = OFF, FCMEN = OFF
#pragma config WRT = OFF, PLLEN = OFF, STVREN = ON, BORV = LO, LVP = OFF
//
//******************* 定義 *******************************************
#define _XTAL_FREQ 4000000
#define i2cStart() SSP1CON2bits.SEN=1;while(SSP1CON2bits.SEN)
#define i2cStop() SSP1CON2bits.PEN=1;while(SSP1CON2bits.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 を押している時間
OSCCON = 0b01101010; // 内部クロック4Mhz
PORTA = 0x00;
TRISA = 0xFF; //Port すべて入力
ANSELA = 0x00; //すべてデジタル
WPUA = 0xFF; // 弱プルアップ ON
nWPUEN = 0;
IOCAN = 0b00111000; // ↓状態変化割り込み
INTCONbits.IOCIE = 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); // チャタリング防止
IOCAF = 0; // PORTA 状態変化割り込み準備
NOP();
SLEEP(); // SW が押されるまでスリープ
NOP();
}
}
//********************************************************************
// mS 単位の遅延
//********************************************************************
void delay_ms (int ms){
while(ms-- > 0)__delay_ms(1);
}
//********************************************************************
// SSP1を I2C Master mode、SCL 100kHz @ 8MHz に設定
//********************************************************************
void i2cintl(void){
SSP1CON1 = 0b00001000; // I2C Master modeにする
SSP1CON2 = 0x00; // PowerOn初期値にする
SSP1STAT = 0b10000000; // スルーレート制御はOff
SSP1ADD = 9; // クロックの設定 100k@4MHz
SSP1CON1bits.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);
}
//********************************************************************
// SSP1BUF に1文字保存し送信終了を待つ
//********************************************************************
void i2cTxData(char data){
PIR1bits.SSP1IF = 0; // 終了フラグクリア
SSP1BUF = data; // データセット
while(!PIR1bits.SSP1IF); // 送信終了待ち
}
//*****************************************************************/
// 新しい周波数をセットする
// 引数は、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ビットを立てる
}