You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

LPCXpresso1549生成35-45kHz chirp信号频率异常问题咨询

问题分析与修复方案

你的猜测完全正确——主循环里用轮询Timer的方式控制采样输出,确实会导致实际采样率远低于预期的96000Hz,这就是为什么chirp的低频端被拉到3200Hz的核心原因。下面具体说说问题出在哪,以及怎么修复:

为什么当前代码的采样率不准?

你现在的代码是在主循环里不断检查Timer的时间,等达到10µs左右就输出一个样本。这种方式有两个致命缺陷:

  • 轮询的延迟不可控:主循环里的浮点数比较(t.read() >= 0.00001)、Timer的读取操作,甚至MCU后台的系统调度,都会让每次输出样本的间隔远大于10µs。比如浮点数运算本身就比整数慢,加上循环里的其他判断,实际间隔可能变成几十甚至上百微秒,直接把采样率拉低到几千Hz,自然就把chirp的低频段拖垮了。
  • Timer的精度不够:mbed的通用Timer类如果用的是软件模拟或者低精度硬件计时,本身就没法精准捕捉10µs这么小的时间窗口,误差会被不断放大。

正确的实现方式:用硬件定时器触发

要实现96000Hz这种高精度的采样率,必须靠硬件级别的同步触发,不能让CPU在主循环里瞎忙活。推荐两种靠谱的方案:

方案1:用Ticker定时器中断输出样本

mbed的Ticker是基于硬件定时器的高精度计时工具,能精准触发定时中断。我们可以让它每隔1/96000s触发一次中断,在中断里输出下一个样本,这样就能保证严格的时间间隔。

代码示例:

#include "mbed.h"
#include "chirp.h"

AnalogOut aout(P0_12);
Ticker sample_ticker;
volatile int sample_idx = 0;

void output_next_sample() {
    // 输出当前样本,然后更新索引(循环播放)
    aout.write_u16(chirpData[sample_idx]);
    sample_idx = (sample_idx + 1) % NUM_SAMPLES;
}

int main() {
    // 设置触发间隔:1/96000 秒,确保精度用浮点数计算
    sample_ticker.attach(&output_next_sample, 1.0f / 96000.0f);
    
    // 主循环可以闲置或者做其他任务,不需要管采样输出
    while (true) {
        ThisThread::sleep_for(100ms);
    }
}

方案2:DMA+定时器触发(零CPU开销,精度最高)

如果想追求极致的精度和效率,可以用DMA直接把你的chirpData数组传输到DAC,完全不需要CPU干预。LPC1549支持这个功能,配置步骤大概是:

  1. 把定时器配置成96000Hz的触发频率
  2. 开启DAC的DMA请求,关联到定时器的触发信号
  3. 设置DMA的数据源为chirpData数组,目标为DAC的数据寄存器
  4. 启动DMA和定时器,数据就会自动源源不断地输出到DAC

这种方式完全避免了CPU中断的开销,采样率的精度只由硬件定时器决定,是最理想的方案。

验证方法

修复后可以用示波器或者频率计验证:

  • 先输出一个固定的交替值(比如0和4095),测量信号周期是否接近1/96000 ≈ 10.4µs,确认采样率正确
  • 再播放chirp信号,测量频率范围是否回到35000Hz到45000Hz的预期区间

内容的提问来源于stack exchange,提问作者Thang Dinh

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.21 03:58:34