
简介2019年电赛D题“简易电路特性测试仪”的完整硬件设计与STM32源码包面向电子设计竞赛参赛者、嵌入式开发人员以及需要完成电路测试类课题的本科及研究生。资源以工程源码为核心包含硬件原理图设计、STM32F4底层驱动、测量算法及配套说明文档。包内共315个文件以160个.h头文件和143个.c源文件为主体工程采用标准外设库组织覆盖定时器、ADC、USART、RCC、FLASH、CAN等驱动模块另含工程配置文件、汇编启动文件、库文件、PDF技术手册及HTML注释页压缩后约4.71MB结构紧凑便于按模块查阅。代码中的core.asm、stm32f4xx_*.c等展示了从时钟配置到外设初始化的完整框架对复现2019年电赛D题、理解电路特性测量方法、调试增益/频率响应/阻抗等参数有直接帮助。已有71人学习下载也可在源码基础上修改算法以扩展测量项适合用作赛题复盘、毕业设计或嵌入式课程设计参考工程。1. 2019电赛D题“简易电路特性测试仪”不拆放大器从两个端子把四个参数测出来2019年全国大学生电子设计竞赛D题要求给一个未知的单管共射放大电路做“体检”不拆电路板只用两个端子接入一台“简易电路特性测试仪”把输入电阻、输出电阻、电压增益和上限频率测出来误差还追求在5%以内。麻烦在于放大器是一个黑盒子每做一次测量动作都会改变它的工作状态读回来的电压已经不是原来的电压这很容易让初次参赛的队伍在查错上耗时。这道题真正考察的不是某个放大电路设计得多漂亮而是从信号源、模拟开关、幅值检波到STM32计算这一整条测量链路的严谨程度。这里要讲的是电赛中普遍采用的“DAC正弦激励 模拟开关切换已知电阻 双路检波 STM32源码计算”的完整实现路径从硬件设计到代码逻辑全部落在可复现的细节上。2. 测量原理与系统组成用四次切换把Ri、Ro、Au和fH分别引出来2.1 输入电阻采用“串阻切换法”关键在于两次读取输入节点电压单管共射放大器的输入电阻不能直接用万用表电阻挡测量因为三极管基极回路处于有源工作状态。常见做法是在信号源与放大器输入端之间串入一只已知电阻Rs然后切换一次开关测两次输入节点电压。第一次让开关S1闭合信号源Vs直接送到放大器输入端此时输入节点电压V1近似等于信号源开路电压第二次让S1断开Rs串入信号通路输入节点电压变为V2。对交流等效电路而言V2是Vs经过Rs与放大器输入电阻Ri分压后的值V2 Vs × Ri / (Ri Rs)两次测量联立可反解出输入电阻Ri Rs × V2 / (V1 - V2)这个公式成立的前提是信号源电压Vs在两次切换之间完全一致。直接用STM32片内DAC输出驱动时DAC等效内阻会随着负载变化而飘动导致V1和V2不满足同一个Vs所以信号源后级必须加低阻抗缓冲电路。另一个容易忽视的点是V2的绝对数值可能只有V1的十分之一ADC量化误差会被分母上的小差值放大。为了摊平这个误差检波级要保证足够的增益并且ADC读数不能只采一次就计算最好连续读多次取平均。典型的测量条件如下表实际备赛时可以按待测放大器的量级调整参数建议取值设计理由测试基频1kHz避开电源纹波和运放低频噪声便于检波器稳定Rs分档1kΩ / 10kΩ / 100kΩ覆盖单管放大器常见输入电阻范围正弦幅度200mV~1Vp-p兼顾放大器线性区与检波器灵敏度接口方式双通道同时读让增益计算不受信号源幅值漂移干扰2.2 输出电阻用“空载与带载对照”戴维南模型简化成两个读数输出电阻对应的是放大器输出端向外部看去的等效内阻。测量时要分两次读取输出节点的检波电压第一次S2断开输出端空载记录Vo_open第二次S2接通输出端接入已知负载电阻RL记录Vo_load。按戴维南等效电路放大器输出端相当于一个理想电压源串联一个内阻Ro带载后的输出电压满足Vo_load Vo_open × RL / (Ro RL)反解得到Ro RL × (Vo_open - Vo_load) / Vo_loadRL的取值要与放大器实际带载能力匹配。如果RL选得太小输出波形削底失真Vo_load读数偏低如果RL选得太大空载和带载两次读数几乎相同公式分母差值为零误差被无限放大。电赛常用的可选负载是470Ω、1kΩ、4.7kΩ三档程序中根据Vo_open与Vo_load的差值比例自动选择最合适的一档。2.3 增益要同时读输入输出两个检波通道扫频以-3dB点确定上限频率增益测量不能先读一次输入电压再读一次输出电压因为两次读数之间信号源幅值会慢漂。正确做法是同一时刻对两路检波器输出同时采样用输入通道读数Vin_det和输出通道读数Vout_det相除Au Vout_det / Vin_det由于两路检波电路完全同构输入输出的比例系数会互相抵消这个设计能让增益读数的精度明显高于单通道巡检方式。频率特性测量则在此基础上增加扫频从1kHz开始依次将DAC输出频率切换为2kHz、5kHz、10kHz、20kHz、50kHz、100kHz、200kHz每次切换后重新采集两路检波电压记录增益跌落至中频增益0.707倍时对应的频率即为上限频率fH。扫频过程中的等待时间不能固定不动。检波器低通滤波器的时间常数约1.8ms频率越低正弦波周期越长低通输出稳定需要更多个信号周期频率越高阶梯谐波越多反而需要更长的滤波时间。经验值是1kHz档等待约100ms10kHz档约50ms100kHz档约20ms。若用STM32片内DAC直接产生正弦波还要注意DAC更新率的物理极限100kHz时正弦表点数必须降为16~32点否则DMA追求高更新率会直接把DAC速度拉爆这个细节在3.1节继续展开。2.4 为什么选“模拟检波 ADC读直流”而不是“ADC直接采波形”也有人会想直接用STM32 ADC以高采样率采集正弦波形再用FFT或最小二乘法求幅值不是能省掉整套检波电路吗这个思路在1kHz下可行但题目要求上限频率往往到几百kHzSTM32F103的12位ADC最高约1MSPS100kHz信号每个周期只能采约10个点FFT结果对相位截断和非同步采样非常敏感实际精度反而比模拟检波差。而“全波整流 低通 ADC读直流”的方案把高频波形信息变成缓慢的直流ADC的压力大幅降低计算也变成简单的比例换算。这套架构对参赛者更友好排查问题时也容易用万用表逐级定位是电赛D题的常见稳妥路线。3. 硬件设计DAC信号源、开关矩阵与双路全波检波电路3.1 信号源链路STM32 DAC输出之后要接低通、缓冲和限流电阻DAC引脚出来不能直接接待测放大器主要原因是STM32F103片内DAC输出阻抗偏大、驱动能力弱外部负载一变输出电压幅度就会跟着变。常见的信号源链路分三级设计第一级是RC低通或运放二阶低通滤除DAC阶梯波的高频分量第二级是单位增益缓冲用OPA227或AD8628这类低噪声运放搭成电压跟随器把等效输出阻抗降到几欧以下第三级是输出端串一只100Ω电阻既保护运放在接线错误时不至于短路损坏也能在长距离杜邦线下保持稳定的驱动阻抗。低通滤波器截止频率要按最高扫频频率的5~10倍设计。如果只测1kHz基频截止频率设15kHz就够了要测到100kHz运放必须选择宽带型截止频率提到500kHz以上。这里经常出现一个矛盾DAC更新率不够时100kHz正弦波每周期只有16个采样点阶梯谐波落到500kHz附近低通很难完全滤干净。专业电赛作品通常直接用AD9833等DDS芯片替代DACSPI写一次频率寄存器就能输出任意频率的干净正弦波。若坚持用STM32片内DAC就要像4.1节那样按频率动态切换正弦查找表点数不能一个表走到底。3.2 模拟开关与控制口用GPIO控制S1和S2再解决导通电阻问题开关矩阵负责把Rs和RL接入或切出测量回路。简易方案是用CD4066它在5V供电下导通电阻为几十到一百多欧价格便宜、控制简单但导通电阻会随信号电压摆动影响分压精度。预算充足的团队会选择DG441或MAX4664这类低导通电阻模拟开关导通电阻降到4Ω量级同时对1kHz~100kHz信号仍有平坦响应。控制接口只需要两个GPIO约定如下开关作用拉高电平后的状态STM32引脚S1控制已知电阻Rs是否串入输入回路Rs接入PD0S2控制已知电阻RL是否接入输出端RL接入PD1程序里切换S1和S2时必须互斥不能在同一次测量里让两个开关同时闭合。更关键的是在每一切换动作后留出足够的稳定时间等检波电容把新状态下的直流电平重建起来。PD0和PD1配置为推挽输出初始化时先全部置低避免上电瞬间开关误动作。3.3 双路幅值检波全波整流 有源滤波避开二极管死区幅值检波是整个模拟前端最需要小心的地方。直接用一个二极管对正弦波整流在信号幅度低于0.5V时二极管正向压降会带来巨大非线性根本没法用于精密测量。电赛里更常见的做法是精密全波整流电路两枚二极管放在运放反馈环内部运放的深度负反馈把二极管死区“压掉”使得小信号也能得到线性整流。整流输出接一只8.2kΩ电阻和0.22μF电容构成低通滤波器时间常数约1.8ms把全波整流后的脉动直流平滑为稳定的ADC输入电压。输入端和输出端各放一路完全相同的检波电路分别接到STM32的ADC_IN0和ADC_IN1。输入检波通道前还要加一级电阻分压用100kΩ100kΩ把放大器输入电压衰减一半避免过高的信号直接打进运放输入端。输出通道则可直接接入因为放大器输出电压通常已在运放允许范围内。两路检波器共用同一条模拟地在STM32模拟电源引脚处单点汇总数字地和模拟地用0Ω电阻隔开这部分布线决定了最终读数的噪声底。4. STM32源码实现正弦表播放、检波值采集与参数计算4.1 用TIM2 DMA让DAC自动循环输出正弦波程序里不能用延时方法一点一点往外输出正弦数据否则CPU被占用扫频和显示逻辑无法并行。常见做法是用定时器作为DAC的触发源DMA在每次定时器事件到来时自动把正弦查找表里的一个值搬到DAC数据寄存器循环传输CPU全程不被阻塞。首先生成512点正弦查找表#define SIN_TAB_LEN 512 uint16_t sine_tab[SIN_TAB_LEN]; void gen_sine_table(uint16_t amp) { for (uint16_t i 0; i SIN_TAB_LEN; i) { float phase 2.0f * 3.1415926f * i / SIN_TAB_LEN; uint32_t v 2048 (uint32_t)(amp * arm_sin_f32(phase)); sine_tab[i] v 0x0FFF; } }DAC是12位数字量0对应0V4095对应满量程电压所以正弦波需要叠加上约一半量程的直流偏置也就是2048。参数amp是正弦波半幅对应的数字量例如要输出1Vp-p的正弦峰值0.5V按3.3V满量程换算大约为620个LSB。此处调用了CMSIS-DSP的arm_sin_f32若不使用DSP库直接用C标准库sin函数生成一次表也完全够用。接着启动定时器和DMA传输htim2.Init.Prescaler 0; htim2.Init.Period 139; // 72MHz / 140 ≈ 514kHz DAC更新率 HAL_TIM_Base_Init(htim2); HAL_DAC_Start_DMA(hdac, DAC_CHANNEL_1, (uint32_t*)sine_tab, SIN_TAB_LEN, DAC_ALIGN_12B_R); HAL_DAC_Start(hdac, DAC_CHANNEL_1); HAL_TIM_Base_Start(htim2);DAC更新率除以正弦表点数就是输出频率514k / 512 ≈ 1.004kHz这个偏差在测量中不会带来问题因为增益和阻抗计算都只是在同一激励下做比例换算。需要扫频时则直接修改TIM2的Period并同步更换对应的查找表点数比如把表换成64点DAC更新率设为640kHz即得10kHz正弦。TIM2的更新事件必须同时配置为DAC触发源和DMA请求源这两项在CubeMX里对应“Trigger”和“DMA Settings”漏掉任一项DAC都只会输出恒定电平。4.2 读取检波电压等待稳定、连续多次平均、按LSB变化量判断是否到位检波器输出的直流电压不是开关切换后马上跳变的而是按RC指数规律逐步逼近目标值。读取前必须先做软件延时再读取ADC值。下面的函数封装了一次单通道读取uint16_t read_adc_ch(uint32_t channel) { ADC_ChannelConfTypeDef sCfg {0}; sCfg.Channel channel; sCfg.Rank ADC_REGULAR_RANK_1; sCfg.SamplingTime ADC_SAMPLETIME_71CYCLES_5; HAL_ADC_ConfigChannel(hadc1, sCfg); HAL_ADC_Start(hadc1); HAL_ADC_PollForConversion(hadc1, 100); uint16_t val HAL_ADC_GetValue(hadc1); HAL_ADC_Stop(hadc1); return val; }采样时间选用71.5周期比最短采样时间带来更低的内阻和噪声。检波器稳定时间约为主滤波时间常数的3~5倍1kHz档位等待50ms以上比较稳妥。实际调试时可以先读连续两次观察ADC值差是否小于20个LSB如果差值过大说明检波电容还没充到位需要继续追加等待。等稳定后取4次读数的平均值能明显减少电源纹波和开关噪声带来的随机误差uint32_t average_read(uint32_t channel, uint8_t times) { uint32_t sum 0; for (uint8_t i 0; i times; i) { sum read_adc_ch(channel); HAL_Delay(2); } return sum / times; }4.3 计算Ri、Ro和Au注意除零保护和量程上限提示测量序列按顺序执行完成后用最后读取的相关电压做计算。下面的代码片段展示了核心公式的实现float Ri 9999.0f, Ro 9999.0f, Au 1.0f; if (fabsf(v1 - v2) 0.001f) { Ri rs * v2 / (v1 - v2); } if (vload 0.001f) { Ro rl * (vopen - vload) / vload; } Au vout_det / vin_det; float gain_db 20.0f * log10f(Au);v1和v2分别来自S1闭合、S2断开时输入检波通道的读数vopen和vload分别是S2断开、接通时的输出检波读数。把Ri和Ro的初值设为9999是为了在除零保护触发时让屏幕显示“9999”提示当前档位已超出量程而不是输出一个不确定的垃圾值。rs和rl使用浮点变量赋值方便在代码中按档位切换。计算Au时两路ADC读数都来自同样的检波电路结构比例系数已经抵消所以不需要再做额外换算。4.4 测量状态机四次切换和每次采样绑定避免开关误动作程序主循环用一个带状态号的状态机驱动测量过程每次进入一个状态时先设置对应开关延时等待稳定再读取相应通道然后推进到下一状态#define ST_RI_1 1 #define ST_RI_2 2 #define ST_RO_1 3 #define ST_RO_2 4 uint8_t step ST_RI_1; void meas_tick(void) { switch (step) { case ST_RI_1: S1_CLOSE; // S1闭合直连输入 delay_stable(); v1 average_read(CH_IN, 4); step ST_RI_2; break; case ST_RI_2: S1_OPEN; // S1断开串入Rs delay_stable(); v2 average_read(CH_IN, 4); step ST_RO_1; break; case ST_RO_1: S2_OPEN; // S2断开输出空载 delay_stable(); vopen average_read(CH_OUT, 4); step ST_RO_2; break; case ST_RO_2: S2_CLOSE; // S2闭合接入RL delay_stable(); vload average_read(CH_OUT, 4); calculate_all(); step ST_RI_1; break; } }这样写的优势是每一次ADC采集都紧跟在对应的开关动作之后S1和S2永远不会同时闭合。每次全流程完成约需要几百毫秒屏幕刷新率每秒两三次已经够用。显示部分可直接用OLED的printf格式化输出把Ri、Ro、增益和fH一行行显示出来方便在现场直接记录数据。5. 校准是这套测试仪的临门一脚三类误差源与一组可执行的调试流程5.1 先找出三个看不见的电阻开关导通电阻、检波器非线性、DAC基准漂移第一类误差是开关导通电阻。CD4066导通电阻随信号电压变化当Rs较小或被测电阻接近其导通电阻量级时公式里的Rs实际是“已知电阻 开关电阻”必须让程序把导通电阻补偿进去。做法是在焊接后先用短路块把待测端短接让S1闭合后直接读一次输入电压反推出通路上的附加阻抗存成全局常量供计算时修正。第二类误差来自检波器小信号非线性。精密全波整流在几十毫伏以下仍会因运放增益不足而读数偏低接近满幅时又可能发生饱和。让输入正弦幅度通过程序控制在一个固定范围比如让ADC读数稳定在满量程30%~80%之间再用标准信号源记录5个电压点做分段线性校准就能把这个误差压到可接受水平。第三类误差是DAC和ADC共用的参考电压。STM32的VDDA如果直接接电源轻则纹波扰动重则基准漂移。建议使用外部基准芯片给ADC和DAC同时供电采用同一个模拟电源这样DAC输出幅度和ADC满量程比值保持相对一致增益测量自然稳定。5.2 用一批0.1%精密电阻做整机标定让仪器自己校准自己准备四只精密电阻阻值取1kΩ、4.7kΩ、10kΩ、47kΩ金属膜或线绕的0.1%精度。将仪器的信号输出端直接接在待测端引线上把一个精密电阻一端接信号一端接地在程序里执行Ri测量流程。仪器读出的Ri应当等于外部电阻的标称值如果读数偏差超过1%则按分段差值修正公式里的Rs。输出电阻同样在这四只精密电阻上扫一遍验证Ro公式在多个量级下的一致性。这种标定不需要额外仪器用被测仪器的原始读数反向建立误差表是最快的备赛校准方式。5.3 串口打印中间值调试比盯屏效率高一倍最终显示屏幕只显示结果排查时必须能看到ADC原始值。在状态机每个关键步骤后面用串口输出一行文本一次测量周期打印以下内容printf(Ri step: v1%d v2%d dly%d\r\n, v1, v2, dly_ticks); printf(Ro step: vopen%d vload%d rl%d\r\n, vopen, vload, rl); printf(result: Ri%.2fk Ro%.1f Au%.1fdB fH%.0f\r\n, Ri / 1000.0f, Ro, gain_db, fH);观察两次相邻打印中同一ADC值的变化趋势如果v1和v2的差值满足预期说明开关链路工作正常如果vopen和vload几乎相等说明S2没有真正接通或RL在输出端被其他元件旁路。串口数据还能帮助判断稳定等待时间是否足够当打印值单调增大时只需把delay_stable延长到数值平台期即可。这个调试接口建议保留到交作品前等评审现场需要临时验证某个量级时再靠这行打印快速定位。本文还有配套的精品资源点击获取