51单片机从零开始入门教程 第十六章(模数转换篇)

本文介绍了AD/DA转换器的功能,如模拟-数字(A/D)和数字-模拟(D/A)转换,以及运算放大器在电路中的应用。重点讲解了XPT2046触摸屏控制器的4线电阻式A/D转换器,包括其特性、时序和编程指令。通过实例演示了如何利用这些技术实现液晶屏控制和模拟信号生成。

参考教程:[16-1] AD/DA_哔哩哔哩_bilibili

温馨提示:本篇大多数原理可以不必深究,底层已经将复杂的部分封装好了,写代码的时候照着手册写就可以了。

一、模数转换概述

1、AD/DA介绍

(1)AD(Analog to Digital):模拟-数字转换,将模拟信号转换为计算机可操作的数字信号。(根据前面的学习,单片机看起来只能读取引脚当前是处于高电平还是低电平,并不能读取引脚的实际电压值,但是借助ADC模数转换器,单片机可以直接获取引脚的电压值,而不仅仅是单调的1/0)

(2)DA(Digital to Analog):数字-模拟转换,将计算机输出的数字信号转换为模拟信号。(根据前面的学习,单片机看起来只能将引脚置为高电平或是低电平,也就是说只能提供数字信号,但是借助PWM调制,单片机可以给引脚提供模拟信号,而不仅仅是单调的1/0)

(3)AD/DA转换打开了计算机与模拟信号的大门,极大的提高了计算机系统的应用范围,也为模拟信号数字化处理提供了可能。

2、硬件电路模型

(1)AD转换通常有多个输入通道,用多路选择开关连接至AD转换器,以实现AD多路复用的目的,提高硬件利用率。

(2)AD/DA与单片机数据传送可使用并口(速度快、原理简单),也可使用串口(接线少、使用方便)。

(3)可将AD/DA模块直接集成在单片机内,这样直接写入/读出寄存器就可进行AD/DA转换,单片机的I/O口可直接复用为AD/DA的通道。

3、运算放大器

(1)运算放大器(简称“运放”)是具有很高放大倍数的放大电路单元,内部集成了差分放大器、电压放大器、功率放大器三级放大电路,是一个性能完备、功能强大的通用放大电路单元,由于其应用十分广泛,现已作为基本的电路元件出现在电路图中。

(2)运算放大器可构成的电路有:电压比较器、反相放大器、同相放大器、电压跟随器、加法器、积分器、微分器等。

(3)运算放大器电路的分析方法:虚短、虚断(负反馈条件下)。

(4)四种运放电路:

①电压比较器:

②反向放大器:

③同向放大器:

④电压跟随器:

二、XPT2046介绍

1、XPT2046概述

(1)XPT2046是一款4线制电阻式触摸屏控制器,内含12位分辨率125KHz转换速率的逐步逼近型A/D转换器。

(2)XPT2046内部自带2.5V参考电压,可以作为辅助输入、温度测量和电池监测之用,电池监测的电压范围可以从0V到6V。

(3)XPT2046采用微小的封装形式:TSSOP-16、QFN-16和VFBGA-48。

(4)XPT2046的工作温度范围为-40C~+85C。

2、XPT2046的操作时序及命令字

(1)单片机给XPT2046发送命令字,XPT2046收到命令后,将管脚的模拟信号转换为数字信号,然后通过DOUT将数字信号格式的数据一位一位传给单片机。由于数字信号的数据长度不足两个字节,为了凑够两个字节,低8位或低4位(取决于分辨率是8位还是12位)会使用0填充,单片机软件需要先用位移运算符处理接收到的二进制数据,再转换成十进制数据。

(2)8位命令字的含义:

(3)单端模式输入配置:

①下图所示的是XPT2046触摸ADC芯片的通道选择真值表,对应控制字节里的3位地址选择A2、A1、A0,工作在单端输入模式,用来控制内部模拟多路开关、X/Y轴驱动管、ADC采样输入源。

