/******************************************************************************* * ソース名:UL024TF_Touch_MP3_Player_V1.C * * <動作仕様概要> *  @ SDに格納されている、MP3ファイルを、最大256個まで読出し、そのファイルリスト *    を、カラーQVGA液晶に、1画面16曲ずつ表示する。 *    17曲目からは、スクロール表示を行いながら再生する。 *    16個に満たない場合は、その数のファイルリストを表示する。 *  A 通常タッチをしなければ、最初の曲から順次最大256曲目までの再生を繰返す、 *    ループ再生を行う。 *    再生中の曲の先頭に、マーカー('●')を表示する。 *    これを移動しながら再生を繰返す。 *  B 再生中に、SKIPボタンをタッチすると、再生を中断し、次の曲の再生に移る。 *  C 再生中に、HOMEボタンをタッチすると、再生を中断し、最初の曲の再生に戻る。 *  D 再生中に、VOL+ボタンをタッチすると、音量をアップする。 *  E 再生中に、VOL-ボタンをタッチすると、音量をダウンする。 * * ※ スクロールと最大曲数以外、前回TEST版と異なる点 *    @ 0から始まるファイルNo表示を、1から始まる曲番:Nに変更した。 *    A 曲番の横に続けて、トータル曲数を表示する。→ 例:N010/256 * * ファイルシステム:Microchip MMD File System V1.2.1→ FAT16(FAT32互換) * * 2.4inch カラーQVGA液晶(aitendo): UL024TF * MPEG Audio Codec LSI: VS1011e(EXT CLK:12.288MHz) * * Condition: * 8MHz External X'tal Oscillator, 20x PLL (8MHzx20= 160MHz) * Fcy=160MHz/2=80MHz, Tcy=12.5ns * * CPU: PIC32MX340F256H * * 初期作成日:PIC32MXトレーニング基板使用版 * N.Ishii 2016.7.24 * 修正履歴 * 2016.8.14 * Eagleにて基板製作 * AVCC(Vref)の違い(トレーニング基板使用時=3.31V、今回=3.28V)で、 * タッチボタン座標データを変更する必要が生じた。(今回はソフトで対応) * ソースを変更するが、ソース名は変更しないことにした。 **********************************************************************************/ #include /* PIC32 peripheral library */ #include "colorlcd_libdsPICVH.h" #include #include // コンフィギュレーション設定 // CPU=80MHz Peri=80MHz,HS+PLL,Divider=1/2,PLL=x20,WDT=Off #pragma config FNOSC=PRIPLL, POSCMOD=HS, FPLLIDIV=DIV_2 #pragma config FPLLMUL=MUL_20, FPBDIV=DIV_1, FPLLODIV=DIV_1 #pragma config FWDTEN=OFF, ICESEL=ICS_PGx2 /// タッチボタン座標データ /* short Button[4][2] = {{350,870}, // [0]:ボタン-1:SKIP {170,890}, // [1]:ボタン-2:HOME {160,750}, // [2]:ボタン-3:VOL+ {100,990} // [3]:ボタン-4:VOL- }; */ short Button[4][2] = {{357,855}, // [0]:ボタン-1:SKIP {169,883}, // [1]:ボタン-2:HOME {181,766}, // [2]:ボタン-3:VOL+ {117,988} // [3]:ボタン-4:VOL- }; char str_N[]= "Nxxx"; // FileNo表示用 char str_T[]= "/xxx"; // トータル曲数表示用 char str_V[]= "Vxx"; // 音量表示用 short Count; char MsgScrn[] = "X=xxxx Y=xxxx"; // 座標表示 /// ファイルシステム用変数 FSFILE *fptr; size_t result; SearchRec Record; SearchRec *rptr = &Record; char FileName[256][13]; // 2次元配列: 最大、256ファイルで、1ファイル→13文字(8文字+'.MP3'+NULL)構成 /// VS1011用変数 short Volume, BASS; unsigned char Buffer[256]; /// グローバル変数 short FileNo; short FN_Top; short Total; short i; short SW; char ChgFlag; /// プロトタイプ void DispFiles(void); void SetupScreen(void); short Getscreen(unsigned int chn); short CheckBtn(short x, short y); void TouchFunc(void); void ScrollDisp(void); void HomeFunc(void); void itostring(char digit, unsigned short data, char *buffer); /******* メインルーチン ***********/ int main(void) { //システム最適設定 SYSTEMConfigPerformance(80000000); mJTAGPortEnable(DEBUG_JTAGPORT_OFF); // JTAGを無効化 //I/O設定 AD1PCFG = 0xFFFF; // 全てデジタルに(タッチ用設定は、AN4(X-)、AN3(Y+)なので、0xFFE7) TRISE = 0x0000; // LCDデータバス(DB0-DB7)オール出力 TRISD = 0xFFA7; // LCD_CS,RESET:全て出力・デバッグLED:出力・SW2-5:入力、他未使用ピンは入力設定 TRISB = 0x4FC7; // VS1011_CS,RESET,DCS:出力、DREQ:入力・SD_CS:出力、LCD_WR,LCD_RS:出力、他未使用ピンは入力設定 // (今回は、VS1011は未使用だが、将来使う予定なので、その設定にしておく) TRISF = 0xFFFC; // 今回Fポートは未使用だが、RF0,RF1のみ出力設定にした LATDbits.LATD3 = 1; // デバッグLED消灯 /// 液晶表示器の初期化 Glcd_Init(); Glcd_Clear(BLACK); Glcd_Str(0, 0, "Touch MP3 Player V1", CYAN, BLACK); delay_ms(1000); Glcd_Clear(BLACK); /// VS1011eの初期化 VS1011_Init(); // Initialize VS1011 Port+ SPI2(CKP=4M)+ SDI_TestMode+ CLK Doubler Volume = 0x08; // Set Volume = -8[dB] SetVolume(Volume, Volume); BASS = 0; // Set Bass Boost = off SetBassBoost(BASS, 15); delay_ms(1000); // Start VS1011e Sine Test // VS1011_SineTest(); // Start Sin_5kHz /// 変数初期化 Count= 0; SetupScreen(); // ADC設定変更 FileNo= 0; FN_Top= 1; SW= -1; ChgFlag= 0; /// カード挿入まで待ちファイル有無確認(CDの無いUL024TF使用のため、MDD_MediaDetect()の戻り値を強制的に、'1':挿入にしている。) while(fptr == 0){ Glcd_Clear(BLACK); // 画面消去 if(!MDD_MediaDetect()){ // カード挿入中か? Glcd_Str(0, 0, "Wait Card Insert!", CYAN, BLACK); // 挿入待ちメッセージ(今回はここは常に実行しない) } else{ // 常にカード挿入状態を実行する。 /*** ファイルオープンとファイル名表示 ***/ Glcd_Str(0, 1, "Find Card OK!", CYAN, BLACK); FSInit(); // FS初期化 /* 最初のファイルのサーチ */ result = FindFirst("*.*", ATTR_ARCHIVE, rptr); if(result != 0){ // ファイルありか? Glcd_Str(0, 1, "Find No File?", CYAN, BLACK); // ファイル無しメッセージ } else break; // ファイル発見で抜ける } delay_ms(500); // 0.5秒ごとに繰り返し } /// ファイルが発見できた場合の処理 DispFiles(); // ファイル名一覧表示処理 Glcd_Char(16, 8, 0xE9, GREEN, BLACK); // ボタン-1:Skip 表示(キャラクタ) Glcd_Char(25, 8, 0xE9, YELLOW, BLACK); // ボタン-2:Home 表示(キャラクタ) Glcd_Char(25, 0, 0xEB, CYAN, BLACK); // ボタン-1:VOL+ 表示(キャラクタ) Glcd_Char(25, 16, 0xED, CYAN, BLACK); // ボタン-1:VOL- 表示(キャラクタ) itostring(2, 64-Volume, str_V+1); Glcd_Str(21, 0, str_V, WHITE, BLACK); // 'Vxx'表示 Glcd_Char(0, 0, 0xE4, GREEN, BLACK); // '●'を選択初期位置(先頭)に表示); /// メイン ループ while(1) { /// 曲番表示 itostring(3, FileNo+1, str_N+1); Glcd_Str(16, 16, str_N, WHITE, BLACK); // 'Nxxx'表示 /// 選択されたファイルの再生処理 fptr = FSfopen(FileName[FileNo], "r"); // ファイルを開く if (fptr != 0) { // Success File Open ? // 尚、ファイル名が無い(0)をオープンしようとするとオープンエラー:fptr == 0になる。 // Out of Music Data As Far as EOF of File do{ /// 更新フラグチェックと制御(音量ボタン) if(ChgFlag){ // 更新ありか? ChgFlag = 0; // フラグクリア SetVolume(Volume, Volume); // 音量設定 } MP3_XDCS_IO = 0; /// File Read (Unit 256Byte) result = FSfread(Buffer, 1, 256, fptr); for( i= 0; i 60)&&(Yset < 1000)){ /// 確実なタッチの検出 if((abs(Xset - Xold) < 15) && abs(Yset - Yold) < 15){ Count++; if(Count >= 3){ Count = 0; SW= CheckBtn(Xset, Yset); // 押されたボタン判断 /// 音量ボタンチェック if(SW == 2){ // ボタン2:音量アップ if(Volume > 0) { // 最高0(0dB): 64〜0の範囲で設定 Volume--; itostring(2, 64-Volume, str_V+1); // 'Vxx'表示:表示は、最小0〜最大64の表示に変換 Glcd_Str(21, 0, str_V, WHITE, BLACK); } ChgFlag = 1; // 変更フラグオン SW= -1; } if(SW == 3){ // ボタン3:音量ダウン if(Volume < 64) { // 0〜64の範囲で設定 Volume++; itostring(2, 64-Volume, str_V+1); // 'Vxx'表示:表示は、最小0〜最大64の表示に変換 Glcd_Str(21, 0, str_V, WHITE, BLACK); } ChgFlag = 1; // 変更フラグオン SW= -1; } } } else Count = 0; Xold = Xset; Yold = Yset; } else SW= -1; } /***************************************************** * 選択マーカー移動表示+スクロール処理 ******************************************************/ void ScrollDisp(void) { short i; FileNo++; // 次の行へ if(FileNo < 16) { Glcd_Char(0, FileNo-1, 0x20, BLACK, BLACK); // その前に表示されている、選択キャラクタ'●'をクリアする Glcd_Char(0, FileNo, 0xE4, GREEN, BLACK); // '●'を選択初期位置(先頭)に表示 } else{ //// スクロール表示 for(i= 0; i < 16; i++) Glcd_Str(2, i, " ", BLACK, BLACK); // ファイル名のみクリア i= 0; /// 16曲分のファイル名の表示(スクロール毎に、1つ上にずれる) while(i < 16) { Glcd_Str(2, i, FileName[FN_Top],CYAN, BLACK); FN_Top++; i++; } /// FN_Topは、1回目、17で抜けるので、2回目のために、-15しておけばよい FN_Top = FN_Top - 15; Glcd_Char(0, FileNo, 0x20, BLACK, BLACK);// 現在位置の、選択キャラクタ'●'をクリアする } } /***************************************************************** * HOMEボタンをタッチした時と、オープンエラー時の処理(同じ処理) ******************************************************************/ void HomeFunc(void) { if(FileNo < 16) Glcd_Char(0, FileNo, 0x20, BLACK, BLACK);// 現在位置の、選択キャラクタ'●'をクリアする else Glcd_Char(0, 15, 0x20, BLACK, BLACK);// スクロール領域の場合、最終行の選択キャラクタ'●'をクリアする /// ファイル名のみクリア for(i= 0; i < 16; i++) Glcd_Str(2, i, " ", BLACK, BLACK); /// 初期ファイルリスト表示に戻す。 if(Total >= 16) { // トータル曲数が、16曲以上の場合 for(i= 0; i < 16; i++) Glcd_Str(2, i, FileName[i], CYAN, BLACK); } else { // トータル曲数が、16曲未満の場合 for(i= 0; i < Total; i++) Glcd_Str(2, i, FileName[i], CYAN, BLACK); } FileNo = 0; FN_Top= 1; Glcd_Char(0, FileNo, 0xE4, GREEN, BLACK); // '●'を選択初期位置(先頭)に表示 } /******************************** * 座標取得実行関数 ********************************/ short Getscreen(unsigned int chn) { short i; AD1CON1bits.ADON = 0; AD1CON1bits.DONE = 0; // 手動の場合は変換開始前に、DONEビットをクリアする必要あり(自動クリアしない) AD1CHS = chn; // Select Channel AD1CON1bits.ADON = 1; AD1CON1bits.SAMP = 1; for(i=0; i<100; i++) // Wait Aquisition 11usec Nop(); AD1CON1bits.SAMP = 0; // A/D convert start while(!AD1CON1bits.DONE); // wait conversion return(ADC1BUF0); // return result } /**************************************** * タッチスクリーン用設定変更 ****************************************/ void SetupScreen(void) { /* ADCの設定 */ AD1CON1bits.ADON = 0; AD1CON1 = 0x0000; // ADオフ、手動制御、10bit分解能 AD1CON2 = 0; // AVdd, AVss, SCANなし,MUXAのみ AD1CON3 = 0x0304; // AD用クロック周期:Tad = 10*Tcy= 10*12.5= 125nS/サンプル時間:3Tad= 3*125= 375nS // Tad= 2* 周辺用クロック(Tpbclk=Tcy)* (ADCS(7:0)設定+1)= 2* 12.5* (4+1) AD1CHS = 0x00000000; // チャネル選択(※ S/Hチャンネル設定は上位16bitでする) // AD1PCFG = 0xFFE7; // AN4(X-)、AN3(Y+)→ ここでは、これは必要ない。 AD1CSSL = 0; // 自動スキャンなし AD1CON1bits.ADON = 1; // AD有効化 } /********************************************************** * タッチボタン判定処理 * タッチポイントの座標から、押されたボタンの種別No.を取得 * し、その値を返す ***********************************************************/ short CheckBtn(short x, short y) { short i, btn; /* /// タッチ座標位置表示(デバッグ用) itostring(4, x, MsgScrn+2); itostring(4, y, MsgScrn+9); Glcd_Str(3, 16, MsgScrn, GREEN, BLACK); */ /// ボタンチェック btn = -1; for(i=0; i<4; i++){ if((x > Button[i][0]-15)&&(x < Button[i][0]+15)){ if((y > Button[i][1]-15)&&(y < Button[i][1]+15)) btn = i; } } return(btn); } /*************************************** * 整数からASCII文字に変換 ****************************************/ void itostring(char digit, unsigned short data, char *buffer) { char i; buffer += digit; // 最後の数字位置 for(i=digit; i>0; i--) { // 変換は下位から上位へ buffer--; // ポインター1 *buffer = (data % 10) + '0'; // ASCIIへ data = data / 10; // 次の桁へ } } /*************************************************** * ファイルリストの表示 * 最大256ファイル ****************************************************/ void DispFiles(void){ short i, j; Glcd_Clear(BLACK); // 全画面消去 /// ファイル名の表示 i = 0; j = 0; /// 最初のファイル名の表示と格納 while(Record.filename[j] != 0){ // 名称最後か? FileName[i][j] = Record.filename[j]; // 格納 j++; } Glcd_Str(2, i++, Record.filename, CYAN, BLACK); // 最初のファイル名の表示 /// すべてのファイル名の表示と格納 while(FindNext(rptr) == 0){ // 次のファイルサーチ //// ファイル発見できれば表示し格納 j = 0; // 文字列ポインタリセット if(Record.attributes==ATTR_ARCHIVE) // 発見できたか? while(Record.filename[j] != 0){ // 名称の最後か? FileName[i][j] = Record.filename[j];// 格納 j++; } /// 初期ファイルリストとして、1画面、最大16曲分リスト表示する if(i<=15) Glcd_Str(2, i, Record.filename, CYAN, BLACK); i++; if(i>=256) // 格納ファイルが256個目を超えたか? break; // 終了して抜ける } Total= i; /// トータル・曲数(ファイル数)の表示 itostring(3, Total, str_T+1); Glcd_Str(20, 16, str_T, WHITE, BLACK); }