STM32+AD9850 DDS信号源:频率字、时序与扫频实现

发布时间:2026/11/5 2:27:36

STM32+AD9850 DDS信号源:频率字、时序与扫频实现 简介面向嵌入式初学者、电子设计竞赛选手与高校实验教学场景的STM32波形发生器工程包以正点原子精英板为硬件平台通过单片机驱动AD9850直接数字频率合成芯片输出正弦波、方波、三角波等常见信号可用于信号处理实验、通信系统演示和课程设计验证。压缩包共200个文件约5.34MB以C源文件、头文件、工程配置和编译中间文件为主并包含可打开的工程文件、可执行文件与映射文件便于直接编译、烧录和测试。目前已有3403人学习下载说明该方案在波形发生与频率合成入门实践中具有一定参考价值。读者可据此梳理端口配置、定时器、串行通信及频率控制字的设置关系理解从底层驱动到波形输出的完整实现路径并借助工程结构排查编译、下载与波形调试中的常见问题适合作为课程设计、毕业设计或自学练手的可运行参考。1. 一块 F103 精英板加一片 AD9850能做出什么信号源上个月调一个有源滤波器需要一路干净的正弦做激励实验室的信号发生器被人占着我翻出来抽屉里那块吃灰的 STM32 精英板和一片 AD9850 DDS 模块一个下午搭出了一台能顶用的简易信号源。这套组合的价值就在这里STM32 负责算频率字、发时序、接按键和屏AD9850 负责把数字量变成模拟波形0.029 Hz 的频率分辨率、0~40 MHz 的正弦和方波输出成本不到一台入门信号发生器的零头。适合三类人要做扫频仪、阻抗测量激励源、滤波器和放大器测试的想练手 DDS 原理和并口时序的手上正好有 F103 精英板、想找个能跑通又不太简单的练手项目的。下面从硬件账本一路拆到能改的代码。2. 硬件底子AD9850 的 40 位寄存器与精英板的引脚账很多人拿到模块第一反应是找现成库拷进去发现没波形然后就开始怀疑模块坏了。问题基本都不在芯片上而在于没有把「40 位寄存器」这件事想明白。AD9850 的整个对外接口本质就是一个 40 位移位寄存器加一个锁存信号把这两件事搞清楚剩下的都是 GPIO 电平翻转。2.1 芯片内部32 位相位累加器到底在累加什么AD9850 内部是一个 32 位相位累加器每个时钟周期加上一个步进值频率字 FTW累加器的高位去查一张正弦表查出来的值送 10 位 DAC 转成模拟电流。输出频率和频率字的关系只有一行公式f_out FTW × f_clk / 2^32反过来写就是我们要用的FTW f_out × 2^32 / f_clk。板载有源晶振一般是 125 MHz那么2^32 / 125e6 34.359738368也就是每 1 Hz 对应 34.36 个频率字。这个常数是整份驱动的核心抄错一位输出频率就会差出好几倍而且因为低频段误差绝对值小你测 1 kHz 时还挺准一上到 10 MHz 立刻现原形。把公式反过来看频率分辨率是125e6 / 2^32 ≈ 0.0291 Hz。这个数字很反直觉一颗十几块钱的模块频率步进能做到 0.03 Hz 级别比很多台式机的 1 Hz 步进还细。原因是相位累加器只在数字域做加法输出频率的精度完全由晶振精度和频率字的位数决定跟 DAC 的位数无关。它的代价是频谱纯度DAC 只有 10 位再加上相位截断误差输出频谱里会有一堆杂散要求高的场合还是得靠专用信号源。那 40 位里剩下的 8 位是什么32 位频率字 5 位相位偏移 1 位掉电控制 2 位控制位。相位偏移的单位是360/32 11.25°做两路正交信号或者相位调制的时候用得上掉电位拉起来之后芯片进低功耗输出静默。日常用正弦做激励相位那几位写 0 就够了。2.2 模块引脚与精英板资源对账市面上常见的 AD9850 模块是两排 2.54 排针一排六个是控制口VCC、GND、W_CLK、FQ_UD、DATA、RESET另一排八个是并口数据 D0~D7模块上还引出两路正弦和两路方波方波是片内比较器整出来的旁边有个电位器调阈值。串行模式只接前六个引脚就够并口模式才需要 D0~D7。精英板是 F103ZET672 MHz 主频GPIO 管够我一般这样分模块引脚精英板引脚模式说明W_CLKPB5推挽输出上升沿移入 1 bit最高 40 次翻转完成一次写入FQ_UDPB6推挽输出上升沿把 40 位移位寄存器锁进工作寄存器DATAPB7推挽输出串行数据低位先出RESETPB8推挽输出复位内部字指针D0~D7PB0~PB7推挽输出可选并口模式一次写 8 位速度是串行的 8 倍VCC3.3V电源见 2.3别顺手接 5V之所以让 W_CLK、FQ_UD、DATA、RESET 都挤在 GPIOB 上是为了并口模式下能直接操作GPIOB-ODR一次性把 8 位数据甩出去省掉 8 次位操作。串行和并口共用一个端口改模式只要改一行宏定义。2.3 供电、地与输出端的物理边界第一个坑是电平。模块标称 3.3~5 V 供电很多教程图省事接 5 V然后 3.3 V 的 STM32 输出高电平只有 3.3 V而 5 V 供电时芯片的数字输入高电平门限是0.7 × VDD 3.5 V正好卡在门限下面表现就是「有时候能写进去有时候写不进去」换个杜邦线又好了非常玄学。稳妥做法是模块直接用 3.3 V 供电芯片本身支持 3.3 V 工作输出幅度会略降一点但时序绝对可靠。真要 5 V 供电就得在 DATA、W_CLK、FQ_UD 上加电平转换或者至少加 4.7 kΩ 上拉到 5 V。第二个边界是输出幅度。AD9850 是电流型 DAC满量程 20 mA 左右模块上并了一只 100 Ω 电阻转成电压所以空载拿示波器量出来大概 1 Vpp这是正常的不是模块坏了。想要更大的摆幅得后级加运放我一般用一颗 NE5532 搭个同相放大增益 5 倍带宽够 10 MHz 以内的应用。第三个边界是地。DDS 输出的是几十毫伏级别的小信号叠加在直流偏置上如果模块的地和 STM32 的地只靠一根细杜邦线连着W_CLK 的翻转电流会在地线上产生尖峰示波器上看就是正弦上长毛刺。解决办法很土但有效模块和板子之间多接一根地线模块 VCC-GND 之间并一只 0.1 μF。高频的东西接地永远比代码重要。3. 工程骨架从 CubeMX 时钟树到 ad9850.c 的分层拿到这种「一块板 一个模块」的项目最容易翻车的做法是新建工程把所有东西塞进 main.c调通之后想加个扫频功能发现无从下手。我第二次重构时把驱动层和业务层彻底分开了后来加串口控制、加 OLED 显示都没动过驱动代码。3.1 目录怎么分驱动层、业务层、板级支持工程用 CubeMX 生成骨架然后手工加三个目录Project/ ├── Core/ │ ├── Inc/ main.h, stm32f1xx_hal_conf.h │ └── Src/ main.c, stm32f1xx_it.c, gpio.c, tim.c, usart.c ├── Drivers/ │ ├── AD9850/ │ │ ├── ad9850.h 对外接口 引脚宏 │ │ └── ad9850.c 时序、频率字计算、串/并口实现 │ └── STM32F1xx_HAL_Driver/ ├── BSP/ │ ├── bsp_key.c 按键扫描 │ └── bsp_oled.c 显示可选 └── App/ ├── app_sweep.c 扫频状态机 └── app_menu.c 交互逻辑分层原则很简单ad9850.c里只允许出现「引脚翻转 频率字换算」不允许出现按键、串口、延时业务App/层只调用AD9850_SetFrequencyHz()这种语义接口不碰任何 GPIO。这样一来换一块板子只要改ad9850.h里那五个宏换一个芯片比如 AD9851时钟 180 MHz只要改AD9850_CLKIN_HZ。3.2 时钟与 GPIO 初始化CubeMX 里把 HSE 选成晶振PLL ×9 得到 72 MHzGPIOB 的 PB5~PB8 全部配成推挽输出、低速、无上下拉。低速是有意的这几个脚不需要翻转得特别快速度配高反而让边沿更陡串扰更严重。生成的MX_GPIO_Init()里会有一堆HAL_GPIO_Init实际用到的就四个脚为了后面并口提速我干脆把 PB0~PB7 全配成输出static void MX_GPIO_Init(void) { GPIO_InitTypeDef GPIO_InitStruct {0}; __HAL_RCC_GPIOB_CLK_ENABLE(); /* PB0~PB7 一次配好并口时是 D0~D7串口时只用 PB5/PB6/PB7/PB8 中的几个 */ GPIO_InitStruct.Pin GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3 | GPIO_PIN_4 | GPIO_PIN_5 | GPIO_PIN_6 | GPIO_PIN_7 | GPIO_PIN_8; GPIO_InitStruct.Mode GPIO_MODE_OUTPUT_PP; GPIO_InitStruct.Pull GPIO_NOPULL; GPIO_InitStruct.Speed GPIO_SPEED_FREQ_LOW; HAL_GPIO_Init(GPIOB, GPIO_InitStruct); /* 上电先给一个确定的低电平避免悬空时序 */ HAL_GPIO_WritePin(GPIOB, GPIO_PIN_5 | GPIO_PIN_6 | GPIO_PIN_7 | GPIO_PIN_8, GPIO_PIN_RESET); }这段代码没什么技术含量但有两处值得说一是Pull GPIO_NOPULL模块内部输入是高阻配上下拉会影响边沿形状二是初始化完立刻把所有控制脚拉低因为 STM32 复位后 GPIO 默认是浮空输入这段时间里 W_CLK 上可能有毛刺虽然一般不会真的写乱寄存器但养成习惯比事后排查省事。3.3 三个时序动作RESET、W_CLK、FQ_UDAD9850 的时序图看着复杂抽出来只有三个动作W_CLK 一个上升沿移入一位FQ_UD 一个上升沿把数据锁存生效RESET 加几个 W_CLK 把内部指针归零。三个动作都用一个函数封住后面写代码就是调用组合。/* 一个 W_CLK 正脉冲宽度靠两次 NOP 撑72 MHz 下约 30 ns远大于手册要求的 3.5 ns */ static inline void AD9850_PulseWClk(void) { AD9850_PORT-BSRR AD9850_WCLK_PIN; /* 置高 */ __NOP(); __NOP(); AD9850_PORT-BSRR (uint32_t)AD9850_WCLK_PIN 16; /* 置低 */ } /* 复位RESET 拉高期间给时钟再把 RESET 拉低最后补一个时钟让指针归零 */ void AD9850_Reset(void) { AD9850_PORT-BSRR AD9850_RESET_PIN; __NOP(); __NOP(); AD9850_PulseWClk(); AD9850_PORT-BSRR (uint32_t)AD9850_RESET_PIN 16; AD9850_PulseWClk(); }这里用的是BSRR寄存器而不是HAL_GPIO_WritePin。原因很实际HAL_GPIO_WritePin里面有参数检查、有分支一次调用十几个指令周期串行写 40 位就是 40 次调用用 BSRR 一次写寄存器就完成置位/复位而且 BSRR 是原子的写高 16 位清、低 16 位置不需要读-改-写也就不会打断别的引脚状态。做扫频这种需要频繁改频率字的场景这个差别能到微秒级。提示如果你用的是标准库或者寄存器版工程把 BSRR 换成GPIO_SetBits/GPIO_ResetBits也能跑只是慢一点。别去用GPIO_WriteBit一个一个改那个更慢。4. 驱动拆解频率字计算与 40 位串行写入驱动层真正的代码量不到 100 行但每一行都有坑。这一节把频率字怎么算、40 位怎么一位一位塞进去、接口怎么设计成别人能直接用全部摊开。4.1 频率字一行公式和三种精度写法最直观的写法是用 double 直接套公式代码可读性最好/* 频率字 f × 2^32 / f_clk0.5 做四舍五入 */ uint64_t ftw64 (uint64_t)(freq_hz * 4294967296.0 / AD9850_CLKIN_HZ 0.5); uint32_t ftw (uint32_t)ftw64;4294967296.0就是 2^32写成字面量比pow(2,32)强编译器直接折叠成常量。F103 没有 FPUdouble 是软件模拟的一次乘除大概几十微秒单次设置频率完全感觉不到扫频时要注意见第 6 章。如果要避开浮点就得先乘后除用 64 位整数保证不溢出/* 整数写法整数 Hz 输入先左移 32 位再除避免中间结果被截断 */ uint32_t AD9850_FreqToFTW_Int(uint32_t freq_hz) { /* 40 MHz 时 freq_hz 32 ≈ 1.7e17uint64 上限 1.8e19安全 */ return (uint32_t)(((uint64_t)freq_hz 32) / 125000000ULL); }还有一个坑必须单独拎出来不要用 float。float 只有 24 位尾数10 MHz 对应的频率字是 343597384已经超过 2^24 16777216 了低位会被直接截掉误差能到几千赫兹。而 1 kHz 对应的频率字才 34360float 表示得下所以你测低频会觉得「挺准的」一上高频才发现翻车。这是我在实验室里真实踩过的坑同一份代码低频段和高频段的精度差了一个数量级。几个常用频点可以先手算好调试的时候拿来对表目标频率频率字十进制十六进制写入顺序低字节在前1 kHz343600x0000863838 86 00 00100 kHz34359740x0034694646 69 34 001 MHz343597380x020C49BABA 49 0C 0210 MHz3435973840x147AE14848 E1 7A 14示波器或者频率计量出来的频率明显不对时先别改代码拿这张表对一下你发出去的四个字节八成能定位到是算错了还是发反了。4.2 串行写 40 bit 的完整函数AD9850 内部那个 40 位寄存器本身就是个移位寄存器每来一个 W_CLK 上升沿它把数据线上当前的电平移进去一位。并口模式下一次给 8 位、发 5 次串行模式下给 1 位、发 40 次本质是同一件事。所以串行写的一位函数就是「摆数据 打时钟」/* 发一个字节AD9850 是低位先出所以从 bit0 开始 */ static void AD9850_WriteByte(uint8_t byte) { for (uint8_t i 0; i 8; i) { if (byte 0x01) AD9850_PORT-BSRR AD9850_DATA_PIN; /* 数据 1 */ else AD9850_PORT-BSRR (uint32_t)AD9850_DATA_PIN 16; /* 数据 0 */ AD9850_PulseWClk(); /* 上升沿把这一位移进内部寄存器 */ byte 1; } }有了这个写完整频率就水到渠成先写频率字的低字节再依次写四字节最后一个字节装相位和控制位然后给 FQ_UD 一个上升沿40 位同时生效。static uint8_t s_phase 0; /* 5 位相位单位 11.25° */ void AD9850_SetFrequencyHz(double freq_hz) { /* 上限取 0.4 倍时钟再高输出已经被低通滤得没法看了 */ if (freq_hz 0.0) freq_hz 0.0; if (freq_hz AD9850_CLKIN_HZ * 0.4) freq_hz AD9850_CLKIN_HZ * 0.4; uint32_t ftw (uint32_t)(freq_hz * 4294967296.0 / AD9850_CLKIN_HZ 0.5); AD9850_WriteByte((uint8_t)(ftw)); /* W0~W7 频率字 bit0~7 */ AD9850_WriteByte((uint8_t)(ftw 8)); /* W8~W15 */ AD9850_WriteByte((uint8_t)(ftw 16)); /* W16~W23 */ AD9850_WriteByte((uint8_t)(ftw 24)); /* W24~W31 */ AD9850_WriteByte((uint8_t)((s_phase 0x1F) 3)); /* W32~W39 相位 控制 */ /* FQ_UD 上升沿40 位一次性锁进工作寄存器波形立刻切换 */ AD9850_PORT-BSRR AD9850_FQUD_PIN; __NOP(); __NOP(); AD9850_PORT-BSRR (uint32_t)AD9850_FQUD_PIN 16; }参数说明入参是双精度频率值单位 Hz允许小数比如1234.567。函数内部先做限幅再算频率字限幅比不管更安全——频率字超过 2^32 会溢出成随机值输出个几兆的杂波你根本想不到是哪来的。最后一个字节我用(s_phase 0x1F) 3把 5 位相位放在高 5 位、低 3 位留给掉电和控制位。不同批次的模块和 AD9851 在这几位上的排布有出入相位不敏感时直接写0x00最省事等波形调通了再回来试相位。还有一点容易忽略写完 40 位之后必须给 FQ_UD 脉冲否则数据只在移位寄存器里工作寄存器还是旧值。表现出来就是「程序里明明改了频率示波器上纹丝不动」然后开始怀疑人生。我现在的习惯是AD9850_SetFrequencyHz里 FQ_UD 那段代码用注释框起来画个横线提醒自己别手欠删掉。4.3 对外接口设计set_freq / set_phase / power_down头文件是对外契约写成什么样决定了后面好不好改。我这份是这样接口参数作用AD9850_Init(void)无复位 上电给 1 kHz方便示波器直接找到波形AD9850_Reset(void)无单独复位扫频前调用可以清掉累积误差AD9850_SetFrequencyHz(double)Hz支持小数主接口内部限幅、算字、写 40 位AD9850_SetFrequencyInt(uint32_t)整数 Hz扫频用避开浮点快一个数量级AD9850_SetPhase(uint8_t)0~31单位 11.25°相位偏移做正交或 PSK 用AD9850_PowerDown(uint8_t)0/1掉电控制不输出时省电也降噪初始化函数里有个小技巧上电直接把频率设成 1 kHz。原因是 1 kHz 在示波器上特别好找——时基打到 200 μs/div能看到四五个周期而如果你上电设 10 MHz时基没调好时屏幕上就是一条模糊的亮带很容易误判成「没输出」。void AD9850_Init(void) { AD9850_Reset(); /* 先复位保证内部指针归零 */ AD9850_SetPhase(0); AD9850_SetFrequencyHz(1000.0); /* 上电给 1 kHz示波器一抓就有 */ }4.4 上板验证示波器该看到什么调通的标准不是「能出波形」而是「出的波形和算出来的一致」。我一般按这三步验收第一步静态直流验证。不接示波器用万用表量 W_CLK、FQ_UD、DATA 三个脚正常情况下应该都是低电平0 V如果你量到 1.6 V 左右的中间值说明引脚配成了输入或者被外部拉住了先解决这个再说。第二步频率准确性。设 1 kHz示波器时基 200 μs/div看周期是不是 1 ms设 1 MHz时基 500 ns/div看周期是不是 1 μs。如果频率计的读数和设定值差 1% 到 3%多半是模块晶振的实际频率不是标称的 125 MHz廉价模块用 125 MHz 的有源晶振实际偏差几十 ppm 到几百 ppm 都算正常要做到更准就得实测晶振频率后回填AD9850_CLKIN_HZ。第三步幅度与失真。正弦输出接 100 Ω 负载峰峰值应该在 1 V 左右如果你看到顶部或者底部被削平那是后级负载太重或者供电不足不是 DDS 的问题。方波那一路是片内比较器输出的占空比靠模块上的电位器调出厂位置往往不是 50%调一下就好。注意别把示波器探头直接怼在 DATA 或者 W_CLK 上测时序探头电容会给这根线加几十 pF 负载边沿变缓之后时序可能刚好卡在临界点上测的时候是好的、拔掉探头就坏。真要测时序用第二个通道测输出波形第一个通道测 FQ_UD靠触发关系看相对位置。5. 避坑记录没波形、频率差几倍、波形毛刺的排查顺序这一节是我前后帮人调了七八块板子攒下来的记录按「先看有没有再看准不准最后看好不好」的顺序排照这个顺序查基本不用走回头路。5.1 上电类问题示波器上什么都没有现象程序烧进去串口打印正常示波器两个通道全是平线一点波形都没有。原因最常见的是 DATA 接错了脚。模块上标DATA的那一根是串行数据输入而旁边那排 D0~D7 是并口数据线两者不是一回事。有人照着「并口 D0 是数据线」的说法把串行数据接到 D0 上时序全对数据一位也进不去。第二常见的是 FQ_UD 没有上升沿——HAL_GPIO_WritePin连续写了两次 SET中间没拉低等于没脉冲。解决写一个最小验证程序只做三件事复位、写 1 kHz 频率字、给 FQ_UD 脉冲。用万用表直流档量 FQ_UD正常应该能看到一个瞬间跳变量不出来就用示波器单次触发抓。还不行就把 DATA 换到模块标注的那个脚上重试五分钟能定位。5.2 频率类问题数字对不上现象 A设 10 MHz频率计读 10.003 MHz设 1 kHz读 1.000 kHz几乎不差。原因用了 float 算频率字。float 尾数 24 位10 MHz 的频率字 343597384 超出表示范围低位被截断误差折算到频率上就是几 kHz1 kHz 的频率字才 34360float 完全表示得下所以低频准高频飘。解决改成 double 或者 64 位整数先乘后除见 4.1。改完再测10 MHz 的偏差应该落到晶振精度量级也就是几十 Hz 以内。现象 B设 1 MHz出来 500 kHz或者出来 32 MHz正好是 32 倍。原因500 kHz 是少算了一半通常是 2^31 当成了 2^32 用或者把 AD9851 的 180 MHz 时钟常数套到了 AD9850 上2^32/180e6 23.86比 34.36 小输出频率偏低。32 倍这种整数倍关系基本都是字节顺序写反了把高位当低位先发移位寄存器里拼出来的数就完全变了样。解决拿 4.1 那张频率字对照表用调试器把ftw的值和表里的十进制数比一比。数值对但输出不对就是发送顺序的问题数值本身就不对就是公式或者常数的问题。这两个分支一定要分开查混在一起很容易越改越乱。5.3 波形类问题能出波形但不干净现象正弦波形上有明显的台阶和高频毛刺方波边沿抖动频率越高越严重。原因三个来源按概率排——杜邦线太长且 W_CLK 与 DATA 平行走线时钟串到数据上模块 5 V 供电、3.3 V 电平余量不足边沿处在门限附近抖动模块 VCC-GND 之间没有去耦W_CLK 每次翻转都在电源上打出尖峰。解决先换短杜邦线10 cm 以内把 W_CLK 和 DATA 分开走模块改 3.3 V 供电VCC-GND 并一只 0.1 μF 瓷片电容位置尽量贴近模块引脚。三招做完还不行就在AD9850_PulseWClk里多加几个__NOP()把时钟频率降下来先确认功能再谈速度。现象正弦幅度只有 0.5 Vpp 左右以为是模块坏了。原因AD9850 是电流输出20 mA 满量程模块上用 100 Ω 电阻转电压理论上的峰峰值就在 1 V 上下。如果后级接了很重的负载比如直接接 50 Ω幅度会被拉得更低。解决空载或者接 1 kΩ 以上负载测量确认幅度正常要驱动 50 Ω 或者要更大摆幅就加一级运放缓冲。别指望从模块引脚直接拉出几伏的摆幅那不是它的能力范围。6. 二次开发扫频、调制与上位机协议的改造路线把这套东西当信号源用只是起点真正有意思的是把它改成能扫频、能调制、能被上位机控制的小仪器。这里给两条我最常用的改造路线。第一条是提速。串行写 40 位要翻 40 次时钟每次时钟加两次数据操作一共上百条指令72 MHz 下大概几十微秒。扫频时每个点都要写一次1000 个点就是几十毫秒扫频速度上不去。换成并口模式一次写 8 位5 次就完成速度直接快 8 倍/* 并口写 40 位PB0~PB7 一次给出 8 位5 个 W_CLK 完成扫频时用这个 */ void AD9850_Write40_Parallel(uint32_t ftw, uint8_t phase) { uint8_t buf[5] { (uint8_t)(ftw), (uint8_t)(ftw 8), (uint8_t)(ftw 16), (uint8_t)(ftw 24), (uint8_t)((phase 0x1F) 3) }; for (uint8_t i 0; i 5; i) { /* 只改低 8 位高 8 位保持原状避免把别的引脚带翻 */ AD9850_PORT-ODR (AD9850_PORT-ODR 0xFF00) | buf[i]; AD9850_PulseWClk(); } AD9850_PORT-BSRR AD9850_FQUD_PIN; __NOP(); __NOP(); AD9850_PORT-BSRR (uint32_t)AD9850_FQUD_PIN 16; }用这段代码的前提是 D0~D7 必须连续接在 PB0~PB7 上0xFF00那个掩码就是按这个假设写的换引脚的话掩码要跟着改改错了会把你别的外设引脚带着一起翻转现象非常诡异。第二条是扫频状态机。把扫频放在App/app_sweep.c里用 TIM2 出 1 ms 中断中断里只做一件事查表取下一个频率点调用并口写函数指针加一到尾部回卷。频率表用对数分布而不是线性分布因为人耳和大部分频响测试都关心倍频程10 Hz 到 1 MHz 按十倍频程分每个十倍频程 100 个点一共 500 个点1 ms 一个点一次扫完 0.5 秒示波器 XY 模式下看幅频特性很直观。参数建议值说明扫频范围10 Hz ~ 1 MHz再高的话模块低通和运放带宽都跟不上每十倍频程点数100500 点覆盖 5 个十倍频程步进间隔1 ms受限于串口/屏刷新再快人眼也跟不上频率表存储const uint32_t[]放本文还有配套的精品资源点击获取
延伸阅读

