文章目录

  • 一、ADC介绍
    • 1.ADC简介
    • 2.ADC 转换原理
  • 二、XPT2046 芯片介绍
  • 三、硬件设计
  • 四、软件设计
    • 1.ADC 读写函数
    • 2.主函数
  • 五、实验现象

  前面我们介绍的都是对数字信号的操作也就是 0 和 1 操作,本节我们就来讲解 如何检测外部模拟信号,因为我们使用的 STC89C5x 单片机内部不含 ADC 接口,所以需要外接一个 ADC 转换芯片将模拟信号转换成数字信号供单片机处理。我们开发板上集成了一个 ADC 模数转换电路,选用的 ADC 芯片是 12 位的 AD 芯片- XPT2046。本节要实现的功能是:通过 ADC 转换电路采集电位器电压值,将采集转换后的 AD 值通过数码管显示。

一、ADC介绍

  我们知道 51 单片机系统内部运算时用的全部是数字量,即 0 和 1,因此对单片机系统而言,无法直接操作模拟量,必须将模拟量转换成数字量。所谓数字量,就是用一系列 0 和 1 组成的二进制代码表示某个信号大小的量。用数字量表示同一个模拟量时,数字位数可以多也可以少,位数越多则表示的精度越高,位数越少表示的精度就越低。

1.ADC简介

  ADCanalog to digital converter)也称为模数转换器,是指一个将模拟信号转变为数字信号。单片机在采集模拟信号时,通常都需要在前端加上 A/D 芯片
  下面我们看下 ADC主要技术指标

  1. 分辨率
      ADC 的分辨率是指对于允许范围内的模拟信号,它能输出离散数字信号值的个数。这些信号值通常用二进制数来存储,因此,分辨率经常用比特作为单位,且这些离散值的个数是 2 的幂指数。
      例如:12 位 ADC 的分辨率就是 12 位,或者说分辨率为满刻度的 1/(2^12)。一个 10V 满刻度的 12 位 ADC 能分辨输入电压变化最小值是
    10 V × 1 / ( 2 12 ) = 2.4 m V 10V×1/(2^{12})=2.4mV 10V×1/(212)=2.4mV

  2. 转换误差
      转换误差通常是以输出误差的最大值形式给出。它表示 A/D 转换器实际输出的数字量和理论上的输出数字量之间的差别。常用最低有效位的倍数表示。例如给出相对误差≤±LSB/2,这就表明实际输出的数字量和理论上应得到的输出数字量之间的误差小于最低位的半个字。

  3. 转换速率
      ADC 的转换速率是能够重复进行数据转换的速度,即每秒转换的次数。而完成一次 A/D 转换所需的时间(包括稳定时间)则是转换速率的倒数。

