
简介一份聚焦高精度正弦信号源设计的论文资料适合从事信号检测、嵌入式测量系统及模拟激励单元开发的工程师参考。论文以某型飞机发动机参数检测系统的振动校准为背景提出利用“砖码”组合原理通过MAX038芯片、定制千分之一精度分压电阻、低漂移运放LM124及电子开关MAX4536构成加法网络实现120Hz、峰值0.01V至10V、步进0.01V且失真小于1%的激励信号源。同时针对嵌入式系统I/O资源受限问题采用三片CT1194移位寄存器串联的串入并出方案仅用两个I/O口即可控制12路电子开关。资源为单篇word格式论文共1个doc文件压缩包仅21KB内容包含原理分析、硬件框图、控制流程及具体编码例程。目前已有91人学习对有类似高精度低频信号源设计需求的读者而言具有直接借鉴意义。1. 高精度信号源论文拆解一个 0.01V 步进的“砖码”正弦激励方案高精度信号源在工程测量里的地位不用多讲但要在一个嵌入式系统里做出频率 120Hz、峰值从 0.01V 到 10V 可调、失真小于 1% 的正弦激励信号就不光是选器件的事了。直接买信号发生器成本高还不方便自动化测量用 D/A 加高阶滤波器在 Windows 平台下软件实时性又撑不住。这篇 word 格式的论文参考资料给了一个很经典的路子——借用砖码论文原文写“砖码”就是砝码称重的思路先做一路高质量 120Hz 正弦基准再用三组定权值信号通过电子开关和加法器组合出任意幅值。文档从需求、原理、选型、框图一直讲到源码和实例适合正在做传感器标定、监测系统功能验证或者模拟激励单元的从业者照着复现。2. 砖码原理与器件选型为什么 12 路开关就能拼出 0.01V 到 10V2.1 砖码称重三组定权值信号凑出一个十进制数砖码称重的逻辑很朴素一杆秤配一套固定重量的砝码用砝码的不同组合来表示不同重量。把“砝码”换成“信号幅度”之后这个方案就变成了先把一路 120Hz 的正弦基准经过精密分压分出三个量级、每级 4 个固定幅值的砖码信号再用电子开关决定哪些砖码接入一个比例加法器加法器输出就是这些砖码幅值之和。需求里幅值范围是 0.01V 到 10V、步进 0.01V也就是说幅值有一位整数位加两位小数位。对应地砖码分成三组整数组是 5V、4V、2V、1V组合出 1V 到 10V 的整数幅值十分位组是 0.5V、0.4V、0.2V、0.1V组合出 0.1V 到 0.9V百分位组是 0.05V、0.04V、0.02V、0.01V组合出 0.01V 到 0.09V。三组加起来正好 12 个砖码覆盖 0.01V 到 10V 之间所有 0.01V 整数倍的幅值。这套设计有个隐含优势所有砖码都来自同一个正弦振荡器只是幅度被分压电阻按比例缩小频率、相位、失真特性完全一致。加法器输出端得到的是一个幅度等于砖码组合值之和的纯净正弦波没有 D/A 转换的量化台阶也不依赖 Windows 平台做高速实时输出。加法器本身是反相求和结构12 路砖码各自经过一路累加电阻接到运放反相端输出经过反馈电阻回来。这里反相只是把正弦波相位翻转 180°激励信号不关心相位方向幅值完全保留。2.2 器件选型每个元件都在回答一个精度问题论文的选型基本围绕“比例精度”和“失真度”两个目标展开每一个器件都是在补一个具体的洞。正弦基准选用 MAX038。这是一款经典的多波形信号发生芯片输出正弦波频率可在较宽范围内调节芯片内部结构能保证向外提供失真度小于 1% 的正弦信号。对 120Hz 这种固定频率应用来说用外部阻容设定频率后输出的稳定性和纯度都够用。要注意 MAX038 早已停产工程复现时可以用 DDS 芯片或 MCU 加 DAC 替代这个在第 6 章细说。比例精度靠定制电阻。砖码幅值之间的比例完全由分压电阻的阻值比例决定而不是由电阻绝对值决定。论文把所有分压电阻全部定制阻值精度做到千分之一这是整个方案 1% 精度预算里最关键的一笔。如果这里用普通 1% 精度电阻电阻误差可能吃掉一半预算再叠加运放和开关误差总指标大概率保不住。运放选用 LM124 低漂移运放搭比例加法器。幅值下限到了 10mV 量级运放的输入失调电压和温漂会直接影响小信号档的精度低漂移器件是必须的。电子开关选用 MAX4536 的 4 路单刀单掷开关三片正好 12 路。MAX4536 属于导通电阻小、漏电小的模拟开关配合几十千欧的加法器网络影响可以压得很低。2.3 加法器电阻取几十千欧把开关导通电阻压进误差预算电子开关看起来只是接通和断开但实际导通后还有几十欧姆的导通电阻这个电阻串进信号通路会参与分压。如果加法器的累加电阻只有几百欧几十欧的导通电阻会造成百分之几的误差把累加电阻和反馈电阻都取到几十千欧导通电阻占比就掉到千分之一量级计算时可以忽略。常见做法是反馈电阻和每一路累加电阻选同一个标称值比如 20kΩ 到 50kΩ 之间这样各路增益一致求和比例就是纯砖码权值比例。配合 0.1% 定制电阻整条链路的比例误差才能收进 1% 以内。下面这张表是我按这套方案的典型参数估算的误差预算可以帮助理解各环节的权重误差来源典型量级对输出的影响分压电阻比例误差0.1%直接决定砖码幅值比例开关导通电阻几十欧串入几十千欧网络小于 0.2%各档位增益轻微偏移运放增益误差与漂移0.05%0.1%小信号档影响更大正弦基准幅度波动0.1%0.3%所有档位等比例偏移总体叠加控制在 1% 以内可行前提是各环节都不偷工。论文结束语给出的结论是精度和失真度都不超过 1%和这份预算基本吻合。120Hz 属于低频运放带宽完全不是瓶颈真正要盯的是电阻比例和开关导通电阻这两处。3. 硬件控制链路三片 CT1194 串成 12 位移位寄存器两个 I/O 口接管 4096 种组合3.1 12 位控制字怎么映射到 12 路开关先明确控制字结构。12 个电子开关对应 12 位控制信号某一位为 1 表示这一路的砖码接入加法器为 0 表示断开。位与砖码的对应关系按三组十进制位排列最低 4 位控制百分位砖码中间 4 位控制十分位砖码最高 4 位控制整数位砖码。每组内部按 5421 码的权值顺序排列组内最高位的权值是该组最大的那个砖码。位序所属分组砖码权值Q1bit0百分位0.01VQ2bit1百分位0.02VQ3bit2百分位0.04VQ4bit3百分位0.05VQ5bit4十分位0.1VQ6bit5十分位0.2VQ7bit6十分位0.4VQ8bit7十分位0.5VQ9bit8整数位1VQ10bit9整数位2VQ11bit10整数位4VQ12bit11整数位5V12 位控制字一共有 4096 种组合但真正作为有效幅值使用的只有 0.01V 到 10V 之间约 1000 个档位其余属于冗余或非法组合。实际编码时按 5421 码约束生成组合避免输出落在非标称步进上。这张映射表建议直接贴在原理图旁边后面写编码函数时逐位对照能省掉大量排查时间。3.2 三片 CT1194 串联串行进、并行出控制字 12 位就需要 12 个开关控制端。如果直接从 PC-104 的 I/O 卡拉 12 根线出来8255 的端口资源根本不够。论文的解决办法是单并转换用三片 4 位移位寄存器 CT1194 串联组成一个 12 位的串入并出寄存器。CT1194 是 4 位移位寄存器把第一片的串行输出接到第二片的串行输入端第二片的输出再接第三片三片共用同一个时钟级联后就是 12 位移位寄存器。送数时把 12 位控制字按从低到高的顺序逐位放到 DATA 线上每来一个时钟上升沿数据往里移一位。12 个时钟过后12 位数据并行出现在 Q1 到 Q12 上直接驱动电子开关的控制端。这个做法本质是拿时间换引脚用 12 个时钟周期换取 10 个 I/O 口的节省。对 PC-104 这种资源紧张的嵌入式平台来说这是一笔非常划算的买卖。论文里还专门提到复位操作即在送数前先把寄存器清一遍防止上电后随机状态导致开关误动作。3.3 8255 C 口的位控给移位寄存器造出数据和时钟论文所用 PC-104 I/O 卡的扩展 I/O 口是用 8255 实现的。8255 的 C 口具有位控功能可以对任意一位单独做位置位或位清零而不影响其它位的状态。于是从 C 口任取两位一位当 DATA一位当 CLK再加上一根可选的复位线 RD就能完成 12 路开关的全部控制。8255 工作在模式 0 时C 口分成高、低两个 4 位组位控操作通过对 C 口寄存器写特定数值实现。因为可以按位操作代码里只需要改变一根线的电平不会连带修改其它输出线。论文把 C2 定义为 RD、C3 定义为 DATA、C4 定义为 CLK这三个口线的分配可以根据自己板卡的原理图调整关键是记住最少只需要 DATA 加 CLK 两根线加一根复位线。提示移植到别的板卡时先查清 8255 C 口每一位的物理走线和电平极性再对照本章节的映射表验证不要默认源码里的端口值可以直接照抄。4. 软件流程5421 码编码与 3.96V 实例从幅值到 0x3C6 的完整换算4.1 5421 码每一位十进制数独立编码5421 码是一种十进制编码码制中相应位的权值分别是 5、4、2、1。也就是说一个 4 位组合从高位到低位分别代表 5、4、2、1把这四位里为 1 的权值相加就是它表示的十进制数。它和常用的 8421BCD码区别在于最高位权值是 5 而不是 8这正好对应砖码分组里 5/4/2/1 的结构。论文的表 1 给出了十进制数到 5421 码的转换规则。以论文给出的三个转换结果为例十进制 3 对应 0x03组合是 21十进制 6 对应 0x06组合是 42十进制 9 对应 0x0C组合是 54。也就是说编码时把一个十进制数拆成 5、4、2、1 四个权值的和对应位置 1其余位清 0 即可。少数数字存在多种拆法比如 5 可以是 50也可以是 41这类歧义位要由表 1 固定下来保证编码唯一。十进制数5421 码4 位权值 5-4-2-100000100012001030011401005010160110701118101191100注意这张表里 5 到 9 的编码是按论文给出的 6、9、3 三个样例和权值相加规则反推的目的是保持组合风格一致。如果你拿到的版本里表 1 对歧义位的定义不同以原表为准编码函数必须跟着原表走。4.2 幅值换算实例3.956V 怎样变成 0x3C6论文用 f(t)3.95sin240πt V 作为例子演示全流程。要求幅值 3.95V实际软件里输入的数值是 3.956换算步骤如下。第一步把幅值放大 100 倍取整。3.956 乘 100 得到 395.6四舍五入到 396。这一步把带两位小数的幅值变成整数便于逐位取十进制位。第二步按十进制位拆分 396。396 除以 10 取余得 6这是百分位数字记为 C1396 整除 10 得 3939 除以 10 取余得 9这是十分位数字记为 C2396 整除 100 得 3这是整数位数字记为 C3。第三步把三个十进制位分别编码成 5421 码再移位拼接。C16 对应 0x06放在控制字最低 4 位C29 对应 0x0C左移 4 位变成 0x0C0C33 对应 0x03左移 8 位变成 0x300。三者按位或得到 12 位控制字 0x3C6二进制是 0011 1100 0110。# 幅值转 12 位控制字Python 版便于验证 def amplitude_to_code(a): b round(a * 100) # 放大 100 倍取整如 3.956 - 396 c1 b % 10 # 百分位 c2 (b // 10) % 10 # 十分位 c3 b // 100 # 整数位 # 5421 编码表权值 5-4-2-1 table [0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0xB, 0xC] code table[c1] | (table[c2] 4) | (table[c3] 8) return code print(hex(amplitude_to_code(3.956))) # 输出 0x3c6这段代码的逻辑是先放大取整消除小数再逐位拆十进制位然后查表得到每组 4 位 5421 码最后按位移动到对应的螺母位置。验证一下 0x3C6 实际接通的砖码bit1 对应 0.02Vbit2 对应 0.04Vbit6 对应 0.2Vbit7 对应 0.4Vbit8 对应 1Vbit9 对应 2V总和 3.96V正好是目标档位。4.3 送数程序复位、置数、时钟沿控制字算出来之后剩下的工作是通过 DATA 和 CLK 两根线把它送进移位寄存器。按论文源码的逻辑流程是先把寄存器复位然后从最低位开始逐位送数据每一位都先放好 DATA 电平再产生一个时钟上升沿让数据移入。论文给出的核心代码逻辑如下// Address 为 8255 C 口地址按论文定义C2 为 RD、C3 为 DATA、C4 为 CLK // 第一步复位移位寄存器 Outp(Address, 0x04); // RD 有效清空寄存器 Delay(0.01); Outp(Address, 0x05); // RD 释放寄存器可接收数据 Delay(0.01); // 第二步12 位控制字从低到高逐位送入 for (i 0; i 12; i) { if (bit[i] 1) { Outp(Address, 0x08); // CLK 拉低 Delay(0.01); Outp(Address, 0x07); // DATA 置 1 Delay(0.01); Outp(Address, 0x09); // CLK 拉高上升沿锁存 } else { Outp(Address, 0x08); // CLK 拉低 Delay(0.01); Outp(Address, 0x06); // DATA 置 0 Delay(0.01); Outp(Address, 0x09); // CLK 拉高上升沿锁存 } }这段代码的时序要点是“数据先就位时钟再跳变”先把 DATA 电平写稳定再拉高 CLK 产生上升沿数据在上升沿被移入寄存器。Delay(0.01) 用来保证 8255 位控操作和移位寄存器建立时间的余量PC-104 时代用软件延时最省事。要特别注意的是源码里端口数值和注释的对应关系在不同板卡上存在差异移植到自己的板卡时先逐位验证硬件连接再上真实控制字否则容易出现开关乱动的怪现象。4.4 把换算和送数串进控制面板流程实际测量时操作员在控制面板输入需要的激励幅值程序按 4.2 的步骤换算成 12 位控制字再按 4.3 的时序送数最后在 Vout 处得到对应幅值的 120Hz 正弦信号。整个过程是开环数字控制没有反馈回路换挡速度只受送数时间和输出稳定时间限制。按每步 Delay 0.01 秒估算一次换挡大约 0.15 秒对振动校准这种准静态场景完全够用。想提高换挡速度可以把延时压缩到移位寄存器数据建立时间的极限但必须实测确认这一步省不得。5. 避坑与排查精度、时序与编码五个高频翻车点5.1 小信号档幅值偏差大比例不对现象0.01V 到 0.1V 档位输出明显偏离目标值偏差方向不随档位线性变化切到 1V 以上档位时偏差变小。原因电子开关导通电阻有几十欧姆串在信号通路里参与分压。小信号档的累加电阻如果不够大导通电阻带来的相对误差会被放大档位越低越明显。解决按论文做法把加法器的反馈电阻和累加电阻都取到几十千欧让导通电阻占比降到千分之一以下。分压电阻用 0.1% 精度定制件。我一般会额外做一组实测短接开关量出加法器增益误差反过来修正编码表把小信号档的残余偏差再压掉一截。5.2 移位寄存器输出乱位某一路开关随机跳动现象送完 12 次数据后开关组合与预期控制字不符个别开关状态随机跳动或者整体错位一位。原因DATA 建立时间不足。8255 位控写完后电平刚变化马上拉时钟上升沿移位寄存器采到的是中间态或上一位的残留电平。另一个常见原因是循环次数与寄存器级数不匹配少送一位或多送一位。解决严格执行“先放 DATA再产生时钟沿”的顺序在数据写完之后、时钟沿之前留出稳定时间。循环次数固定为 12与三级 CT1194 的级数一致。调试时用一个已知控制字反复送用逻辑分析仪对比 Q1 到 Q12 的输出一眼就能看出是时序问题还是位序问题。5.3 用普通二进制直接编码只有部分档位正确现象幅值能被编码但某些档位的输出误差超过一个步进出现系统性偏差比如 0.09V 之后跳到 0.11V。原因把 0.01V 步进直接当作二进制位权来编码。这个方案的 12 位控制字内部是三组独立的 5421 码每组表示一个十进制位整个控制字不是普通 8421 二进制数。直接按二进制换算会在进位处产生错误组合。解决严格按照“幅值乘 100 取整拆成 C1、C2、C3分别 5421 编码移位拼接”的流程写函数。函数写完用 0.01、0.10、1.00、3.95、9.99 这几个特殊点做全流程测试重点看进位和边界档位。5.4 幅值随时间漂移小信号档尤其明显现象开机一段时间后固定档位的输出幅值缓慢变化0.01V 档的变化比例明显大于 10V 档。原因运放失调电压温漂、分压电阻温度系数、基准源长期漂移三者的叠加。小信号档本身只有毫伏级任何微小的直流漂移折算成相对误差都会被放大。解决用低漂移运放论文选 LM124 就是这个原因分压电阻选低温度系数的金属膜电阻。如果项目允许加法器后面加一级可控增益放大级微调档位用放大级补偿而不是继续细分砖码。5.5 输出波形上有毛刺像叠加了窄脉冲现象示波器看输出正弦波顶部或过零处出现很窄的毛刺失真度测量结果明显超过 1%。原因电子开关切换瞬间产生电荷注入时钟和数据的数字跳变通过电源或地耦合到模拟输出端。解决数字地和模拟地单点连接时钟线、数据线远离加法器输入电阻区域加法器反馈电阻两端并联一个几十皮法的补偿电容抑制高频尖峰。这一步论文没细写但在类似电路里几乎是必做的尤其是输出要接 FFT 分析时毛刺对失真度读数的影响非常大。6. 验证与扩展示波器 FFT 看失真再把方案搬到 STM326.1 验证失真度与幅值精度复现完成后验证重点是两个指标失真度不超过 1%幅值精度不超过 1%。用示波器的高分辨率 FFT 模式测输出看 120Hz 基波和 2、3、4 次谐波的幅度。总谐波失真 THD 用各谐波幅度平方和开根号再除以基波幅度计算只要 THD 小于 1% 就满足指标。测 0.01V 档时要注意示波器底噪通常把输入通道设成交流耦合并限制带宽或者加一级低噪声前置放大再测量。幅值精度用数字万用表或示波器测峰值分别取 0.01V、0.10V、1.00V、3.96V、10.00V 几个档位记录实测值和理论值对比。重点看一个档位切换到相邻档位时误差有没有跳变跳变超过一个步进多半是编码问题回头核对 5421 码表。6.2 移植到 STM32用 GPIO 重新实现送数时序原方案依赖 PC-104 和 8255今天复现大多数场景会换成单片机。砖码加法器和移位寄存器的结构完全可以保留把 8255 换成 MCU 的 GPIO把 CT1194 换成常见的 74HC595 串入并出移位寄存器两片级联就是 16 位容量只用低 12 位即可。送数时序和论文里完全一致// STM32 上用 GPIO 模拟 74HC595 移位输出控制 12 路电子开关 void send_amplitude_code(uint16_t code) { // code 是 12 位控制字比如 3.96V 对应的 0x3C6 for (int i 0; i 12; i) { // 先放数据从最低位开始 if (code (1 i)) GPIO_SetBits(GPIOB, DATA_PIN); else GPIO_ResetBits(GPIOB, DATA_PIN); delay_us(1); // 等待数据建立 GPIO_ResetBits(GPIOB, CLK_PIN); // CLK 拉低 delay_us(1); GPIO_SetBits(GPIOB, CLK_PIN); // CLK 拉高上升沿移入 delay_us(1); } }代码里的 code 是 12 位控制字移位顺序从最低位开始和论文“由低到高输入移位寄存器”的要求一致。换成 74HC595 后注意级联接法第一片的 Q7 接第二片的 DS两片共用 CLK。如果芯片带 OE 输出使能脚把 OE 接到 MCU 上等 12 位全部送完再使能输出开关切换时就不会出现中间状态。从那以后我每次做多路模拟开关的幅值控制第一件事就是画一张“位数—权值”映射表贴在原理图边上编码函数和送数函数都按这张表写再拿已知档位实测回读。希望帮到你。本文还有配套的精品资源点击获取