PIC12F1822の基本動作から応用プログラムまでを学びます。

ホーム
16F18313
16F18325
16F18346
16F1619
Curiosity
---
---
    
12F1822
16F1455
16F1459
18F14K50
18F26J50
dsPIC
その他
DSP ラジオ BK1088

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ビットを立てる
}