2.ADC 转换原理

  AD 转换器(ADC)将模拟量转换为数字量通常要经过 4 个步骤:采样、保持、量化和编码。所谓采样即是将一个时间上连续变化的模拟量转换为时间上离散变化的模拟量。如下图所示:

  将采样结果存储起来,直到下次采样,这个过程叫做保持。一般采样器和保持电路一起总称为采样保持电路。将采样电平归化为与之接近的离散数字电平,这个过程叫做量化。将量化后的结果按照一定数制形式表示就是编码。将采样电平(模拟值)转换为数字值时,主要有两类方法:直接比较型与间接比较型。

  • 直接比较型:就是将输入模拟信号直接与标准的参考电压比较,从而得到数字量。常见的有并行 ADC 和逐次比较型 ADC
  • 间接比较型:输入模拟量不是直接与参考电压比较,而是将二者变为中间的某种物理量在进行比较,然后将比较所得的结果进行数字编码。常见的有双积分型 ADC

  下面就以常用的逐次比较型 ADC 和双积分型 ADC 介绍其工作原理。

  • 逐次逼近型 ADC
      采用逐次逼近法的 AD 转换器是有一个比较器、DA 转换器、缓冲寄存器和控制逻辑电路组成,如下图所示:

      基本原理:从高位到低位逐次试探比较,就像用天平秤物体,从重到轻逐级增减砝码进行试探。
      逐次逼近法的转换过程:初始化时将逐次逼近寄存器各位清零,转换开始时,先将逐次逼近寄存器最高位置 1,送入 DA 转换器,经 DA转换后生成的模拟量送入比较器,称为 U0,与送入比较器的待转换的模拟量 Ux进行比较,若 U0<Ux,该位 1 被保留,否则被清除。然后再将逐次逼近寄存器次高位置 1,将寄存器中新的数字量送 DA 转换器,输出的 U0 再与 Ux 比较,若 U0<Ux,该位 1 被保留,否则被清除。重复此过程,直至逼近寄存器最低位。转换结束后,将逐次逼近寄存器中的数字量送入缓冲寄存器,得到数字量的输出。逐次逼近的操作过程是在一个控制电路的控制下进行的。
  • 双积分型 ADC
      采用双积分法的 AD 转换器由电子开关、积分器、比较器和控制逻辑等部件组成。如下图所示:

      基本原理:将输入电压变换成与其平均值成正比的时间间隔,再把此时间间隔转换成数字量,属于间接转换。
      双积分法 AD 转换过程:先将开关接通待转换的模拟量 ViVi 采样输入到积分器,积分器从零开始进行固定时间 T 的正向积分,时间 T 到后,开关再接通与 Vi 极性相反的基准电压 Vref,将Vref输入到积分器,进行反向积分,直到输出为 0V 时停止积分。Vi 越大,积分器输出电压越大,反向积分时间也越长。计数器在反向积分时间内所计的数值,就是输入模拟电压 Vi 所对应的数字量,实现了 AD 转换。

二、XPT2046 芯片介绍

  XPT2046 是一款 4 线制电阻式触摸屏控制器,内含 12 位分辨率 125KHz转换速率逐步逼近型 A/D 转换器。XPT2046 支持从 1.5V5.25V 的低电压I/O 接口。XPT2046 能通过执行两次 A/D 转换查出被按的屏幕位置,除此之外,还可以测量加在触摸屏上的压力。内部自带 2.5V 参考电压,可以作为辅助输入、温度测量和电池监测之用,电池监测的电压范围可以从 0V6VXPT2046 片内集成有一个温度传感器。在 2.7V 的典型工作状态下,关闭参考电压,功耗可小于 0.75mWXPT2046 采用微小的封装形式:TSSOP-16,QFN-16VFBGA-48。工作温度范围为-40℃~+85℃。与 ADS7846TSC2046AK4182A 完全兼容。

  1. 主要特性
    ①工作电压范围为 1.5V~5.25V
    ②支持 1.5V~5.25V 的数字 I/O
    ③内含 2.5V 参考电压源
    ④电源电压测量( 0V~6V
    ⑤内建结温测量功能
    ⑥触摸压力测量
    ⑦采用 3 线制 SPI 通信接口
    ⑧具有自动省电功能

  2. 芯片管脚说明


      XPT2046 是一种典型的逐次逼近型模数转换器(SAR ADC),包含了采样/保持、模数转换、串口数据 输出等功能。同时芯片集成有一个 2.5V 的内部参考电压源、温度检测电路,工作时使用外部时钟。XPT2046 可以单电源供电,电源电压范围为 2.7V~5.5V。参考电压值直接决定 ADC 的输入范围,参考电压可以使用内部参考电压,也可以从外部直接输入 1V~VCC 范围内的参考电压(要求外部参考电压源输出阻抗低)。XYZVBATTempAUX 模拟信号经过片内的控制寄存器选择后进入 ADCADC 可以配置为单端或差分模式。选择 VBATTempAUX 时应该配置为单端模式;作为触摸屏应用时,应该配置为差分模式,这可有效消除由于驱动开关的寄生电阻及外部的干扰带来的测量误差,提高转换精度。单端和差分模式输入配置如下图所示:

      XPT2046 数据接口是串行接口,其典型工作时序如下图所示,图中展示的信号来自带有基本串行接口的单片机或数据信号处理器。处理器和转换器之间的的通信需要 8 个时钟周期,可采用 SPISSIMicrowire 等同步串行接口。一次完整的转换需要 24 个串行同步时钟(DCLK)来完成。
      前 8 个时钟用来通过 DIN 引脚输入控制字节。当转换器获取有关下一次转换的足够信息后,接着根据获得的信息设置输入多路选择器和参考源输入,并进入采样模式,如果需要,将启动触摸面板驱动器。3 个多时钟周期后,控制字节设置完成,转换器进入转换状态。这时,输入采样-保持器进入保持状态,触摸面板驱动器停止工作(单端工作模式)。接着的 12 个时钟周期将完成真正的模数转换。如果是度量比率转换方式(SER/DFR=0),驱动器在转换过程中将一直工作,第 13 个时钟将输出转换结果的最后一位。剩下的 3 个多时钟周期将用来完成被转换器忽略的最后字节(DOUT 置低)。

      在对 XPT2046 进行控制时,控制字节由 DIN 输入的控制字命令格式如下所示:

三、硬件设计

  本实验使用到硬件资源如下:

  • 动态数码管
  • ADC模块

  动态数码管电路在前面章节都介绍过,这里就不再重复。下面来看下开发板上 ADC 模块电路,如下图所示:


  从上图中可以看出,该电路是集成的,XPT2046 芯片的控制管脚接至单片机P3.4~P3.7 管脚上,XPT2046 芯片的 ADC 输入转换通道分别接入了 AD1 电位器、NTC1 热敏传感器、GR1 光敏传感器,还有一个外接通道 AIN3 接在 DACPWM)模块的 J52 端子上供外部模拟信号检测。
  注意:上图中 XPT2046DOUT 脚与 DS18B20 温度传感器均连接到单片机的P3.7,因此该两个外设资源不能同时使用,可以分时复用。

