MENU

29 DA数模转换(PWM输出)

July 29, 2020 • 51单片机

--- 当前时间: ---

29 DA数模转换(PWM输出)

29.1 DAC转换原理和技术指标

29.1.1 D/A转换器的基本原理及分类

T型电阻网络D/A转换器:

由图可知,运放两个输入端为“虚地”,所以电位都约为0

所以无论开关在0或者1,最后两个2R都会并联得到R,和R串联又会变成2R,以此类推到最前端,相当于两个2R的电阻并联,那么可以知道电流为:

$$ \Large\tag{29.1}I=\dfrac{V_{REF}}{R} $$

那么电流就有如下的关系:

$$ \Large\begin{gathered} I_7 = \dfrac{I}{2^1},\\ I_6 = \dfrac{I}{2^2},\\ \cdots\\ I_0 = \dfrac{I}{2^8}\,\, \end{gathered}\tag{29.2} $$

当输入数据$D_7\sim D_0$为$1111\,\,1111\text B$时有:

$$ \Large\tag{29.3}I_{O1}=I_7+I_6+\cdots+I_0=\dfrac{I}{2^8}(2^7+2^6+\cdots+2^0) $$

$$ \Large\tag{29.4}I_{O2}=0 $$

若$\large R_{fb}=R$,那么$V_0$只和$V_{REF}$有关,即:

$$ \Large\begin{aligned} V_O&=-I_{O1}\times R_{fb}\\ &=-I_{O1}\times R\\ &=-\dfrac{\,\dfrac{V_{REF}}{R}\,}{2^8}(2^7+2^6+\cdots+2^0)\times R\\ &=-\dfrac{V_{REF}}{2^8}(2^7+2^6+\cdots+2^0)\\ &\xlongequal{\LARGE Z\triangleq2^7+2^6+\cdots+2^0=1111\,\,1111B\Large}-\dfrac{V_{REF}}{2^8}\times Z \end{aligned}\tag{29.3} $$

可见,输出电压的大小与数字量具有对应的关系

29.1.2 D/A转换器的主要性能指标

29.1.2.1 分辨率

分辨率是指输入数字量的最低有效位(LSB)发生变化时,所对应的输出模拟量(常为电压)的变化量,它反映了输出模拟量的最小变化值

分辨率与输入数字量的位数有确定的关系,可以表示成$\large\dfrac{FS}{2^n}$,$FS$表示满量程输入值,$n$为二进制位数

对于$5V$的满量程

  • 采用8位的DAC时,分辨率为$\large\dfrac{5V}{256}=19.5mV$
  • 采用12位的DAC时,分辨率则为$\large\dfrac{5V}{4096}=1.22mV$

显然,位数越多分辨率就越高

29.1.2.2 线性度

线性度(也称非线性误差)是实际转换特性曲线与理想直线特性之间的最大偏差

常以相对于满量程的百分数表示

如$\pm1\%$是指实际输出值与理论值之差在满刻度的$\pm1\%$以内

29.1.2.3 绝对精度和相对精度

【绝对精度】

绝对精度(简称精度)是指在整个刻度范围内,任一输入数码所对应的模拟量实际输出值与理论值之间的最大误差

绝对精度是由DAC的增益误差(当输入数码为全1时,实际输出值与理想输出值之差)、零点误差(数码输入为全0时,DAC的非零输出值)、非线性误差和噪声等引起的

绝对精度(即最大误差)应小于1个LSB

【相对精度】

相对精度与绝对精度表示同一含义,用最大误差相对于满刻度的<u>百分比</u>表示

29.1.2.4 建立时间

建立时间是指输入的数字量发生满刻度变化时,输出模拟信号达到满刻度值的$\pm\dfrac{1}{2}LSB$所需的时间,是描述D/A转换速率的一个动态指标

  • 电流输出型DAC的建立时间短
  • 电压输出型DAC的建立时间主要决定于运算放大器的响应时间

根据建立时间的长短,可以将DAC分成超高速($<1\mu s$)、高速($10\sim1\mu s$)、中速($100\sim10\mu s$)、低速($\geqslant100\mu s$)几档

应当注意,精度和分辨率具有一定的联系,但概念不同。DAC的位数多时,分辨率会提高,对应于影响精度的量化误差会减小。但其它误差(如温度漂移、线性不良等)的影响仍会使DAC的精度变差

29.2 PWM工作原理

29.2.1 PWM简介

PWM是Pulse Width Modulation的缩写,中文意思就是脉冲宽度调制,简称脉宽调制

它是利用微处理器的数字输出来对模拟电路进行控制的一种非常有效的技术,其控制简单、灵活和动态响应好等优点而成为电力电子技术最广泛应用的控制方式

其应用领域包括测量,通信,功率控制与变换,电动机控制、伺服控制、调光、开关电源,甚至某些音频放大器,因此学习PWM具有十分重要的现实意义

29.2.2 功率控制的PWM等效控制

如果将这种变占空比信号接入控制系统,可以实现设备控制,例如呼吸灯、电机控制

