跳转至

1. 简介及前言

1.1 简介

我们主要来介绍AD(Analog to digital)外设,中文名叫做模拟转数字,主要用于实现从物理的连续模拟信号转变为在芯片中传输的离散数字信号,例如实现一个示波器的、信号采集器等都至关重要。

因为我们知道,对于任意一个波形或者任意一个物理世界中存在的信号来说,它都不是一个数字信号而是一个实实在在的模拟信号。而模拟信号通过AD芯片可以量化成我们的数字信号

将模拟信号转变为数字信号的电子元件或者电路,将经过与标准量比较处理后的模拟量转换为以二进制数值表示的离散信号。模拟信号向数字信号转换过程一般分为四个步骤:采样、保持、量化、编码。采样与保持,一般是在电路中弯沉,而量化和编码则需要我们这里的AD芯片

常用的AD芯片的种类及结构有很多中类型:逐次逼近型、流水线型、闪速、积分型、压频、智能等转换器

AD的外围电路也与很多:信号调理电路、电压基准电路等

关于很多原理,就需要参考书籍进行学习,例如这里参考的就是《常用A/D、D/A器件手册》,是我在实验室的书架中看到的一本书

1.2 前言

不同的产品尽管在性能指标及体系结构上与差异,但市场上绝大多数的器件都是针对通用领域来设计的,从用户的角度上来讲,不仅价格昂贵,而且很难做选择。

按照领域细分:随着工业制造工艺的进步,使得为专门应用设计的器件成为可能。最明显的领域如多媒体数字信号编解码器(CODEC),这一设计针对音频领域专门涉及到高性能数据转换器件。采用$I^2S$接口传输音频数据,采用$I^2C总线作为控制总线等。

高速度:这种趋势在两个领域应用中十分明显:一个是软件无线电,另一个是示波器及信号分析设备。所谓软件无线电,就是采用数字信号处理的技术,在可编程控制的通用硬件平台上,利用软件来定义实现无线电台的各部分功能,包括:前端接收、中频处理以及信号的基带处理等。

高精度:Σ-Δ型ADC(也称为过采样转换器)是一种高精度的转换器,它采用增量编码方式进行量化编码,最高分辨率达到24位,通过模拟Σ-Δ调制器和数字抽取滤波器来实现高分辨率的数字信号转换。此外,流水线型ADC也是一种高效且强大的模数转换器,它能够提供高速、高分辨率的模数转换,并且具有低功率消耗和较小的芯片尺寸。

SoC技术的应用及智能转换器:片上系统(SoC)已经称为继承电路发展的去世。大部分传感器需要进行信号调整以消除潜在的测量误差。这些误差包括增益和偏移误差、环境或固有噪声以及传感器自身传递函数的非线性。这些要求使得A/D转换器本身要做的事情不仅是从模拟信号到数字信号的转换,可能还需要完成信号调理、补偿、误差修正、数据格式转换、提供激励源或偏置,甚至在片上系统上集成一个控制器。从用户的角度来看,它们是带有A/D转换器及D/A转换器的处理器。从数据的角度来看,它们是基于SoC技术的集成了处理器的A/D转换器,可以把他们称为“智能A/D转换器

2. AD的基本概述

从AD的名字可以看出,AD就是将时间连续、幅值也连续的模拟量转换成时间离散、幅值也离散的数字信号。

3. AD的通信协议

TLC549内部具有4MHZ的系统时钟,并且该时钟域I/O CLOCK是独立工作的,所以我们无需特殊的速度或相位匹配就可以进行时序的操作

3.1 AD时序图

在这里我们需要注意几个问题:

  1. 当CS为高时,转换结果输出串行输出端DATA OUT处于高阻状态,此时I/O CLOCK不起作用
  2. 当CS为低时,AD前一次转换数据A的最高位A7立即出现在数据线DATA OUT上,其余的7位数据在I/O CLOCK的下降沿一次由时钟同步输出。因此可在I/O CLOCK的上升沿读取数据。
  3. 当CS变为低电平到I/O CLOCK的第一个时钟到来至少需要1.4us。
  4. I/O CLOCK不能超过1.1MHZ。
  5. 读完8位数据,AD开始转换这次的采样数据,以便下一次读取。转换时片选信号CS必须置高电平,每次转换时间不超过17us,开始于CS变为低电平后I/O CLOSK的第8个下降沿,没有转换完成标志信号;也没有启动控制端,只要读取前一次数据后马上开始新的AD转换,转换完成之后进入保持状态。

4. TLC549_AD串行芯片的实战

它以8位开关电容逐次逼近型[^1]的方法实现AD转换,其内部具有4MHZ的系统时钟,转换速度小于17us,它允许的最大转换速率为40_000次/s,电源为3V-6V,能方便地采用三线串行接口方式与各种微处理器进行链连接