四、软件设计

  本节所要实现的功能是:数码管上显示 AD 模块采集电位器的电压值。
  程序框架如下:

  • 编写公共文件
    打开public.c文件,代码如下:

    #include "public.h"/*
    函 数 名 : delay_10us
    函数功能 : 延时函数,ten_us=1 时,大约延时 10us
    输 入 : ten_us
    输 出 : 无
    */
    void delay_10us(u16 ten_us)
    {while(ten_us--);
    }/*
    函 数 名 : delay_ms
    函数功能 : ms 延时函数,ms=1 时,大约延时 1ms
    输 入 : ten_us
    输 出 : 无
    */
    void delay_ms(u16 ms)
    {u16 i,j;for (i=ms;i>0;i--){for (j=110;j>0;j--);}
    }
    

    其头文件public.h为:

    /*
    头文件作用如下:包含头文件,定义全局变量,声明函数
    */
    #ifndef _public_H
    #define _public_H#include "reg52.h"//对系统默认数据类型进行重定义
    typedef unsigned char u8;
    typedef unsigned int u16;//函数声明
    void delay_10us(u16 ten_us);
    void delay_ms(u16 ms);#endif
    
  • 编写数码管显示功能
    打开smg.c文件,代码如下:

    #include "smg.h"//使用数组保存共阴极数码管0-F的段码数据
    u8 gsmg_code[17] = {0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};/*
    函 数 名 : smg_display
    函数功能 : 动态数码管显示
    输入 : 无
    输出 : 无
    */
    void smg_display(u8 dat[],u8 pos)
    {u8 i = 0;u8 pos_temp = pos - 1; //位置与位选进行统一for (i=pos_temp;i<8;i++){//位选switch (i){case 0 : LSC = 1;LSB = 1;LSA = 1;break;case 1 : LSC = 1;LSB = 1;LSA = 0;break;case 2 : LSC = 1;LSB = 0;LSA = 1;break;case 3 : LSC = 1;LSB = 0;LSA = 0;break;case 4 : LSC = 0;LSB = 1;LSA = 1;break;case 5 : LSC = 0;LSB = 1;LSA = 0;break;case 6 : LSC = 0;LSB = 0;LSA = 1;break;case 7 : LSC = 0;LSB = 0;LSA = 0;break;}//给当前位传送段选数据SMG_A_DP_PORT = dat[i-pos_temp];delay_10us(100);  //延时1ms,循环一轮8ms,小于肉眼可区分的24msSMG_A_DP_PORT =0x00; //消音,消除上一次数码管段选数据对下一次的影响}
    }
    

    其头文件smg.h

    #ifndef _smg_H
    #define _smg_H#include "public.h"//使用宏定义数码管段码口
    #define SMG_A_DP_PORT P0
    //定义数码管位选信号控制管脚
    sbit LSA = P2^2;
    sbit LSB = P2^3;
    sbit LSC = P2^4;extern u8 gsmg_code[17];void smg_display(u8 dat[],u8 pos);#endif
    
  • 编写 ADC 转换函数

  • 编写主函数

