51单片机DAC数模转换
DAC介绍
1、DAC简介
DAC(Digital to analog converter)即数字模拟转换器,它可以将数字信号转换为模拟信号。它的功能与 ADC 相反。
2、技术指标
分辨率:DAC 的分辨率是输入数字量的最低有效位(LSB)发生变化时,所对应的输出模拟量(电压或电流)的变化量。它反映了输出模拟量的最小变化值。
线性度:线性度(也称非线性误差)是实际转换特性曲线与理想直线特性之间的最大偏差。常以相对于满量程的百分数表示。
绝对精度和相对精度:绝对精度(简称精度)是指在整个刻度范围内,任一输入数码所对应的模拟 量实际输出值与理论值之间的最大误差。
建立时间:建立时间是指输入的数字量发生满刻度变化时,输出模拟信号达到满刻度值的±1/2LSB 所需的时间。是描述 D/A 转换速率的一个动态指标。
3、DAC工作原理
了解了 DAC 基本概念及特性后,再来看下其工作原理,下面以T型电阻网络 DAC 来介绍。其内部结构图如下所示:
DAC 输出电压计算公式:V0=Vref * z/256
公式中的 z 表示单片机给的数字量,vref 为参考电压,通常我们是接在系统电源上,即 5V,数值 256 表示 DAC 精度为 8 位。
DAC 主要由数字寄存器、模拟电子开关、位权网络、求和运算放大器和基准电压源(或恒流源)组成。用存于数字寄存器的数字量的各位数码,分别控制对应位的模拟电子开关,使数码为 1 的位在位权网络上产生与其位权成正比的电流值,再由运算放大器对各电流值求和,并转换成电压值。 上述的模拟电子开关都分别接着一个分压的器件,比如说电阻。模拟开关的个数取决于 DAC 的精度。那么 N 个电子开关就把基准电压分为 N 份(并不是平均分哦),而这些开关根据输入的二进制每一位数据对应开启或者关闭,把分压的器件上的电压引入输出电路中。
PWM介绍
1、PWM简介
出于成本考虑,在实际开发应用中,使用较多的是通过 PWM 来模拟 DAC 输出。 下面就先来了解下 PWM 相关概念
PWM 是 Pulse Width Modulation 的缩写,中文意思就是脉冲宽度调制,简称脉宽调制。它是利用微处理器的数字输出来对模拟电路进行控制的一种非常有效的技术,其控制简单、灵活和动态响应好等优点而成为电力电子技术最广泛应用的控制方式,其应用领域包括测量,通信,功率控制与变换,电动机控制、伺服控制、调光、开关电源,甚至某些音频放大器,因此学习 PWM 具有十分重要的现实意义。
2、PWM工作原理
PWM 是一种对模拟信号电平进行数字编码的方法。通过高分辨率计数器的使用,方波的占空比被调制用来对一个具体模拟信号 的电平进行编码。PWM 信号仍然是数字的,因为在给定的任何时刻,满幅值的直流供电要么完全有(ON),要么完全无(OFF)。电压或电流源是以一种通(ON)或断 (OFF)的重复脉冲序列被加到模拟负载上去的。通的时候即是直流供电被加到负载上的时候,断的时候即是供电被断开的时候。只要带宽足够,任何模拟值都可以使用 PWM 进行编码。 PWM 对应模拟信号的等效图,如下图所示:
从图中可以看到,上图 a 是一个正弦波即模拟信号,b 是一个数字脉冲波形即数字信号。我们知道在计算机系统中只能识别是 1 和 0,对于 51 单片机芯片,要么输出高电平(5V),要么输出低电平(0),假如要输出 1.5V 的电压,那么就必须通过相应的处理,比如本章所要讲解的 PWM 输出,其实从上图也可以看到,只要保证数字信号脉宽足够就可以使用 PWM 进行编码,从而输出 1.5V 的电压。
PWM 的输出其实就是对外输出脉宽可调(即占空比调节)的方波信号,信号频率是由 T 的值决定,占空比由 C 的值决定。其示意图如图所示
从上图中可以看到,PWM 输出频率是不变的,改变的是 C 的值,此值的改变将导致 PWM 输出信号占空比的改变。占空比其实就是一个周期内高电平时间与 周期的比值。而频率的话可以使用 51 单片机的定时器确定。
硬件原理
从上图中可知,PWM 输出控制管脚接在单片机 P2.1 管脚上,DAC1 为 PWM 输出信号,将其连接一个 LED,这样可以通过指示灯的状态直观的反映出 PWM 输出电压值变化。LM358 芯片与这些电容电阻构成了一个跟随电路,即输入是多少, 输出即为多大电压,输出电压范围是 0-5V。输出信号由 J52 端子的 DAC1 引出, 在其端子上还有一个 AIN3 脚,它是上一章介绍 ADC 时的外部模拟信号输入通道。 如果使用短接片将 DAC1 和 AIN3 短接,这样就可以使用 XPT2046 芯片采集检测 PWM 输出信号。
软件编写
程序框架如下:
编写 DAC 转换函数
编写主函数
实验:DAC(PWM)模块上的指示灯 DA1 呈呼吸灯效果,由暗变亮再由亮变暗。
#include <REGX52.H>
//管脚定义
sbit PWM=P2^1;
//定义全局变量
unsigned char G_TimeH=0; //保存定时器初值高 8 位
unsigned char G_TimeL=0; //保存定时器初值低 8 位
unsigned char G_TimeScale=0; //保存PWM周期 = 定时器初值*G_TimeScale
unsigned char G_Duty=0; //保存PWM占空比
/*
G_Time存储的为定时器定时的时间,G_TimeScale为将一个周期分为几个小周期。
例如G_Time=0.01ms G_TimeScale=100。则是大周期 = G_Time * G_TimeScale=1ms。
G_Duty则是在小周期中有多少周期为高电平,有多少为低电平。
例如G_Duty=30,则是在100个小周期中30个为高电平,70个为低电平。
*/
void Delay(unsigned int x)
{
while(x--);
}
//PWM初始化函数
void PWM_Init()
{
TMOD|=0X01; //定时器 0 模式,工作方式 1
TH0=G_TimeH; //定时初值设置
TL0=G_TimeL;
ET0=1; //打开定时器 0 中断允许
TR0=1; //打开定时器
EA=1; //打开总中断
}
//PWM中断函数
void pwm() interrupt 1
{
static unsigned int time=0;
TH0=G_TimeH; //定时器初值设置
TL0=G_TimeL;
time++;
if(time>=G_TimeScale) //PWM周期 = 定时器初值 * G_TimeScale,重新开始计数
time=0;
if(time<=G_Duty) //占空比
PWM=1;
else
PWM=0;
}
void main()
{
unsigned char Dir=0; //控制呼吸灯是向着亮还是暗变换
//初值赋值
G_TimeH=0xFF; //定时时间为 0.01ms
G_TimeL=0xF6;
G_TimeScale=100; //分成100个小周期
G_Duty=0; //占空比先设置为 0% ,从暗开始变化
PWM_Init();
while(1)
{
if(Dir==0) //当 Dir=0 灯向着亮变化
{
G_Duty++; //占空比递增
if(G_Duty==70) //当达到一定值切换方向,占空比最大到100,但到达70左右再肉眼也分辨不出亮度变化
Dir=1;
}
else //当 Dir=1 灯向着暗变化
{
G_Duty--;
if(G_Duty==0)
Dir=0;
}
Delay(100); //短暂延时,让呼吸灯有一个流畅的效果
}
}
————————————————
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/zhouhaoNB_/article/details/127757048
|