第一次把DAC0832插上面包板时,我以为8位D/A转换就是“数据写进去、模拟电压出来”这么简单。等到示波器探针往输出端一放,才发现满屏毛刺,数值也根本对不上代码里算好的预期。折腾了一个晚上,最后老老实实把手册里的引脚功能一条条对着电路板梳理,又把直通、单缓冲、双缓冲这三种工作模式的锁存逻辑彻底想通,输出才终于稳定下来。这篇教程就按我自己的踩坑顺序来写:先从内部原理讲清楚这块芯片怎么工作,再逐个引脚说明接线要点,接着把三种工作模式拆开揉碎,最后给出一套可以直接抄的电路、代码,以及实测中经常踩到的坑。适合正在做单片机课设的学生、想自己搭波形发生器的电子爱好者,以及第一次接触并行DA芯片的入门工程师。
1. 为什么到今天还要玩DAC0832:先搞清楚它解决什么问题
1.1 数模转换在信号链里的定位
单片机算出来的东西永远是二进制数字量,但现实世界里的电压、电流、声音是连续变化的模拟量。DAC(数模转换器)就是干这个桥接工作的:给它一个数字码,它输出一个对应的模拟电流或电压。DAC0832是目前教材里出现频率最高的并行8位DA芯片之一,结构典型,价格便宜,非常适合用来理解DAC的基本原理。
它和现在MCU自带的12位、16位DAC相比,有个非常明显的特点:并行输入。数据D0-D7共8根线,一次直接送一个字节过来,不需要像I2C或SPI那样一位一位串行传输。这个特性带来的好处是更新速度快,只要你把数据放到引脚上,芯片就能响应;代价也很直接,占用IO口数量多,8根数据线加4-5根控制线,一个最小系统就吃掉大半个单片机的引脚。
另一个容易忽略的关键点是:DAC0832是电流输出型DAC,不是电压输出型。它输出的是一对互补电流IOUT1和IOUT2,想要得到电压信号,必须外加运算放大器做电流电压转换。很多新手一上来就拿着万用表去测IOUT引脚对地电压,那测出来的是一个随负载随便飘的值,根本不能说明问题。这个点后面会单独用一节来讲。
1.2 内部结构:R-2R电阻网络的二进制电流分配
DAC0832能实现数模转换的核心,是内部的R-2R梯形电阻网络。这个名字很形象,整个网络只用了两种阻值的电阻,一种是R,一种是2R,按“梯形”的结构排开。每个二进制位控制一个电子开关,开关决定这一位的电流是流向IOUT1还是IOUT2。
当8位数据进来时,每一位对应的电流权重是不一样的。最高位D7贡献满量程的一半,D6贡献四分之一,D5贡献八分之一,以此类推,最低位D0只贡献满量程的1/256。这正好就是二进制权重。最终IOUT1的电流可以写成:
IOUT1 = (D / 256) × (VREF / R)
其中D是0到255的数字码,R是内部梯形网络的等效电阻。VREF是参考电压,它直接决定满量程电流大小。所以VREF必须稳定、干净,因为输出电流是直接跟它成比例的,参考电压上的一点点纹波,最后都会按系数传到模拟输出上。
芯片内部还有一组非常巧妙的结构:两级锁存器。第一级叫输入寄存器,第二级叫DAC寄存器,两级之间由控制信号分开。正是因为有了这两个独立的锁存器,DAC0832才能玩出直通、单缓冲、双缓冲三种工作模式。很多人学这个芯片时只记住了三种模式的名字,却不明白为什么需要两个锁存器,等到后面讲模式时你会看到,双缓冲模式下第二级锁存器是用来实现“多路同时更新”的,这在控制多路输出时非常重要。
1.3 主要性能指标怎么看
看DAC芯片,先抓几个指标就够了:
| 指标 | DAC0832典型值 | 说明 |
|---|---|---|
| 分辨率 | 8位 | 输出满量程的1/256为一个台阶 |
| 建立时间 | 约1μs | 数据更新后输出稳定到这个精度需要的时间 |
| 参考电压VREF | -10V到+10V | 可以是负电压,也可以正电压 |
| 电源VCC | +5V到+15V | 供电范围宽,但逻辑阈值也随之变化 |
| 功耗 | 约20mW | 非常省电 |
| 输出形式 | 互补电流IOUT1/IOUT2 | 需要外部运放转电压 |
分辨率8位意味着什么?如果VREF接5V,那么理想情况下每个最小台阶对应5V除以256,约19.5mV。也就是说,你写0x00输出理论上是0V(实际上有一个很小的失调),写0x01输出约19.5mV,写0xFF输出约4.98V,永远到不了完整的5V。这个“永远到不了满量程”的特性经常让新手困惑,但这是R-2R梯形网络的正常现象,不是芯片坏了。
建立一个直观概念:8位精度做波形发生器、电机调速、模拟电压输出完全够用;但要是做精密电源、音频高保真输出,8位就不太够看了,最好换12位或16位的DA芯片。DAC0832的价值更多在教学、实验和对并行时序的理解上。
2. 逐脚核对:DAC0832引脚功能与接线前的电路设计
DAC0832常见封装是DIP20,一共有20个引脚。第一次用这块芯片时,我犯过一个很蠢的错误:把ILE当成“锁存使能”,以为要拉低才能锁存数据。实际上ILE的全称是Input Latch Enable,高电平有效,它配合CS和WR1共同控制第一级寄存器。单看名字很容易搞反,这也是为什么我建议先把引脚功能表打印出来放旁边。
2.1 20个引脚完整对照表
| 引脚号 | 名称 | 类型 | 功能 | 特别注意 |
|---|---|---|---|---|
| 4-7, 13-16 | DI0-DI7 | 数字输入 | 8位并行数据输入 | DI0是最低位,DI7是最高位 |
| 17 | ILE | 数字输入 | 输入锁存使能 | 高电平有效,常接5V |
| 1 | CS | 数字输入 | 片选 | 低电平有效,与WR1配合 |
| 2 | WR1 | 数字输入 | 第一级写信号 | 低电平有效,上升沿锁存 |
| 18 | WR2 | 数字输入 | 第二级写信号 | 低电平有效,上升沿锁存 |
| 19 | XFER | 数字输入 | 传输控制 | 低电平有效,控制第二级 |
| 8 | VREF | 模拟输入 | 参考电压 | 决定满量程电流,需干净稳定 |
| 9 | RFB | 模拟反馈 | 内部反馈电阻引出 | 配合运放做电流电压转换 |
| 11 | IOUT2 | 模拟输出 | 互补电流输出2 | 常接运放或地 |
| 12 | IOUT1 | 模拟输出 | 主电流输出1 | 与D/256成正比 |
| 3 | AGND | 模拟地 | 模拟地 | 与DGND单点连接 |
| 10 | DGND | 数字地 | 数字地 | 与AGND单点连接 |
| 20 | VCC | 电源 | 正电源 | +5V到+15V,需去耦电容 |
2.2 数字侧引脚:控制信号之间的逻辑关系
数字侧除了8根数据线,还有5根控制线:ILE、CS、WR1、WR2、XFER。它们的逻辑关系并不复杂,但很多人搞不清“谁和谁是一组”。
第一组是第一级输入寄存器的控制信号:ILE、CS、WR1。只有当ILE=1、CS=0、WR1=0三者同时满足时,数据线上的值才能进入第一级寄存器;当WR1从0变成1(上升沿)时,当前数据被锁存住,之后数据线再怎么变化,都不会影响里面保存的值。
第二组是第二级DAC寄存器的控制信号:WR2、XFER。类似地,XFER=0、WR2=0时,数据从第一级寄存器传到第二级;WR2上升沿时锁存。
这里有个特别容易混淆的地方:芯片型号里的0832,很多人会以为“写数据”只需要控制WR1就行,把CS直接接地。实际上CS也必须保持低电平,否则第一级寄存器根本不响应。我在面包板上调试时就遇到过这种问题:单独给WR1打脉冲,输出纹丝不动,查了半天才发现CS被悬空了,处于不确定电平。
2.3 模拟侧引脚:IOUT、RFB、VREF的配合关系
模拟侧是DAC0832真正的灵魂,也是最容易出问题的地方。前面说了,它是电流输出型,IOUT1和IOUT2是一对互补电流,两者的和始终等于满量程电流。当D=0x00时,IOUT1为0,IOUT2为满量程;当D=0xFF时,IOUT1接近满量程,IOUT2接近0。如果直接拿万用表量IOUT1对地电压,得到的是电流流过你万用表内阻和寄生电阻后的结果,既不准确也不线性。
标准做法是接一个运算放大器,把电流转成电压。最简单可靠的是反相放大器接法:运放反相输入端接IOUT1,同相输入端接模拟地AGND,IOUT2直接接AGND,RFB引脚接到运放反相输入端和输出端之间,利用芯片内部的反馈电阻完成电流电压转换。这时输出:
VOUT = -(D / 256)× VREF
注意这个负号。如果VREF接+5V,输出就是0到-5V的负电压。想要正电压输出,有两种办法:一是把VREF换成-5V参考电压;二是在后面再串一级反相放大器,把负电压翻成正电压。很多实验板上直接标着“0-5V输出”的接线图,实际上是两级运放或者用了负参考电压,看电路图时要留意。
VREF的范围是-10V到+10V,它既可以是正也可以是负,这就让DAC0832天然支持双极性输出。配合外部运放可以做成正负电压摆动的信号源,比如输出-5V到+5V的扫频信号。
3. 三种工作模式逐层拆解:直通、单缓冲、双缓冲
DAC0832之所以能在教科书里占据一席之地,很大程度上就是因为这三个工作模式把锁存器的概念讲得特别清楚。说白了,三种模式的差别就是两级寄存器分别处于“透明状态”还是“锁存状态”。
3.1 直通模式:数据进去,输出马上变
直通模式是所有模式里最简单的。把ILE接高电平,CS、WR1、WR2、XFER全部接低电平,这时两级寄存器全部处于透明状态,数据线上的8位数据直接作用于内部的R-2R网络,IOUT1电流跟前一秒数据线的值严格对应。
直通模式的优点是响应极快,没有任何锁存延迟。只要数据线电平变了,输出马上就变。缺点也很致命:如果单片机总线上有其他操作,或者数据线本身有抖动,这些毛刺会毫无保留地直接传进模拟输出。另外这种方式不适合“先准备好数据、再统一更新”的场景。
直通模式的软件最简单,代码都不用专门初始化控制引脚:
#include <reg51.h> sbit DAC_ILE = P2^4; sbit DAC_CS = P2^0; sbit DAC_WR1 = P2^1; sbit DAC_WR2 = P2^2; sbit DAC_XFER = P2^3; void dac_pass_through_init(void) { DAC_ILE = 1; DAC_CS = 0; DAC_WR1 = 0; DAC_WR2 = 0; DAC_XFER = 0; } void main(void) { unsigned char i = 0; dac_pass_through_init(); while (1) { P0 = i++; // 数据直接出现在模拟输出端 // 不加延时的话,输出频率会非常高 } }3.2 单缓冲模式:最常见的实用配置
单缓冲模式的意思是:两级寄存器中只使用一级做锁存,另一级保持直通。实践中绝大多数人用的是“第一级锁存、第二级直通”的接法:ILE接高电平,WR2接低,XFER接低,然后通过CS和WR1控制数据的写入。
在这种配置下,数据线变化时不会立刻影响模拟输出。必须等WR1产生一个上升沿,数据才被锁存进第一级寄存器,并且马上穿过第二级透明通道到达DAC核心。这个模式的好处是:可以先把数据准备好,再触发写脉冲,避免数据线中间过程的毛刺被输出。写时序也更符合“处理器先算好后赋值,再产生写信号”的习惯。
51单片机上的单缓冲操作:
#include <reg51.h> #include <intrins.h> #define DAC_DATA P0 sbit DAC_CS = P2^0; sbit DAC_WR1 = P2^1; sbit DAC_WR2 = P2^2; sbit DAC_XFER = P2^3; sbit DAC_ILE = P2^4; void dac_init(void) { DAC_ILE = 1; DAC_WR2 = 0; // 第二级直通 DAC_XFER = 0; // 第二级直通 DAC_CS = 1; DAC_WR1 = 1; } void dac_write(unsigned char val) { DAC_CS = 0; // 选中芯片 DAC_WR1 = 0; // 第一级进入透明状态 DAC_DATA = val; // 数据放到总线上 _nop_(); _nop_(); DAC_WR1 = 1; // 上升沿锁存数据 DAC_CS = 1; // 释放片选 } void main(void) { unsigned char i = 0; dac_init(); while (1) { dac_write(i++); // 输出0到255循环,形成锯齿波 } }注意P0口在51单片机上是开漏输出,如果直接用P0接DAC0832的数据线,必须在P0上接一排上拉电阻(比如10kΩ排阻到5V),否则高电平是浮空的。这个问题在51实验板上非常常见,DAC输出波形奇怪,先检查P0口上拉。
3.3 双缓冲模式:多路同步更新的关键
双缓冲模式才是DAC0832真正的精髓。
先想象一个场景:你想用一个单片机控制两块DAC0832,分别输出正弦波和余弦波,并且要求两路信号在同一个瞬间完成跳变。如果只用单缓冲,你只能先写DAC1,再写DAC2,这两次写入之间隔了几条指令的时间,输出会有时间差。对于需要严格相位关系的场合,这个时间差是不能接受的。
双缓冲模式解决这个问题的方式是:把两级寄存器都用起来。先分别把两路数据写进各自的输入寄存器(第一级锁存),此时DAC寄存器(第二级)里的旧数据还维持着原来的输出,模拟输出没有变化。等两路数据都装填好了,再统一给XFER发一个低脉冲,两块芯片的第二级同时锁存新数据,模拟输出就在同一个时刻完成切换。
这就是为什么需要两级锁存器。第二级不是多余的,它是为了“多路DAC同步刷新”而设计的。单缓冲模式下第二级直通,看似浪费,其实只是没有用到它的同步能力而已。
双缓冲模式下STM32的模拟时序:
// 假设数据线接PC0-PC7 // 控制线:PB0=CS1, PB1=WR1_1, PB2=CS2, PB3=WR1_2 // PB4=WR2(共用), PB5=XFER(共用), PB6=ILE(共用) #define DAC1_CS_L() GPIOB->BRR = GPIO_PIN_0 #define DAC1_CS_H() GPIOB->BSRR = GPIO_PIN_0 #define DAC1_WR_L() GPIOB->BRR = GPIO_PIN_1 #define DAC1_WR_H() GPIOB->BSRR = GPIO_PIN_1 #define DAC2_CS_L() GPIOB->BRR = GPIO_PIN_2 #define DAC2_CS_H() GPIOB->BSRR = GPIO_PIN_2 #define DAC2_WR_L() GPIOB->BRR = GPIO_PIN_3 #define DAC2_WR_H() GPIOB->BSRR = GPIO_PIN_3 #define DAC_XFER_L() GPIOB->BRR = GPIO_PIN_5 #define DAC_XFER_H() GPIOB->BSRR = GPIO_PIN_5 void dac_load(uint8_t val, uint8_t ch) { GPIOB->BRR = GPIO_PIN_6; // ILE拉低,先不使能 if (ch == 1) { DAC1_CS_L(); DAC1_WR_L(); GPIOC->ODR = (GPIOC->ODR & 0xFFFFFF00) | val; DAC1_WR_H(); // 锁存到第一级 DAC1_CS_H(); } else { DAC2_CS_L(); DAC2_WR_L(); GPIOC->ODR = (GPIOC->ODR & 0xFFFFFF00) | val; DAC2_WR_H(); DAC2_CS_H(); } GPIOB->BSRR = GPIO_PIN_6; // ILE拉高,使能 } void dac_sync(void) { DAC_XFER_L(); DAC_XFER_H(); // 两路第二级同时锁存 }双缓冲模式的接线要求是:两块芯片的数据线和控制线可以分别连接,但XFER往往会并在一起,这样一次低脉冲就能同时刷新多块DAC。
三种模式的对比,用一张表总结会比较直观:
| 模式 | ILE | CS | WR1 | WR2 | XFER | 数据更新机制 | 适用场景 |
|---|---|---|---|---|---|---|---|
| 直通 | 1 | 0 | 0 | 0 | 0 | 数据线直接进DAC核心 | 实时连续输出,教学演示 |
| 单缓冲 | 1 | 0 | 脉冲 | 0 | 0 | 数据先锁存第一级,第二级直通 | 单路普通DAC输出 |
| 双缓冲 | 1 | 0 | 脉冲 | 脉冲 | 脉冲 | 数据先写第一级,XFER统一到第二级 | 多路同步输出,波形合成 |
4. 从零搭一套可用的DAC0832最小系统
理论讲完,该动手了。这里给出一套我实际用过的最小系统方案,元件都很常见,面包板或者洞洞板都能搭起来。
4.1 硬件清单与选型说明
| 元件 | 型号/规格 | 数量 | 用途 |
|---|---|---|---|
| DAC0832 | DIP20封装 | 1 | 核心DA芯片 |
| 运算放大器 | TL081或LM358 | 1 | 电流电压转换 |
| 51单片机或STM32开发板 | 任意 | 1 | 输出数据和控制信号 |
| 精密基准源 | TL431或REF3025 | 1 | 提供稳定VREF |
| 电阻 | 10kΩ排阻或分立的1kΩ-10kΩ | 若干 | P0上拉、基准分压 |
| 电容 | 100nF瓷片电容 | 2-3 | 电源去耦 |
| 面包板/洞洞板 | - | 1 | 搭电路 |
运放选型上,TL081是经典的FET输入运放,输入偏置电流很小,配合DAC0832的高阻输出很合适;如果手头只有LM358也能工作,只是高端线性略差一点。面包板搭电路时,运放供电需要双电源的话会比较麻烦,可以直接用单电源LM358,输出范围大约0到3.5V,够验证功能。想要完整0到5V输出,最好给运放提供正负电源,比如正负5V或正负12V。
4.2 面包板接线要点:处理好地和电源再去碰信号
接线顺序很关键。我的习惯是先接电源和地,再接基准,最后接数据线和控制线。
VCC接5V,对地并一个100nF瓷片电容,放在芯片VCC引脚附近。AGND和DGND在芯片附近用一根导线单点连在一起,然后一起回到电源地。为什么要单点连接?因为数字信号跳变时会在数字地上产生很大的瞬态电流,如果模拟地和数字地走线混在一起,噪声会通过地线耦合到模拟电路。单点连接能让数字噪声尽量在数字地回路里消化,不污染模拟地。
注意数字信号线的走线尽量短,数据线和控制线不要和模拟输出线平行。面包板空间允许的话,在DAC芯片和IOUT输出之间留一点间隔。
4.3 电流转电压的两种运放接法
接法一:反相输出,VREF接正电压时输出0到负电压。
运放LM358(用双电源±5V) IOUT1 ----> 运放反相输入端(-) IOUT2 ----> AGND RFB ----> 运放输出端,同时也连接到反相输入端 运放同相输入端(+)接AGND这种接法输出VOUT = -(D/256)× VREF。VREF=+5V时,输出0到-5V。
接法二:两级运放翻正,输出0到+5V。
第一级运放同接法一,VOUT1 = -(D/256)× VREF 第二级运放做反相比例放大,放大倍数为-1,把VOUT1翻成正电压这个方法多用一个运放,但逻辑清晰、可调增益,我在万能板上测试时用的就是这种结构。
4.4 波形发生器实测:锯齿波、三角波、正弦波
电路搭好后,先别急着接反馈和控制线,把DAC调成直通模式,手动给数据线接一个固定电平(比如全部接地),用万用表量IOUT1转出来的电压,确认基本为零。再用手碰触一根数据线接高电平,电压应该跳一个台阶。这一步能快速排除接线错误。
确认基础功能后,写程序输出锯齿波:
#include <reg51.h> #include <intrins.h> sbit DAC_ILE = P2^4; sbit DAC_CS = P2^0; sbit DAC_WR1 = P2^1; sbit DAC_WR2 = P2^2; sbit DAC_XFER = P2^3; void delay_us(unsigned int us) { while (us--) _nop_(); } void dac_init(void) { DAC_ILE = 1; DAC_WR2 = 0; DAC_XFER = 0; DAC_CS = 1; DAC_WR1 = 1; } void dac_write(unsigned char val) { DAC_CS = 0; DAC_WR1 = 0; P0 = val; _nop_(); _nop_(); DAC_WR1 = 1; DAC_CS = 1; } void main(void) { unsigned char i = 0; dac_init(); while (1) { dac_write(i); delay_us(50); // 调整这个值可以改变锯齿波频率 i++; } }锯齿波实测频率大概是1 /(256 × 延时时间),如果延时50μs,那么一个完整周期是256 × 50μs = 12.8ms,频率约78Hz。把这个延时减小到5μs左右,波形频率能到几百赫兹,但要注意51单片机本身执行dac_write的开销,实际最高频率会有上限。
三角波只需要在两个方向上分别递增递减:
void main(void) { unsigned char i = 0; char dir = 1; dac_init(); while (1) { dac_write(i); delay_us(30); if (dir == 1) { i++; if (i == 255) dir = -1; } else { i--; if (i == 0) dir = 1; } } }正弦波则建议在程序里存一张256点的正弦查找表,然后循环输出。相位差可以通过查表偏移量实现,比如正弦波输出sin_table[i],余弦波输出sin_table[(i + 64) % 256],3.3节里的双缓冲同步正好用在这里。
如果用STM32,GPIO配置要选对。STM32的GPIO有8种工作模式,驱动DAC0832数字输入端用“推挽输出”模式就够了,速度选择中等(GPIO_SPEED_FREQ_MEDIUM),不需要开漏。开漏模式必须外接上拉电阻,否则引脚只能拉低不能拉高,容易让人误以为芯片坏了。如果你的数据线是3.3V单片机接5V供电的DAC0832,后面会专门讲电平问题。
5. 实测中踩过的坑和处理方案
这一节全部来自实际调试中的记录。DAC0832本身不难,但几乎所有问题都出在“看起来简单”的细节上。
5.1 输出波形完全不对:检查VREF是不是真的稳定
我第一次把VREF直接接在电源5V上,结果输出波形带着明显的高频纹波,用万用表看平均值好像对,但示波器上一塌糊涂。原因很简单:数字电路工作时,5V电源上本来就叠加着大量开关噪声,这些噪声直接作为参考电压进入DAC,等于把噪声按比例打印到了模拟输出上。
解决方法是给VREF加基准源。最简单的用TL431搭一个2.5V基准,电路只需要两个电阻和一个电容。TL431的输出精度和温漂比电源好得多。如果手头有REF3025这类精密基准芯片更好,直接接上就能用。注意更换VREF后,满量程电压也会变,2.5V基准时每个LSB约9.8mV,做计算时别拿5V的表格硬套。
5.2 输出台阶跳变时毛刺特别大:这是8位并行DAC的宿命
直通模式或者快速连续写入时,你会在输出上看到很强的毛刺,尤其数据从0x7F跳到0x80时,毛刺幅度可能比预期台阶还要大。原因在于内部多位电流开关切换时间不是完全一致的,D7位开关切换时,低位的几个开关还在“路上”,导致输出在一瞬间出现接近满量程的尖峰。
这个毛刺是并行DAC固有的,只能抑制,不能完全消除。可以用的办法包括:输出端加RC低通滤波器,让尖峰被滤掉;或者用运放构成低通反馈;必要时用采样保持器去毛刺。DAC0832做语音或音频波形输出时,这类毛刺会造成可闻的底噪,所以要性能还是得换串行高精度DAC。
5.3 数据写进去但输出没反应:先查CS和WR1的“同时有效”
单缓冲模式里,数据要进入第一级寄存器有两个前提条件:CS为低、WR1为低。两个条件同时满足时寄存器才透明,数据才能进去。如果你在软件里只拉了WR1,忘记拉CS,或者CS还处于高电平,那么寄存器根本不会响应。
调试时我习惯用一个LED接到CS引脚,程序执行到“CS=0”那一步时,LED应该点亮,通过LED状态确认控制信号有没有真正拉低。另外,有的单片机执行速度很快,WR1低电平持续时间只有几百纳秒,对DAC0832这类老芯片来说太短的话,可以加几条空指令或者一个简单的延时函数,把低电平拉长到1μs以上,稳妥很多。
5.4 8位精度的物理边界和软件补偿
8位DAC的精度极限是1/256,但实际精度还受VREF精度、内部电阻温度漂移、运放失调电压等影响。实测满量程误差在0.5%到1%都很正常。如果你只是想要一个大概的电压,不需要校准;但如果你需要某个特定电压值,可以做个两点校准。
做法很简单:写0x00记录实际输出电压V0,写0xFF记录实际输出电压V255,然后线性插值。这样要输出目标电压V_target时,对应的数字码就是:
D = (V_target - V0) / (V255 - V0) × 255
注意V0通常不是严格的0V,运放失调会让它有十几毫伏到几十毫伏的偏置,忽略它的话,低端输出误差会非常显眼。
5.5 3.3V单片机和5V芯片混接:电平转换不能靠赌
DAC0832是TTL电平兼容芯片,但它的逻辑阈值会随VCC变化。VCC=5V时,高电平最小输入阈值大约2V,3.3V单片机输出的高电平约3.0V,理论上够用,实际好多项目也这样跑通了。但如果你把VCC升到12V,TTL高电平阈值可能会跟着变高,3.3V信号就不一定可靠了。
保险做法是在中间加一片74HCT245或者用简单三极管做电平转换。74HCT245的输入兼容3.3V,输出能到5V,SDIP封装焊起来也不难。至少,不要抱“理论能工作就肯定能工作”的心态,尤其是做产品而非实验的时候。
最后再分享一点我个人的使用习惯。第一次给DAC0832上电,先把所有控制信号固定成直通模式,用万用表确认每一位的权重都正常,再写单缓冲时序,最后才上双缓冲。这样一旦出问题,你能快速定位是硬件接线、控制时序还是模式配置的锅。你要是纯粹为了出个电压,完全有更省引脚的单片机自带DAC可用;但如果你想彻底搞懂并行总线时序、锁存器原理和R-2R梯形网络,DAC0832依然是块难得的活教材。