1.ADC 读写函数

  打开 xpt2046.c 文件,代码如下:

#include "xpt2046.h"
#include "intrins.h"/*
* 函 数 名 : xpt2046_wirte_data
* 函数功能 : XPT2046 写数据
* 输 入 : dat:写入的数据
* 输 出 : 无
* 注意    :CLK 由低到高产生一个上升沿,通过DIN写入数据
*/
void xpt2046_wirte_data(u8 dat)
{u8 i;CLK = 0;  _nop_();for (i=0;i<8;i++)//循环 8 次,每次传输一位,共一个字节{DIN = dat >> 7;//先传高位再传低位dat <<= 1;//将低位移到高位CLK = 1;//CLK 由低到高产生一个上升沿,从而写入数据_nop_();CLK = 0;_nop_();     }
}/*
* 函 数 名 : xpt2046_read_data
* 函数功能 : XPT2046 读数据
* 输 入 : 无
* 输 出 : XPT2046 返回 12 位数据
* 注意    : CLK 由高到低产生一个下降沿,从DOUT读取数据
*/
u16 xpt2046_read_data(void)
{u8 i;u16 dat = 0;CLK = 0;_nop_();for (i=0;i<12;i++)//循环 12 次,每次读取一位,大于一个字节数,所以返回值类型是 u16{dat <<= 1;CLK = 1;_nop_();CLK = 0; //CLK 由高到低产生一个下降沿,从而读取数据_nop_();dat |= DOUT;//先读取高位,再读取低位。}return dat;
}/*
* 函 数 名 : xpt2046_read_adc_value
* 函数功能 : XPT2046 读 AD 数据
* 输 入 : cmd:控制指令
* 输 出 : XPT2046 返回 AD 值
*/
u16 xpt2046_read_adc_value(u8 cmd)
{u8 i;u16 adc_value = 0;CS = 0;    //使能 XPT2046CLK = 0; //先拉低时钟_nop_();xpt2046_wirte_data(cmd); //发送控制命令for (i=6;i>0;i--);  //延时等待转换结果CLK = 0;_nop_();CLK = 1;//发送一个时钟,清除 BUSY忙时信号_nop_();adc_value=xpt2046_read_data();CS = 1;//关闭 XPT2046,此时为高阻态return adc_value;
}

根据前面 XPT2046 时序图可知,XPT2046 完成一个完整的转换需要 24 个串行时钟,也就是需要 3 个字节的 SPI 时钟。XPT2046 前 8 个串行时钟,是接收 1 个字节的转换命令,接收到转换命令了之后,然后使用 1 个串行时钟的时间来完成数据转换(当然在编写程序的时候,为了得到精确的数据,你可以适当的延时一下) ,然后返回 12 个字节长度(12 个字节长度也计时 12 个串行时钟)的转换结果。然后最后 4 个串行时钟返回 4 个无效数据,可以忽略。xpt2046_read_adc_value 函数就是按照这个时序实现。至于xpt2046_wirte_dataxpt2046_read_data 函数是 IO 口模拟的 SPI 读写时序,与 DS1302 的读写是一样的。
  其头文件xpt2046.h为:

