ARTICLE DETAIL

资讯详情

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

Proteus仿真51单片机DAC0832数模转换实验:原理、波形与精度校准

Proteus仿真51单片机DAC0832数模转换实验:原理、波形与精度校准 简介面向51单片机初学者的Proteus数模转换仿真实验资料包完整演示在Proteus环境下利用DAC0832芯片实现数模转换的电路搭建与程序控制适合学习单片机接口技术、模拟信号输出及嵌入式仿真调试的读者。压缩包共二十一个文件体积仅约638KB包含Proteus工程文件、C语言控制源码、汇编启动文件、编译目标与列表文件、多张仿真结果截图等覆盖从原理图绘制、代码编写到仿真验证的主要环节。目前已有5064人学习是同类实验中较直观的入门参考。借助这套资料可掌握DAC0832的引脚连接与单缓冲、双缓冲等工作模式理解51单片机通过I/O口发送数字量并转换为模拟电压的完整流程还可结合C程序、启动文件与工程配置快速复现实验为音频输出、波形发生等数模应用打下基础。1. Proteus仿真51单片机数模D/A转换实验为什么要从DAC输出先跑起来D/A转换实验最直观的结果是单片机输出的数字量变成了示波器上一条连续爬升的电压线而不是定时器翻转出来的方波。Proteus仿真把这个过程压缩到一台电脑里不需要焊板子、找电源双击打开元件库找到DAC0832拉一个运放就能把51单片机的P0口变成真正有电压输出的模拟量通道。这个实验适合两类人一类是单片机刚学完定时器和中断、对数据转换还停留在概念阶段的学生另一类是手边没有DAC芯片、又想快速验证波形算法或闭环控制策略的工程师。把原理、芯片选型、接线和驱动代码按顺序过一遍后续做信号发生器、直流电机调速、温控电路都会碰到同一套数模转换思路。2. D/A转换的基本原理与DAC0832选型在Proteus里把电路摆干净2.1 从LSB到满量程的量化关系D/A转换输出的电压怎么算数模转换做的事一句话就能说清把一个二进制数字量按比例变成电流或电压。8位DAC的数字输入范围是0~255输出范围从0到接近参考电压Vref。单极性输出时输出电压和输入数字量D的关系是V_out V_ref × D / 256这里分母是256而不是255是很多第一次做实验的人会忽略的点。数字量255对应的是V_ref × 255/256离V_ref还差一个LSB。LSB就是最低位对应的电压步进8位DAC配置5V参考电压时LSB 5/256 ≈ 19.5mV。这意味着输出永远到不了真正的5.000V满量程输出是4.980V左右。DAC0832是电流输出型器件芯片直接输出的是Io1和Io2两个电流引脚后面必须接运算放大器才能把电流转成电压。Proteus仿真里如果只把示波器接在Io1脚上看到的电压读数是没有意义的因为电流源没有对地形成电压转换路径。这正是很多仿真实验“结果不对”的第一个原因。2.2 DAC0832和DAC0808怎么选两个常见Proteus仿真芯片的差别做51单片机D/A转换实验Proteus元件库里最常见的两个芯片是DAC0832和DAC0808。两者都是8位电流输出型DAC主要差异在数字接口结构上。对比项DAC0832DAC0808数字输入锁存两级锁存带输入寄存器和DAC寄存器无内部锁存输入电平直通控制引脚CS、WR、XFER、ILE需配合时序无片选和写信号数据直接决定输出典型应用与单片机总线连接多路信号切换模拟信号发生器、需要高频更新的场景Proteus中接线控制引脚多新手容易漏接ILE引脚少但数据口不能长期悬空我一般建议实验用DAC0832原因不是它性能更好而是它的数据锁存结构更接近工业总线设计的思路。51单片机P0口是准双向口写数据到P0后电平能保持住DAC0832内部再把数据锁存到DAC寄存器里整个交互过程有明确的时序边界适合拿来理解“写一个数据到外设”到底发生了什么。DAC0808虽然接线简单但它没有锁存单片机P0口一旦被其他外设复用DAC输出就会抖动。2.3 在Proteus 8 Professional里添加DAC0832并完成输出电压电路Proteus中放置DAC0832的步骤和放置普通元件没有区别在元件选择界面输入DAC0832下拉列表会出现DAC0832。放置后建议先检查引脚名称芯片引脚从DI0到DI7是8位数据输入CS是片选、WR是写信号、ILE是锁存使能XFER是传输控制。要特别注意AGND和DGND必须同时接地Proteus仿真中两者分开接地多半能跑但实物焊接时分开了就是模拟地噪声的源头。把电流输出转成电压的典型接法如下Io1接运算放大器反相输入端Io2接运算放大器同相输入端Rfb接运放输出端到反相输入端的反馈回路Vref接5V运放用±12V供电运放可选TL081或OP07Proteus元件库搜索TL081即可。这个电路的本质是让Io1的输出电流流过反馈电阻Rfb在运放输出端形成电压。由于Rfb在DAC芯片内部已经串好了仿真时不需要外接反馈电阻直接把Rfb引脚连到运放输出即可。连接完成后给运放加上正负电源电压输出节点就准备好了。2.4 芯片供电与参考电压的常见误区DAC0832的Vcc和Vref是两个不同的引脚很多初学者会直接把两个脚都接5V。这样的接法在仿真中不会报错但Vref决定了输出满量程Vcc只负责芯片内部逻辑供电。实验想要0~10V输出时Vref接10VVcc保持5V两者必须分开放置。Proteus仿真里还有一个容易被忽略的点是多字节数据在总线上的建立时间。DAC0832的数据引脚DI0到DI7同时接在P0口上程序里执行一条P0 value语句时8个引脚的电平并不是严格同时到达的差别可能是纳秒级。仿真模型对这种细节不敏感但实物中这会造成输出毛刺。后面第五章会专门讲怎么处理这个问题。3. 51单片机驱动DAC0832的C语言实现时序、函数与第一个锯齿波3.1 P0口、片选与写信号的配合DAC0832对时序的要求是什么DAC0832的两级锁存结构决定了它的时序流程。第一级是输入寄存器由CS和WR控制第二级是DAC寄存器由XFER和WR2控制。当ILE为高时CS和WR同时为低数据总线上的值被写入输入寄存器WR上升沿把数据锁存住。如果XFER和WR2保持低电平DAC寄存器的内容会跟随输入寄存器相当于直通模式这是实验中最常用的接法。关键动作的正确顺序是先保证P0口数据稳定再拉低CS和WR数据被送到输入寄存器最后把WR拉高完成锁存。如果把顺序颠倒先拉低WR再写P0仿真里也许每次碰巧能工作但在真实芯片上会因为数据建立时间不足出现随机错误输出。完整的控制信号定义如下ILE接高电平或直接接Vcc使输入锁存器使能XFER接低电平或直接接地让DAC寄存器直通WR2接低电平或直接接地DAC寄存器始终选通CS和WR由单片机P2口控制这样接完之后单片机只需要控制CS和WR两个引脚就能完成一次D/A转换。3.2 写一个DAC0832数据输出函数控制引脚的C语言实现基于上面的直通模式驱动代码可以做得非常简洁。下面的函数完成一次数字量到模拟电压的输出#include reg51.h sbit DAC_CS P2^0; sbit DAC_WR P2^1; sbit DAC_XFER P2^2; sbit DAC_ILE P2^3; void dac0832_output(unsigned char value) { P0 value; // 先把数据放到P0口等待稳定 DAC_ILE 1; // ILE拉高输入锁存器使能 DAC_CS 0; // 片选有效 DAC_WR 0; // 写信号拉低数据进入输入寄存器 DAC_XFER 0; // XFER拉低DAC寄存器直通 DAC_WR 1; // WR上升沿锁存当前数据 DAC_CS 1; // 片选释放完成一次写入 }代码的逻辑是先把P0口的值准备好然后依次让控制引脚进入有效状态。DAC_XFER在这里始终拉低所以无论哪一次写入数据都会直接穿透到DAC寄存器Io1引脚立即反映出新的数字量对应的电流值。最后拉高WR和CS是为了让下一次写入有明确的状态边界避免连续写入时数据混淆。在Proteus中跑这个函数可以用单步调试观察Io1引脚电流。把value设为128Io1电流理论值是满量程的一半设成0电流接近0。如果能看到这个变化说明数据通路没有问题。3.3 第一个可观察的波形用延时让D/A转换输出变成锯齿波有了输出函数下一步是让它动起来。经典做法是让数据从0递增到255再回到0反复循环。这个循环里加入软件延时控制波形的频率。代码如下void delay_approx_1ms(void) { unsigned int i; for (i 0; i 125; i); } void main(void) { unsigned char val 0; while (1) { dac0832_output(val); val; delay_approx_1ms(); } }这段代码的效果是每次延时1ms左右数字量加1输出电压按约19.5mV的步进爬升。从0到255一共255次递增整个上升段大概255ms然后val从255再加1会溢出回绕到0电压瞬间跌回接近0V形成锯齿波。Proteus里运行时把虚拟示波器接在运放输出端能看到周期约255ms的锯齿波。如果波形不理想先检查延时时间再检查运放供电。常见问题是运放只接了正电源没有接负电源导致输出只能从0V往上摆出现波形削底。3.4 用定时器中断替代软件延时波形的频率是否稳定软件延时的缺陷是占用了CPU而且波形周期会受循环内其他语句影响。更稳定的做法是用定时器中断比如每1ms进入一次中断在中断服务函数里更新DAC数据。这样主循环可以做其他事情波形周期完全由定时器初值决定。void timer0_isr(void) interrupt 1 { TH0 0xFC; // 1ms重装载值12MHz晶振下对应约1000微秒 TL0 0x18; dac0832_output(current_val); current_val; }定时器中断方式在Proteus仿真中更接近真实应用也是后续做正弦波查表输出的基础。使用软件延时观察简单波形没问题但测量波形频率并和理论值对比时会发现误差来源集中在主循环其他语句的执行时间上。4. 用Proteus示波器观察三角波和正弦波D/A转换的输出精度怎么评4.1 虚拟示波器的接入位置电流输出和电压输出的区别Proteus的虚拟示波器在右侧工具栏的虚拟仪器菜单里图标是一个示波器屏幕。放置后把A通道探头接到运放输出端地线接到电路公共地。探头接到DAC0832的Io1引脚上测出来的不是有效电压前面说过Io1是电流输出端必须经过运放转换。接好之后的界面上能看到的电压波形才是51单片机配合D/A转换链路真正输出的结果。如果电路连接正确但示波器显示是一条平直线先检查运放电源是否加上再看程序里dac0832_output是否被执行。Proteus的虚拟示波器默认显示的是单通道时域波形频率显示在屏幕下方可以用它来核对锯齿波的周期。4.2 三角波生成代码查表法与实时计算法的差异分析三角波比锯齿波多了下降段。直接用for循环按顺序输出递增和递减的数据就能实现不需要查表。实现如下void triangle_wave(void) { unsigned char i; while (1) { for (i 0; i 255; i) { dac0832_output(i); delay_approx_1ms(); } for (i 255; i 0; i--) { dac0832_output(i); delay_approx_1ms(); } } }这段代码生成的是从0爬升到255、再回落到0的三角波。上升段有255个输出点下降段有255个输出点波形对称。i是无符号字符型判断条件i 0在i递减到0时退出循环不会出现下溢。实时计算的缺点是每次都要先计算再输出虽然对三角波来说计算开销不大但换成正弦波时会有明显影响。51单片机做浮点运算非常慢实时计算sin函数连几百赫兹都跑不上所以波形应用普遍用查表法把预先计算好的波形数据存在数组里中断里逐个取出。4.3 正弦波查表法如何生成一张256点8位正弦表正弦波输出比三角波多一个环节先准备好一张数据表程序周期性从表中取数据交给DAC。8位DAC的正弦表设计要考虑输出范围典型公式是table[i] 128 127 × sin(2π × i / 256)加128是为了让输出在0到255之间避免负值乘以127是让峰值不超过255。生成这张表最方便的办法是用Python临时跑一下把输出结果直接粘进C代码import math for i in range(256): v int(128 127 * math.sin(2 * math.pi * i / 256)) print(v, end, ) if (i 1) % 16 0: print()打印出来的256个数就是正弦表。在C代码中定义code unsigned char sine_table[256] { 128, 131, 134, 137, 140, 143, 146, 149, /* 这里粘贴完整生成的256个值 */ };code关键字表示把数组存放在程序存储区不占用RAM。51单片机RAM只有128字节放不下256字节的数组用code定义是必须的。然后主循环或定时器中断里按顺序查表void sine_wave(void) { unsigned int index 0; while (1) { dac0832_output(sine_table[index]); index; if (index 256) index 0; delay_approx_1ms(); } }每1ms输出一个采样点256点组成一个完整正弦周期所以输出频率约为3.9Hz。想要提高频率缩短延时即可。要注意的是DAC输出的是阶梯状正弦波不是光滑曲线Proteus示波器上会看到明显的小台阶这是8位DAC在幅度方向量化精度不足的正常表现。4.4 仿真波形里的阶梯和失真D/A转换分辨率的实际限制把示波器时间轴拉近正弦波的每个采样点之间能看到台阶。台阶幅值对应一个LSB约19.5mV。如果总输出范围是5V8位DAC只能把波形在幅度方向分成256级所以阶梯不可避免。另一个容易观察到的现象是波形顶端不够圆润有时还会出现平顶。这不是芯片坏了而是查表数据接近最大值255时量化误差造成相邻采样点数值相同。想要减小这个误差只有提高DAC分辨率比如换成12位DACLSB降到1.2mV。仿真中可以用这个方法对比8位和12位DAC的波形差异用来理解分辨率对输出质量的影响。5. D/A输出毛刺与精度修正仿真中能提前验证的三个细节5.1 零点校准与满量程校准用示波器游标读取准确数值Proteus虚拟示波器上可以直接用鼠标拖动游标读取波形任意时刻的电压值。做D/A转换实验时测量零点比看波形形状更重要。程序让DAC输出0记录示波器读到的电压再让DAC输出255记录满量程电压。两者相减除以255得到实际每级步进电压。如果零点读数不是0V检查运放同相输入端的Io2接地是否正确。DAC0832的输出电流Io2与Io1方向相反Io2应该接到运放同相输入端配合反馈让输出以0V为起点。接反了会造成输出电压整体偏移而且偏移量会随数字量变化很难通过软件补偿。用示波器游标校准的意义在于它为后面所有波形实验建立了一个基准。知道每步19.5mV之后三角波的峰值电压可以直接从示波器上读出来比对误差超过5%就要怀疑Vref是否准确。5.2 减少输出毛刺的写入顺序数据先于锁存信号稳定的原因毛刺是D/A转换最烦人的问题之一。Proteus仿真中对数字时序的建模比较宽松毛刺不一定能直接重现但养成良好的写入习惯还是能从波形上看出差别。DAC数据更新过程中如果片选信号和锁存信号的上升沿出现在P0口数据尚未稳定的瞬间DAC会锁存到一个中间电平输出波形上出现窄脉冲毛刺。规避方法很简单每次写数据时严格按照先更新P0、再拉低片选和写信号、最后拉高写信号的顺序。前面给的dac0832_output函数已经按这个顺序写好了。还有一个更彻底的技巧是每两次更新之间把CS拉高一段时间让DAC输出保持稳定后再进行下一次转换。程序里体现为DAC_CS 1; dac0832_output(value);先释放片选再调用输出函数。这样每个输出周期都能把数据稳定时间留出来避免高位和低位数据跳变时间不一致造成的输出毛刺。5.3 在Proteus中设计一个简单的两点校正流程DAC的参考电压Vref在仿真中是一个理想源但在实物板上会随负载变化。更实用的校准做法是两个点的软件修正把实际测量的零点偏移和满量程偏移存下来每次输出数据前做线性变换。假设零点偏移为offset实际增益为gain理论满量程为F则修正公式为out (theoretical_value - offset) / gain在Proteus中可以用这个思路做一个开环校准实验先输出0和255两组数据记录示波器的实际电压再写一个修正函数把目标电压换算成DAC输入数据。整个过程能在仿真阶段把校准流程跑通等移植到硬件时只需要把实际测量值替换进去就能直接验证实物上的D/A转换精度。这是Proteus仿真除了看波形之外的另一个价值所在把算法和流程在虚拟环境里验证好实物调试的变量就只剩下硬件本身了。本文还有配套的精品资源点击获取
返回列表