更多相关文章

2026/11/5 2:27:36

UKF与CKF算法在电动汽车路面附着系数估计中的应用

1. 项目概述与背景在电动汽车控制系统中,路面附着系数估计一直是个让人头疼的问题。想象一下,你正开着电动车在暴雨中行驶,突然车轮打滑的那一瞬间,车辆稳定系统能否快速准确地识别路面状况,直接关系到行车安全。这就是…

2026/11/5 2:27:36

MATLAB控制系统仿真源码:拆包跑通、参数扫描与避坑

简介:这份《MATLAB与控制系统仿真实践》第3版配套源码面向学习控制系统仿真、希望动手复现书中实例的高校师生与工程技术人员,重点解决控制理论到MATLAB/Simulink实现之间的衔接问题,需注意其为源码包而非教材电子书。压缩包共390个文件、约1…

2026/11/5 2:27:36

D-S证据理论多传感器融合MATLAB实现与拒判决策

简介:这是一份面向多传感器信息融合学习者与MATLAB实践者的轻量代码资源,围绕D-S证据理论展开,帮助读者把基本概率分配、证据冲突处理与Dempster组合规则落实到可运行脚本中,适用于课程实验、算法入门和中小型融合原型的二次开发。…

2026/11/5 3:17:45

ADS122U04与PIC18实现高精度PT100温度采集全解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/11/5 3:17:45