#ifndef _xpt2046_H
#define _xpt2046_H#include "public.h"//定义XPT2046控制管脚
sbit DOUT = P3^7; //串行数据输出管脚
sbit DIN = P3^4;  //串行数据输入管脚
sbit CS = P3^5;
sbit CLK = P3^6;  //外部时钟信号输入管脚//声明函数
void xpt2046_wirte_data(u8 dat);
u16 xpt2046_read_data(void);
u16 xpt2046_read_adc_value(u8 cmd);#endif

2.主函数

  打开 main.c 文件,代码如下:

/*
实验名称:ADC 模数转换实验--电位器电压采集
接线说明:
实验现象:下载程序后,数码管上显示 AD 模块采集电位器的电压值
注意事项:需要注意电位器功能采集对应的A2、A1、A0分别是什么,这里是001
*/
#include "public.h"
#include "smg.h"
#include "xpt2046.h"/*
* 函 数 名 : main
* 函数功能 : 主函数
* 输 入 : 无
* 输 出 : 无
*/
void main(void)
{u16 adc_value = 0;float adc_vol; //ADC电压值u8 adc_buf[3];while (1){adc_value=xpt2046_read_adc_value(0x94);//测量电位器adc_vol=5.0*adc_value/4096;//将读取的 AD 值转换为电压adc_value=adc_vol*10;//放大 10 倍,即保留小数点后一位adc_buf[0]=gsmg_code[adc_value/10]|0x80;adc_buf[1]=gsmg_code[adc_value%10];adc_buf[2]=0x3e;//显示单位 Vsmg_display(adc_buf,6); }
}

  主函数代码非常简单,首先调用外设头文件,然后定义一些变量存储 AD 值和电压值,进入 while 循环,读取电位器的 AD 值,根据 XPT2046 单端模式输入配置表可知,要采集 X+脚通道的信号,则配置值为 0X94。得到 AD 值后,可按照如下公式计算电压值:Vref*ADC_Value/分辨率。其中 Vref 是参考电压,XPT2046 接入的是 5VADC_Value 是读取的 AD 值,分辨率是 ADC 的位数(2^12=4096)。经过公式计算后会得到小数,所以定义了一个 float 型变量 adc_vol 存储,然后将该值放大 10 倍,目的是保留小数后一位。最后将得到的电压值转换为数码管段码数据显示。

五、实验现象

  使用 USB 线将开发板和电脑连接成功后(电脑能识别开发板上 CH340 串口),把编译后产生的.hex 文件烧入到芯片内,实现现象如下:数码管上显示 AD 模块采集电位器的电压值。

注意:调节电位器 AD1 时,数码管上显示的电压值也将变化。

  对于光敏电阻和热敏电阻以及 AIN3 外部采集通道实验,大家可以直接打开实验工程,它们与电位器电压采集程序相比仅仅是配置命令不同而已。

  • 电位器对应的采集通道命令:0X94
  • 光敏电阻对应的采集通道命令:0XA4
  • 热敏电阻对应的采集通道命令:0XD4
  • 外部输入AIN3 对应的采集通道命令:0XE4

