日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 人文社科 > 生活经验 >内容正文

生活经验

单片AT89C2051 + SD卡 + 3310LCD = 音乐播放器

發布時間:2023/11/27 生活经验 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 单片AT89C2051 + SD卡 + 3310LCD = 音乐播放器 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

http://www.amobbs.com/thread-4503884-1-1.html

?

這個小玩意,采用 ATMEL 的傳統51MCU作主控制芯片,加上SD卡和顯示屏,就可以作簡單的音樂播放器了,雖然音質不怎么樣,不過作為DIY還是蠻有樂趣,希望大家喜歡。
沒有采用FAT文件系統,只是按扇區讀取SD卡,由于2051資源有限,改為4051有望可以操作FAT,但目前程序還在不斷完善中。
128byte怎樣讀取512byte的扇區數據?可以采用邊讀邊播放的方式,就能解決。音樂文件是32KHz取樣率的WAV文件,所以和HIFI就沾不上邊了。
程序是用C來編寫,以方便交流,資料整理中,完善后再上傳。

這是未經整理的程序,有點亂,湊合著看,有時間再進一步改進。
SD部分是修改于本壇的一個貼子
----------------------------------------------------------
添加部分注釋,提高可讀性

#include <reg51.h>#include <INTRINS.H>#include <MATH.H>#include "LCD_3310.H"#define uchar unsigned char#define uint  unsigned int#define ulong unsigned long/************ 定義管腳 *************/
sbit DOUT = P3^0;  //SD卡數據輸出
sbit CLK  = P3^1;  //SD卡時鐘輸入
sbit DIN  = P3^2;  //SD卡數據輸入
sbit CS   = P3^3;  //SD卡片選使能/************ 全局變量 ************/                                                                                                                       
uchar pbuf[64]; //數據緩沖區
uchar p;        //播放緩沖區指針
uchar px;       //頻譜顯示的X坐標