②表头字段释义:

        A2、A1、A0:3位通道选择地址,单片机下发控制命令的核心选择位,8种组合对应8路测量通道

        VBAT / AUXIN / TEMP:ADC正输入源(+IN),分别对应电池电压监测、外部辅助模拟输入、片内温度传感器(TEMP0/TEMP1 两路温度采集)

        YN/XP/YP:四线触摸板的4个电极引脚(XN、XP、YN、YP)

        Y-位置 / X-位置 / Z1-位置 / Z2-位置:标识当前配置用于采集哪类坐标 / 压力信号

        X-驱动 / Y-驱动:内部MOS驱动管开关状态,On代表导通给触摸电极施加驱动电压,off代表关闭驱动

③8组通道功能逐条解析:

        A2A1A0=000:TEMP0片内温度采集,X/Y驱动全部关闭

        A2A1A0=001:采集Y轴触摸坐标,Y驱动导通,XP作为ADC采样输入

        A2A1A0=010:VBAT 电池电压监测,触摸驱动全部关闭

        A2A1A0=011:采集触摸压力(Z轴),XN、YP驱动导通,Z1通道采样压力

        A2A1A0=100:采集触摸压力(Z轴),XN、YP驱动导通,Z2通道采样压力

        A2A1A0=101:采集X轴触摸坐标,X驱动导通,YP作为ADC采样输入

        A2A1A0=110:AUXIN外部辅助模拟电压采集,触摸驱动关闭

        A2A1A0=111:TEMP1片内温度采集,X/Y驱动全部关闭

3、开发板上的ADC模块

4、性能指标

(1)分辨率:指AD/DA数字量的精细程度,通常用位数表示。例如,对于5V电源系统来说,8位的AD可将5V等分为256份,即数字量变化最小一个单位时,模拟量变化5V/256=0.01953125V,所以,8位AD的电压分辨率为0.01953125V。AD/DA的位数越高,分辨率就越高

(2)转换速度:表示AD/DA的最大采样/建立频率,通常用转换频率或者转换时间来表示,对于采样/输出高速信号,应注意AD/DA的转换速度是否满足。

三、模数转换应用实验

1、AD模数转换实验

(1)该项目需要用到液晶屏模块的代码以及延时函数。

(2)添加缺失的代码文件,然后进行编译,按照主函数中的注释进行调试。

①XPT2046.h文件:

#ifndef __XPT2046_H__
#define __XPT2046_H__

//命令字宏定义(需要对照手册)
//全部选择单端输入方式,2位为1
//XP就是X+,YP就是Y+(对应开发板原理图)

//8位转换分辨率
#define XPT2046_XP_8    0x9C  //1001 1100(1000 1100也可以)
#define XPT2046_YP_8    0xDC  //1101 1100
#define XPT2046_VBAT_8  0xAC  //1010 1100
#define XPT2046_AUX_8   0xEC  //1110 1100
//12位转换分辨率
#define XPT2046_XP_12    0x94  //1001 0100(1000 0100也可以)
#define XPT2046_YP_12    0xD4  //1101 0100
#define XPT2046_VBAT_12  0xA4  //1010 0100
#define XPT2046_AUX_12   0xE4  //1110 0100


unsigned int XPT2046_ReadAD(unsigned char Command);

#endif

②XPT2046.c文件:

#include <REGX52.H>
#include "Delay.h"

sbit XPT2046_CS = P3^5;
sbit XPT2046_DCLK = P3^6;
sbit XPT2046_DIN = P3^4;
sbit XPT2046_DOUT = P3^7;