51单片机 | ADC模数转换实验相关推荐

  1. 51单片机——ADC模数转换实验

    目录 一.功能描述 二.ADC介绍 2.1 逐次逼近型ADC转换原理 2.2 ADC的主要技术指标 三.XPT2046芯片介绍 3.1 XPT2046外部引脚 3.2 XPT2046的命令字 3.3 ...

  2. 51单片机ADC模数转换

    51单片机ADC模数转换 ADC介绍 1.ADC简介 ​        ADC(analog to digital converter)也称为模数转换器,是指一个将模拟信号转变为数字信号.单片机在采集 ...

  3. 51单片机的仿真实验——1602显示屏显示万年历与温度

    实验内容: 1:数字钟设计 2:基于DS18B20的温度测量模块设计 问题描述: 之前笔者写过一篇用数码管显示日历与温度的实验记录(51单片机的仿真实验--数码管显示日历与温度).但是数码管在仿真软件 ...

  4. 51单片机ADC0832模数转换+ LCD1602显示+Proteus仿真

    51单片机ADC0832模数转换+ LCD1602显示+Proteus仿真 Proteus仿真 在Proteus SP2仿真过程中发现无法读取ADC0832的数据.解决办法:在proteus安装目录下 ...

  5. 51单片机 ADC0809模数转换与显示+Proteus仿真

    51单片机 ADC0809模数转换与显示+Proteus仿真 Proteus仿真 实例代码 /*********************************/ #include <reg52 ...

  6. 【Proteus仿真】51单片机红外无线通信实验

    [Proteus仿真]51单片机红外无线通信实验 Proteus仿真 使用说明 接收端的单片机加载接收端的Hex文件,发射端加载发射端的Hex文件,仿真过程中,接收端响应有点慢,当长时间无数据发送时, ...

  7. 自学51单片机 - 矩阵按键实验

    自学51单片机 - 矩阵按键实验 1.开发板原理图 2.程序 2.1 行列式扫描法 2.2 线翻转扫描法 3.结果 1.开发板原理图 2.程序 2.1 行列式扫描法 /**************** ...

  8. 51单片机中断系统实验

    51单片机中断系统实验 一.实验内容 INT0端接单次脉冲发生器.按一次脉冲产生一次中断,CPU使P1.0状态发生一次反转,P1.0接LED灯,以查看信号反转. 根据实验内容编写一个程序,并在实验系统 ...

  9. ADC 模数转换实验

    生活中的模拟信号,如温度.声音.压力等,需要转换为更方便储存.处理和发射的数字形式. 51 单片机无法直接操作这些模拟量,其系统内部时运算都是数字量 0 和 1,因此必须将模拟量转换成数字量.数字量, ...

最新文章

  1. 解决 The mysql extension is deprecated and will be r
  2. Object.defineProperty的理解
  3. 数据挖掘之关联分析四(连续属性处理)
  4. 基础001_Xilinx V7资源
  5. java 的io流需要学吗_Java的IO流之字节流,必须要学得内容,你会嘛?
  6. SWF反编神器Action Script Viewer终身免费升级!
  7. Python风格总结:函数
  8. postgresql搭建从库
  9. delphi 运算符
  10. 昆仑固件涉密专用计算机,存储处理国家秘密的计算机信息系统按照涉密程序实行...
  11. android 带箭头的框,带有工具提示箭头的Android PopupWindow
  12. CH Dream(侠客行)
  13. 【icem】非结构体网格的质量+混合网格的合并问题
  14. 白宁超计算机科学院,基于主动学习的传统中医症状本体构建方法研究综述.PDF...
  15. c语言实现学生档案管理系统
  16. 第三方支付(微信支付)支付流程分析
  17. 聊聊我眼中恺明大神MAE的成功之处
  18. 是否对纯色背景的IDE感到乏味?那就让vscode背景变成你想要的样子
  19. 孙陶然:每个成功企业的背后都有一系列的创新
  20. 我的世界显示服务器领地指令,我的世界服务器领地指令有哪些 指令详细介绍...

热门文章

  1. 【Android App】物联网中查看手机支持的传感器及实现摇一摇功能-加速度传感器(附源码和演示 超详细)
  2. Android水果连连看案例
  3. 实战31:基于opencv的图像碎片拼接复原系统 附完整代码可作为毕设
  4. 换个新头像(解决彩色图亮度不均衡)
  5. 【宋飞】 java 3D学习笔记
  6. k8s学习-CKA真题-Etcd数据库备份恢复
  7. NetSuite SuiteTax之中国影响
  8. UE5(虚幻5)如何实现每隔5秒执行一次事件
  9. iOS截屏分享功能实现
  10. PCA9685版OTTO开源跳舞机器人