fireholder.github.io

伪文艺女青年,状高冷,话少爱热闹


Blog | Archive | About

ADC/DAC 详解

06 Apr 2017 | 单片机

ADC/DAC 详解

ADC/DAC 详解

1 介绍

1.1 DAC1

Digital-Analog Converter,数模转换器。将数字量转换成模拟量,使输出的模拟量与输入的数字量成正比的电路。简称D/A转换器或DAC。

1.2 ADC

Analog-Digital Converter,模数转换器。将模拟量转换为数字量。简称A/D转换器或ADC。

2 原理

2.1 D/A

数字量是用代码按数位组合而成的,对于有权码,每位代码都有一定的权值,如能将每一位代码按其权的大小转换成相应的模拟量,然后,将这些模拟量相加,即可得到与数字量成正比的模拟量,从而实现数字量—模拟量的转换。

D/A 转换主要由数码寄存器、n 位模拟开关、解码网络、求和电路等组成。

2.1.1 种类

D/A 转换器的种类很多,例如:T 型电阻网络、倒 T 型电阻网络、权电流、权电流网络、CMOS 开关型等。

%E5%80%92T%E5%9E%8B%E7%BD%91%E7%BB%9C%E5%8E%9F%E7%90%86%E5%9B%BE.png

Figure 1: 倒T型网络原理图

2.1.2 技术指标

  1. 分辨率

    分辨率:其定义为 D/A 转换器模拟输出电压可能被分离的等级数。n位 DAC 最多有2个模拟输出电压。位数越多 D/A 转换器的分辨率越高。

    分辨率也可以用能分辨的最小输出电压与最大输出电压之比给出。

  2. 转换精度

    转换精度是指对给定的数字量,D/A 转换器实际值与理论值之间的最大偏差。

    产生原因:由于 D/A 转换器中各元件参数值存在误差,如基准电压不够稳定或运算放大 器的零漂等各种因素的影响。

    要求:DAC的精度一定要高于ADC。

2.2 A/D

2.2.1 分类

  1. 并联比较型

    特点:转换速度快,转换时间 10ns~1us,但电路复杂。

  2. 逐次逼近型

    特点:转换速度适中,转换时间为几us到100us,转换精度高,在转换速度和硬件复杂度之间达到一个很好的平衡。

  3. 双积分型

    特点:转换速度慢,转换时间几百us到几ms,但抗干扰能力最强。

2.2.2 过程

由于输入的模拟信号在时间上是连续量,所以一般的 A/D 转换过程为:采样、保持、量化和编码。

  1. 采样

    采样是将随时间连续变化的模拟量转换为在时间上离散的模拟量。

    需遵循采样定理:fs>=2fm 即采用信号的频率需不小于输入模拟信号的最好频率分量的频率的两倍。

  2. 保持

    在取样电路后要求将所采样的模拟信号保持一段时间,以为后续的量化编码的过程提供一个稳定的值。

  3. 量化和编码

    数字信号在数值上是离散的。采样–保持电路的输出电压还需按某种近似方式归化到与 之相应的离散电平上,任何数字量只能是某个最小数量单位的整数倍。量化又称幅值量化,把采样信号经过舍入或截尾的方法变为只有有限个有效数字的数,这一过程称为量化。若取信号可能出现的最大值为A,另其分为D个间隔,则每个间隔长度为R=A/D,R称为量化增长或量化步长。2

    量化后的数值最后还需通过编码过程用一个代码表示出来。将离散幅值经量化变为二进制数字的过程中,把采样后的节点变为程序代码可以识别的二进制码,把这些节点以合理的顺序排列出来,实现把一连串的模拟信号用数字信号描述出来的过程即编码。经编码后得到的代码就是A/D 转换器输出的数字量。

    两种近似量化方式:只舍不入量化方式、四舍五入量化方式。为减小误差,后者优于前者。

