文章目录
一、AD/DA介绍
•AD(Analog to Digital):模拟-数字转换,将模拟信号转换为计算机可操作的数字信号
•DA(Digital to Analog):数字-模拟转换,将计算机输出的数字信号转换为模拟信号
•AD/DA转换打开了计算机与模拟信号的大门,极大的提高了计算机系统的应用范围,也为模拟信号数字化处理提供了可能
二、硬件电路模型
通过电阻阻值的变化,引起电压的变化,通过AD转换可将电压这个模拟信号转化为数字信号,DA则是反过来
•AD转换通常有多个输入通道,用多路选择开关连接至AD转换器,以实现AD多路复用的目的,提高硬件利用率
•AD/DA与单片机数据传送可使用并口(速度快、原理简单),也可使用串口(接线少、使用方便,一位一位的发送)
•可将AD/DA模块直接集成在单片机内(性能稍微好一点的都是集成在芯片内部),这样直接写入/读出寄存器就可进行AD/DA转换,单片机的IO口可直接复用为AD/DA的通道,DA转换一般都是一个通道。DA实际用的少,可以用PWM来代替。
三、硬件电路
经典的AD与DA芯片(了解其原理即可,实际不会去使用)
ADC0809
8路模拟开关用于选择哪个端口来进行数据输入,是由三个地址线来决定的;AD转换就是将输入的电压信号转化为数字信号,通过缓冲器就可将数据输出。
DAC0832
开发板上的AD/DA模块
(注:视频中的运算放大器部分跳过)
四、常用AD/DA性能指标
•分辨率:指AD/DA数字量的精细程度,通常用位数表示。例如,对于5V电源系统来说,8位的AD可将5V等分为256份,即数字量变化最小一个单位时,模拟量变化5V/256=0.01953125V,所以,8位AD的电压分辨率为0.01953125V,AD/DA的位数越高,分辨率就越高
•转换速度:表示AD/DA的最大采样/建立频率,通常用转换频率或者转换时间来表示,对于采样/输出高速信号,应注意AD/DA的转换速度
五、XPT2046
XPT2046是一款4线制电阻式触摸屏控制器,内含12位分辨率125KHz转换速率逐步逼近型A/D转换器。XPT2046支持从1.5V到5.25V的低电压I/0接口。XPT2046能通过执行两次A/D转换查出被按的屏幕位置,除此之外,还可以测量加在触摸屏上的压力。内部自带2.5V参考电压,可以作为辅助输入、温度测量和电池监测之用,电池监测的电压范围可以从0V到6V。XPT2046片内集成有一个温度传感器。在2.7V的典型工作状态下,关闭参考电压,功耗可小于0.75mW。XPT2046采用微小的封装形式:TSSOP-16,QFN-16和VFBGA
-48。工作温度范围为-40℃~+85℃。与ADS7846、TSC2046、AK4182A 完全兼容。采用 3 线制 SPI 通信接口
XPT2046时序:
DCLK:上升沿输入,下降沿输出,当然也可以在数据输入的时候,与其他设备进行数据输出,即全双工通信
输出2个字节,只需用到12位,剩下的4位用0填充
根据芯片数据手册,TACQ最短为1.5ms
关于命令字的说明:
差分模式:计算两端的差值
单端模式:一端接地,读另一端的值即可
单片机中X-已经接地,X+为AIN0,所以用单端模式
XPT2046 的内部 2.5V参考电压源可通过控制位PD1进行关闭或者打开。 PD1为1采用内部参考电压,PD1为0采用外部参考电压,根据原理图,VREF接VCC,外部参考电压为5V.本实验采用外部电压,至于是否用低功率模式,都可以。
单端模式输入配置图:
六、实验1:AD实验
现象:LCD显示可调电阻、热敏电阻和光敏电阻的值,且随着电阻的变化,LCD显示的值也会随之改变
1、创建文件
XPT2046.c及其头文件
2、引脚定义
在XPT2046.c文件中
//引脚定义
sbit XPY2046_DIN=P3^4;
sbit XPY2046_CS=P3^5;
sbit XPY2046_DCLK=P3^6;
sbit XPY2046_DOUT=P3^7;
3、读AD值函数
在XPT2046.c文件中
本实验用8位模式
#include <REGX52.H>
//引脚定义
sbit XPY2046_DIN=P3^4;
sbit XPY2046_CS=P3^5;
sbit XPY2046_DCLK=P3^6;
sbit XPY2046_DOUT=P3^7;
/**
* @brief ZPT2046读取AD值
* @param Command 命令字,范围:头文件内定义的宏,结尾的数字表示转换的位数
* @retval AD转换后的数字量,范围:8位为0~255,12位为0~4095
*/
unsigned int XPT2046_ReadAD(unsigned char Command)
{
unsigned char i;
unsigned int Data=0;
XPY2046_DCLK=0;//先将时钟先置为0,当然这条语句不用也行,反正读完数据后DCLK也是0
XPY2046_CS=0;//片选有效
//从高到低将命令码发出去
for(i=0;i<8;i++)
{
XPY2046_DIN=Command&(0x80>>i);//将Command从高到低放到DIN口
//根据芯片手册,DCLK拉高后立马拉低,时间上允许(手册上是微秒级)
XPY2046_DCLK=1;//从0到1,产生上升沿,数据输入
XPY2046_DCLK=0;//再置为0,用于下一次的数据输入
}
//根据时序图,在读数据之前,有一段空闲时间,可以加延时,但是时间很短,可以不用加延时就可读出数据
//读出数据
for(i=0;i<16;i++)
{
XPY2046_DCLK=1;
XPY2046_DCLK=0;//下降沿读出数据
//从高到低,读出的数据存储到Data里
//因为Data默认为0,如果DOUT为0,则不执行if里面的语句,则Data的该位为0(默认值)
//如果DOUT为1,则执行语句,用或运算,使得Data的该位置1
//这样就把DOUT中的数据一位一位的放入Data中
if(XPY2046_DOUT){Data|=(0x8000>>i);}
}
XPY2046_CS=1;//结束
//右移8位,则高8位为0,低8位为有效位
return Data>>8;
}
4、命令码宏定义
为了方便测量哪个输入量,对相应的地址位(A2-A0)进行宏定义
S必须为1,A2-A0地址位,MODE为1(8位模式),SER/DFR为1(单端模式),PD1为0(外部电压),PD0为0(低功率模式)
测量X+,根据单端模式输入配置图,A2-A0可以为001,也可以为011,以001为例,故命令码为1001 1100即0x9C,011为0xBC
#define XPT2046_XP 0x9C //0xBC
测量Y+,A2-A0为101,命令码为1101 1100即0xDC
#define XPT2046_YP 0xDC
测量VBAT,A2-A0为010,命令码为1010 1100即0xAC
#define XPT2046_VBAT 0xAC
测量AUX,A2-A0为110,命令码为1110 1100即0xEC
#define XPT2046_AUX 0xEC
5、测试
测试读AD值的函数功能是否正常
#include <REGX52.H>
#include "LCD1602.h"
#include "Delay.h"
#include "XPT2046.h"
unsigned int ADValue;
void main()
{
LCD_Init();
LCD_ShowString(1,1,"ADJ");
while(1)
{
ADValue = XPT2046_ReadAD(XPT2046_XP);
LCD_ShowNum(2,1,ADValue,4);
Delayms(10);//也可以不用延时
}
}
转动可调电阻,LCD上显示的值会随之改变(0-255,因为是8位,最高255)
6、增加12位的模式
在XPT2046.h中增加相应的宏定义,与8位模式同理(只需将MODE位变为0)
#ifndef _XPT2046_H__
#define _XPT2046_H__
#define XPT2046_VBAT_8 0xAC
#define XPT2046_AUX_8 0xEC
#define XPT2046_XP_8 0x9C //0xBC
#define XPT2046_YP_8 0xDC
#define XPT2046_VBAT_12 0xA4
#define XPT2046_AUX_12 0xE4
#define XPT2046_XP_12 0x94 //0xB4
#define XPT2046_YP_12 0xD4
unsigned int XPT2046_ReadAD(unsigned char Command);
#endif
在XPT2046.c中增减相应的判断逻辑
#include <REGX52.H>
//引脚定义
sbit XPY2046_DIN=P3^4;
sbit XPY2046_CS=P3^5;
sbit XPY2046_DCLK=P3^6;
sbit XPY2046_DOUT=P3^7;
/**
* @brief ZPT2046读取AD值
* @param Command 命令字,范围:头文件内定义的宏,结尾的数字表示转换的位数
* @retval AD转换后的数字量,范围:8位为0~255,12位为0~4095
*/
unsigned int XPT2046_ReadAD(unsigned char Command)
{
unsigned char i;
unsigned int Data=0;
XPY2046_DCLK=0;//先将时钟先置为0,当然这条语句不用也行,反正读完数据后DCLK也是0
XPY2046_CS=0;//片选有效
//从高到低将命令码发出去
for(i=0;i<8;i++)
{
XPY2046_DIN=Command&(0x80>>i);//将Command从高到低放到DIN口
//根据芯片手册,DCLK拉高后立马拉低,时间上允许(手册上是微秒级)
XPY2046_DCLK=1;//从0到1,产生上升沿,数据输入
XPY2046_DCLK=0;//再置为0,用于下一次的数据输入
}
//根据时序图,在读数据之前,有一段空闲时间,可以加延时,但是时间很短,可以不用加延时就可读出数据
//读出数据
for(i=0;i<16;i++)
{
XPY2046_DCLK=1;
XPY2046_DCLK=0;//下降沿读出数据
//从高到低,读出的数据存储到Data里
//因为Data默认为0,如果DOUT为0,则不执行if里面的语句,则Data的该位为0(默认值)
//如果DOUT为1,则执行语句,用或运算,使得Data的该位置1
//这样就把DOUT中的数据一位一位的放入Data中
if(XPY2046_DOUT){Data|=(0x8000>>i);}
}
XPY2046_CS=1;//结束
if(Command & 0x08)//MODE位为1
{
//右移8位,则高8位为0,低8位为有效位
return Data>>8;
}
else//MODE位为0
{
//右移4位,则高4位为0,低12位为有效位
return Data>>4;
}
}
转动可调电阻,LCD上显示的值会随之改变(0-4095,因为是12位,最高4095)
7、主函数
#include <REGX52.H>
#include "LCD1602.h"
#include "Delay.h"
#include "XPT2046.h"
unsigned int ADValue;
void main()
{
LCD_Init();
LCD_ShowString(1,1,"ADJ NTC GR");
while(1)
{
ADValue=XPT2046_ReadAD(XPT2046_XP_8); //读取AIN0,可调电阻
LCD_ShowNum(2,1,ADValue,3); //显示AIN0
ADValue=XPT2046_ReadAD(XPT2046_YP_8); //读取AIN1,热敏电阻
LCD_ShowNum(2,6,ADValue,3); //显示AIN1
ADValue=XPT2046_ReadAD(XPT2046_VBAT_8); //读取AIN2,光敏电阻
LCD_ShowNum(2,11,ADValue,3); //显示AIN2
Delayms(100);
}
}
七、实验2:DA实验
使得LED灯呈现呼吸灯状态
在PWM控制直流电机速度的工程上进行修改main.c即可,参考链接:江科大51单片机学习笔记之呼吸灯与直流电机(PWM)_rebened小橙的博客-CSDN博客
原理就是改变PWM占空比,与之前的原理一样
#include <REGX52.H>
#include "Key.h"
#include "Timer.h"
#include "Nixie.h"
#include "Delay.h"
sbit DA = P2^1;
//计数值和比较值,用于输出PWM
unsigned char Counter, Compare;
unsigned char i;
void main()
{
Timer0Init();
Compare = 5;
while(1)
{
for(i=0;i<100;i++)
{
Compare=i; //设置比较值,改变PWM占空比
Delayms(10);
}
for(i=100;i>0;i--)
{
Compare=i; //设置比较值,改变PWM占空比
Delayms(10);
}
}
}
//定时器0的中断处理函数
void Timer0_Routine() interrupt 1
{
TL0 = 0x9C; //设置定时初值
TH0 = 0xFF; //设置定时初值
Counter++;
Counter %= 100;
if(Counter < Compare)
{
DA = 1;
}
else
{
DA = 0;
}
}
更多51单片机笔记见主页
1288

被折叠的 条评论
为什么被折叠?



