ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

微机原理接口:ADC0809与DAC0832的逐次逼近、时序与调试

微机原理接口:ADC0809与DAC0832的逐次逼近、时序与调试 做了这么多年微机原理与接口技术的实验带教A/D 与 D/A 转换器也就是常说的 ADA 转换器这一章翻车率是最高的没有之一。前面的 8255、8253、8259 实验只要连线照图插、代码照书敲基本都能跑出结果到了 ADC0809 和 DAC0832 这里同样是照抄示波器上可能什么都不显示或者读回来的数据永远钉在一个固定值上通道切来切去也没变化。问题在于前面那些实验是纯数字世界内部的事而 ADA 转换器是数字世界和模拟世界之间唯一的通道——一边讲电平、时序、参考源另一边讲端口地址、汇编指令、握手信号任何一侧理解偏了现象都会表现为没反应。这篇内容面向的是正在做微机接口实验的学生、需要把单片机或工控板上的模拟量接进来的嵌入式新手以及想重新把 AD/DA 这条链路捋清楚的从业者。我不会只给你一段能跑的代码而是把为什么要这么接这个参数是怎么算出来的读出来不对时该按什么顺序查这三件事讲透。代码用 8086 汇编写硬件按国内实验箱最常见的 ADC0809 DAC0832 8255 8253 组合来搭但里面关于时序、参考电压、地址译码的那些判断逻辑换个平台照样用。1. 为什么A/D、D/A转换是微机接口里最两面派的一章1.1 数字的世界与模拟的世界之间横着一堵墙CPU 只认高低电平它眼里的一切都是 0 和 1。而现实世界里的温度、压力、光照、声音全是连续变化的电压或电流。ADC 干的事是把连续切成离散用一串二进制数去近似表示某个瞬间的电压值DAC 干的事正好相反把一串二进制数还原成一个电压值。这两件事听起来简单但近似两个字里藏着全部的难点切得够不够细分辨率、切得多快转换速度、切得准不准精度。我一直觉得理解 ADA 转换器最好的切入点不是看芯片手册而是先想清楚一件事转换器本身是个哑巴它不会主动告诉你它什么时候在忙、什么时候忙完了。它只有几个引脚一个告诉你我开始转换了一个告诉你我转完了一个让你把结果拿走。所以接口设计的核心其实是设计一套我问你答的握手流程。CPU 通过端口地址去敲转换器的门转换器用状态引脚回话CPU 判断状态再取数据——这就是接口的全部含义。把这个逻辑想通了你会发现硬件接口和软件里的 API 接口是同一套思维调用方发起请求写端口、被调用方返回状态码读状态引脚、双方约定好数据格式几位的并行数据、还要考虑幂等性重复读会不会拿到脏数据。当年学接口定义、引脚定义时觉得枯燥后来做系统集成才发现这套先约定、再握手、后传数据的模式几十年没变过。1.2 我第一次做ADC0809实验时读回来全是0xFF说个真实的经历。我第一次做 ADC0809 采集实验接好线、烧完程序用调试器看内存里存的结果八个通道读回来全是 FF。当时第一反应是数据线接反了拔了重插还是 FF。又怀疑程序读错了端口把地址翻来覆去改了一遍依旧 FF。折腾了快两个小时最后发现问题出在两个地方一是我把 EOC 的查询极性判断反了程序在转换中的状态下就直接去读数了那时候数据总线是浮空的上拉电阻把它拉成了全 1二是参考电压的跳线帽没插VREF 悬空芯片压根没正常工作。这两件事后来成了我给学生强调最多的两条读数全是 FF 或全是 00八成不是数据线的问题而是根本没转换成功或者读的时机不对。数字电路里浮空输入被上拉成高电平是最常见的假象它看起来像数据全 1实际上意味着没有任何有效驱动。1.3 先把接口这件事想明白在动手写汇编之前我建议先把下面这张角色分工表在心里过一遍。很多同学一上来就写 IN/OUT 指令结果连谁控制谁都没搞清楚代码自然对不上硬件。角色负责什么对应引脚/信号CPU发起启动、查询状态、读取结果地址总线、控制总线、数据总线地址译码器把地址翻译成片选信号74LS138 等产生 CSADC把模拟量转成数字量START、EOC、OE、A/B/C8255给 CPU 提供并行的输入输出口PA、PB、PC8253提供转换所需的时钟OUT0看懂这张表你就明白为什么实验箱上的线那么多每一根线都对应一个谁问谁答的动作。少接一根 EOCCPU 就永远不知道转换结束了少接一根 OE数据就永远送不到总线上。2. ADC0809的内核逐次逼近到底是怎么猜出电压的2.1 用天平称重理解逐次逼近ADC 有好几种实现方式最常见的是逐次逼近型SAR和双积分型。ADC0809 属于前者。逐次逼近这个名字听着玄其实就是二分查找的硬件版。打个比方你有一堆砝码重量分别是 128g、64g、32g、16g、8g、4g、2g、1g要称出一个未知物体的重量。你会先把最重的 128g 放上去如果超了就拿下来如果不够就留着然后依次试 64g、32g……每试一次就确定结果的一个二进制位。8 个砝码试完就得到 8 位二进制结果。逐次逼近 ADC 内部就是这个逻辑一个 DAC、一个比较器、一个逐次逼近寄存器SAR。启动后SAR 从最高位开始置 1内部 DAC 把这个猜测值转成电压和输入电压比大小——猜大了就把这一位清 0猜小了就保留。8 位就是比 8 次转换结束SAR 里的值就是结果。理解了这一点你就能解释很多现象。比如输入电压刚好卡在两个量化级之间时结果会在这两个值之间跳动这叫量化抖动是原理决定的不是电路的毛病。再比如转换时间基本固定ADC0809 大约是 100 微秒跟时钟频率直接相关因为无论输入多大它都要老老实实比 8 次。2.2 分辨率、量化误差、转换时间三个参数怎么算这三个参数是选型和调试时绕不开的而且都能算不用死记。分辨率等于参考电压除以 2 的位数次方。ADC0809 是 8 位如果参考电压是 5V1 LSB 5V / 2^8 5V / 256 ≈ 19.53 mV也就是说输入电压每变化 19.53mV输出数字量才动一格。如果实验箱的输入电位器旋钮转了半天数字量才跳一下别怀疑芯片坏了是 8 位精度就这水平。量化误差是量化过程本身带来的误差最大值为 ±1/2 LSB也就是 ±9.77mV。它是原理性的无法消除只能通过提高位数或降低参考电压来减小。转换时间在 ADC0809 上由外部时钟决定。芯片手册给的典型时钟是 640kHz时钟越高转换越快但不能超上限。转换时间大约等于8 2个时钟周期含启动和输出延迟所以 640kHz 下大约是 100 微秒左右。这就回答了实验里一个常见疑问为什么我用查询方式采样频率上不去因为每次采样至少要等 100 微秒加上查询和存储的开销一秒钟能采几千次就不错了。想快就得上并行转换或者流水线结构。顺便说一句如果换成 12 位的 AD574分辨率一下子变成 5V/4096 ≈ 1.22mV量化误差也缩小到 ±0.61mV但转换时间、成本和接口复杂度都会上去。位数不是越高越好够用就行这个权衡在后面的章节还会展开。2.3 引脚分工与地址译码的配合ADC0809 有 28 个引脚但真正跟接口相关的不多我按功能分成四组电源组VCC、GND、VREF、VREF-、模拟输入组IN0 到 IN7 加 A、B、C 三个通道选择、数字输出组D0 到 D7带三态输出缓冲、控制组START、ALE、EOC、OE、CLK。A、B、C三位通道选择码000 选 IN0111 选 IN7一共 8 个通道。注意它们不只是选择还要配合 ALE 锁存。ALE地址锁存允许。上升沿把 A/B/C 锁进芯片。START启动转换。上升沿复位内部寄存器下降沿正式开始转换。EOC转换结束标志。转换中为低转换完成后变高——注意这个是高有效判断错极性是初学者最大的坑。OE输出允许。给高电平D0-D7 才把结果送到总线上。工程里最优雅的做法是把 ALE 和 START 并在一起由地址译码信号触发。这样 CPU 只要往对应端口执行一次写操作硬件就自动完成选中通道 锁存 启动三个动作软件上干净利落。具体做法是把地址总线的 A0、A1、A2 直接接到 ADC 的 A、B、C把高位地址译码后的信号接到 ALE 和 START。这样一来写 0E0H 就是采 IN0写 0E1H 就是采 IN1通道和地址一一对应代码可读性极高。很多教材采用另一种接法用 8255 的 PC0 到 PC2 输出通道号PC3 发 STARTPC7 读 EOC。这种接法更手工每一步都要软件干预调试时反而容易出错。两种都能用但我推荐前者——能用硬件干的事别交给软件这是接口设计里一条通用的原则。3. DAC0832从R-2R梯形网络到三种缓冲模式3.1 权电阻网络为什么被淘汰DAC 的核心任务是把二进制数变成电流或电压。最直观的实现是权电阻网络每一位对应一个电阻电阻值和这一位的权重成反比最高位电阻最小、电流最大所有支路电流加起来就是输出。8 位就需要 8 个阻值跨度 128 倍的电阻。听起来挺美实际做不出来。8 位要求电阻比值达到 128:112 位就是 2048:1在集成电路里根本没法保证精度——电阻的相对误差直接就变成了非线性误差。所以工程上几乎全用R-2R 梯形电阻网络整个网络只用两种阻值的电阻R 和 2R靠支路的串并联关系产生二进制权重。R-2R 的另一个好处是输出电流与数字量成正比关系非常干净Iout VREF × D / 256其中 D 是 8 位数字量0 到 255。这个公式是理解 DAC0832 的钥匙后面算输出电压全靠它。3.2 直通、单缓冲、双缓冲的选择逻辑DAC0832 内部有两个数据寄存器输入寄存器受 WR1 和 CS 控制和 DAC 寄存器受 WR2 和 XFER 控制还有一个 ILE 信号。这两个寄存器怎么用决定了它的三种工作方式。直通方式WR1、WR2 都接地ILE 接高电平两个寄存器相当于透明数据一到就转换。这种方式最简单适合用 8255 的某个口直接输出数据、实时更新波形的场景。缺点是 CPU 每次输出都会立刻改变模拟输出中间过程可能产生毛刺。单缓冲方式只让一个寄存器起作用另一个直通。数据先被一级锁存等 CPU 给个信号再更新输出。比直通稍微干净一点。双缓冲方式两个寄存器都用上数据先存进输入寄存器再由 XFER 信号搬到 DAC 寄存器。这种方式的价值在于可以同时更新多路 DAC 的输出。比如你要做多通道波束合成或者 XY 示波器图形两路 DAC 的输出必须严格同步如果每路单独直通更新中间会有时间差图形就会歪。双缓冲让两路都先把数据准备好然后一个信号同时放行输出就完全同步了。工作方式WR1/WR2 接法典型用途同步性直通都接地单路简单波形输出无同步概念单缓冲一级有效一级直通单路、需要一点缓冲一般双缓冲两级独立控制多路同步输出严格同步在接口实验里如果只是让 DAC 输出一个锯齿波或正弦波给示波器看直通或单缓冲就够了。但如果你想做两路 DAC 画一个圆那必须上双缓冲否则调出来的图形永远是个歪椭圆。3.3 数字量到电压的换算与运放接法DAC0832 输出的是电流IOUT1 和 IOUT2而且电流方向是从引脚往外流因为内部是电流沉结构所以必须接一个运放做 I/V 转换。标准接法是反相放大器IOUT1 接运放反相输入端IOUT2 接同相输入端并接地反馈电阻 RFB 接在输出和反相输入端之间。这样输出电压就是Vout -VREF × D / 256如果 VREF 接 5VD0 时输出 0VD255 时输出约 -4.98V输出是负的。想要正电压输出要么把 VREF 接负电压要么在运放后面再加一级反相。这个负号很有迷惑性。我见过不少人接完电路发现示波器上波形在零位以下第一反应是运放坏了其实是反相放大的必然结果。记住一句话DAC0832 配反相运放输入正参考电压输出就是负电压。想都不用想。另外还有一个细节DAC0832 的参考电压范围是 ±10V 到 ±25VVREF 引脚上是 -10V 到 10V 之间都可以但为了和 ADC 的参考电压一致、方便做回环实验DAC 输出接 ADC 输入通常统一取 5V。4. 汇编层驱动查询与中断两条路线的完整代码4.1 硬件连线与端口地址分配表先把地址分配定下来后面所有代码都基于这套地址。这套地址在国内实验箱上很常见你根据自己板子的译码电路改一下即可。器件端口地址用途8255 PA060H输入接 ADC 数据线 D0-D78255 PB061H输出接 DAC 数据线 DI0-DI78255 PC062HPC7 输入接 EOC其余备用8255 控制口063H写方式控制字8253 通道0040H分频产生 ADC 时钟8253 控制口043H写方式控制字ADC08090E0H - 0E7H通道 0 - 7写操作触发 ALESTARTDAC08320F0H写操作更新输出ADC 那边走的是地址即通道的接法地址低三位 A0-A2 接 ADC 的 A、B、C译码信号接 ALE 和 START读信号接 OEEOC 接 8255 的 PC7。这样一次 OUT 就完成了通道选择和启动一次 IN 就完成了数据读取。4.2 8255与8253的初始化8255 的方式控制字要这么定A 口方式 0 输入接收 ADC 数据B 口方式 0 输出送给 DACC 口高四位输入PC7 读 EOCC 口低四位输出备用。把控制字的位拆开算D71方式设置标志D6D500A 组方式 0D41A 口输入D31C 口高四位输入D20B 组方式 0D10B 口输出D00C 口低四位输出。拼起来就是10011000B也就是98H。8253 用来给 ADC 提供时钟。假设实验箱给的是 2MHz 时钟源ADC0809 希望工作在 500kHz 左右那么计数初值 2MHz / 500kHz 4。通道 0 用方式 3方波发生器最合适因为方波占空比接近 50%适合做转换时钟。控制字同样拆位SC1SC000选通道 0RL1RL011先读写低字节再读写高字节M2M1M0011方式 3BCD0二进制计数。拼起来是00110110B即36H。; ; 初始化8255 8253 ; 8255: PA输入, PB输出, PC高四位输入, PC低四位输出 ; 8253: 通道0 方式3, 计数初值4 (2MHz - 500kHz) ; INIT_IO PROC ; ---- 8255 初始化 ---- MOV DX, 063H MOV AL, 98H OUT DX, AL ; ---- 8253 通道0 初始化 ---- MOV DX, 043H MOV AL, 36H ; 通道0, 方式3, 二进制 OUT DX, AL MOV DX, 040H MOV AL, 04H ; 低字节 4 OUT DX, AL MOV AL, 00H ; 高字节 0 OUT DX, AL ; 8255 控制字已经写了, PC0 复位一下避免残留电平 MOV DX, 062H MOV AL, 00H OUT DX, AL RET INIT_IO ENDP注意 8253 写计数值的顺序控制字里 RL1RL011 表示 16 位读写先低字节后高字节这个顺序绝对不能颠倒。颠倒了的后果是计数器初值变成 1024时钟频率直接掉到 2kHzADC 转换慢得像蜗牛你还以为是程序卡死了。4.3 查询EOC采集8个通道查询方式的核心是先启动、再等 EOC 变高、最后读数据。这个顺序一步都不能乱。很多人写反了先读再启动读回来的自然是没有意义的残值。; ; 采集指定通道, 结果返回在 AL ; 入口: BL 通道号 (0-7) ; SAMPLE PROC PUSH DX PUSH BX ; ---- 第一步: 启动转换 ---- MOV AL, BL MOV DX, 0E0H ADD DX, AX ; 0E0H 通道号 OUT DX, AL ; 写操作产生 ALE START ; ---- 第二步: 等待 EOC 变高 ---- WAIT_HERE: MOV DX, 062H IN AL, DX TEST AL, 80H ; 检查 PC7, 即 EOC JZ WAIT_HERE ; EOC0 表示还在转换, 继续等 ; ---- 第三步: 读取转换结果 ---- MOV DX, 0E0H ADD DX, BX IN AL, DX ; 数据经 8255 PA 送回 POP BX POP DX RET SAMPLE ENDP这段代码有三个细节值得说。第一OUT DX, AL里的 AL 值其实无所谓因为启动信号是由写操作产生的数据线上是什么不影响。这一点和很多人的直觉相反——他们以为写进去的是通道号实际上通道号已经由地址线决定了数据总线在这里只是陪跑。第二TEST AL, 80H之后用JZ而不是JNZ原因就是前面说的 EOC 高有效。EOC 为低说明还在转换所以要一直循环等待。如果你板子上的 EOC 接的是反相后的信号这里就得改成JNZ。这是最容易错的地方务必拿万用表量一下 EOC 在转换前后的电平。第三这个查询循环是死等期间 CPU 什么也干不了。8 通道依次采集一遍大约需要 8×100μs 0.8ms这段时间 CPU 完全被占用。如果系统里还有别的事要干就得改用中断方式。中断方式的做法是把 EOC 经过 8259 接到 CPU 的 INTR转换结束时触发中断中断服务程序里读数据。这样 CPU 在等待期间可以做别的事情。不过中断方式在实验里调试起来麻烦得多涉及 8259 的初始化、中断向量表填写、中断结束命令稍微错一处就进不了中断。我的建议是先把查询方式调通确认硬件链路没问题再换中断方式否则你分不清是硬件问题还是中断配置问题。4.4 用DAC输出锯齿波与正弦波DAC 这边就简单多了写一次端口就更新一次输出。先看锯齿波; ; 输出锯齿波, 幅度 0 - 255 ; SAWTOOTH PROC NEXT_STEP: MOV DX, 0F0H OUT DX, AL ; 输出当前值 INC AL ; 累加 ; ---- 软件延时, 控制输出频率 ---- PUSH CX MOV CX, 30 DLY: LOOP DLY POP CX JMP NEXT_STEP SAWTOOTH ENDP频率可以算出来256 个台阶每个台阶的耗时包括一次 OUT、一次 INC、一次压栈出栈加 30 次 LOOP。8086 上 LOOP 指令大约 17 个时钟周期30 次就是 510 个周期加上其他指令算 560 个周期。如果 CPU 主频 5MHz每个台阶约 112μs256 个台阶就是一个完整周期大约 28.7ms对应频率约35Hz。示波器上应该能看到一个还不错的锯齿波。想调频率就改延时循环的计数初值非常简单。如果要输出正弦波就不能靠累加了得预先算好一张 256 点的正弦表存在内存里然后依次查表输出; ; 查表输出正弦波 ; SINE_TAB 为 256 字节的正弦采样表 ; SINE_OUT PROC LEA SI, SINE_TAB MOV CX, 256 PLAY: MOV AL, [SI] MOV DX, 0F0H OUT DX, AL INC SI PUSH CX MOV CX, 20 DLY2: LOOP DLY2 POP CX LOOP PLAY RET SINE_OUT ENDP正弦表怎么生成用 Python 或 Excel 算一遍就行公式是D 128 127 × sin(2πi/256)i 从 0 到 255取整后写成一串 DB 数据。注意要把结果限制在 0 到 255 之间负数和高位溢出会让波形顶部被削平。这里有个实测经验查表输出的正弦波频率不能太高。因为 CPU 是一条一条指令搬数据的256 个点搬完要花不少时间加上延时能做到几百赫兹就不错了。想要高频正弦波得靠硬件 DDS 或者专用波形发生器芯片靠软件搬数据是有物理上限的。5. 上电没反应按这个顺序往下查5.1 先看参考电压和转换时钟这是我排查 ADA 电路的第一站没有例外。因为这两样东西一旦出问题所有现象都是什么都读不到。参考电压怎么查万用表量 VREF 和 VREF- 之间的电压ADC0809 应该是 5V 左右或你设计的值。如果量出来是 0V 或者飘忽不定检查跳线帽、检查供电。VREF 悬空的时候芯片内部的比较器没有基准逐次逼近的结果完全随机表现出来就是读回来的数在乱跳。转换时钟怎么查用示波器量 ADC0809 的 CLK 引脚应该有稳定的方波。如果没有波形先量 8253 的 OUT0 有没有输出再量 8253 的 CLK0 有没有输入。我遇到过一种情况8253 的时钟源引脚接的是实验箱上一个没使能的输出示波器上看是一条直线折腾了半天才发现是跳线问题。时钟这条链路要一节一节往前量别跳步。如果时钟是有的但频率明显不对八成是 8253 的计数初值写错了回头检查高低字节的写入顺序。5.2 EOC极性判断错导致的死循环现象是程序卡在查询循环里出不来或者读回来的数据是固定值。这两个现象的根因其实是同一个EOC 的状态判断错了。正确做法是拿示波器同时看 START 和 EOC 两个信号。启动时应该能看到 START 上一个负脉冲随后 EOC 从高变低保持大约 100μs然后回到高。如果你的 EOC 是反的比如中间加了反相器那查询条件就得反过来写。还有一种情况是 EOC 一直保持高程序一次都不等就往下走读回来的是上一次的残值或者浮空值。这说明转换根本没启动往两个方向查一是 START 信号有没有真正产生示波器量二是 ALE 有没有正常锁存通道号。一个实用的小技巧在查询循环里加一个计数上限超时就跳出并置一个错误标志。这样程序不会永远卡死你能从错误标志判断是转换没完成还是别的问题比盯着一个卡住的调试器强得多。5.3 数据总线冲突与地址译码的重叠ADC 的三态输出、8255 的输出、DAC 的输入都挂在同一条数据总线上。如果它们的片选信号在地址上重叠了就会出现两个器件同时说话总线电平被拉成一个中间值读回来什么都有可能。典型的错误是地址空间划分得太紧。比如 ADC 占了 0E0H 到 0E7H而 8255 用的是 060H 到 063H这本来不冲突。但如果地址译码器只接了部分高位地址线实际会把多个地址段映射到同一个器件上看上去不冲突的地址其实重叠了。排查方法很土但很有效把可疑地址逐个写数据用示波器看对应的片选引脚会不会动作。如果两个不同地址都让同一个芯片的 CS 变低那就是地址译码有重叠。解决方法是把地址线接全或者用 74LS688 之类的比较器做更精确的译码。另外ADC 的三态输出必须由 OE 控制OE 不有效时它是高阻态这时候数据总线该由别的器件驱动或者由上拉电阻保持。如果上拉电阻没焊总线浮空读回来就是随机的而且每次还不一样。5.4 几个看着没问题的隐性坑下面这些坑的共同特点是电路图上看不出问题但实际就是不工作。第一个坑8255 的口在不同实验箱上地址基准不一样。有的板子 PA 是 060H有的是 280H有的是 300H。写代码前一定要对着板子上的丝印或者手册确认别照抄别人的地址。第二个坑ADC0809 的模拟输入悬空。空着的输入通道会感应周围的电场读回来的值随机跳动。如果只用一个通道其他不用的通道最好接地或者接一个固定电压。第三个坑DAC 运放的供电。运放需要正负双电源如果只给了正电源负半周输出会被削平波形看起来像是被切了一刀。这个现象在示波器上非常明显看到削顶先量运放供电。第四个坑输入信号超出量程。ADC0809 的输入范围是 0 到 VREF如果输入信号带了负电压芯片内部的保护二极管会导通轻则读数错乱重则烧芯片。加一个限流电阻和钳位二极管是最稳妥的做法。6. 从实验箱走向工程精度、速度与成本的三角6.1 软件过采样与均值滤波实验里采一个值就够了真实产品里一个值根本不能用——噪声会让相邻两次采样差出好几个 LSB。最经济的解决办法是软件滤波不需要改硬件。最简单的是算术平均连续采 16 次求和后右移 4 位。这个操作在汇编里就是 16 次读加一个移位开销很小但能把随机噪声压下去大约 4 倍噪声按 √N 衰减。代价是等效采样率降到原来的 1/16。再进一步是过采样加抽取。如果你的 ADC 是 12 位但系统只需要 10 位有效数据那就可以用 16 倍过采样加平均理论上能把有效位数提高 2 位等效于用 12 位的硬件做出了 14 位的分辨率。这个技巧在低成本的单片机上特别实用原理是白噪声在平均过程中会互相抵消而真实信号不会。需要注意的是过采样只对随机噪声有效。如果噪声是周期性的干扰比如电源纹波平均多少次都消不掉反而可能因为采样时刻固定而把干扰固化下来。这种情况要么在硬件上滤掉要么让采样时刻随机抖动一下。滤完波记得做校准。至少做两点校准输入端接 0V 采一组接满量程采一组算出增益和偏移写进程序里做线性修正。这一步能把芯片本身的偏移误差和增益误差消掉大半成本几乎为零。6.2 参考源与地平面的处理很多人以为精度完全取决于 ADC 的位数其实参考电压的质量才是天花板。ADC 的转换结果本质上是在和参考电压比较参考电压如果本身在抖结果再好也好不到哪去。实验箱上用的大多是普通的稳压源纹波在毫伏级。换到 12 位以上的应用这个纹波就已经超过 1 个 LSB 了。工程上的做法是给参考源单独供电、单独布线、加上大电容和小电容并联去耦。所谓分开数字地和模拟地也是同一个道理数字电路的开关噪声会通过地线耦合到模拟部分把最后几位的精度吃掉。具体做法是在 PCB 上把地分成数字地和模拟地两块中间只在一个点用磁珠或 0 欧电阻连起来。ADC 的 AGND 接模拟地DGND 接数字地。这个细节在小信号采集里是决定性的实验阶段感受不到一旦上到工业现场不做这个分离就会出各种莫名其妙的漂移。还有一个常被忽略的点ADC 的输入阻抗。逐次逼近型 ADC 的输入是一个开关电容网络采样瞬间会从信号源抽一小股电流。如果信号源的内阻太大这个电流会让输入电压瞬间塌下去采到的是错的。解决办法是在前面加一个电压跟随器运放缓冲把高阻信号变成低阻驱动。6.3 采样保持器什么时候必须加采样保持器S/H的作用是在转换期间冻结输入电压。逐次逼近 ADC 需要大约 100μs 来完成 8 次比较如果在这段时间里输入电压一直在变那就相当于每次比较用的都是不同的值结果是错的。什么时候必须加判断标准是看输入信号在转换时间内变化了多少。如果变化量超过 1/2 LSB误差就不可接受了。举个例子一个 8 位 ADC参考 5V1 LSB 是 19.53mV转换时间 100μs。假设输入是正弦波允许的最大变化率是 19.53mV / 100μs ≈ 195 V/s。对一个幅度 5V 的正弦波最大斜率是 2πfA代入 5V 幅度解出 f ≈ 6.2Hz。也就是说输入信号频率超过 6Hz理论上就需要采样保持器了。这个数字第一次算出来的时候挺吓人的但这就是 8 位、100μs 的硬件限制。实际使用中因为正弦波大部分时间斜率较小可以放宽到几十赫兹。所以后来的 ADC 芯片比如 ADC0804 的后续型号大多把采样保持电路集成进去了用起来省心。但如果你手上是老的 ADC0809采动态信号时一定要在前面加 S/H否则波形失真会非常明显。顺带说个接口设计上的联想法。软件里我们也会遇到类似的问题一个请求发出去了被调用方处理需要时间这段时间里如果请求参数被别的线程改了结果就乱了。解决思路和采样保持器一模一样——在进入临界区之前把数据快照一份。硬件的采样保持和软件的快照隔离本质上是同一个问题的两种表述这也是为什么我一直觉得接口这门课值得反复看它教的不是某个芯片而是一整套处理异步协作的方法论。如果你手上正好在做这个实验我的建议是别急着抄代码。先拿万用表把 VREF、CLK、EOC 三个点量一遍确认硬件链路是活的再写一个最简单的单通道采集把原始值打到数码管上转动电位器看数值有没有跟着变。这一步通了剩下的多通道扫描、波形输出、滤波校准都是在这个基础上加东西。我见过太多人一上来就想做完整的采集加显示加通信结果卡在最基础的时序上越调越乱。另外补一句不同实验箱的接线和地址差异很大本文的代码是基于地址即通道这种最干净的接法写的。如果你的板子是 8255 的 PC 口控制 START 和通道选择那 SAMPLE 过程里的启动部分要改成先输出通道号到 PC0-PC2再从 PC3 打一个启动脉冲等待和读取部分不用动。改的时候记得保持启动—等待—读取这个三段式结构不变顺序错了什么都白搭。
返回列表