找回密码
 立即注册
楼主: health

MP3解码播放流畅@Ai8051U核心板-擎天柱,8051U移植minimp3解码库

[复制链接]

20

主题

238

回帖

1990

积分

金牌会员

积分
1990
发表于 2026-6-20 16:12:52 | 显示全部楼层
hea*** 发表于 2026-6-13 12:30
下载程序使用STC-ISP常规操作,选择hex文件,设置时钟40MHz。

没有找到HEX文件
回复

使用道具 举报 送花

20

主题

238

回帖

1990

积分

金牌会员

积分
1990
发表于 2026-6-20 16:34:28 | 显示全部楼层
如何实现播放一首完整的音乐?
回复

使用道具 举报 送花

25

主题

245

回帖

2717

积分

金牌会员

积分
2717
 楼主| 发表于 2026-6-20 19:34:27 | 显示全部楼层
lcl*** 发表于 2026-6-20 16:12
没有找到HEX文件

源码编译一下就有hex了,主要是因为mp3数据放在c源码中了,可以根据需用嵌入自己的mp3文件,编译生成hex。
回复

使用道具 举报 送花

25

主题

245

回帖

2717

积分

金牌会员

积分
2717
 楼主| 发表于 2026-6-20 19:36:53 | 显示全部楼层
lcl*** 发表于 2026-6-20 16:34
如何实现播放一首完整的音乐?

完整mp3音乐需要外扩spi flash或TF卡了。本程序是用的内部flash,只有64KB空间,程序占用一部分,大约只剩30KB用于保存音频文件。
回复

使用道具 举报 送花

20

主题

238

回帖

1990

积分

金牌会员

积分
1990
发表于 2026-6-21 07:51:22 | 显示全部楼层
hea*** 发表于 2026-6-20 19:36
完整mp3音乐需要外扩spi flash或TF卡了。本程序是用的内部flash,只有64KB空间,程序占用一部分,大约只 ...

谢谢
回复

使用道具 举报 送花

20

主题

238

回帖

1990

积分

金牌会员

积分
1990
发表于 2026-6-21 07:52:24 | 显示全部楼层
hea*** 发表于 2026-6-20 19:34
源码编译一下就有hex了,主要是因为mp3数据放在c源码中了,可以根据需用嵌入自己的mp3文件,编译生成hex ...

如何把MP3文件数据转成C源码?
回复

使用道具 举报 送花

25

主题

245

回帖

2717

积分

金牌会员

积分
2717
 楼主| 发表于 2026-6-21 13:59:57 | 显示全部楼层
lcl*** 发表于 2026-6-21 07:52
如何把MP3文件数据转成C源码?

bin转C数组。
可以找个专用的小工具程序,例如segger的Bin2C.exe。
或者通用的二进制编辑软件,例如winhex,打开bin文件,复制为C数组格式。
----------------------------------------------------------------------------------------------
先用任意音频编辑软件,截取mp3一段,转换为指定码率和采样率,保存为新的mp3文件。
然后将此mp3文件作为bin转换为C数组格式。
音频编辑软件例如格式工厂,cooledit,命令行可以用ffmpeg。
回复

使用道具 举报 送花

已绑定手机

0

主题

1

回帖

6

积分

新手上路

积分
6
发表于 2026-8-4 22:54:36 | 显示全部楼层
命主函数文件在编译的时候,180行和183行的括号会报错
回复

使用道具 举报 送花

54

主题

397

回帖

860

积分

高级会员

积分
860
发表于 2026-9-4 21:04:07 | 显示全部楼层
erci*** 发表于 2025-12-24 09:08
MP3播放器,I2S-DAC 版本:

void play(){
        pcm_run_flag = 0;
        while (1)
        {
                        nbuf = 0;
                        mp3dec_init(&mp3d);               
       
                        do
                        {
                                count = mp3dec_decode_frame(&mp3d, song + nbuf, sizeof(song) - nbuf, (mp3d_sample_t *)upcm0, &info);
                                nbuf += info.frame_bytes;
                                while(pcm_run_flag);
                                send_pcm_data(upcm0, count);
                               
                                if(nbuf >= (sizeof(song)-273)) nbuf = 0;                       
                                count = mp3dec_decode_frame(&mp3d, song + nbuf, sizeof(song) - nbuf, (mp3d_sample_t *)upcm1, &info);
                                nbuf += info.frame_bytes;
                                while(pcm_run_flag);
                                send_pcm_data(upcm1, count);                       
                               
                                if(nbuf >= (sizeof(song)-273)) nbuf = 0;
                        } while (info.frame_bytes);
        }
}