4.1 引脚含义如下:

  • REF+:正基准电压输入 2.5V≤REF+≤Vcc+0.1。

  • REF-:负基准电压输入端,-0.1V≤REF-≤2.5V。且要求:(REF+)-(REF-)≥1V。

  • VCC:系统电源3V≤Vcc≤6V。

  • GND:接地端。

  • /CS:芯片选择输入端,要求输入高电平 VIN≥2V,输入低电平 VIN≤0.8V。

  • DATA OUT:转换结果数据串行输出端,与 TTL 电平兼容,输出时高位在前,低位在后。

  • ANALOGIN:模拟信号输入端,0≤ANALOGIN≤Vcc,当 ANALOGIN≥REF+电压时,转换结果为全“1”(0FFH),ANALOGIN≤REF-电压时,转换结果为全“0”(00H)。

  • I/O CLOCK:外接输入/输出时钟输入端,同于同步芯片的输入输出操作,无需与芯片内部系统时钟同步。

4.2 芯片连接原理

芯片手册及实验解析文档链接如下:

https://zikwq.lanzout.com/b00rn1bf8h 密码:9q6b

4.3 逐次逼近型原理

4.4量化电平

4.5 代码模块

框图针对FPGA设计,其中data为AD的输出数据,也就是FPGA的输入端

