DFPlayerをPICで操作する その3 関数に関心を | 波動砲口形状研究

DFPlayerをPICで操作する その3 関数に関心を

 回路ができたので次はプログラムですね。まずは左のボタンで1曲目、右のボタンで2曲目が流れるものを載せておきます。一番下にありますので、コピペ、ビルド、書き込みをして動くか確かめてみてください。

 
 解説も一応しておきます。が、これ読む人いるのかなあ…
 
 そういえばブログテーマ「模型電飾の為だけのPIC」では、見て参考にしていただくのが目的なので、何の役にも立たない、個人的なつぶやきや愚痴は書かない方針なんです本当は。でもこのPIC+DFPlayerのシリーズでは気がつくとやたらそういうのを書いてる。
 
 もうね、勝手に漏れるんですよ頭から。なんででしょうね。年ですかね。今回もいつの間にかそういうの書いているんで大分消しましたよ。

 

 

・シリアル通信関係の設定

 PICからDFPlayerへ命令するためにはシリアル通信を使います。DFPlayerは①一度に送るデータの大きさ、②データのやり取りの方法③やり取りの速さ、のそれぞれで

 

①8ビット ②非同期 ③9600ボー

 

というので通信しないと分かってくれません。DFPlayerにはほとんど柔軟性がないのでPICの方で合わせてあげる必要があります。

 

 プログラム中、オレンジにしているのがそれに関する設定です。①については特に指定しなければPICも8ビット通信のようです。②の非同期に関する設定はオレンジでアンダーライン、③9600ボーで送信させる設定はオレンジで太字にしています。

 

 細かい注釈をコメントとして入れていますが、これらは全部削除してもらっても動作には影響しません。全部省くと実は必要なのは

 

        //シリアル通信の初期設定
            TXSTA = 0b00100100 ;
            SPEN = 1;
            SPBRGL = 51 ;
            TXCKSEL = 0 ;
        //シリアル通信の初期設定ここまで

 

これだけです。

 

 

・シリアル通信(発信)を行う関数

 C言語(にかぎらず様々なプログラム言語)では特定の作業を行う小さなプログラムに名前を付けて「関数」と呼ぶ習わしがあります。

 

 関数名はこれ、その中身はこれ、という定義を書いておくと、以降は関数名を書きさえすればいつでもどこでもその小さなプログラムの機能が呼び出せます。

 

 ところで扱うのがデータだけなら、特定のデータをそこに放り込むと、作業の結果加工された別のデータになって戻ってくるので、関数という名前もまだわかります。

 

 しかしPIC上では、物理的というか電気的な動作もその関数をつかってやらせたりするので、関数というのは実のところどうもピンとこない名前です。

 
 まあ世間に逆らってもしょうがないのでここでもそう呼びます。
 

 シリアル通信の機能は、UART_Write(char data)という関数を定義してやっています。この関数は以下の太字のように定義されています。 

 

    void UART_Write(char data)
    {
      while(TRMT==0);

      {

      TXREG = data;
      }

    }

 

 シリアル通信のモジュールのイメージは、戦闘機のカタパルトです。データという戦闘機が、カタパルトに乗せられて次々と打ち出されてゆきます。

 

 PICには、TSRという、自動で戦闘機を打ち出すカタパルトがあります。しかしここにユーザーは直接戦闘機を送り込むことはできません。

 

 その手前のTXREGというエレベーターにデータを置くことで、TSRというカタパルトにデータが移され、打ち出されます。

 

 (各レジスタ、ビットのもう少しまともな説明は、データシートのP275~あたりを見てください。)

 

 問題はTXREGにデータを置いた後、次のデータを置くタイミングです。まだTSRにデータが移っていないのにTXREGに書き込んでしまうと、意図したように動かなくなります。

 

 それを防ぐのに役立つのがTRMTというこれまた自動で動く信号機です。この信号機は、TSRがデータを打ち出すと一旦赤(TRMT=1)になり、TXREGからTSRにデータが移されると青(TRMT=0)になります。

 

 つまり、TXREGにデータを置きなさい、でもそれは信号が青(TRMT==0)のときだけだよ、という指示をするのが、 この関数の役割です。

 
*これは許可されてないのにエレベータに載っちゃうの図ですね。この後パイロットはえらい目にあいます。
 
 

・DFPlayerに指示する関数

 特定の機体番号の戦闘機を、特定の順番で送り込んでやると、DFPlayerは言う事を聞いてくれます。

 

 何をさせたいかで送る番号は変わってきます。その一覧はデータシートに載っています。

 

 SDカードの一つ目のファイルを再生してほしいなら、7E FF 06 03 00 00 01 EF です。太字にした0102に替えれば、二つ目のファイルを再生します。

 

 DF_SpecifyPlay(int n)関数は、7E、 FF、 06、・・・と順番に戦闘機を送り出す指示をやっています。指示を受けて実際にエレベーターにデータを載せる作業を請け負っているのがUART_Write(data)です。

 
    //ルートディレクトリのn番目の曲を再生する関数

    void DF_SpecifyPlay(int n)

  {
    UART_Write(0x7E);
    UART_Write(0xFF);
    UART_Write(0x06);
    UART_Write(0x03);
    UART_Write(0x00);
    UART_Write(0x00);
    UART_Write(n);
    UART_Write(0xEF);

    }

 

 ここでは指定した番号の曲を再生する関数しか作っていないのですが、同じ要領で例えば 7E FF 06 06 00 00 1E EF と送る関数を作ってやると、それでボリュームを指示できます。1Eのところの大きさを変えるとボリュームが変わるわけです。

 

 