2.2.3 参数指标

  1. 转换精度
    1. 分辨率

      最大输入电压一定时,输出位数越多,量化单位越小,分辨率愈越。

    2. 转换误差

      表示 A/D 转换器实际输出的数字量和理论上的输出数字量之间的差别。常用最低有效位的倍数表示

  2. 转换时间

    指从转换控制信号到来开始,到输出端得到稳定的数字信号所经过的时间。

    积分型A/D转换时间是毫秒级,属于低速A/D;逐次比较型是微秒级,属于中速A/D;并行/串行可达到纳秒级,属于高速A/D。

3 单片机中的具体应用

3.1 STC

3.1.1 原理

STC15_ADC.png

这里 10 位的 A/D 转换结果位数由不同的 CLK-DIV.5(PCON2.5)/ADRJ值来决定。

STC15 系列单片机 ADC 由多路选择开关、比较器、逐次比较寄存器、10 位 DAC、转换结果寄存器(ADC-RES 和 ADC-RESL)以及 ADC-CONTR 构成。

通过模拟多路开关,将通道 ADC0~7 的模拟量输入并且送给比较器。用数/模转换器(DAC)转换的模拟量与输入的模拟量通过比较器进行比较,将比较结果保存到逐次比较寄存器,并通过逐次比较寄存器输出转换结果。AD 转换结束后,最终的转换结果保存到 ADC 转换结果寄存器 ADC-RES 和 ADC-RESL,同时,置位 ADC 控制寄存器ADC-CONTR 中的 A/D 转换结束标志位 ADC-FLAG,以供程序查询或发出中断申请。其中,模拟通道由 ADC 控制寄存器 ADC-CONTR 中的 CHS2~CHS0 来确定。ADC 的转换速度由 ADC 控制寄存器中的 SPEED1 和 SPEED0 确定。在使用 ADC 之前,应先给 ADC 上电,也就是置位 ADC控制寄存器中的 ADC-POWER 位。

公式如下:

  1. 当 ADRJ=0 时(结果取 10 位),Vin = [(ADC-RES[7:0],ADC-RESL[1:0])/ 1024 ] * Vcc。
  2. 当 ADRJ=0 时(结果取 8 位),Vin = [(ADC-RES[7:0])/ 256 ] * VCC

注意:这个逐次比较是从最高位开始的。

  1. 当 ADRJ=1 时(结果取 10 位),Vin = [(ADC-RES[1:0],ADC-RESL[7:0])/ 1024 ] * Vcc。
  1. 相关寄存器
    1. P1 口模拟功能控制寄存器:P1ASF。分别控制 P1.n 口作为模拟功能 A/D 使用,这里的 n=0~7。STC15 系类单片机的 A/D 转换口在 P1 口(P1.7~P1.0),有 8 路 10 位高速 A/D 转换器,速度可达到 300KHZ(30 万次/秒)。
    2. ADC 控制寄存器: ADCCONTR

3.1.2 代码例程(STC12)

BYTE ch=0;                     //定义A/D通道
void adc_isr interrupt 5 using 1
{
  ADC_CONTR &=!ADC_FLAG;
  SendData(ADC_RES);
  if(++ch>7)ch=0;
  ADC_CONTR = ADC_POWER | ADC_SPEEDLL | ADC_START | ch;
}

void InitADC( )
{

P1ASF = 0xff;     //Set all P1 as analog input port
ADC_RES = 0;      //Clear previous result
ADC_CONTR = ADC_POWER | ADC_SPEEDLL | ADC_START | ch;
Delay(2);//ADC power-on delay and Start A/D conversion
}

3.2 STM323

3.2.1 原理

STM32 拥有 1~3 个 ADC ( STM32F101/102 系列只有 1 个 ADC),这些 ADC 可以独立 使用,也可以使用双重模式(提高采样率)。 STM32 的 ADC 是 12 位逐次逼近型的模拟数 字转换器。它有 18 个通道,可测量 16 个外部和 2 个内部信号源。各通道的 A/D 转换可 以单次、连续、扫描或间断模式执行。 ADC 的结果可以左对齐或右对齐方式存储在 16 位 数据寄存器中。

