STC32G12K128, PWM-DAC频率问题?时钟源如何设置
PWM作为载波输出音频信号。目前8位PWM。主频24M .载波频率40Khz.通过二阶阻容滤波效果不好。莎莎声明显。将主频调高到25M9位PWM 。此时载波频率大概34K .偏低。但是听感明显比8位PWM好
现在想做10位PWM 。但是主频不能在高。PWM时钟源如何设置?
现在的想法是系统工作主频24M .经过2分频=12M 然后*8 =96M 作为PWM的高级时钟源。通过P34端口输出。这样可以输出11位PWM。载波频率大概在48K左右。
下载下面帖子的例程包,解压缩,参考两个程序:
01B-HSPWMA-4对互补PWM输出P2口
02B-HSPWMB-4个单端PWM输出P2口
HSPWM的时钟是144MHz,40KHz的PWM频率,可以得到幅度为3600的PWM,音质会很好。
STC32G-高级PWM范例程序下载
https://www.stcaimcu.com/thread-1778-1-1.html
(出处: 国芯人工智能技术交流网站)
梁工 发表于 2026-5-11 22:11
下载下面帖子的例程包,解压缩,参考两个程序:
01B-HSPWMA-4对互补PWM输出P2口
02B-HSPWMB-4个单端PWM输出 ...
谢谢梁工:已经设置成功。还有一个问题想请教一下。我测试通过CAN发送8点正弦波。非常稳定正常。但是传输实际音频的时候失真很严重,我的音频采集是通过DMA 。转换两次。然后经过A_LOW编码发送。语音采样率8K,每32毫秒采集256字节。通过编码输出128字节。(标准帧32帧)采集和解码都是双缓冲。采集A 发送B 。采集满256字节发送标志==1.在主循环发送32帧。(实际测试接收时间不丢包需要12.5毫秒)。DMA在定时器中断125us触发一次。困惑很久没找到原因。现在真实音频是信号源产生1K正弦波。收到失真抖动。unsigned char ALAW_Encode(int pcm)
{
unsigned char sign, comp, seg;
unsigned int temp;
if (pcm >= 0)
{
sign = 0;
temp = pcm;
}
else
{
sign = 0x80;
temp = -pcm;
}
if (temp > 32635) temp = 32635;
temp += 33;
if (temp >= 16384) seg = 7;
else if (temp >= 8192)seg = 6;
else if (temp >= 4096)seg = 5;
else if (temp >= 2048)seg = 4;
else if (temp >= 1024)seg = 3;
else if (temp >= 512) seg = 2;
else if (temp >= 256) seg = 1;
else seg = 0;
comp = (seg << 4) | ((temp >> (seg + 3)) & 0x0F);
comp ^= 0x55;
return sign | comp;
}
// A-LAW解码实现
int ALAW_Decode(unsigned char alaw)
{
unsigned char sign, seg;
unsigned int temp;
alaw ^= 0x55;
sign = alaw & 0x80;
alaw &= 0x7F;
seg = (alaw >> 4) & 0x07;
temp = (0x80 | (alaw & 0x0F)) << (seg + 3);
temp -= 33;
if (seg != 0)
temp += 4 << seg;
if (sign) return -(int)temp;
else return (int)temp;
}
// A-LAW块编码:256个PCM样本→256字节A-LAW数据
void alaw_encode_block(int *in, unsigned char *out, unsigned int n)
{
unsigned int i;
int sample16;
for (i = 0; i < n; i++)
{
// 原PCM是12bit(-2048~2047),扩展到16bit适配A-LAW
sample16 = in<< 4;
out = ALAW_Encode(sample16);
}
}
// A-LAW块解码:256字节A-LAW→256个PCM样本
void alaw_decode_block(unsigned char *in, int *out, unsigned int n)
{
unsigned int i;
int pcm16;
for (i = 0; i < n; i++)
{
pcm16 = ALAW_Decode(in);
// 还原为12bit PCM
out = pcm16 >> 2;
}
}
void prepare_pwm_buf(int *pcm, unsigned int *pwm, unsigned int n)
{
unsigned int i;
long val;
// unsigned long temp;
for (i = 0; i < n; i++)
{
val = (long)pcm + 2048;
if (val < 10)val = 10;
if (val > 4085) val = 4085;
// temp = (unsigned long)(val - 10) * 255;
// pwm = (unsigned char)(temp / (4085 - 10));
pwm = (val - 10) * 511 / 4075;
}
}
void Timer0_ISR(void) interrupt 1
{
// 输出当前采样点的PWM占空比
PWM_SetDuty(rx_pwm);
// 播放指针+1
play_pos++;
// 播放完一帧256点,回到0重新开始
if(play_pos >= PCM_SAMPLE_NUM)
{
play_pos=0;
silence_cnt++;// 静音计数+1
// 连续多帧没收到新数据 → 填充静音,防止噪音
if(silence_cnt>3)
{
fill_silence(rx_pwm, PCM_SAMPLE_NUM);
silence_cnt=0;
}
}
}不知道哪里的问题? zhang32568 发表于 2026-5-12 15:30
谢谢梁工:已经设置成功。还有一个问题想请教一下。我测试通过CAN发送8点正弦波。非常稳定正常。但是传输 ...
还没空详细看代码。
“语音采样率8K,每32毫秒采集256字节。通过编码输出128字节。”这个是错误的,应该是“语音采样率8K,每32毫秒采集256点512字节,通过A-LAW编码输出256点256字节数据。” 梁工 发表于 2026-5-12 16:20
还没空详细看代码。
“语音采样率8K,每32毫秒采集256字节。通过编码输出128字节。”这个是错误的,应 ...
啊 。256点。每个点12位需要两个字节512字节。我前面说错了。压缩后256字节。发送32帧。每帧8字节。32*8 = 256 没有错 zhang32568 发表于 2026-5-12 18:03
啊 。256点。每个点12位需要两个字节512字节。我前面说错了。压缩后256字节。发送32帧。每帧8字节。32* ...
A-LAW是一种折叠码,要处理正确哦,8K采样声音也很好的。
页:
[1]