|
|
发表于 2026-9-4 21:04:07
|
显示全部楼层
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;
}
|
|