というわけで、これでPICからDFPlayerを操作できるようになりました。次回は、DFPlayerに入れるデータについて説明します。

 

 

↓↓↓↓プログラムここから↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓

 

#include <xc.h>
#define _XTAL_FREQ 8000000 //8Mhzで動かすので_XTAL_FREQは8000000 これ書いとかないとdelayが使えない。


//コンフィグ設定
#pragma config FOSC = INTOSC //内部クロック使用
#pragma config WDTE = OFF    //ウオッチドッグタイマーなし
#pragma config PWRTE = ON    //電圧の立ち上がり後の安定待ちをする
#pragma config MCLRE = OFF   //RA3をリセットに使わない
#pragma config CP = OFF      //プログラムメモリ保護なし
#pragma config CPD = OFF     //データメモリ保護なし
#pragma config BOREN = ON    //電圧降下したらPIC停止(許容する程度はBORVで指定)
#pragma config CLKOUTEN = OFF//クロック出力無効
#pragma config IESO = OFF    //2段階起動モードON
#pragma config FCMEN = OFF   //外部クロック監視をしない
#pragma config WRT = OFF     //書き込み禁止しない
#pragma config PLLEN = OFF   //高速クロック(32MHz)使わない
#pragma config STVREN = ON   //スタックがオーバーフローしたらリセット
#pragma config BORV = HI     //PIC停止電圧設定HIGH
#pragma config LVP = OFF     //低電圧プログラミングしない


//関数のプロトタイプ宣言
void UART_Write(char data);
void DF_SpecifyPlay(int n);

//メイン関数ここから
    void main(void) {
        //特殊レジスタの設定
             OSCCON     = 0b01110010 ; // 内部クロックは8MHzとする
             OPTION_REG = 0b00000000 ; // デジタルI/Oに内部プルアップ抵抗を使用する
             ANSELA     = 0b00000000 ; // アナログは使用しない(すべてデジタルI/Oに割当てる)
             TRISA      = 0b00011000 ; // RA4、RA3は入力その他のピンは出力
             WPUA       = 0b00011000 ; // RA4、RA3には内部プルアップ抵抗をつなぐ
             PORTA      = 0b00000000 ; // 出力ピンの初期化(全てLOWにする)    

        //シリアル通信の初期設定
            //送信(TX)関係 8ビット、非同期、9600ボーで通信する設定
            TXSTA = 0b00100100 ;

            //上記TXSTAによる設定は下記丸印のビットを個別にセットしてもOK
                //  bit7 CSRC= 0: クロック源(非同期なのでここは無視される) 
                //○bit6 TX9=  0: 8ビット送信 
                //◎bit5 TXEN= 1: 送信有効
                //○bit4 SYNC= 0 EUSARTモード非同期 
                // bit3 SENDB=0: ブレーク文字送信ビット
                //◎bit2 BRGH=1: 高ボーレート選択ビット非同期の場合のハイレート
                //  bit1 TRMT= 0: 送信シフト レジスタ ステータス
                //  bit0 TX9D= 0: 送信データの9ビット目
            //以上8つは数値をセットしなければデフォルトはゼロ(のはず)なので本当に書く必要があるビットは◎だけ。
            
            SPEN = 1;
            //シリアルポートのON、OFFを操作するレジスタ
            //EUSARTトランスミッタを非同期モードとして有効化するには、3 つの制御ビットを以下のように設定します。TXEN = 1, SYNC = 0, SPEN = 1(データシートP287)
            
            BRG16 = 0 ;
            //8ビット・非同期送信の場合、BRG16 = 0とBRGH=1の組み合わせでのボーレートの計算式は(1)ボーレート=クロック数/(16 (n+1))であり(データシートP298)、
            //算出された値をSPBRGLに格納することでボーレートを指定できる。(これもセットすべき値がゼロなので書かなくても大丈夫)  

            SPBRGL = 51 ;
            //DFPlayerのボーレートは9600で固定されている。PICの方も9600にするためにここの数値をセットする。
            //クロック数4Mhzなら:25、8Mhz:51、16:Mhz:103、32Mhz:207これらの数値の計算式は既述の(1)式の通り。

            //PIC12f1822専用の設定項目
            TXCKSEL = 0 ;   // 7番ピン(RA0)をTX(送信)ピンにする。ここを1にすると3番ピン(RA4)がTXに
            //RXDTSEL = 0 ;   // 6番ピン(RA1)をRX(受信)ピンにする。ここを1にすると2番ピン(RA5)がRXに RX使わないのでコメントアウト
      //シリアル通信の初期設定ここまで

            
       while(1) {

        if (RA3 == 0 ) { //ボタンを押すと
                DF_SpecifyPlay(1) ;//関数DF_SpecificPlayに曲番号1を送る
                __delay_ms(1000);//
            }  
        
        if (RA4 == 0 ) { //ボタンを押すと
                DF_SpecifyPlay(2) ;//関数DF_SpecificPlayに曲番号2を送る
                __delay_ms(1000);//
            }  

 
       }//while(1)ここまで)

    }//メイン関数ここまで



//シリアル通信書き込み用関数
    void UART_Write(char data)
    {
      while(TRMT==0);

      {

      TXREG = data;
      }

    }

//シリアル通信書き込み用関数ここまで

 


//DFPlayer用の関数
    //ルートディレクトリのn番目の曲を再生する関数
    void DF_SpecifyPlay(int n){
    UART_Write(0x7E);
    UART_Write(0xFF);
    UART_Write(0x06);
    UART_Write(0x03);
    UART_Write(0x00);
    UART_Write(0x00);
    UART_Write(n);
    UART_Write(0xEF);

    }

//DFPlayer用の関数ここまで