基于砖码原理的高精度正弦信号源:0.01V步进实现与嵌入式控制
2026/9/23 16:53:00 网站建设 项目流程

简介:一份聚焦高精度正弦信号源设计的论文资料,适合从事信号检测、嵌入式测量系统及模拟激励单元开发的工程师参考。论文以某型飞机发动机参数检测系统的振动校准为背景,提出利用“砖码”组合原理,通过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 到 10V

2.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 码的权值顺序排列,组内最高位的权值是该组最大的那个砖码。

位序所属分组砖码权值
Q1(bit0)百分位0.01V
Q2(bit1)百分位0.02V
Q3(bit2)百分位0.04V
Q4(bit3)百分位0.05V
Q5(bit4)十分位0.1V
Q6(bit5)十分位0.2V
Q7(bit6)十分位0.4V
Q8(bit7)十分位0.5V
Q9(bit8)整数位1V
Q10(bit9)整数位2V
Q11(bit10)整数位4V
Q12(bit11)整数位5V

12 位控制字一共有 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 的权值相加就是它表示的十进制数。它和常用的 8421(BCD)码区别在于最高位权值是 5 而不是 8,这正好对应砖码分组里 5/4/2/1 的结构。

论文的表 1 给出了十进制数到 5421 码的转换规则。以论文给出的三个转换结果为例:十进制 3 对应 0x03,组合是 2+1;十进制 6 对应 0x06,组合是 4+2;十进制 9 对应 0x0C,组合是 5+4。也就是说,编码时把一个十进制数拆成 5、4、2、1 四个权值的和,对应位置 1,其余位清 0 即可。少数数字存在多种拆法,比如 5 可以是 5+0,也可以是 4+1,这类歧义位要由表 1 固定下来,保证编码唯一。

十进制数5421 码(4 位,权值 5-4-2-1)
00000
10001
20010
30011
40100
50101
60110
70111
81011
91100

注意:这张表里 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,这是百分位数字,记为 C1;396 整除 10 得 39,39 除以 10 取余得 9,这是十分位数字,记为 C2;396 整除 100 得 3,这是整数位数字,记为 C3。

第三步,把三个十进制位分别编码成 5421 码再移位拼接。C1=6 对应 0x06,放在控制字最低 4 位;C2=9 对应 0x0C,左移 4 位变成 0x0C0;C3=3 对应 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.02V,bit2 对应 0.04V,bit6 对应 0.2V,bit7 对应 0.4V,bit8 对应 1V,bit9 对应 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 看失真,再把方案搬到 STM32

6.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 位全部送完再使能输出,开关切换时就不会出现中间状态。

从那以后我每次做多路模拟开关的幅值控制,第一件事就是画一张“位数—权值”映射表贴在原理图边上,编码函数和送数函数都按这张表写,再拿已知档位实测回读。希望帮到你。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询