尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

51单片机+DAC0832三角波发生器:硬件接线、C51编程与Proteus仿真

51单片机+DAC0832三角波发生器:硬件接线、C51编程与Proteus仿真 简介基于单片机的DAC0832三角波产生与输出设计是一套面向单片机初学者的完整项目资料。它围绕8051等常见单片机主控讲解如何利用DAC0832将数字信号转换为模拟电压并结合三角波生成算法PWM或累加器方式实现信号输出能够在Proteus中完成从原理图到波形验证的全流程。压缩包共14个文件大小仅131KB包含Keil工程.uvproj/.uvopt、C语言源程序与hex烧录文件以及Proteus设计工程.pdsprj/.pdsbak和仿真备份结构清晰便于对照学习。目前已有698人学习下载。读者可从中获得可直接运行的代码与仿真环境理解DAC0832的引脚、时序和转换原理也能通过修改程序观察三角波频率与幅值变化是巩固数模转换知识、提升嵌入式调试能力的实用素材。1. 用 DAC0832 做三角波跳过 PWM直接写模拟电压用单片机产生三角波最常见的思路是用 PWM 加 RC 滤波。但 PWM 出来的本质是方波要靠后级积分电路“抹”成近似三角波频率稍微调高波形就走样。DAC0832 这个 8 位并行 D/A 转换器的做法完全不同单片机直接向它写一个字节输出引脚就立刻出现对应的模拟电压。三角波本质上是一串线性递增再递减的电压序列只要单片机按固定时间间隔连续写入 0x00、0x01、0x02……再反向递减DAC 引脚上就是真正的三角波不需要滤波器“凑”波形。这个项目适合做课程设计、信号发生器原型验证以及想搞明白“并行 DAC 到底怎么挂在单片机上”的人——它的时序比 SPI/I2C 接口直观得多一条 WR 信号就能把数据锁存到输出。2. DAC0832 与 51 单片机的硬件互连单缓冲模式下的引脚级接线2.1 DAC0832 的三种工作模式怎么选DAC0832 片内有两级锁存器输入寄存器和 DAC 寄存器。三级控制信号 ILE、CS、WR1 管第一级WR2、XFER 管第二级。如果两个锁存器都保持“透明”状态数据直接送到 DAC 转换器叫直通模式只锁存第一级、第二级直通叫单缓冲模式两级都独立锁存叫双缓冲模式。在单 DAC 输出的场合我一般选单缓冲模式。51 单片机的 P0 口作为数据总线WR1 连接到单片机的 WR 引脚P3.6CS、WR2、XFER 直接接地ILE 接高电平。这样每次执行MOVX DPTR, A指令时单片机自动拉低 WR数据总线上的字节就被锁存进 DAC 寄存器输出立即更新。双缓冲模式是给“多个 DAC 同步更新”准备的硬件上要多占两根 IO 口控制 XFER这个项目用不上选了反而增加理解负担。2.2 引脚连接对照表与电路搭建Proteus 里建工程时按下面的对照关系连线51 单片机引脚DAC0832 引脚说明P0.0 ~ P0.7D0 ~ D78 位并行数据输入需外接 10kΩ 排阻上拉P3.6 (WR)WR1写信号低电平有效高电平 VCCILE输入锁存允许必须为高低电平 GNDCS片选接地使能低电平 GNDWR2第二级写信号直通接地低电平 GNDXFER传送控制直通接地运放输出Rfb反馈电阻引脚接运放输出形成负反馈注意 P0 口是开漏输出必须加上拉电阻不然高电平拉不上去DAC 收到的数据全是错的。Rfb 引脚不要直接接地DAC0832 的输出 IOUT1、IOUT2 是电流型输出要接一个运算放大器转成电压。Proteus 里放一片 LM358正相输入端接地IOUT1 接反相输入端IOUT2 也接地Rfb 接运放输出端输出公式是Vout - (Vref × 数字量) / 256这里的负号表示运放输出与参考电压反相。如果想让输出是正电压可以把 Vref 接 -5V如果 Vref 接 5V运放输出就是 -5V 到 0V 的负向三角波。我在 Proteus 里验证时习惯用 Vref 5V输出接一个反相比例放大电路再翻回正电压但只为了看波形的话直接看负向三角波也不影响判断线性度。2.3 初始化引脚与最小驱动代码硬件连接确认后软件侧先把数据总线和写信号配置好。51 单片机复位后 P0 口默认是高电平P3.6 是准双向口不需要额外配置方向寄存器但为了保证上电瞬间 DAC 不输出随机电压初始化时先向 DAC 写入 0x00// dac0832_driver.c #include reg52.h #define DAC0832_BASE 0xFFFF // 地址无关MOVX 寻址任意外部地址均触发 WR sfr P0 0x80; void DAC0832_Init(void) { P0 0x00; // 数据总线先清零 DAC0832_Write(0x00); // 写一次 0让运放输出为 0V } void DAC0832_Write(unsigned char value) { P0 value; // 数据送到 P0 口 DAC0832_BASE value; // 触发 MOVX 写操作WR 引脚产生低脉冲 }DAC0832_BASE value是 C51 中触发外部数据存储器写操作的常用写法编译后生成 MOVX DPTR, A 指令单片机会自动在 WR 引脚输出低电平脉冲DAC0832 在 WR 上升沿锁存数据。这里地址值是多少无所谓因为 CS 已经接地总线上的任何 MOVX 写操作都会命中 DAC0832。P0 是数据口也是低 8 位地址口直接赋值后外部锁存器会锁存到同样的值但由于 CS 接地只要 WR 被拉低DAC 就完成数据锁存不会出现“地址和数据竞争”的问题。3. C51 程序实现定时器中断与线性步进累加生成三角波3.1 从原理到代码查表还是实时计算三角波生成算法有两条路查表法和实时累加法。查表法先把 256 个点的波形数据存进数组主循环里依次读出写入 DAC优点是代码简洁、波形点数可控缺点是要占用 256 字节的 RAM 或 ROM。实时累加法用一个变量不断加步进值到上限再反向减不占存储空间而且步进值可调改变三角波斜率只需改一个变量适合在仿真里观察参数变化效果。我写这个项目时选了实时累加法原因有两点一是 51 单片机内部 RAM 只有 128 字节256 点的查找表在标准 8051 里放不下要挪到 code 区初学者容易搞混 data 和 code 关键字二是累加法的“方向标志位”概念对理解 DAC 输出本质更有帮助——三角波不是凭空生成的而是 DAC 分辨率256 级和时间间隔共同决定的阶梯波。3.2 定时器中断里做累加完整源码三角波的频率由“步进更新频率”和“步长”共同决定。定时器 T0 每次中断向 DAC 写入一个新值方向为正时当前值加 step到达 0xFF 后换方向方向为负时减 step到达 0x00 后再次翻转。代码如下// triangle_wave.c #include reg52.h #define DAC_PORT P0 #define TRIANGLE_MAX 0xFF #define TRIANGLE_MIN 0x00 #define TIMER0_RELOAD_H 0xFF // 12MHz 晶振定时 50us 的初值高字节 #define TIMER0_RELOAD_L 0x9C // 初值低字节 unsigned char current_value 0x00; unsigned char direction 1; // 1 向上累加0 向下递减 unsigned char step 0x04; // 步进值越大波形斜率越陡 void Timer0_Init(void) { TMOD 0xF0; // 保留 T1 的配置位 TMOD | 0x01; // T0 工作方式 116 位定时器 TH0 TIMER0_RELOAD_H; // 加载初值高字节 TL0 TIMER0_RELOAD_L; // 加载初值低字节 ET0 1; // 开 T0 中断 EA 1; // 开总中断 TR0 1; // 启动 T0 } void Timer0_ISR(void) interrupt 1 { TH0 TIMER0_RELOAD_H; // 重装载初值 TL0 TIMER0_RELOAD_L; if (direction 1) { current_value step; if (current_value TRIANGLE_MAX) { current_value TRIANGLE_MAX; direction 0; } } else { current_value - step; if (current_value TRIANGLE_MIN) { current_value TRIANGLE_MIN; direction 1; } } DAC_PORT current_value; // 送到 DAC0832 } void main(void) { Timer0_Init(); while (1) { // 主循环可以改 step 或做键盘扫描 } }这段代码最关键的部分是把 DAC 写入放在中断服务函数里。实时性抖动电平是模拟输出最忌讳的主循环里做别的事情比如扫描键盘、刷新 LCD都会造成中断响应延迟导致相邻两个输出点的时间间隔不相等。放在中断里只要中断优先级不被打断每次 DAC 写入间隔就是精确的 50 微秒三角波线性度才有保证。参数说明step 0x04表示每次累加 4 个 LSB从一个谷底到峰顶需要 64 次更新一个完整周期 128 次更新周期 T 128 × 50us 6.4ms对应频率约 156Hz。step增大一倍输出点数减半频率翻倍但波形台阶感更强step减小到 0x01输出 256 级全分辨率频率最低但波形最平滑。实际调频率时我一般先固定中断周期只改 step 变量观察频率变化是否符合“反比”关系。3.3 定时器初值计算公式定时器初值不是拍脑袋定的。12MHz 晶振下51 单片机机器周期 12 / 12MHz 1usT0 工作在方式 116 位计数从初值计数到 65536 溢出。要得到 50us 的中断周期需要计数 50 个机器周期初值 65536 - 50 65486 0xFFCE。但上面代码里写的是 0xFF9C也就是 65536 - 100 65436对应 100us 中断周期。原因是我把中断服务函数里的重装载指令和条件判断也算了进去——从退出中断到下一次初值装载完成大约有 2 到 3 条指令的额外开销库函数风格写法按 50us 算出来的实际频率偏低 1% 到 2%。工程上更稳妥的办法是先用逻辑分析仪或示波器测实际中断间隔再反过来修正初值。目标中断周期理论初值 (12MHz)实际推荐初值步进值 0x04 时三角波频率50 us0xFFCE0xFFCE156.25 Hz100 us0xFF9C0xFF9C78.125 Hz200 us0xFF380xFF3839.06 Hz500 us0xFE0C0xFE0C15.625 Hz如果换用 11.0592MHz 晶振机器周期约 1.085us初值需要按实际机器周期重新计算。Proteus 仿真默认晶振就是 12MHz直接套用上表即可实际烧录到开发板时先确认晶振频率再决定是否修正。4. Proteus 仿真验证虚拟示波器与 hex 文件联调4.1 加载工程与写入固件拿到项目压缩包后用 Proteus 8 及以上版本打开bao.pdsprj工程文件。先不要急着点运行双击原理图里的 AT89C51 芯片在 Edit Component 对话框的 Program File 一栏点击文件夹图标选择同目录下的bao.hex。这里有个容易被忽略的细节Proteus 识别的是 hex 文件而不是 uvproj 工程文件Keil 编译输出 hex 默认在工程目录的 Output 或 Objects 子文件夹下如果压缩包里只有一个bao文件没有后缀先检查它是不是被改了名的 hex 文件用记事本打开看到以:02000004开头的行就是 Intel HEX 格式确认无误后手动补上.hex后缀再加载。晶振频率设置为 12MHz这直接影响仿真里定时器中断时间是否和真实硬件一致。设置方法是双击 AT89C51在 Component 属性页的 Clock Frequency 里填 12MHz。如果这个值保持默认的 1MHz定时器溢出速度会慢 12 倍三角波频率变成大约 13Hz波形肉眼看就是在缓慢爬升容易被误判为程序逻辑错误——这是我见过最多的“仿真不对”原因。4.2 仿真运行与三角波测量启动仿真后从 Proteus 左侧工具栏的 Virtual Instruments 面板选出 OSCILLOSCOPE虚拟示波器把通道 A 接在运放输出端地接模拟地。运行仿真大约 0.5 秒后示波器上应该出现锯齿状波形。如果看到的是斜线而不是三角波说明两个可能一是 DAC0832 的 ILE 引脚未接高电平输入寄存器一直处于锁存状态单片机写的数据进不去输出停留在固定电压二是 WR 信号没有真正连接MOVX 写操作发生时 DAC0832 收不到低脉冲。这两处都是虚焊和漏线的重灾区用 Proteus 的 Wire Label 模式给网络标号不要靠肉眼看线有没有连上。示波器面板上的时间轴分辨率调小到每格 1ms 左右波形细节才看得清楚。三角波的“线性”核心在于上升段和下降段的折点是否尖锐。如果折点出现圆弧说明运放带宽不足或反馈电阻过大Proteus 里 LM358 模型是理想运放一般不会出现真板子上就要换高速运放。如果波形上升段比下降段长检查direction翻转时是否多执行了一次加减例如向上到达 0xFF 后先赋TRIANGLE_MAX再反转方向但反转后第一次中断不应该立刻减而是保持峰值一个周期。目前代码在等于限幅值的那次中断就已经翻转方向下一个中断马上递减峰值只存在一个中断周期属于正常三角波而非梯形波。4.3 常见仿真异常排查对照波形现象可能原因排查步骤输出为固定电压P0 口上拉电阻缺失或 WR 未连线检查 10kΩ 排阻是否连接用电压探针量 P0.0 是否随程序变化频率明显偏低晶振频率没设成 12MHz双击单片机查看 Clock Frequency波形有毛刺Vref 引脚悬空或电源滤波不足Vref 接 5V 并在旁边并联 0.1uF 电容波形到一半停住定时器中断被其他中断抢占确认没有开启串口中断或外部中断完全无输出HEX 未加载或加载了错误文件用文本编辑器看 hex 文件内容是否为空5. 三角波频率整定与波形畸变修正三角波频率的精确公式是f 中断频率 / (2 × 512 / step)。其中 512 是完整周期需要的更新次数上升 256 / step 次下降 256 / step 次2 是因为上升下降各占半个周期。代入 step 4中断周期 100us中断频率 10kHzf 10000 / (2 × 512 / 4) 10000 / 256 ≈ 39Hz与前面表格一致。调节频率有两条路径改定时器初值改变中断频率对整体频率按比例缩放波形台阶数保持不变改 step 改变每次跳变的幅度频率变化是离散的只适合粗调。工程上我一般先把 step 固定为 1用定时器初值精确设基准频率再考虑是否把 step 调大换取更高频率。减少三角波台阶感有三个实用技巧。第一是在运放输出端并联一个 100pF 到 1nF 的电容构成一阶低通滤波截止频率设在三角波基频的 10 倍以上可以有效消除 DAC 量化产生的毛刺但电容太大会把三角波拐角磨圆。第二是在 DAC0832 的 Vref 引脚并联 0.1uF 和 10uF 双电容高频去耦和低频稳压同时兼顾输出波形噪声会明显降低。第三是采用双缓冲模式把 DAC0832 的 WR2 和 XFER 分别接到单片机的 P1.0 和 P1.1先让数据进输入寄存器再统一拉低 XFER 更新 DAC 寄存器——这样多路 DAC 可以同步切换单路输出时还能避免 WR 脉冲期间的输出毛刺传到模拟端代价是每次要写两个地址而不是一个。仿真里先把三条都试一遍对比示波器波形再决定实物板保留哪条特别是电容值Proteus 里 100pF 和 1nF 的滤波效果差异用示波器量一下就能直观看到。本文还有配套的精品资源点击获取
返回列表