code ulong Track[17] = {   //0x15000,0x58000   SD卡中各聲音文件的首址,以后打算把這些數據放在SD卡的特定配置文件中再讀入。0xd7800-0x8a00,0x76b800-0x8a00,0xedc000-0x8a00,0x1752800-0x8a00,0x1F08000-0x8a00,0x2569800-0x8a00,0x2EDB800-0x8a00,0x3480000-0x8a00,0x3BFA800-0x8a00,0x41EB000-0x8a00,0x48EF000-0x8a00,0x508A000-0x8a00,0x59AE800-0x8a00,0x60AF000-0x8a00,0x6878000-0x8a00,0x6DBE000-0x8a00,0x7525800-0x8a00,};/******* SD訪問錯誤碼的定義 *******/#define INIT_CMD0_ERROR   0X01#define INIT_CMD1_ERROR   0X02#define READ_BLOCK_ERROR  0X03#define WRITE_BLOCK_ERROR 0X04/********* 通用延時函數 ***********/
void delay(uint i){while(i--);}/******** SD寫入一個字節 **********/
void spi_write(uchar x){   //不采用循環結構是為了提高處理速度DIN = x & 0x80;CLK = 0;CLK = 1;DIN = x & 0x40;CLK = 0;CLK = 1;DIN = x & 0x20;CLK = 0;CLK = 1;DIN = x & 0x10;CLK = 0;CLK = 1;DIN = x & 0x08;CLK = 0;CLK = 1;DIN = x & 0x04;CLK = 0;CLK = 1;DIN = x & 0x02;CLK = 0;CLK = 1;DIN = x & 0x01;CLK = 0;CLK = 1;}/******* SD慢速寫入一個字節 ********/
void spi_write_low_speed(uchar x){uchar i;for(i = 8; i; --i){DIN = x & 0x80;x <<= 1;CLK = 0;delay(1);CLK = 1;delay(1);}}/*********** SD讀入一字節 ***********/
uchar spi_read(void){   //利用51串口的同步移位功能,以達了最高的讀度2MHz CLKRI = 0;while(RI == 0);return SBUF;}/******** SD慢速讀入一字節 **********/
uchar spi_read_low_speed(void){uchar temp,i;for(i = 8; i; --i){CLK = 0;delay(1);temp <<= 1;if(DOUT) temp++;CLK = 1;delay(1);}return temp;}/******** 發送一組SD命令 ************/
uchar write_cmd(uchar data *pcmd){uchar temp,time=0,i;for(i = 0; i<6; i++) //一條命令都是6個字節,形參用指針,{                    //指向6個字節命令,
        spi_write(pcmd);}do                   //看看寫進去沒有,通過so管腳
    {temp = spi_read();time++;}                    //一直到讀到的不是0xff或超時,退出去while(temp==0xff && time<100);return temp;}/****** 慢速發送一組SD命令 **********/
uchar write_cmd_low_speed(uchar *pcmd){uchar temp,time=0,i;for(i=0;i<6;i++)    //一條命令都是6個字節,形參用指針,{                   //指向6個字節命令,
        spi_write_low_speed(pcmd);}do                  //看看寫進去沒有,通過so管腳
    {temp = spi_read_low_speed();time++;}                   //一直到讀到的不是0xff或超時,退出去while(temp==0xff && time<100);return temp;}/********* SD卡 激活,復位 *********/
uchar sd_reset(void){uchar time,temp,i;uchar pcmd[6]={0x40,0x00,0x00,0x00,0x00,0x95};CS = 1;for(i = 0; i < 0x0f; i++) //復位時,至少要72個時鐘周期,{                         //現在是,15*8=120個clkspi_write_low_speed(0xff);}CS = 0;time=0;do{temp = write_cmd_low_speed(pcmd);time++;if(time > 100) return INIT_CMD0_ERROR;}while(temp != 0x01);      //校驗碼是0x01,表示寫入成功CS = 1;spi_write_low_speed(0xff);//時序上要求補8個clkreturn 0;                 //返回0,寫入成功
}/************ SD卡初始化 ************/
uchar sd_init(void){uchar time, temp;uchar pcmd[6] = {0x41,0x00,0x00,0x00,0x00,0xff};CS = 0;time = 0;do{temp = write_cmd_low_speed(pcmd);time++;if(time > 100) return INIT_CMD1_ERROR;}             while(temp != 0x00);CS = 1;spi_write_low_speed(0xff);return 0;}/******* 讀取一扇區的點陣圖像 *********/
uchar sd_read_bmp(uchar data *ad){uchar temp, time, x, pcmd[6];uint j = 0;pcmd[0] = 0x51;pcmd[1] = *ad;pcmd[2] = *(++ad);pcmd[3] = *(++ad);pcmd[4] = 0;pcmd[5] = 0xff;CS = 0;time = 0;do{temp = write_cmd(pcmd);if(++time > 100){CS = 1;return READ_BLOCK_ERROR;}}while(temp != 0);//等待SD卡回應while(spi_read() != 0x7f); //0xfe,51的串口移位是LSB優先,所以結果高低位倒置for (j = 0; j < 504; j++)  //3310的分辨率為 84 * 48,總計用504字節
    {LCD3310_write_dat(spi_read());}for (x = 0; x < 10; x++) spi_read(); //略過8字節數據和2字節CRCspi_write(0xff);CS = 1;return 0;}/******* 讀取一扇區的聲音數據 *********/
uchar sd_read_sector(uchar data *ad){uchar temp, time, pcmd[6];uint j = 0;pcmd[0] = 0x51;pcmd[1] = *ad;pcmd[2] = *(++ad);pcmd[3] = *(++ad);pcmd[4] = 0;pcmd[5] = 0xff;CS = 0;time = 0;do{temp = write_cmd(pcmd);if(++time > 100){CS = 1;return READ_BLOCK_ERROR;}}while(temp != 0);//等待SD回應的時間有點長,所以在這里插入顯示模擬的頻譜圖temp = pbuf[16];         //隨便挑一個數據顯示LCD3310_set_XY(px,5);    //設定顯示位置px += 6;if (px >= 39) px = 0;if (temp & 0x80) temp ^= 0x80; //求得聲音振幅else temp = 0x80 - temp;temp = Level[temp>>4];         //不同幅度對應不同的譜線圖案
    LCD3310_write_dat(temp);LCD3310_write_dat(temp);LCD3310_write_dat(temp);while(spi_read() != 0x7f);//0xfe,51的串口移位是LSB優先,所以結果高低位倒置while(1)     //讀取512字節數據
    {RI = 0;_nop_(); pbuf[j++ & 63] = SBUF; //為求快速,不用函數調用RI = 0;_nop_(); pbuf[j++ & 63] = SBUF; //直接啟動串口移入RI = 0;_nop_(); pbuf[j++ & 63] = SBUF; //連續讀四字節RI = 0;_nop_(); pbuf[j++ & 63] = SBUF;if(j >= 512) break;while((((uchar)j - p) & 63) > 55);     //檢測播放進度,}                                          //如果緩沖區接近溢出,先暫停等待spi_read();//略過 crcspi_read();//略過 crcspi_write(0xff);//SD 時序要求補8個脈沖CS = 1;return 0;}/**************************** 主程序 *******************************/
int main(void){uchar key,n,Count,Min,Sec;ulong addr;  // SD 的扇區地址
P1   = 0x80; // DAC 輸出中點電壓RI   = 1;REN  = 1;TMOD = 0x02;TH0  = 256 - 62.5;  //定時器設定約為 32KHz,和WAV文件取樣率對應ET0  = 1;EA   = 1;px   = 0;n    = 64;do pbuf[--n] = 0x80; while(n); //填充播放緩沖區delay(65535);LCD3310_init();LCD3310_set_XY(0,0);LCD3310_write_cmd(0x22);       //設定LCD掃描順序
    sd_reset();sd_init();addr = 0x4f400;sd_read_bmp((uchar) &addr);    //顯示歡迎畫面while (D_C == 1) ;while (D_C == 0) ;             //等待按鍵delay(65535);//==============  main loop ==================while(1)  //循環播放所有曲目
    {TR0 = 0;LCD3310_write_cmd(0x22);LCD3310_set_XY(0,0);addr = 0x4f600 + ((uint)n<<9);sd_read_bmp((uchar) &addr); //顯示歌名、歌手LCD3310_write_cmd(0x20);TR0  = 1;p    = 0xd0;Min  = 0;Sec  = 0;Count= 0;for (addr = Track[n]; addr < Track[n+1];)//播放第n曲
        {//============ 按鍵處理 ===============key = (key >> 2) | (P3 & 0x30); //僅一句的掃鍵函數,包括掃描和消抖if (key == 0x03)                //鍵碼為03是播放/暫停鍵
            {LCD3310_set_XY(78,5);TCON ^= 0x10;               //TR0 取反if (TR0) LCD3310_print(11); //顯示播放符號else     LCD3310_print(12); //顯示暫停符號
            }       else if (key == 0x2b)           //鍵碼為2b是前一曲
            {if ((Min || (Sec & 0xf0))) n--;//10秒后跳本曲開始else n -= 2;                   //10秒內跳前一曲break;}else if (key == 0x17)           //鍵碼為17是后一曲break;//======== 讀一扇區數據或暫停 =========if (TR0 == 0) {delay(2000); continue;}sd_read_sector((uchar) &addr);addr += 512;//=========== 播放時間計數 ============Count += 2;if (Count >= 125){Count -= 125;Sec++;if ((Sec & 0x0f) > 9){Sec += 6;if (Sec >= 0x60){Sec = 0;Min++;if ((Min & 0x0f) > 9){Min += 6;if (Min > 0x60) Min = 0;}}}}//======= 分時間片顯示時間/標志 ========switch (Count & 14){case 2: LCD3310_set_XY(44,5);LCD3310_print(Min>>4);//分鐘十位break;case 4: LCD3310_set_XY(50,5);LCD3310_print(Min&15);//分鐘個位break;case 6: LCD3310_set_XY(56,5);LCD3310_print(10);    //分隔符break;case 8: LCD3310_set_XY(62,5);LCD3310_print(Sec>>4);//秒十位break;case 10: LCD3310_set_XY(68,5);LCD3310_print(Sec&15);//秒個位break;case 12:LCD3310_set_XY(78,5);if (Count & 0x40) LCD3310_print(13); //閃動播放符號else LCD3310_print(11); }}n++;       //下一曲n &= 15;   //這個SD卡只有16首歌}//while(1);}//main()void timer0 (void) interrupt 1 using 1{if (TL0 & 1) _nop_(); //消除中斷響應時間不一致,造成的頻率抖動P1  = pbuf[++p & 63]; //輸出一個聲音數據
}

這是3310 LCD 部分

#include <reg51.h>#include <INTRINS.H>sbit SDIN = P3^2; //P3^2sbit SCLK = P3^4;sbit D_C  = P3^5;sbit SCE  = P3^7;code unsigned char Font[70] = {0x3E, 0x51, 0x49, 0x45, 0x3E ,  // 00x00, 0x42, 0x7F, 0x40, 0x00 ,  // 10x42, 0x61, 0x51, 0x49, 0x46 ,  // 20x21, 0x41, 0x45, 0x4B, 0x31 ,  // 30x18, 0x14, 0x12, 0x7F, 0x10 ,  // 40x27, 0x45, 0x45, 0x45, 0x39 ,  // 50x3C, 0x4A, 0x49, 0x49, 0x30 ,  // 60x01, 0x71, 0x09, 0x05, 0x03 ,  // 70x36, 0x49, 0x49, 0x49, 0x36 ,  // 80x06, 0x49, 0x49, 0x29, 0x1E ,  // 90x00, 0x00, 0x36, 0x36, 0x00 ,  // :0x7f, 0x3e, 0x1c, 0x08, 0x00 ,  // >0x3e, 0x3e, 0x00, 0x3e, 0x3e ,  // ||0x00, 0x00, 0x00, 0x00, 0x00 ,  //" "
 };    code unsigned char Level[8] = {0x80,0xc0,0xe0,0xf0,0xf8,0xfc,0xfe,0xff,};extern void delay(unsigned int i);void LCD3310_write_cmd(unsigned char cmd){D_C  = 0;SCLK = 0;SCE  = 0;delay(3);SDIN = cmd & 0x80;SCLK = 1;SDIN = cmd & 0x40;SCLK = 0;SCLK = 1;SDIN = cmd & 0x20;SCLK = 0;SCLK = 1;SDIN = cmd & 0x10;SCLK = 0;SCLK = 1;SDIN = cmd & 0x08;SCLK = 0;SCLK = 1;SDIN = cmd & 0x04;SCLK = 0;SCLK = 1;SDIN = cmd & 0x02;SCLK = 0;SCLK = 1;SDIN = cmd & 0x01;SCLK = 0;SCLK = 1;D_C  = 1;SDIN = 1;SCE  = 1;}void LCD3310_write_dat(unsigned char dat){//    D_C  = 1;SCLK = 0;SCE  = 0;delay(3);SDIN = dat & 0x80;SCLK = 1;SDIN = dat & 0x40;SCLK = 0;SCLK = 1;SDIN = dat & 0x20;SCLK = 0;SCLK = 1;SDIN = dat & 0x10;SCLK = 0;SCLK = 1;SDIN = dat & 0x08;SCLK = 0;SCLK = 1;SDIN = dat & 0x04;SCLK = 0;SCLK = 1;SDIN = dat & 0x02;SCLK = 0;SCLK = 1;SDIN = dat & 0x01;SCLK = 0;SCLK = 1;D_C  = 1;SDIN = 1;SCE  = 1;}void LCD3310_init(void){LCD3310_write_cmd(0x21);LCD3310_write_cmd(0xd7);LCD3310_write_cmd(0x06);LCD3310_write_cmd(0x20);LCD3310_write_cmd(0x0c);}void LCD3310_set_XY(unsigned char x,unsigned char y){if (x >= 84) return;if (y >= 6)  return;LCD3310_write_cmd(0x80 | x);LCD3310_write_cmd(0x40 | y);}void LCD3310_print(unsigned char n){n = (n << 2) + n;LCD3310_write_dat(Font[n]);LCD3310_write_dat(Font[++n]);LCD3310_write_dat(Font[++n]);LCD3310_write_dat(Font[++n]);LCD3310_write_dat(Font[++n]);}

?回復【104樓】maxims
呵呵,希望能解釋一下電路
-----------------------------------------------------------------------

R1、C1 組成LCD的上電復位電路。
R2~R4是上拉電阻,雖然2051的IO有內部的弱上拉,但這三個IO是LCD接口與鍵盤接口復用,需要上拉強一點。
R5、R6、Q1組成OC輸出的反相器,當SCE為高電平時,三極管導通,鍵盤使能,LCD通信中止;當SCE為低電平時,LCD通信使能,鍵盤斷開。需要注意的是圖中左右兩鍵沒加隔離二極管,不要同時按下,否則引起顯示錯亂。
R2~R6的參數不要大幅度改動,這些參數是經過計算得到一個比較合適的值。
晶振、C3、C5沒什么好說,這些都單片機系統必需的。
R7、R8是P1.0和P1.1的上拉電阻,因為這兩個口是開漏輸出。
R9~R24組成R2R型DAC,選取50K/100K是因為2051輸出高電平的帶載能力差,電阻太小將導致DAC線性變差。這里的電阻最好用1%的金屬膜電阻,以改善DAC的線性度。50K電阻是非標電阻,這里用51K和2.7M電阻并聯代替。
C6是高頻濾波電容,以減少DAC輸出的高頻噪聲。
C7是輸出耦合電容,連接LINE OUT輸出端子,輸出阻抗較高,50K,只能接功放機或有源音箱。如果接耳機,需加一級放大,可以用運放做跟隨器,或用TDA2822功放IC,能帶個小嗽叭。

?

回復【105樓】jeep
//由于部分顯示數據在sd卡中,所以sd卡需要存入一個特別的文件//
那個是特別文件還不明白你的意思
-----------------------------------------------------------------------

回復【108樓】wsm80828
很想知道這個
//由于部分顯示數據在sd卡中,所以sd卡需要存入一個特別的文件//??

-----------------------------------------------------------------------

是一個存放歌曲名稱、歌手名稱、歌曲首址和長度的文件,2051只有2K ROM,不可能把整個中文字庫存進ROM內,只能存在SD卡中,以圖片形式存貯,需要時讀入。哪位能用VB或VC做一個轉換工具自動生成一個playlist.dat就方便了。

?

?

U32 GetRootDir(void)
{

? ? ? ? U32 root, fat1, fat2;
? ? ? ? MMCRdBolckOne(0x00,Buffer);? ?? ?// 讀取SD卡中的數據
? ? ? ?
? ? ? ? fat1 = ((Buffer[0x0f]<<8) | Buffer[0x0e]) * 512;
? ? fat2 = ((Buffer[0x25]<<8) | Buffer[0x24]) * 512 + fat1;
? ? ? ? root = ((Buffer[0x25]<<8) | Buffer[0x24]) * 512 + fat2;
? ? ? ?
? ? ? ? return root;
}
這里是使用512的緩存,可以修改成樓主的64緩存,只要讀取出第 0x0e,0x0f, 0x25,0x24地址的數據就可以計算了

用于查找根目錄的函數,那樣就可以查找歌曲了
根目錄 每32個數據表示一個文件,分辨出WAV格式的文件 找到相應的簇地址,然后進行播放

?

?

馬老師你好,對于你所提及的問題,在我轉換過的聲音文件中也有同樣體現。究其原因,主要是8BIT取樣深度不夠,聲音電平在接近零點時,由于隨機噪聲的影響,導致取樣值在0x80,0x79,0x81這間變化,以產生噪聲。我認為這種噪聲一直都存在,只是其它聲音較大時掩蔽了而矣。
? ? 解決方法,可參考類似杜比動態降噪技術,作這樣的處理:檢測當前聲音幅度,如果在持續的一段時間內(比如0.2秒)聲音幅度小于一定值(比如0x80 正負1),那么都過濾為0x80,即可解決此問題。
? ? 我記得有些音頻處理軟件可以進行這種變換,我回去找找。即使沒有,編個小程序轉一下也不難。

?

聽過【149樓】所提供的8BIT聲音樣本,發現其噪聲很大,估計所用的商業軟件在轉換算法上有問題。我用WINDOWS XP附件自帶的錄音機,打開原始16BIT聲音文件,然后另存為44KHz 8BIT,效果也比【149樓】的好得多。

?

回復【151樓】cowboy
聽過【149樓】所提供的8bit聲音樣本,發現其噪聲很大,估計所用的商業軟件在轉換算法上有問題。我用windows xp附件自帶的錄音機,打開原始16bit聲音文件,然后另存為44khz 8bit,效果也比【149樓】的好得多。
-----------------------------------------------------------------------

謝謝!

我使用過幾個商業軟件,如上圖中的AUDITION、天天靜聽等,都是如此。自己寫了一個轉換程序,就是直接簡單的采用除256的方法,直接把16位降成8位,這樣處理后,靜音部分可以完全轉換為靜音,而且總的噪聲比這些商業軟件小了許多(-3db左右),但是還有,還是可以比較清晰的聽到,尤其是當調節音量輸出比較大的時候。

我會試一下WINDOWNS的附件,聽聽效果。

現在手頭的項目,需要語音提示。考慮到存儲容量,使用8K、8位的WAV數據,應該可以達到電話的語音質量,對于一般應用夠了。其它都可以,成本也不高,就是轉換數據本聲的噪聲。想找一種簡單的處理辦法。

后面我還會繼續提供一些我使用過的處理辦法。

另外是否其它的朋友有這方面的經驗,軟件或算法,只要提供一個思路就可以了,先表示感謝。

?

/**********************************************************************************************/

點擊此處下載 ourdev_611680M0SOZB.rar(文件大小:2.32M) (原文件名:goldwave v5.23 漢化版.rar)
用這個轉換成8Bit單聲道PCM文件,效果很好。16Bit轉8Bit不會改變采樣頻率,故需先轉成32KHz的其它格式再轉成PCM

?

回復【154樓】machao
回復【151樓】cowboy??
聽過【149樓】所提供的8bit聲音樣本,發現其噪聲很大,估計所用的商業軟件在轉換算法上有問題。我用windows xp附件自帶的錄音機,打開原始16bit聲音文件,然后另存為44khz 8bit,效果也比【149樓】的好得多。
-----------------------------------------------------------------------
謝謝!
我使用過幾個商業軟件,如上圖中的audition、天天靜聽等,都是如此。自己寫了一個轉換程序,就是直接簡單的采用除256的方法,直接把16位降成8位,這樣處理后,靜音部分可以完全轉換為靜音,而且總的噪聲比這些商業軟件小了許多(-3db左右),但是還有,還是可以比較清晰的聽到,尤其是當調節音量輸出比較大的時候。
我會試一下windowns的附件,聽聽效果。
現在手頭的項目,......
-----------------------------------------------------------------------

馬老師我提個建議吧。我做過類似的項目,是用PWM直接接一功放驅動喇叭。沒有加低通濾波,當使用20K以下的采樣頻率WAV文件時有嘯聲,使用20K以上時人就聽不到了。這里應該是由PWM的高低電平跳動引起的,使用DA應該沒有類似問題。
所以我就沒有采用8K的采樣,而是使用24K采樣,8:2的ADPCM編碼方式。對比下文件大小:8KHz 8Bit的PCM格式64Kbps, 24KHz 8Bit ADPCM為 24*8/4 = 48Kbps,只有8K的3/4大小。而音質上壓縮的肯定比降低采樣頻率更好一些。
這里也有一個小問題,我使用這個軟件編8:4 ADPCM再解碼時有很大噪音,這里是因為其碼表可能與我用的不同。網上8bit的ADPCM基本上沒有,我是將16位的改成8位的,所以碼表是可能不同。我的解決辦法是自己編碼再自己解碼,8:2也能達到較好的效果,聽歌尚可,語音更不用說,用DA的話效果肯定更好,而加濾波的話有些音色會變。

?

播放BUF和讀取BUF我是分開的,開辟了兩個數據區A,B,這樣就不用讀一個播放一個。播放完BUF_A再播放BUF_B,同時BUF_A從FLASH中讀取相應數據,依此循環。

?

回復【159樓】amazing030

謝謝您了,我會用你建議的goldwave v5.23.rar試一下的。

壓縮編碼的方式我知道,做過圖象的壓縮,JPEG,H26x等。在這個項目上,不想使用這么復雜的東西。我設計是提供一個DS卡,和規定的文件名,然后給的PC程序給用戶。用戶自己需要什么語音自己在PC上做,然后轉換成8位的,考入SD卡就可以了。

另外,系統使用8位MCU,時鐘也就10M左右,還要做其它的事情,ADPCM解碼,還是不做的好。

另外,你的解釋是不對的。我提供的兩個文件與系統播放無關,就是在PC上轉換,然后在PC上播放,采樣率為44.1k。僅用PC轉換,在PC播放,沙沙的噪聲非常明顯。與什么PWM沒有關系。

?

解決數字音頻信號傳輸中劣化方式(http://www.av010.com/jswz_html/jswz2280_1.html)

專業的解釋,看來解決比較困難了。

/**********************************************************************************************/

回復【80樓】cowboy
-----------------------------------------------------------------------
小弟不才,
請問樓主
void timer0 (void) interrupt 1 using 1
{
? ? if (TL0 & 1) _nop_(); //消除中斷響應時間不一致,造成的頻率抖動
? ? P1??= pbuf[++p & 63]; //輸出一個聲音數據
}

這其中的" & 63"的作用是什么呢?

?

回復【167樓】hongfadg
-----------------------------------------------------------------------

p & 63 是取8位“p”中的低6位,舍棄高2位,由于緩沖區只有64字節,“++p & 63”正好循環指向pbuf[0]至pbuf[63]。

?

/**********************************************************************************************/

播放器升級預告,增加FAT32文件系統,也就是可以隨意增減音樂文件,不必按連續的儲存空間存放文件,允許有文件碎片,同時也不再需要在SD卡內存放一個經特殊制作系統文件。
硬件沒改變,只是軟件升級,雖然增加了FAT32部分代碼,但總代碼量仍在2K以內,89C2051能裝得下。
測試基本通過,整理好后再上傳。

上傳升級版的整套工程文件,以及SD內的示范文件。

點擊此處下載 ourdev_615881TB11F5.rar(文件大小:429K) (原文件名:SD_player.rar)

由于水平有限,程序可能還有很多不完善的地方,希望大家多提意見。特別是SD卡驅動和FAT32文件系統,本人理解并不深入,程序對各種SD卡的兼容性未作詳細測試,有可能出現某些SD卡不能播放的情況。對SD卡的基本要求是 文件系統為FAT32格式,暫不支持FAT16;SDHC高速卡也不支持。

/**********************************************************************************************/

轉載于:https://www.cnblogs.com/LittleTiger/p/3976672.html

總結

以上是生活随笔為你收集整理的单片AT89C2051 + SD卡 + 3310LCD = 音乐播放器的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。