江科大51单片机学习笔记之AD/DA

一、AD/DA介绍

•AD(Analog to Digital):模拟-数字转换,将模拟信号转换为计算机可操作的数字信号

•DA(Digital to Analog):数字-模拟转换,将计算机输出的数字信号转换为模拟信号

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

二、硬件电路模型
image-20230725195134164

通过电阻阻值的变化,引起电压的变化,通过AD转换可将电压这个模拟信号转化为数字信号,DA则是反过来

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

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

•可将AD/DA模块直接集成在单片机内(性能稍微好一点的都是集成在芯片内部),这样直接写入/读出寄存器就可进行AD/DA转换,单片机的IO口可直接复用为AD/DA的通道,DA转换一般都是一个通道。DA实际用的少,可以用PWM来代替。

三、硬件电路

经典的AD与DA芯片(了解其原理即可,实际不会去使用)

ADC0809

image-20230725195452546

8路模拟开关用于选择哪个端口来进行数据输入,是由三个地址线来决定的;AD转换就是将输入的电压信号转化为数字信号,通过缓冲器就可将数据输出。

DAC0832

image-20230725195517303

开发板上的AD/DA模块

image-20230725200131504

(注:视频中的运算放大器部分跳过)

四、常用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时序:

image-20230726164651216

DCLK:上升沿输入,下降沿输出,当然也可以在数据输入的时候,与其他设备进行数据输出,即全双工通信

输出2个字节,只需用到12位,剩下的4位用0填充

根据芯片数据手册,TACQ最短为1.5ms

关于命令字的说明:

image-20230801111620837

差分模式:计算两端的差值

单端模式:一端接地,读另一端的值即可

单片机中X-已经接地,X+为AIN0,所以用单端模式

image-20230801112318657

XPT2046 的内部 2.5V参考电压源可通过控制位PD1进行关闭或者打开。 PD1为1采用内部参考电压,PD1为0采用外部参考电压,根据原理图,VREF接VCC,外部参考电压为5V.本实验采用外部电压,至于是否用低功率模式,都可以。

单端模式输入配置图:

image-20230801151654654
六、实验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单片机笔记见主页

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值