STM32 的 ADC 最大的转换速率为 1Mhz,也就是转换时间为 1us (在 ADCCLK=14M,采样周期 为 1.5 个 ADC 时钟下得到),不要让 ADC 的时钟超过 14M,否则将导致结果准确度下降。STM32 将 ADC 的转换分为 2 个通道组:规则通道组和注入通道组。规则通道相当于你正常运行的程序,而注入通道呢,就相当于中断。在你程序正常执行的时候,中断是可以打断你的执行的。同这个类似,注入通道的转换可以打断规则通道的转换,在注入通道被转换完成之后,规则通道才得以继续转换。STM32 其 ADC 的规则通道组最多包含 16 个转换,而注入通道组最多包含 4 个通道。

STM32 的 ADC 在单次转换模式下,只执行一次转换,该模式可以通过 ADCCR2 寄存器的 ADON 位(只适用于规则通道)启动,也可以通过外部触发启动(适用于规则通道和注入通道),这是 CONT 位为 0。以规则通道为例,一旦所选择的通道转换完成,转换结果将被存在 ADCDR 寄存器中,EOC(转换结束)标志将被置位, 如果设置了 EOCIE,则会产生中断。然后 ADC 将停止,直到下次启动 。

STM32 的 DAC 模块(数字/模拟转换模块)是 12 位数字输入,电压输出型的 DAC。 DAC可以配置为 8 位或 12 位模式,也可以与 DMA 控制器配合使用。 DAC 工作在 12 位模式时,数据可以设置成左对齐或右对齐。 DAC 模块有 2 个输出通道,每个通道都有单独的转换器。在双 DAC 模式下, 2 个通道可以独立地进行转换,也可以同时进行转换并同步地更新 2 个通道的输出。 DAC 可以通过引脚输入参考电压 VREF+以获得更精确的转换结果。

  1. 采样周期的设置

    一般来说 AD 采样时间是需要时间 的, STM32的 AD 最大转换速率是 1us, 所以这里设置的时候, 不要小于 1us, 否则会导致结果误差大。那么怎么设置呢?比如说,我们设置的采样周期为 1.5 个周期,而我们的 AD频率为 14MHZ。 (这个频率是通过设置分频得到的) 那么我们的转换时间是多少呢?那么 AD 转换一次所需要的总 的周期数为 1.5 + 12.5 = 14。这个 1.5 就是我们设置的采样周期,而这个 12.5 是固定的必须加的,它是基础时间。那么我们就可以很轻易算出,在 14MHZ 的频率下, 14 个周期的时间就是 1us。

    STM32_ADC.png

3.2.2 代码例程(标准库函数版)

  1. A/D
    void adc_init()
    {
    GPIO_InitTypeDef GPIO_InitStructure;
    ADC_InitTypeDef ADC_InitStructure;
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_AFIO|RCC_APB2Per
    iph_ADC1,ENABLE);
    RCC_ADCCLKConfig(RCC_PCLK2_Div6);//12M 最大 14M 设置 ADC 时钟(ADCCLK)
    GPIO_InitStructure.GPIO_Pin=GPIO_Pin_1;//ADC
    GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AIN; //模拟输入
    GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
    GPIO_Init(GPIOA,&GPIO_InitStructure);
    ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;
    ADC_InitStructure.ADC_ScanConvMode = DISABLE;
    ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;
    ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
    ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
    ADC_InitStructure.ADC_NbrOfChannel = 1;
    ADC_Init(ADC1, &ADC_InitStructure);
    //设置指定 ADC 的规则组通道,设置它们的转化顺序和采样时间
    ADC_RegularChannelConfig(ADC1,ADC_Channel_1,1,ADC_SampleTime_239Cycles5);
    ADC_Cmd(ADC1,ENABLE);
    ADC_ResetCalibration(ADC1);//重置指定的 ADC 的校准寄存器
    while(ADC_GetResetCalibrationStatus(ADC1));//获取 ADC 重置校准寄存器的状态
    ADC_StartCalibration(ADC1);//开始指定 ADC 的校准状态
    while(ADC_GetCalibrationStatus(ADC1));//获取指定 ADC 的校准程序
    ADC_SoftwareStartConvCmd(ADC1, ENABLE);//使能或者失能指定的 ADC 的软件转换启动功能
    }
    
    adc_init();
    ADC_SoftwareStartConvCmd(ADC1, ENABLE);
    while(!ADC_GetFlagStatus(ADC1,ADC_FLAG_EOC));//转换结束标志位
    value=value+ADC_GetConversionValue(ADC1);//返回最近一次 ADCx 规则组的转换结果
  2. D/A
    void dac_init()
    //DAC 初始化
    {
    GPIO_InitTypeDef GPIO_InitStructure;
    DAC_InitTypeDef DAC_InitStructure;
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_AFIO,ENABLE);
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_DAC,ENABLE);
    GPIO_InitStructure.GPIO_Pin=GPIO_Pin_4;//DAC_1
    GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AIN;//模拟量输入
    GPIO_Init(GPIOA,&GPIO_InitStructure);
    GPIO_SetBits(GPIOA,GPIO_Pin_4);//输出高
    DAC_InitStructure.DAC_Trigger=DAC_Trigger_None;//不使用触发功能
    DAC_InitStructure.DAC_WaveGeneration=DAC_WaveGeneration_None;//不使用三角波
    //屏蔽 幅值设置
    DAC_InitStructure.DAC_LFSRUnmask_TriangleAmplitude=DAC_LFSRUnmask_Bit0;
    //关闭缓存
    DAC_InitStructure.DAC_OutputBuffer=DAC_OutputBuffer_Disable;
    DAC_Init(DAC_Channel_1,&DAC_InitStructure);//初始化 DAC 通道 1
    DAC_Cmd(DAC_Channel_1,ENABLE);//使能 DAC1
    DAC_SetChannel1Data(DAC_Align_12b_R,0);//12 位 右对齐 写 0 数据
    }