数字信号的面积和模拟信号是相同的

29.2.3 PWM工作原理

PWM是一种对模拟信号电平进行数字编码的方法

通过高分辨率计数器的使用,方波的占空比被调制用来对一个具体模拟信号的电平进行编码

PWM信号仍然是数字的,因为在给定的任何时刻,满幅值的直流供电要么完全有(ON),要么完全无(OFF),电压或电流源是以一种通(ON)或断(OFF)的重复脉冲序列被加到模拟负载上去的:

  • 通的时候即是直流供电被加到负载上的时候
  • 断的时候即是供电被断开的时候

只要带宽足够,任何模拟值都可以使用PWM进行编码

占空比(duty ratio)的含义:

$$ \Large\tag{29.4}b(\%)=\dfrac{T_H}{T}\times100\% $$

控制$TIMx\_CCRx$即可控制占空比的大小达到目的,但是输出的还是数字信号

可以使用LM358运放电路

29.3 PWM版本的模块电路以及实例代码

【模块电路】

【实例代码】

main.c

#include <reg52.h>

typedef unsigned char u8;        // 0 ~ 255
typedef unsigned int u16;        // 0 ~ 65535

sbit PWM = P2^1;

u16 count = 0, time = 0;

void Timer1Init()
{
    TMOD |= 0x10;
    
    // 1us
    TH1 = 0xFF;
    TL1 = 0xFF;
    
    ET1 = 1;
    EA  = 1;
    TR1 = 1;
}

void main()
{
    bit DIR;
    u16 value = 0;
    Timer1Init();
    
    while(1)
    {
        if(count > 100)
        {
            count = 0;
            
            if(DIR == 0)         value++;
            else if(DIR == 1)     value--;
        }
        
        if(value == 1000)        DIR = 1;
        else if(value == 0)        DIR = 0;
        
        // period: 1000 * 1us
        if(time > 1000)            time = 0;
        
        // duty ratio
        if(time < value)        PWM = 1;
        else                    PWM = 0;
    }
}

void Timer1() interrupt 3
{
    TH1 = 0xFF;
    TL1 = 0xFF;
    time++;
    count++;
}

29.4 PCF8591芯片版实例代码

芯片手册参考28.3

i2c.h

#ifndef _I2C_H_
#define _I2C_H_

#include <reg52.h>

#ifndef uchar
#define uchar unsigned char
#endif

#ifndef uint
#define uint unsigned int
#endif

sbit SCL = P2^1;
sbit SDA = P2^0;

void  I2CStart();
void  I2CStop();
uchar I2CSendByte(uchar dat);
/*uchar I2CReadByte();*/

#endif

i2c.c

#include "i2c.h"

void Delay10us()
{
    uchar a, b;
    for(b = 1; b > 0; b--)
        for(a = 2; a > 0; a--);
}

void I2CStart()
{
    SDA = 1;
    Delay10us();
    SCL = 1;
    Delay10us();
    SDA = 0;
    Delay10us();
    SCL = 0;
    Delay10us();
}

void I2CStop()
{
    SDA = 0;
    Delay10us();
    SCL = 1;
    Delay10us();
    SDA = 1;
    Delay10us();
}

uchar I2CSendByte(uchar dat)
{
    uchar a = 0, b = 0;
    for(a = 0; a < 8; a++)
    {
        SDA = dat >> 7;
        dat <<= 1;
        Delay10us();
        
        SCL = 1;
        Delay10us();
        SCL = 0;
        Delay10us();
    }
    
    SDA = 1;
    Delay10us();
    SCL = 1;
    while(SDA)    // waiting
    {
        b++;
        if(b > 200)
        {
            SCL = 0;
            Delay10us();
            // error
            return 0;
        }
    }
    SCL = 0;
    Delay10us();
    return 1;    // success
}

/*
uchar I2CReadByte()
{
    uchar a = 0, dat = 0;
    SDA = 1;
    Delay10us();
    for(a = 0; a < 8; a++)
    {
        SCL = 1;
        Delay10us();
        dat <<= 1;
        dat |= SDA;
        Delay10us();
        SCL = 0;
        Delay10us();
    }
    return dat;
}
*/

main.c

#include <reg52.h>
#include "i2c.h"

typedef unsigned char u8;        // 0 ~ 255
typedef unsigned int u16;        // 0 ~ 65535

void delay(u16 i)
{
    while(i--);
}

void PCF8591DAC(u8 value)
{
    I2CStart();
    I2CSendByte(0x90);            // write
    I2CSendByte(0x40);
    I2CSendByte(value);
    I2CStop();
}

void main()
{
    bit DIR;
    u8  value = 0;
    
    while(1)
    {
        if(value == 0x00)             DIR = 0;
        else if(value == 0xFF)         DIR = 1;
        
        if(DIR == 0)                  PCF8591DAC(value++);
        else if(DIR == 1)             PCF8591DAC(value--);
        
        delay(2000);
    }
}
Last Modified: August 21, 2020
Archives QR Code
QR Code for this page
Tipping QR Code