unsigned int XPT2046_ReadAD(unsigned char Command)
{
	unsigned char i;
	unsigned int ADVAlue = 0;
	
	XPT2046_DCLK = 0;  //初始时DCLK为0
	XPT2046_CS = 0;    //初始时CS取反为1,所以CS为0
	
	for(i = 0; i < 8; i++)  //写入8位命令
	{
		XPT2046_DIN = Command & (0x80 >> i);  //把命令一位一位地写在DIN上
		XPT2046_DCLK = 1;    //DCLK上升沿写入一位命令
		XPT2046_DCLK = 0;    //为下一个上升沿做准备
	}
	
	Delay(10);
	
	for(i = 0; i < 16; i++)  //读DOUT的16位数据
	{
		XPT2046_DCLK = 1;    //DCLK上升沿,AD往DOUT上发一位数据
		XPT2046_DCLK = 0;    //为下一个上升沿做准备
		if(XPT2046_DOUT)
		{
			ADVAlue |= (0x8000 >> i);  //把DOUT上的数据一位一位地读进来
		}
	}
	
	Delay(10);
	
	XPT2046_CS = 1;  //读过程结束,CS置为1
	
	//DOUT传来的二进制数据为了凑够两个字节,低8位或低4位会使用0填充(Zero Filled)
	//所以得到的二进制数据需要把低位的0去掉才能转换为十进制数据
	if(Command & 0x08)  //判断命令字的第三位
		return ADVAlue >> 8;  //选择8位转换分辨率的处理
	else
		return ADVAlue >> 4;  //选择12位转换分辨率的处理
}

③main.c文件:

#include <REGX52.H>
#include "LCD1602.h"
#include "Delay.h"
#include "XPT2046.h"

unsigned int ADValue = 0;

void main()
{
	LCD_Init();
	LCD_ShowString(1,1,"ADJ  NTC  RG");
	while(1)
	{
		/*
		ADValue = XPT2046_ReadAD(XPT2046_XP_12); //读取X+的电压
		//转动AD/DA模块的电位器
		//理论上选择8位转换分辨率最大值为0255,12位转换分辨率最大值为4095
		LCD_ShowNum(2,1,ADValue,4);
		*/
		
		ADValue = XPT2046_ReadAD(XPT2046_XP_8); //读取X+的电压
		LCD_ShowNum(2,1,ADValue,3);
		
		ADValue = XPT2046_ReadAD(XPT2046_YP_8); //读取Y+的电压
		LCD_ShowNum(2,6,ADValue,3);
		
		ADValue = XPT2046_ReadAD(XPT2046_VBAT_8); //读取VABT的电压
		LCD_ShowNum(2,11,ADValue,3);
		
		Delay(10);
	}
}

2、DA数模转换实验

(1)该项目就是之前实现过的呼吸灯,需要延时函数,然后在main.c文件中添加如下代码,进行编译。

#include <REGX52.H>
#include "Timer0.h"
#include "Delay.h"

sbit DA = P2^1;   //LED2接收模拟信号
unsigned char Counter, Compare, i;

void main()
{
	Timer0_Init();
	Compare = 0;
	while(1)
	{
		//本例就是之前实现过的呼吸灯
//在主函数中不断改变自设的比较值,这样定时器0写出来的方波脉冲占空比会不断变化,从而实现PWM调制(数模转换),产生模拟信号
		for(i=0;i<100;i++)
		{
			Compare = i;
			Delay(10);
		}
		for(i=100;i>0;i--)
		{
			Compare = i;
			Delay(10);
		}
	}
}

void Timer0_Routine()  interrupt 1  //CPU响应中断后执行的函数
{
	Counter++;
	Counter %= 100;
	
	if(Counter < Compare)  //计数器和自设比较值比较
	{
		DA = 1;  //计数器低于比较值,输出高电平
	}
	else
	{
		DA = 0;  //计数器高于比较值,输出低电平
	}
	
	//每次中断结束都要重置计数单元
	TL0 = 0xA4;		//设置定时初值
	TH0 = 0xFF;		//设置定时初值
}

(2)将生成的.hex文件下载到开发板中,观察第二盏LED灯的现象。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Zevalin爱灰灰

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值