3.3 MSP430

3.3.1 原理4

MSP430中有ADC10和ADC12两个模块,ADC12A 模块支持快速12位数模转换,具有一个12位的逐次渐进(SAR)内核,转换控制缓冲区允许没有CPU干预的情况下,多达16路独立ADC采样值进行转换和保持。可以模拟多通道,并且有8路外部通道(A0-A7)和4路内部通道。具有高达200ksps的最大转换率。

ADC 内核将一个模拟输入信号转换为 12 位的数字信号,并将其结果存储在转换存储器中。该内核采用两个可编程/选择的电压(VR+和 VR-)作为转换的上限和下限(即我们说的ADC和DAC的基准信号)。当输入信号大于或等于 VR+时,数字输出(NADC )为最大值(0FFFh),而当输入信号小于者等于 VR-时,输出为 0。在转换控制存储器中定义输入通道和参考电压(VR+和 VR-)。ADC转换结果 Nadc 的计算公式为:

Nadc = 4095 × (Vin-VR -)⁄(VR +-VR -)

其中,4095为212-1,12位ADC将VR+和VR-之间分割成212 等份,然后将输入的模拟信号进行转换,输出0~4095的数字。

ADC12A 内核可通过两个寄存器 ADC12CTL0 和 ADC12CTL1 来进行配置,通过 ADC12ON 位使能内核。在不需要转换时可以关闭 ADC12A以节省功耗。除很少例外,只有当 ADC12ENC = 0 时才能修改ADC12A 控制位。在执行转换前 ADC12ENC 必须置 1。

ADC12A 支持 8 位、10 位及 12 位分辨率模式,可以通过 ADC12RES 位选择。模数转换分别需要 9、11、及 13 个 ADC12CLK 周期。SHI 信号源的极性可以通过 ADC12ISSH 位反转。SAMPCON 信号控制采用周期和启动转换。当 SAMPCON 信号为高时,表示正处在采样过程,SAMPCON 由高到低转换将启动模数转换。ADC12SHP 定义了两种不同的采样时序方法,扩展采样时序和脉冲采样时序。

ADC12共有12个转换通道,设置了16个转换存储器(ADC12MEMx)用于暂时存储转换结果,合理设置后,ADC12硬件会自动将转换结果保存到相应的存储器里。

MSP430_ADC.png

3.3.2 代码例程5