void send_pcm_data(u16* buffer,u16 len){
    i2s_buffer_index = 0;
    i2s_buffer = buffer;
       
    i2s_buffer_len = len;
    pcm_run_flag = 1;

};   


大佬,这个例程里 解码出来的应该就是pcm了,对吧。那如何转成占空比呢?难道这个可以直接当占空比写给 pwm的寄存器?  还是说要转换一下? 我问ai,它说是     duty = pcm * (FOSC/SAMPLE_RATE - 1) / 65535);  是这样的吗?


我之前看梁工有个例程里 有一段代码是这样写的 ,不过梁工的例程数据来源是pc发的。这个例子是梁工焊接的板子,我没试过,不知道是不是。


void WritePWMA(u8 addr, u8 dat)
{
    while (HSPWMA_ADR & 0x80); //等待前一个异步读写完成
    HSPWMA_DAT = dat;          //准备需要写入的数据
    HSPWMA_ADR = addr & 0x7f;  //设置间接访问地址,只需要设置原XFR地址的低7位
    //HSPWMA_ADDR寄存器的最高位写0,表示写数据
}

void timer0_ISR (void) interrupt TMR0_VECTOR
{
    P27 = 1;    //解码时间指示
    if(B_PlayEn) {  //正在播放
        if(ByteCnt >= ByteLength) { //播放完成了
            B_PlayEn = 0;
            P20 = 1;
        } else if(rd_index != wr_index) {   //数据流未溢出
            WritePWMA((u8)&PWMA_CCR_LEFT_H, (u8)(left_pwm/256));        // 比较值, 控制占空比(高电平时钟数)
            WritePWMA((u8)&PWMA_CCR_LEFT_L, (u8)(left_pwm%256));
            WritePWMA((u8)&PWMA_CCR_RIGHT_H, (u8)(right_pwm/256));  // 比较值, 控制占空比(高电平时钟数)
            WritePWMA((u8)&PWMA_CCR_RIGHT_L, (u8)(right_pwm%256));

            WritePWMA((u8)&PWMA_CCR2H, (u8)(left_pwm >> 8));
            WritePWMA((u8)&PWMA_CCR2L, (u8)(left_pwm & 0xFF));

            if(MusicType == 1) {    //PCM,  WAV类型, fmttag=0x01-->PCM, 0x02-->Windows ADPCM, 0x06-->A Law, 0x07-->Mu Law, 0x11-->IMA ADPCM
                if(MusicChannel == 1) { //单声道   5.5us
                    left_pwm = (u16)voice_buff[rd_index] + ((u16)voice_buff[rd_index+1]<<8);    //左声道
                    rd_index += 2;
                    rd_index &= 0x0fff;
                    ByteCnt += 2;       //每个采样2个字节
                    left_pwm += 32768;  //有符号转位无符号
                    left_pwm /= 16;     //转位12位PWM值
                    right_pwm = left_pwm;   //单声道
                } else {    //双声道   6.5us
                    left_pwm = (u16)voice_buff[rd_index] + ((u16)voice_buff[rd_index+1]<<8);    //左声道
                    rd_index += 2;
                    right_pwm = (u16)voice_buff[rd_index] + ((u16)voice_buff[rd_index+1]<<8);   //左声道
                    rd_index += 2;
                    rd_index &= 0x0fff;
                    ByteCnt += 4;       //每个采样4个字节
                    left_pwm += 32768;  //有符号转位无符号
                    left_pwm /= 16;     //转位12位PWM值
                    right_pwm += 32768; //有符号转位无符号
                    right_pwm /= 16;    //转位12位PWM值
                }
            }

            else if(MusicType == 17) {  //ADPCM,  WAV类型, fmttag=0x01-->PCM, 0x02-->Windows ADPCM, 0x06-->A Law, 0x07-->Mu Law, 0x11-->IMA ADPCM
                if(MusicChannel == 1) { //单声道   平均9us
                    if((rd_index & MusicBlock) == 0) {  //BLOCK开始, 256或512字节一个BLOAK
                        dac_L = (u16)voice_buff[rd_index] + ((u16)voice_buff[rd_index+1] << 8); // 未压缩的采样值
                        rd_index += 2;
                        index_L = voice_buff[rd_index++];   //index值
                        rd_index++;         //空字节
                        ByteCnt += 4;   //4个字节
                        B_high_nibble = 0;
                        dac_L += 32768;     //转成线性
                        cur_sample_L = dac_L;
                        cur_sample_L -= 32768;  //转回有符号
                    } else {
                        decode = voice_buff[rd_index];  //从缓冲读数据字节
                        if(B_high_nibble) { //处理高半字节
                            ByteCnt++;
                            decode >>= 4;
                            rd_index++;     //指向下一个数据
                            rd_index &= 0x0fff;
                        }
                        decode &= 0x0f;
                        delta = ((u32)step_table[index_L] * ((decode & 0x07)*2 +1)) / 8;    // 计算delta
                        if(decode & 8 )     delta = -delta; //负的delta
                        cur_sample_L += delta;  //计算出当前的波形数据
                        if(cur_sample_L >= 32768)   dac_L = 65535;
                        else if(cur_sample_L < -32768)  dac_L = 0;
                        else                            dac_L = (u16)(cur_sample_L + 32768);

                        index_L += index_adjust[decode];
                        if (index_L < 0)    index_L = 0;
                        else if (index_L > 88)  index_L = 88;

                        B_high_nibble = ~B_high_nibble;
                    }
                    dac_R = dac_L;      //单声道
                } else {    //双声道   平均13us, 峰值15us
                    if((rd_index & MusicBlock) == 0) {  //BLOCK开始, 512或1024字节一个BLOAK
                        dac_L = (u16)voice_buff[rd_index] + ((u16)voice_buff[rd_index+1] << 8); // 未压缩的采样值
                        rd_index += 2;
                        index_L = voice_buff[rd_index]; //index值
                        rd_index += 2;

                        dac_R = (u16)voice_buff[rd_index] + ((u16)voice_buff[rd_index+1] << 8); // 未压缩的采样值
                        rd_index += 2;
                        index_R = voice_buff[rd_index]; //index值
                        rd_index += 2;

                        ByteCnt += 8;   //8个字节
                        B_high_nibble = 0;
                        dac_L += 32768;     //转成线性
                        cur_sample_L = dac_L;
                        cur_sample_L -= 32768;  //转回有符号
                        dac_R += 32768;     //转成线性
                        cur_sample_R = dac_R;
                        cur_sample_R -= 32768;  //转回有符号
                    } else {
                        if((rd_index & 0x0007) == 0) {  //2个DWORD 8个字节
                            ADPCM_Data_L[0] = voice_buff[rd_index++];   //不用循坏,时间尽量短
                            ADPCM_Data_L[1] = voice_buff[rd_index++];
                            ADPCM_Data_L[2] = voice_buff[rd_index++];
                            ADPCM_Data_L[3] = voice_buff[rd_index++];
                            ADPCM_Data_R[0] = voice_buff[rd_index++];   //不用循坏,时间尽量短
                            ADPCM_Data_R[1] = voice_buff[rd_index++];
                            ADPCM_Data_R[2] = voice_buff[rd_index++];
                            ADPCM_Data_R[3] = voice_buff[rd_index];
                            B_high_nibble = 0;
                            DecodeCnt = 0;
                        }

                        //================ 左声道解压缩 ============================
                        decode = ADPCM_Data_L[DecodeCnt];   //从缓冲读数据字节
                        if(B_high_nibble)   decode >>= 4;   //处理高半字节
                        decode &= 0x0f;

                        delta = ((u32)step_table[index_L] * ((decode & 0x07)*2 +1)) / 8;    // 计算delta
                        if(decode & 8 )     delta = -delta; //负的delta
                        cur_sample_L += delta;  //计算出当前的波形数据
                        if(cur_sample_L >= 32768)   dac_L = 65535;
                        else if(cur_sample_L < -32768)  dac_L = 0;
                        else                            dac_L = (u16)(cur_sample_L + 32768);

                        index_L += index_adjust[decode];
                        if (index_L < 0)    index_L = 0;
                        else if (index_L > 88)  index_L = 88;
                        //======================== 左声道解压缩完毕 ==================================

                        //======================== 右声道解压缩 ============================
                        decode = ADPCM_Data_R[DecodeCnt];   //从缓冲读数据字节
                        if(B_high_nibble) {     //处理高半字节
                            if(DecodeCnt >= 3) {    //4个字节都处理完成
                                ByteCnt += 8;   //4个字节
                                rd_index++;     //指向下一个数据
                                rd_index &= 0x0fff;
                            }
                            DecodeCnt++;
                            decode >>= 4;
                        }
                        decode &= 0x0f;

                        delta = ((u32)step_table[index_R] * ((decode & 0x07)*2 +1)) / 8;    // 计算delta
                        if(decode & 8 )     delta = -delta; //负的delta
                        cur_sample_R += delta;  //计算出当前的波形数据
                        if(cur_sample_R >= 32768)   dac_R = 65535;
                        else if(cur_sample_R < -32768)  dac_R = 0;
                        else                            dac_R = (u16)(cur_sample_R + 32768);

                        index_R += index_adjust[decode];
                        if (index_R < 0)    index_R = 0;
                        else if (index_R > 88)  index_R = 88;
                        //======================== 右声道解压缩完毕 ==================================

                        B_high_nibble = ~B_high_nibble; //高半字节指示
                    }
                }
                left_pwm  = dac_L/16;   //转位12位PWM值
                right_pwm = dac_R/16;   //转位12位PWM值
            }

            else if(MusicType == 6) {   //A-law, WAV类型, fmttag=0x01-->PCM, 0x02-->Windows ADPCM, 0x06-->A Law, 0x07-->Mu Law, 0x11-->IMA ADPCM
                if(MusicChannel == 1) { //单声道   5.5us
                    law_data = voice_buff[rd_index++] ^ 0x55;       //Get Complement 偶数位取反, 从缓冲读数据字节,偶数位取反,循环队列,指向下一个数据
                    left_pwm = T_Alaw_decode[law_data & 0x7f];      // 解压缩码
                    if(law_data & 0x80) left_pwm = 2048 - left_pwm; //如果是负的
                    else                left_pwm = 2048 + left_pwm; //如果是正的
                    right_pwm = left_pwm;   //单声道
                    rd_index &= 0x0fff;
                    ByteCnt++;      //一个采样1个字节
                } else {    //双声道   6.5us
                    law_data = voice_buff[rd_index++] ^ 0x55;       //Get Complement 偶数位取反, 从缓冲读数据字节,偶数位取反,循环队列,指向下一个数据
                    left_pwm = T_Alaw_decode[law_data & 0x7f];      // 解压缩码
                    if(law_data & 0x80) left_pwm = 2048 - left_pwm; //如果是负的
                    else                left_pwm = 2048 + left_pwm; //如果是正的
                    law_data = voice_buff[rd_index++] ^ 0x55;       //Get Complement 偶数位取反, 从缓冲读数据字节,偶数位取反,循环队列,指向下一个数据
                    right_pwm = T_Alaw_decode[law_data & 0x7f];     // 解压缩码
                    if(law_data & 0x80) right_pwm = 2048 - right_pwm;   //如果是负的
                    else                right_pwm = 2048 + right_pwm;   //如果是正的

                    rd_index &= 0x0fff;
                    ByteCnt += 2;   //一个采样2个字节
                }
            }
        }
    }

    if(TX1_Limit != 0) {
        if(--TX1_Limit == 0)    RxNum = 0;  //超时无数据,重新请求发送
    }
    P27 = 0;
}
回复

使用道具 举报 送花

54

主题

397

回帖

860

积分

高级会员

积分
860
发表于 2026-9-4 21:29:02 | 显示全部楼层
xie2*** 发表于 2026-9-4 21:04
void play(){
        pcm_run_flag = 0;
        while (1)

知道了,这个其实就是占空比。
回复

使用道具 举报 送花

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|手机版|深圳国芯人工智能有限公司 ( 粤ICP备2022108929号-2 )

GMT+8, 2026-9-22 06:04 , Processed in 0.074098 second(s), 88 queries .

Powered by Discuz! X3.5

© 2001-2026 Discuz! Team.

快速回复 返回顶部 返回列表