【Leetcode】4. Median of Two Sorted Arrays

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/11/5 3:17:45

【置顶帖】关于博主/关于博客/博客大事记

关于博主 ● 信息安全从业者 ● 注册信息安全认证专家资质 ● CSDN认证业界专家、安全博客专家 、全栈安全领域优质创作者 ● 【GOLF IT新治理领导力论坛】演讲嘉宾 ● 【EISS企业信息安全峰会】演讲嘉宾 ● 【CSDN隐私计算论坛】演讲嘉宾 ● 【……】演讲嘉宾(很多…

2026/11/5 3:17:45

ADS122U04IPWR与PIC18F86J10的高精度温度采集实战解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/11/5 3:12:42

ADS122U04IPWR+STM32F429ZI工业温度采集系统设计实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/11/4 12:38:23

面向复杂光照与角度的宠物面部识别鲁棒性增强策略

在智慧养宠时代,基于视觉的宠物身份识别技术正逐步从实验室走向家庭应用。然而,与配合度高的人类不同,宠物是典型的“非合作生物识别对象”——它们不会主动配合摄像头调整姿态,更无法控制光照环境。实际应用中,我们常…

2026/11/4 21:04:25

SSM电子书店源码全解析:结构、原理、部署与排错实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/11/5 0:02:07

多智能体协作系统架构设计与实践优化

1. 多智能体协作系统的时代背景2017年Transformer架构的诞生彻底改变了人工智能的发展轨迹。当行业还沉浸在单一大模型带来的性能突破时,Anthropic的研究团队已经将目光投向了更前沿的领域——如何让多个智能体通过协作产生超越单体能力的系统智能。这就像交响乐团中…

2026/11/5 0:02:07

大模型系统性入门实战指南:从原理到部署微调的全链路路线

提到大模型的系统性入门,我先说个结论:这事真不难,难的是资料太散、路线太多,今天这个框架明天那个工具,新人很容易在“收藏夹吃灰”和“教程看到一半放弃”之间反复横跳。市面上关于大模型的内容少说有几十万篇&#…

2026/11/5 0:02:07

鸿蒙文件系统沙箱机制解析与开发实践

1. 鸿蒙文件系统沙箱机制深度解析作为一名从Android转向鸿蒙开发的工程师,我深刻体会到文件系统访问是迁移过程中最先遇到的"拦路虎"。在Android上运行良好的文件读写代码,在鸿蒙真机环境却频频出现文件写入后神秘消失或直接抛出权限拒绝错误的…

2026/11/4 12:38:23

面向复杂光照与角度的宠物面部识别鲁棒性增强策略

在智慧养宠时代,基于视觉的宠物身份识别技术正逐步从实验室走向家庭应用。然而,与配合度高的人类不同,宠物是典型的“非合作生物识别对象”——它们不会主动配合摄像头调整姿态,更无法控制光照环境。实际应用中,我们常…

2026/11/4 21:04:25

SSM电子书店源码全解析:结构、原理、部署与排错实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
☎咨询二维码 ☎ ↑