※拡張子は変更して下さい。(〜.txt → 〜.c) // トラックの終端コード(0xaa)を読み、自動的に停止する機種用 /********************************************************* * ATAPI CD-ROM コントローラー Version 3.0 * 機種 PIC16F887利用版 HI-TECH C * LCD:SC1602BS-B(-SO-GS-K) * R2.05.27更新 適合機種:LG MODEL CRD-8400B **********************************************************/ // RE0:LCD_RS RE1:LCD_E RE3(入力専用ピン)->MCLR // RA0-3:LCD_D4-D7 // RA4-7:Button #define _XTAL_FREQ 40000000 #include __CONFIG(FOSC_INTRC_NOCLKOUT & MCLRE_ON & WDTE_OFF & PWRTE_ON & BOREN_OFF & LVP_OFF); // 内部クロック 4MHz は default、MCLRは使う設定 #define Eject_btn RA7 // sw == 7 Eject/Close/Stop #define Foward_btn RA6 // sw == 6 Forward #define Back_btn RA5 // sw == 5 Back #define Play_btn RA4 // sw == 4 Play/Pause/Resume #define RESET_SW RB7 #define DIOW RB6 #define DIOR RB5 #define LCD_E RE1 #define LCD_RS RE0 // LCD_R/W:GND #define LCD_DATA PORTA struct shape_t { //構造体配列 CD各曲の開始時間を記憶する unsigned char minute; unsigned char second; unsigned char frame; }; struct shape_t jikan[26]; //25trackまで、[0]にはtotal_時間を unsigned char Msg1[] = "Trackxx/xx xx:xx"; // 現在トラック/総トラック数 総時間 unsigned char Msg2[] = "Play xx:xx/xx:xx"; // トラック経過時間 曲の時間 unsigned char Msg3[] = " "; // 動作確認用データの表示 unsigned int counter, i; unsigned char sw, temp, sec_fl; // 1秒経過フラグ unsigned char t0if_cnt; // タイマ0の割り込みカウント用(1バイト0-255) unsigned char ata_addr, ata_data; unsigned char atapi_data_high, atapi_data_low; unsigned char sense_key, ASC, ASCQ; unsigned char open_tray_flag, audio_status, start_flag, error_flag; unsigned char total_track, total_minute, total_second, total_frame; unsigned char track_minute, track_second; // 各曲の演奏時間を記憶 unsigned char play_track, play_minute, play_second, play_frame; unsigned char start_minute, start_second, start_frame; unsigned char hozon_track; void interrupt warikomi(void); void pic_init(); void LCD_init(); void LCD_cmd(unsigned char); void LCD_write(unsigned char); void ON_OFF(); // LCD書込みシグナル void LCD_puts(char *s); void play_hyoji(); // 全体表示 void play_hyoji2(); // 変化するデータを表示 void play_hyoji3(); // 動作確認用データの表示 void track_time(); void LCD_ichi(unsigned char pos); void tostring(unsigned char data, char *buffer); void toascii(unsigned char data2, char *buf); void delay_ms(unsigned int t1); void delay_10us(unsigned int t2); void delay_us(unsigned int t3); void media_check(); void reset_sequense(); void identify_packet_device(); void set_features(); void pre_play(); void tray_lock(); void tray_unlock(); void play(); void stop(); void pause(char select); void read_toc(); void read_sub_channel(); void do_eject(); void read_ata_reg(); void write_ata_reg(); void read_atapi(); void write_atapi(); void send_atapi_command_packet(); void request_sense(); void open_tray(); void close_tray(); void check_command_transfer_end(); void check_waiting_data_from_device(); unsigned char get_disk_status(); unsigned char keysearch(); unsigned char getkey(); unsigned char ADRCTRL; // トラックの性質コード unsigned char MODE; // 動作状態 /************************************************** MODE = 0 : 初期化中 MODE = 3 : 再生中 MODE = 1 : 停止(no disc) MODE = 4 : 一時停止中 MODE = 2 : 停止(disc 有) MODE = 5 : エラー ***************************************************/ // ==================== メイン処理 =========================== main(){ pic_init(); // PICの初期化 LCD_init(); // LCDの初期化 LCD_ichi(0x00); LCD_puts("Wait!"); delay_ms(500); // 変数初期化 MODE = 0; sec_fl = 0; start_flag = 0; open_tray_flag = 0; error_flag = 0; play_track =0; // これを入れないと、最初に最終トラック判定に合致してしまう total_track = 0xff; // 初めは play_track ≠ total_track //====media_check=== media_check(); while(1) { sw = 0x00; sw = getkey(); // どのキーを押した? if(start_flag ==1){ sw = 4; start_flag = 0; } switch(sw){ case 7: // Eject or closeボタン while(Eject_btn == 0); //チャタリング防止用 delay_ms(25); if(MODE == 2){ // 停止中->開く MODE = 1; do_eject(); break; } if(MODE == 3){ // 再生中なら → 停止へ T0IE = 0; //タイマ0割り込み停止 stop(); start_minute = jikan[play_track].minute; start_second = jikan[play_track].second; start_frame = jikan[play_track].frame; play_hyoji(); MODE = 2; break; } if(MODE == 4){ //一時停止中->開く  MODE = 1; do_eject(); break; } //以後は MODE が 0 or 1 のとき if(open_tray_flag == 0){// 閉まってたら開ける MODE = 1; do_eject(); } else { // 開いていたら閉める close_tray(); media_check(); // MODE=2 になって戻る } break; case 6: // Fowardボタン while(Foward_btn == 0); delay_ms(25); if((MODE < 2) || (MODE == 5)){ // (一時)停止中や再生中で break; // 無ければ無視 } //以下は、MODE が 2 or 3 or 4 T0IE = 0; // タイマー0を止めて stop(); // どのモードでも一旦ストップ if((play_track + 1) <= total_track){ play_track++; } else { play_track = 1; // 最後のトラックなら最初へ } start_minute = jikan[play_track].minute; start_second = jikan[play_track].second; start_frame = jikan[play_track].frame; play_hyoji(); //曲表示変更 play(); T0IE = 1; // タイマ0再開 break; case 5: // Backボタン while(Back_btn == 0); delay_ms(25); if((MODE < 2) || (MODE == 5)){ break; } //以下は、MODE が 2 or 3 or 4 T0IE = 0; // タイマー0を止めて stop(); // どのモードでも一旦ストップ if((play_track - 1) > 0){ play_track--; } else { play_track = total_track;// 最初のトラックなら最後へ } start_minute = jikan[play_track].minute; start_second = jikan[play_track].second; start_frame = jikan[play_track].frame; play_hyoji(); //曲表示変更 play(); T0IE = 1; break; case 4: //Play or Pause or Resume while(Play_btn == 0); delay_ms(25); if(MODE == 2){ // 停止中->再生 T0IE = 1; // タイマ0割り込み開始 play(); MODE = 3; // 再生中モード } else if(MODE == 3){ // 再生中->一時停止 T0IE = 0; // タイマ0割り込み停止 pause(0); MODE = 4; // 一時停止中へ } else if(MODE == 4){ // 一時停止中->復帰再生 T0IE = 1; // タイマ0割り込み開始 pause(1); // resume MODE = 3; // 再生中 } break; default: break; } //End_switch(sw) switch(MODE){ case 2: // 停止中 LCD_ichi(0x40); LCD_puts("Stop"); break; case 3: // 再生中 LCD_ichi(0x40); LCD_puts("Play"); break; case 4: // 一時停止中 LCD_ichi(0x40); LCD_puts("Pause"); break; case 5: // エラー時 LCD_ichi(0x00); delay_ms(5); LCD_puts(" Error disc??"); LCD_ichi(0x40); LCD_puts("Push Eject"); break; } //End_switch(MODE) if(sec_fl == 1){ // 1秒ごとの処理(再生中のみ) read_sub_channel(); if(play_track != hozon_track){ // 曲が変わったら hozon_track = play_track; play_hyoji(); //曲表示変更 } play_hyoji2(); sec_fl = 0; // 初期値に } // 最終トラックの終了時の処理(トラック1へ) if((play_track == total_track) && (audio_status != 0x11)){ //audio_status==11h 再生中 play_track = 1; start_minute = jikan[play_track].minute; start_second = jikan[play_track].second; start_frame = jikan[play_track].frame; // 最後のトラックで再生を止める場合 // T0IE = 0; //タイマ0をとめて // stop(); stop(); play(); } // 本体のボタンで or 手で押して閉めた if(open_tray_flag == 1){ // トレイ開のフラグ on temp = get_disk_status(); if(temp == 0x00 || temp == 0x30 || temp == 0x70){ // トレイが閉まっているサイン open_tray_flag = 0; media_check(); } } } //End_while(1) } //End_main //===== タイマ0の割込 =================== void interrupt warikomi(void){ T0IF = 0; // タイマ0割込 1μs×16分周×256≒4.1ms t0if_cnt++; // 244回割込で1秒 if(t0if_cnt == 0){ t0if_cnt = 12; // 初期化 sec_fl = 1; // 1秒経過フラグ } } //======= ドライブの準備 ====== void media_check(){ reset_sequense(); identify_packet_device(); hozon_track = 0; delay_ms(500); //====media_check=== LCD_cmd(0x01); delay_ms(5); LCD_puts("Disc checking"); //===tray_check======= counter = 0; do{ delay_ms(30); // ドライブによって、長さを調整 request_sense(); play_hyoji3(); // 調整用の回数、データ表示 counter++; if(counter > 4 && sense_key == 2 && ASC == 0x3A)counter = 31; // No Disc のコードのときはすぐに break if(counter > 30)break; // 30回超えたら無いと判断して }while(sense_key != 0 || ASC != 0 || ASCQ != 0); if(counter > 30){ // この回数もドライブごとに調整 MODE = 1; // 停止(No Disc) LCD_cmd(0x01); delay_ms(5); LCD_puts("Push "); LCD_ichi(0x40); LCD_puts("No Disc"); return; } else { pre_play(); // Discの情報を記憶して、Loopへ } return; } //=======pre_play 再生の準備 ====== void pre_play(){ read_toc(); if(MODE == 5)return; // 情報をLCDに表示 i= 1; start_minute = jikan[i].minute; start_second = jikan[i].second; start_frame = jikan[i].frame; play_track = i; // とりあえず1トラックから // total_track はそのまま total_minute = jikan[0].minute; total_second = jikan[0].second; total_frame = jikan[0].frame; // 分・秒・フレームとも最後のデータが合計値 play_hyoji(); MODE = 2; // 停止(Disc 有り) start_flag = 1; return; } //=====read_sub_channel ============== void read_sub_channel(){ send_atapi_command_packet(); atapi_data_low = 0x42; //sub_channel atapi_data_high = 0x02; //MSF write_atapi(); atapi_data_low = 0x40; //data要求 atapi_data_high = 0x01; //現在位置 write_atapi(); atapi_data_low = 0x00; atapi_data_high = 0x00; write_atapi(); atapi_data_low = 0x00; atapi_data_high = 0xff; write_atapi(); atapi_data_low = 0xff; atapi_data_high = 0x00; write_atapi(); atapi_data_low = 0x00; atapi_data_high = 0x00; write_atapi(); check_waiting_data_from_device(); read_atapi(); audio_status = atapi_data_high; // audio_status read_atapi(); read_atapi(); ADRCTRL = atapi_data_high; read_atapi(); play_track = atapi_data_low; for(i=0;i<3;i++){ read_atapi(); } play_minute = atapi_data_high; //現在分 read_atapi(); play_second = atapi_data_low; //現在秒 play_frame = atapi_data_high; //frame(表示には不要) return; } //=======read_toc CDの情報 ======== void read_toc(){ unsigned char TRK, MIN, SEC, FRM; for(i=0;i < 26;i++){ //構造体配列の初期化 jikan[i].minute = 0; jikan[i].second = 0; jikan[i].frame = 0; } send_atapi_command_packet(); atapi_data_low = 0x43; atapi_data_high = 0x02; //MSF番号 write_atapi(); atapi_data_low = 0x00; //0:toc要求 atapi_data_high = 0x00; write_atapi(); atapi_data_low = 0x00; atapi_data_high =0x00; write_atapi(); atapi_data_low = 0x00; atapi_data_high = 0xff; write_atapi(); atapi_data_low = 0xff; atapi_data_high = 0x00; write_atapi(); atapi_data_low = 0x00; atapi_data_high = 0x00; write_atapi(); check_waiting_data_from_device(); // ここからCDのデータを読む read_atapi(); read_atapi(); total_track = atapi_data_high; i = 0; // ※配列の添字 == トラック番号 do{ // 曲ごとの時間を記憶する read_atapi(); ADRCTRL = atapi_data_high; read_atapi(); TRK = atapi_data_low; read_atapi(); MIN = atapi_data_high; read_atapi(); SEC = atapi_data_low; FRM = atapi_data_high; if((ADRCTRL & 0x04) != 0)continue; // 0x14 番はデータ・トラック if(TRK == 0xaa){ // 合計時間は jikan(0)に jikan[0].minute = MIN; jikan[0].second = SEC; jikan[0].frame = FRM; break; } else { i++; jikan[i].minute = MIN; jikan[i].second = SEC; jikan[i].frame = FRM; } }while(i < total_track+1); total_track = i; if(i == 0){ // 音楽トラックは無しなら MODE = 5; return; } check_command_transfer_end(); return; } //====== 曲演奏時間の計算 ===== void track_time(){ unsigned char k; unsigned int time1,time2,time_diff; k = play_track; time1 = jikan[k].minute * 60 + jikan[k].second; if(k == total_track){ time2 = jikan[0].minute * 60 + jikan[0].second; } else { time2 = jikan[k+1].minute * 60 + jikan[k+1].second; } time_diff = time2 - time1; track_minute = time_diff / 60; track_second = time_diff % 60; } //======= プレイ表示 ================= void play_hyoji(void){ track_time(); tostring(play_track, Msg1+5); tostring(total_track, Msg1+8); tostring(total_minute, Msg1+11); tostring(total_second, Msg1+14); LCD_cmd(0x01); // Clear Display delay_ms(5); LCD_puts(Msg1); // tostring(start_minute, Msg2+5); tostring(start_second, Msg2+8); tostring(track_minute, Msg2+11); tostring(track_second, Msg2+14); LCD_ichi(0x40); // LCDアドレス(2行目) LCD_puts(Msg2); } //======= プレイ表示2 ================= void play_hyoji2(void){ tostring(play_track, Msg1+5); LCD_ichi(0x00); // LCDアドレス(1行目) LCD_puts(Msg1); tostring(play_minute, Msg2+5); tostring(play_second, Msg2+8); LCD_ichi(0x40); // LCDアドレス(2行目) LCD_puts(Msg2); } //======= プレイ表示3 動作確認 ============ void play_hyoji3(void){ tostring(counter, Msg3+0); toascii(sense_key, Msg3+4); toascii(ASC, Msg3+8); toascii(ASCQ, Msg3+12); LCD_ichi(0x40); // LCDアドレス(2行目) LCD_puts(Msg3); } // ========== カーソル位置 ============= void LCD_ichi(unsigned char pos){ LCD_cmd(0x80+pos); /*表示位置とアドレス 1行目:0x00〜0x13 2行目:0x40〜0x53 */ } // ====== 16進数からascii文字列へ ======= void toascii(unsigned char data, char *buf) { char hd[] = "0123456789ABCDEF"; *buf = hd[data >> 4]; // 上位4桁をASCII変換 buf++; *buf = hd[data & 0x0f]; // 下位4桁をASCII変換 } // ========= int整数からASCII文字に変換 ========= void tostring(unsigned char data, char *buffer) { buffer++; *buffer = (data % 10) + '0'; // 下位桁ASCII変換 // example 54%10 → 4 (+'0') → 0x34(=4h) data = data / 10; // 上位桁へ // 54÷10 → 5 buffer--; // if(data == 0) // 0ならブランク // *buffer = ' '; // else *buffer = data + '0'; // ASCII変換 } // ==================== PICの初期化 =========================== static void pic_init(){ ANSEL = 0x00; // コンパレータを無効, PORTA をデジタルioに ANSELH = 0x00; // コンパレータを無効, PORTB をデジタルioに TRISA = 0xF0; // 0-3:出力  4-7:入力(ボタン)設定 TRISB = 0x00; // 基本 出力 TRISC = 0xFF; // 基本 入力 TRISD = 0xFF; //  〃 TRISE = 0x00; // 基本 出力 LCDのコントロール PORTA = 0xF0; // 最初SWは Off RB7 = 1; // Reset Off OPTION_REG = 0x83;// タイマー0の設定 タイマ0使用プリスケーラ 16分周 (// T0CS = 0;PSA = 0; PS0 = 1; PS1 = 1; PS2 =0; → OPTION_REG) TMR0 = 0; t0if_cnt = 12; // タイマ0 初期値 T0IF = 0; GIE = 1; // タイマ0スタート準備 T0IE = 0; return; } //=== do_eject ===== void do_eject(){ LCD_cmd(0x01); delay_ms(5); LCD_puts("Eject"); open_tray(); LCD_cmd(0x01); delay_ms(5); LCD_puts("Insert A Disc"); LCD_ichi(0x40); LCD_puts("& Push "); } //====== CD-Reset =========== void reset_sequense(){ delay_ms(10); RESET_SW = 0; // RESETスイッチ delay_ms(10); RESET_SW = 1; delay_ms(2); do{ ata_addr = 0x0e; read_ata_reg(); }while((ata_data & 0x80) != 0x00); ata_addr = 0x0e; ata_data = 0xe0; write_ata_reg(); delay_ms(1); ata_addr = 0x0e; ata_data = 0x02; write_ata_reg(); do{ ata_addr = 0x0e; read_ata_reg(); }while((ata_data & 0x80) != 0x00); } // ====device selection protocol void identify_packet_device(){ do{ ata_addr = 0x0e; read_ata_reg(); }while((ata_data & 0x88) != 0x00); // BSY & DRQ = 0 を確認 ata_addr = 0x16; ata_data = 0x00; write_ata_reg(); delay_10us(1); do{ ata_addr = 0x0e; read_ata_reg(); }while((ata_data & 0x88) != 0x00); // hyoji("-Device-")1行目 LCD_cmd(0x01); delay_ms(5); LCD_puts(" - Device -"); // カーソルを2行目に移動して LCD_ichi(0x40); ata_addr = 0x16; ata_data = 0x00; write_ata_reg(); ata_addr = 0x17; ata_data = 0xa1; write_ata_reg(); do{ ata_addr = 0x0e; read_ata_reg(); }while((ata_data & 0x88) != 0x08); for(i=0;i<27;i++)read_atapi();//空読み for(i=0;i<8;i++){ //16文字分 read_atapi(); LCD_write(atapi_data_high); LCD_write(atapi_data_low); } for(i=0;i<221;i++)read_atapi(); //残りを空読み 全256ワード set_features(); return; } //=== set features command ===== void set_features(){ ata_addr = 0x0e; ata_data = 0x0a; write_ata_reg(); ata_addr = 0x11; ata_data = 0x03; write_ata_reg(); ata_addr = 0x12; ata_data = 0x01; write_ata_reg(); ata_addr = 0x16; ata_data = 0x00; write_ata_reg(); ata_addr = 0x17; ata_data = 0xef; write_ata_reg(); return; } //=========================== void request_sense(){ send_atapi_command_packet(); //==test unit ready for(i=0;i<6;i++){ atapi_data_low = 0x00; atapi_data_high = 0x00; write_atapi(); } send_atapi_command_packet(); //==request sense atapi_data_low = 0x03; atapi_data_high = 0x00; write_atapi(); atapi_data_low = 0x00; atapi_data_high = 0x00; write_atapi(); atapi_data_low = 18; //Allocation Length 18 atapi_data_high = 0x00; write_atapi(); for(i=0;i<3;i++){ atapi_data_low = 0x00; atapi_data_high = 0x00; write_atapi(); } check_waiting_data_from_device(); //デバイス→ホストか?データ転送要求か?チェック ata_addr = 0x10; for(i=0;i<2;i++){ read_atapi(); } sense_key = atapi_data_low & 0x0F; //Sense Key for(i=0;i<5;i++){ read_atapi(); } ASC = atapi_data_low; ASCQ = atapi_data_high; for(i=0;i<2;i++){ read_atapi(); } return; } //=============================== void send_atapi_command_packet(){ do{ ata_addr = 0x0e; read_ata_reg(); }while((ata_data & 0x80) != 0x00); //not BUSYを確認 ata_addr = 0x0e; // Device Control ata_data = 0x0a; write_ata_reg(); ata_addr = 0x11; // Features ata_data = 0x00; write_ata_reg(); ata_addr = 0x12; // Sector Count ata_data = 0x00; write_ata_reg(); ata_addr = 0x13; // Sector Number ata_data = 0x00; write_ata_reg(); ata_addr = 0x14; // Byte Count Low ata_data = 0xff; write_ata_reg(); ata_addr = 0x15; // Byte Count High ata_data = 0xff; write_ata_reg(); ata_addr = 0x16; // Device/Head ata_data = 0x00; write_ata_reg(); ata_addr = 0x17; // Command ata_data = 0xa0; write_ata_reg(); do{ ata_addr = 0x12;// Interrupt Reason read_ata_reg(); }while((ata_data & 0x07) != 0x01);// xxxxx001 になれば do{ ata_addr = 0x0e;// Status read_ata_reg(); }while((ata_data & 0x88) != 0x08);// 0xxx1xxx になれば } //======================== void read_atapi(){ PORTB = 0xF0; delay_10us(1); //遅延時間は微妙 DIOR = 0; delay_10us(1); //長過ぎても不可 atapi_data_high = PORTC; atapi_data_low = PORTD; DIOR = 1; delay_10us(1); return; } //======================= void write_atapi(){ TRISC = 0x00; //PORTCを出力設定 TRISD = 0x00; //PORTD 〃 PORTB = 0xF0; PORTC = atapi_data_high; PORTD = atapi_data_low; delay_10us(1); DIOW = 0; DIOW = 1; TRISC = 0xFF; //PORTCを入力設定に戻す TRISD = 0xFF; //PORTD 〃 delay_10us(1); return; } //====================== void read_ata_reg(){ TRISD = 0xff; //PORTDを入力に ata_addr |= 0xE0; //ata_addr は 0xE? PORTB = ata_addr; delay_10us(1); DIOR = 0; delay_10us(1); ata_data = PORTD; DIOR = 1; delay_10us(1); } //===================== void write_ata_reg(){ TRISD = 0x00; //PORTDを出力に ata_addr |= 0xE0; //RB5,6,7を1に PORTB = ata_addr; PORTD = ata_data; delay_10us(1); DIOW = 0; DIOW = 1; //DIOWに信号 TRISD = 0xFF; //PORTDを入力に delay_10us(1); return; } //==================== void check_waiting_data_from_device(){ do{ //デバイス→ホストか ata_addr = 0x12; read_ata_reg(); }while((ata_data & 0x03) != 0x02);//0,1ビットのみ有効に do{ //データ転送要求か delay_10us(1); //これを入れたら samsung も通った ata_addr = 0x0E; read_ata_reg(); }while((ata_data & 0x88) != 0x08); return; //3,7ビットのみ有効に } //====== Open-tray 開 =========== void open_tray(){ tray_unlock(); // ロック解除 send_atapi_command_packet(); atapi_data_low = 0x1b; // start/stop atapi_data_high = 0x00; write_atapi(); atapi_data_low = 0x00; atapi_data_high = 0x00; write_atapi(); atapi_data_low = 0x02; //Eject atapi_data_high = 0x00; write_atapi(); for(i=0;i<3;i++){ atapi_data_low = 0x00; atapi_data_high = 0x00; write_atapi(); } check_command_transfer_end(); open_tray_flag = 1; return; } //======= close tray 閉 ======= void close_tray(){ tray_unlock(); // ロック解除 send_atapi_command_packet(); atapi_data_low = 0x1b; atapi_data_high = 0x00; write_atapi(); atapi_data_low = 0x00; atapi_data_high = 0x00; write_atapi(); atapi_data_low = 0x03; atapi_data_high = 0x00; write_atapi(); for(i = 0;i<3;i++){ atapi_data_low = 0x00; atapi_data_high = 0x00; write_atapi(); } check_command_transfer_end(); open_tray_flag = 0; return; } //======= エラー・チェック ============ void check_command_transfer_end(){ do{ ata_addr = 0x0e; read_ata_reg(); if((ata_data & 0x01) != 0x00){ // errorなら MODE = 5; // errorモード break; } }while((ata_data & 0xC8) != 0x40); // if not (BSY=0 and DRDY=1 and DRQ=0) then retry if(MODE == 5)return; do{ ata_addr = 0x12; read_ata_reg(); }while((ata_data & 0x07) != 0x03); // if not (REL=0 and I/O=1 and C/D=1) then retry return; } //===== トレーロック ===== void tray_lock(){ // prevent/allow medium removal command send_atapi_command_packet(); atapi_data_low = 0x1e; atapi_data_high = 0x00; write_atapi(); atapi_data_low = 0x00; atapi_data_high = 0x00; write_atapi(); atapi_data_low = 0x03; // lock atapi_data_high = 0x00; write_atapi(); for(i = 0;i<3;i++){ atapi_data_low = 0x00; atapi_data_high = 0x00; write_atapi(); } } //===== トレーロック解除 ===== void tray_unlock(){ // prevent/allow medium removal command send_atapi_command_packet(); atapi_data_low = 0x1e; atapi_data_high = 0x00; write_atapi(); for(i = 0;i<5;i++){ atapi_data_low = 0x00; // unlock atapi_data_high = 0x00; write_atapi(); } } //===== Play 再生 ======== void play(){ send_atapi_command_packet(); atapi_data_low = 0x47; //Play Audio MSF atapi_data_high = 0x00; write_atapi(); atapi_data_low = 0x00; atapi_data_high = start_minute;//開始分 write_atapi(); atapi_data_low = start_second;//開始秒 atapi_data_high = start_frame;//開始フレーム write_atapi(); atapi_data_low = total_minute; atapi_data_high = total_second; write_atapi(); atapi_data_low = total_frame; atapi_data_high = 0x00; write_atapi(); atapi_data_low = 0x00; atapi_data_high = 0x00; write_atapi(); check_command_transfer_end(); MODE = 3; // 再生中 tray_lock(); // トレーをロック return; } //====== Stop 停止 ========= void stop(){ send_atapi_command_packet(); atapi_data_low = 0x4e; //stop atapi_data_high = 0x00; write_atapi(); for(i=0;i<5;i++){ atapi_data_low = 0x00; atapi_data_high = 0x00; write_atapi(); } check_command_transfer_end(); MODE = 2; // 停止中(disc有り) return; } //====== Pause 一時停止 ========= void pause(char select){ // pause/resume send_atapi_command_packet(); atapi_data_low = 0x4b; //pause/resume atapi_data_high = 0x00; write_atapi(); for(i=0;i<3;i++){ atapi_data_low = 0x00; atapi_data_high = 0x00; write_atapi(); } atapi_data_low = select; //pause:0/resume:0x01 atapi_data_high = 0x00; write_atapi(); atapi_data_low = 0x00; atapi_data_high = 0x00; write_atapi(); check_command_transfer_end(); return; } //======Get Disk Status =======- unsigned char get_disk_status(){ unsigned char hozon; send_atapi_command_packet(); atapi_data_low = 0x5a; //==mode_sense=== atapi_data_high = 0x00; write_atapi(); atapi_data_low = 0x0d; atapi_data_high = 0x00; write_atapi(); atapi_data_low = 0x00; atapi_data_high = 0x00; write_atapi(); atapi_data_low = 0x00; atapi_data_high = 0x00; write_atapi(); atapi_data_low = 8+8; atapi_data_high = 0x00; write_atapi(); atapi_data_low = 0x00; atapi_data_high = 0x00; write_atapi(); delay_ms(5); for(i=0;i<2;i++){ read_atapi(); } hozon = atapi_data_low; for(i=0;i<6;i++){ read_atapi(); } return(hozon); } // ==================== LCDコマンドWRITE ================= static void LCD_cmd(unsigned char cmd) { //DATA→RA0-3 LCD_RS = 0; // 制御コマンド出力設定 LCD_DATA = (LCD_DATA & 0xF0) | ((cmd >>4) & 0x0F); ON_OFF(); // 上位4ビット書き込み LCD_DATA = (LCD_DATA & 0xF0) | (cmd & 0x0F); ON_OFF(); // 下位4ビット書き込み delay_us(50); return; } // ========== LCDデータWRITE(1文字表示) ================= static void LCD_write(unsigned char ltr) { LCD_RS = 1; // 表示データ出力設定 LCD_DATA = (LCD_DATA & 0xF0) | ((ltr >>4) & 0x0F); ON_OFF(); // 上位4ビット書き込み LCD_DATA = (LCD_DATA & 0xF0) | (ltr & 0x0F); ON_OFF(); // 下位4ビット書き込み delay_us(50); return; } // ========== LCD に「文字列」を書く ============== void LCD_puts(char *s){ LCD_RS = 1; while(*s)LCD_write(*s++); } // ==================== LCDの初期化 =========================== static void LCD_init() { delay_ms(15); LCD_E = 0; LCD_RS = 0; LCD_DATA = 0x30; // DB4-7に'3'を出力(8bitモードに)@ ON_OFF(); delay_ms(5); ON_OFF(); // DB4-7に'3'を出力(8bitモードに)A delay_us(200); ON_OFF(); // DB4-7に'3'を出力(8bitモードに)B delay_us(200); LCD_DATA = 0x20; // DB4-7に'2'を出力(4bitモードに) ON_OFF(); delay_us(200); // ここからは4bitモードで、Busyフラグが使える LCD_cmd(0x28); // DL=0:4bit ,N=1:2lines ,F=0:5*7dot LCD_cmd(0x08); // Display off LCD_cmd(0x0C); // Display on ,cursor on ,no blink LCD_cmd(0x06); // Entry mode (Inc ,No Shift) LCD_cmd(0x01); // Clear Display delay_ms(5); return; } // ==== Enable Signal On Off ===== void ON_OFF(){ LCD_E = 1; NOP(); LCD_E = 0; } // ==========遅延ルーチン========== void delay_ms(unsigned int t1){ while(t1--){ __delay_ms(1); } } void delay_10us(unsigned int t2){ while(t2--){ __delay_us(10); } } void delay_us(unsigned int t3){ while(t3--){ __delay_us(1); } } /***** 押されている(=0の)SWを探すSUB *****/ unsigned char keysearch(){ unsigned char tsw; tsw = 0x00; switch (PORTA & 0xF0){ // 0b11110000とのAND case 0b01110000: tsw = 7; //RA7(Eject)on break; case 0b10110000: tsw = 6; //RA6(Forward) on break; case 0b11010000: tsw = 5; //RA5(Back) on break; case 0b11100000: tsw = 4; //RA4(Play/Pause) on break; } return (tsw); } /*** 5回連続で「押」を確認したら、その値を返す ***/ unsigned char getkey(){ unsigned char newval, oldval, cnt; oldval = 0x00; while(1){ for(cnt = 0; cnt < 5; cnt++){ newval = keysearch(); if(newval != oldval){ cnt = 0; oldval = newval; } delay_10us(10); } return(newval); } } //==== End of program =================