```verilog TCL549.v module TLC549( clk, //系统输入时钟 ioclk,//AD驱动时钟 data, //TLC549的数据串行输出端,相对于FPGA为输入 cs, //AD片选信号 rst_n,//系统复位 segdata,//数码管段选 segcs//数码管位选 ); input clk; input data; input rst_n;

output reg cs; output reg ioclk; output reg [7:0]segdata; output reg [2:0]segcs;

reg[31:0] count; reg[24:0]count1ms; reg[3:0] cnt; reg[2:0]number; reg[1:0] state; reg[7:0]dataout; reg[15:0]tenvalue; reg clk1ms;

parameter sample=2'b00, display=2'b01;

//-----------数据采集时钟----------- always@(posedge clk) begin if(count<16'd1000)
count<=count+1'b1;
else begin count<=0; ioclk<=~ioclk; end end

//-----------数码管驱动时钟----------- always@(posedge clk) begin if(count1ms>25'd1000_0) begin clk1ms<=~clk1ms; count1ms<=0; end else count1ms<=count1ms+1; end

//-----------AD数据采集----------- always@(negedge ioclk) begin case(state) sample: begin cs<=0; dataout[7:0]<={dataout[6:0],data}; if(cnt>4'd7) begin cnt<=0; state<=display;
end
else begin cnt<=cnt+1; state<=sample; end end display: begin cs<=1; tenvalue<=(dataout * 1000 * 25 )/256; state<=sample; end default: state<=display; endcase end

//-----------数码管译码----------- function[7:0] leddata; input[3:0] datain; begin case(datain) 4'd0: leddata=8'b11000000;//0 4'd1: leddata=8'b11111001;//1 4'd2: leddata=8'b10100100;//2 4'd3: leddata=8'b10110000;//3 4'd4: leddata=8'b10011001;//4 4'd5: leddata=8'b10010010;//5 4'd6: leddata=8'b10000010;//6 4'd7: leddata=8'b11111000;//7 4'd8: leddata=8'b10000000;//8 4'd9: leddata=8'b10010000;//9 4'd10: leddata=8'b10111111;//- 4'd11: leddata=8'b01111111;//. default:leddata=8'bzzzz_zzzz; endcase end endfunction

//-----------数码管扫描----------- always@(posedge clk1ms) begin if(number==4) number<=0; else begin number<=number+1; case(number) 4'd0: begin segdata<=leddata((tenvalue/10)%10);//个位
segcs<=3'b011; end 4'd1: begin segdata<=leddata((tenvalue/100)%10);//十位
segcs<=3'b010; end 4'd2: begin segdata<=leddata((tenvalue/1000)%10); //百位
segcs<=3'b001; end 4'd3: begin segdata<=leddata(tenvalue/10000);//千位
segcs<=3'b000; end endcase end end

endmodule




# 5. 3PA1030双路高速AD并行芯片的实战

参考野火FPGA第24_dig_volt教程资料

```verilog adc.v
`timescale  1ns/1ns
////////////////////////////////////////////////////////////////////////
// Author        : EmbedFire
// Create Date   : 2019/08/10
// Module Name   : adc
// Project Name  : dig_volt
// Target Devices: Altera EP4CE10F17C8N
// Tool Versions : Quartus 13.0
// Description   : 电压计算模块
//
// Revision      : V1.0
// Additional Comments:
// 
// 实验平台: 野火_征途Pro_FPGA开发板
// 公司    : http://www.embedfire.com
// 论坛    : http://www.firebbs.cn
// 淘宝    : https://fire-stm32.taobao.com
////////////////////////////////////////////////////////////////////////

module  adc
(
    input   wire            sys_clk         ,   //时钟
    input   wire            sys_rst_n       ,   //复位信号,低电平有效
    input   wire    [7:0]   ad_data         ,   //AD输入数据

    output  wire            ad_clk          ,   //AD驱动时钟,最大支持20Mhz时钟
    output  wire            sign            ,   //正负符号位
    output  wire    [15:0]  volt                //数据转换后的电压值
);
//********************************************************************//
//******************Parameter And Internal Signal ********************//
//********************************************************************//
//parameter define
parameter   CNT_DATA_MAX = 11'd1024;    //数据累加次数

//wire  define
wire    [27:0]  data_p      ;   //根据中值计算出的正向电压AD分辨率
wire    [27:0]  data_n      ;   //根据中值计算出的负向电压AD分辨率

//reg define
reg             median_en   ;   //中值使能
reg     [10:0]  cnt_median  ;   //中值数据累加计数器
reg     [18:0]  data_sum_m  ;   //1024次中值数据累加总和
reg     [7:0]   data_median ;   //中值数据
reg     [1:0]   cnt_sys_clk ;   //时钟分频计数器
reg             clk_sample  ;   //采样数据时钟
reg     [27:0]  volt_reg    ;   //电压值寄存

//********************************************************************//
//***************************** Main Code ****************************//
//********************************************************************//
//数据ad_data是在ad_sys_clk的上升沿更新
//所以在ad_sys_clk的下降沿采集数据是数据稳定的时刻
//FPGA内部一般使用上升沿锁存数据,所以时钟取反
//这样ad_sys_clk的下降沿相当于sample_sys_clk的上升沿
assign  ad_clk = ~clk_sample;

//sign:正负符号位
assign  sign = (ad_data < data_median) ? 1'b1 : 1'b0;

//时钟分频(4分频,时钟频率为12.5Mhz),产生采样AD数据时钟
always@(posedge sys_clk or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        begin
            cnt_sys_clk <=  2'd0;
            clk_sample  <=  1'b0;
        end
        else
        begin
            cnt_sys_clk <=  cnt_sys_clk + 2'd1;
        if(cnt_sys_clk == 2'd1)
            begin
            cnt_sys_clk <=  2'd0;
            clk_sample  <=  ~clk_sample;
            end
        end

//中值使能信号
always@(posedge clk_sample or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        median_en   <=  1'b0;
    else    if(cnt_median == CNT_DATA_MAX)
        median_en   <=  1'b1;
    else
        median_en   <=  median_en;

//cnt_median:中值数据累加计数器
always@(posedge clk_sample or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        cnt_median    <=  11'd0;
    else    if(median_en == 1'b0)
        cnt_median    <=  cnt_median + 1'b1;

//data_sum_m:1024次中值数据累加总和
always@(posedge clk_sample or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        data_sum_m  <=  19'd0;
    else    if(cnt_median == CNT_DATA_MAX)
        data_sum_m    <=  19'd0;
    else
        data_sum_m    <=  data_sum_m + ad_data;

//data_median:中值数据
always@(posedge clk_sample or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        data_median    <=  8'd0;
    else    if(cnt_median == CNT_DATA_MAX)
        data_median    <=  data_sum_m / CNT_DATA_MAX;
    else
        data_median    <=  data_median;

//data_p:根据中值计算出的正向电压AD分辨率(放大2^13*1000倍)
//data_n:根据中值计算出的负向电压AD分辨率(放大2^13*1000倍)
assign  data_p = (median_en == 1'b1) ? 8192_0000 / ((255 - data_median) * 2) : 0;
assign  data_n = (median_en == 1'b1) ? 8192_0000 / ((data_median + 1) * 2) : 0;

//volt_reg:处理后的稳定数据
always@(posedge clk_sample or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        volt_reg    <= 'd0;
    else    if(median_en == 1'b1)
        if((ad_data > (data_median - 3))&&(ad_data < (data_median + 3)))
            volt_reg    <= 'd0;
        else    if(ad_data < data_median)
            volt_reg <= (data_n *(data_median - ad_data)) >> 13;
        else    if(ad_data > data_median)
            volt_reg <= (data_p *(ad_data - data_median)) >> 13;
    else
        volt_reg    <= 'd0;

//volt:数据转换后的电压值
assign  volt    =   volt_reg;

endmodule

6. 常见的其他AD芯片知识汇总

参考资料

[1]. 书籍:常用A/D、D/A器件手册-张志刚主编-电子工业出版社出版

[2]. https://zhuanlan.zhihu.com/p/682927018