//******************************************************************************
//   MSP430F552x Demo - ADC12, Sample A0, Set P1.0 if A0 > 0.5*AVcc
//
//   Description: A single sample is made on A0 with reference to AVcc.
//   Software sets ADC12SC to start sample and conversion - ADC12SC
//   automatically cleared at EOC. ADC12 internal oscillator times sample (16x)
//   and conversion. In Mainloop MSP430 waits in LPM0 to save power until ADC12
//   conversion complete, ADC12_ISR will force exit from LPM0 in Mainloop on
//   reti. If A0 > 0.5*AVcc, P1.0 set, else reset.
//
//                MSP430F552x
//             -----------------
//         /|\|                 |
//          | |                 |
//          --|RST              |
//            |                 |
//     Vin -->|P6.0/CB0/A0  P1.0|--> LED
//
//   Bhargavi Nisarga
//   Texas Instruments Inc.
//   April 2009
//   Built with CCSv4 and IAR Embedded Workbench Version: 4.21
//******************************************************************************

#include <msp430.h>

int main(void)
{
  WDTCTL = WDTPW + WDTHOLD;                 // Stop WDT
  ADC12CTL0 = ADC12SHT02 + ADC12ON;         // Sampling time, ADC12 on
  ADC12CTL1 = ADC12SHP;                     // Use sampling timer
  ADC12IE = 0x01;                           // Enable interrupt
  ADC12CTL0 |= ADC12ENC;
  P6SEL |= 0x01;                            // P6.0 ADC option select
  P1DIR |= 0x01;                            // P1.0 output

  while (1)
  {
    ADC12CTL0 |= ADC12SC;                   // Start sampling/conversion

    __bis_SR_register(LPM0_bits + GIE);     // LPM0, ADC12_ISR will force exit
    __no_operation();                       // For debugger
  }
}

#if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)
#pragma vector = ADC12_VECTOR
__interrupt void ADC12_ISR(void)
#elif defined(__GNUC__)
void __attribute__ ((interrupt(ADC12_VECTOR))) ADC12_ISR (void)
#else
#error Compiler not supported!
#endif
{
  switch(__even_in_range(ADC12IV,34))
  {
  case  0: break;                           // Vector  0:  No interrupt
  case  2: break;                           // Vector  2:  ADC overflow
  case  4: break;                           // Vector  4:  ADC timing overflow
  case  6:                                  // Vector  6:  ADC12IFG0
    if (ADC12MEM0 >= 0x7ff)                 // ADC12MEM = A0 > 0.5AVcc?
      P1OUT |= BIT0;                        // P1.0 = 1
    else
      P1OUT &= ~BIT0;                       // P1.0 = 0

    __bic_SR_register_on_exit(LPM0_bits);   // Exit active CPU
  case  8: break;                           // Vector  8:  ADC12IFG1
  case 10: break;                           // Vector 10:  ADC12IFG2
  case 12: break;                           // Vector 12:  ADC12IFG3
  case 14: break;                           // Vector 14:  ADC12IFG4
  case 16: break;                           // Vector 16:  ADC12IFG5
  case 18: break;                           // Vector 18:  ADC12IFG6
  case 20: break;                           // Vector 20:  ADC12IFG7
  case 22: break;                           // Vector 22:  ADC12IFG8
  case 24: break;                           // Vector 24:  ADC12IFG9
  case 26: break;                           // Vector 26:  ADC12IFG10
  case 28: break;                           // Vector 28:  ADC12IFG11
  case 30: break;                           // Vector 30:  ADC12IFG12
  case 32: break;                           // Vector 32:  ADC12IFG13
  case 34: break;                           // Vector 34:  ADC12IFG14
  default: break;
  }
}

Footnotes:

1

《STC15单片机实战指南》

2

《51菜鸟到ARM(STM32)高手进阶之路》

3

普中实验

4

《MSP430F55xx Users Guide》

5

TI MSPWare官方例程

Author: 徐文婷

Created: 2017-04-07 Fri 17:56

Emacs 24.5.1 (Org mode 8.2.10)

Validate

comments powered by Disqus

Older · View Archive (56)

PWM 详解

<!DOCTYPE html PUBLIC “-//W3C//DTD XHTML 1.0 Strict//EN” “http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd”>

PWM 详解

Newer

PID 详解