您现在的位置是:首页 >其他 >51单片机(十六)AD/DA网站首页其他

51单片机(十六)AD/DA

乘凉~ 2024-06-17 10:25:04
简介51单片机(十六)AD/DA

❤️ 专栏简介:本专栏记录了从零学习单片机的过程,其中包括51单片机和STM32单片机两部分;建议先学习51单片机,其是STM32等高级单片机的基础;这样再学习STM32时才能融会贯通。
☀️ 专栏适用人群 :适用于想要从零基础开始学习入门单片机,且有一定C语言基础的的童鞋。
?专栏目标:实现从零基础入门51单片机和STM32单片机,力求在玩好单片机的同时,能够了解一些计算机的基本概念,了解电路及其元器件的基本理论等。

⭐️ 专栏主要内容: 主要学习51单片机的功能、各个模块、单片机的外设、驱动等,最终玩好单片机和单片机的外设,全程手敲代码,实现我们所要实现的功能。
? 专栏说明 :如果文章知识点有错误的地方,欢迎大家随时在文章下面评论,我会第一时间改正。让我们一起学习,一起进步。
?专栏主页:http://t.csdn.cn/HCD8v

本学习过程参考:https://space.bilibili.com/383400717

单片机安装软件、各种资料以及源码的路径:
https://pan.baidu.com/s/1vDTN2o8ffvczzNQGfyjHng
提取码:gdzf

本节主要介绍学习AD/DA的相关知识,包括AD/DA基础知识、AD/DA通俗解释、硬件电路模型、运算放大器、AD/DA性能指标、AD/DA原理、XPT2046、本节目标等;并利用两个小实验来写程序进行练习,分别是AD模数转换以及 DA数模转换,最后附上相关代码。

一、AD/DA和本节目标

1.1 AD/DA基础知识

1.1.1 AD/DA的通俗解释

参考自:https://zhuanlan.zhihu.com/p/431750381

在信号这个大家族中,有两兄弟特别引人注目,就是“模拟”和“数字”。

什么是“模拟”?

“模拟”是“数字”的兄长。

“模拟”是对我们生活的实体的一种表达方式。
在这里插入图片描述

比如说你在看一本书,白纸黑字映入你的眼帘,在你的大脑中就会有反应,你从书中知道了一些东西,我们说印在纸上的字是一种“模拟”。与此相类似,你用笔在纸上记下的一个电话号码或是写下的一首诗歌,还有刻在石头上的古代碑文,这些都是“模拟”。除了文字以外,我们在生活中还能见到许多“模拟”的东西,比如说一幅风景画,又比如说你在电视上或是电影院的屏幕上看到听到了孩子们的欢歌笑语,你在电话里听到了朋友的声音。
“模拟”需要载体或是信息的存储媒体,比如说一张白纸,又比如说是一盒胶卷。
“模拟”需要工具,比如说你有一台电视机,那么电视机的荧光屏和喇叭都属于模拟设备。
“模拟”需要传播方式,比如说你可以和一个十几米外的朋友说话,但是如果你的朋友在几百公里以外,你就不得不需要电话,电话网通过“模拟信号”将你的声音传到了几百公里甚至几千公里以外。

什么是“数字”?
类似于“模拟”,数字也是我们生活中的实体的一种表达方式。
你可以用笔在纸上记下一个电话号码,也可以把这个电话号码输入你的计算机存储器;你可以看一本印刷成册的书,也可以看存储在CD-ROM中的电子出版物;你可以听收音机播放的音乐,也可以听一盘音乐光盘(CD)。
数字信息的最小度量单位叫做“比特”,有时也叫“位”,意即二进制的一位。在媒体中传输的讯号是以比特的电子形式组成你的数据。

在这里插入图片描述

比特的定义是:比特是一种存在的状态:开或关,真或伪,上或下,入或出,黑或白。出于实用的目的,我们把比特想成1或0。
应该说这个定义相当准确,但一个在电脑和英语方面知识程度不高的人仍然没有弄懂“比特”究竟是什么。
“比特”是英语bit一词的音译。bit一词是由binary(二进制的)和digit(数字)两个词压缩而成的,所以bit即“二进制数字”,亦即0和1。“数字时代”准确的意思是“二进制数字时代”或“比特时代”那么这0和1到底是什么意思呢?我们从一个简单的例子说起。
在使用电脑的时候,我们可以根据我们的需要和喜好,通过一些位于显示器底部的旋钮来调节显示图形,在这些旋钮下面,分别写着center(居中度)、size(大小)、brightness(亮度)、contrast(对比度)。这些调节都有一定的可调幅度,我们可能在这个幅度内任意选择哪一种居中度、大小等。
除这些旋钮外,还有一个“机关”却不是这样,这个机关的两边分别写着0和1。这就是显示屏的开关。它没有调节幅度,通过它我们只能选择非此即彼的两种状态:开(on)和关(off)。显示屏的亮度、对比度等都有两个极点,在这两个极点之间的“值”是多值性的。而开关的周期只有两个值,即它的两个极点。“进制”的“进”,就是周期所包含的“值”。比如“十进制”数字,就是一个变化周期里包含十个“值”数字。同样道理,二进制数字就是变化周期里包含二个值的数字。我们采用何种“进制”对一种事物的存在状态计数,表面上,要看衡量事物状态的“值”的多少,其实“进制”与事物的状态值并无必然的、唯一的关联。
事实上,电脑完全可以用0和1这两个数字将多进制状态的“值”表示或“翻译”出来。数是抽象的,但数的观念却源于人的具体的感觉经验。我们对于十进制计数方法习以为常。当一个人说“一年有12个月”这句话时,他可能觉得“12”这个数字唯一正确地表示了一年的月份数。进而他可能会认为,数字与事物的数量同样都是客观的–除了说一年有12个月,你还能说一年有多少个月?
这是对于数字本质的一种似是而非的看法。极端地说,对于“一年有多少个月”这个问题,可以有很多不同的“答案”。这样说听起来简直荒唐透顶,细究起来却并不然。当我们采用不同进制来表示事物的数量时,我们对事物的数量就可以说出不同的“答案”,而且这些“答案”都是对的。
比如可以说一人有65岁,也可说他有01000001岁。只是后一种说法我们听起来相当别扭,因为我们早已习惯了用十进制数字来表达数量。如果采用“六进制”数字(世界上似乎还没有哪个民族采用过这种进制的数字),那么就可以说一年有二“六”个月。如果螃蟹有朝一日进化到与人接近的水平,它们很可能采用“八进制数字”来计数,那么在它们看来,一年就有一“八”又四个月。
这样说并非完全是开玩笑。我只是想说明,“数字”其实并非我们通常所认为的那样“客观”。说到底,它是人对于客观事物的数量的主观映象。
除了“比特”(bit),我们还经常会遇到几个数字信息度量单位。字节(byte)是一种比“比特”更抽象或是高级的度量单位,一般来说,一个字节有8位,即8个比特。还有三个缩写,“K”、“M”和“G”。1K=1024,在中文里我们通常叫它“千”;1M=1024×1K,在中文里我们通常叫它“兆”;1G=1024×1M,在中文里我们通常叫它“千兆”或者“吉”。
比特(位)通常用于数据在网络上传输的情况下,比如我们一般都说这条电话线一秒钟可以传送9600比特的二进制流,而不是说1200字节。字节通常用在数据的存储系统中,比如说这个文件的大小是2M,这里指的是字节而不是比特,又比如是1.44M软盘、20G硬盘,指的也是字节。
模拟信号和数字信号有着很大的区别。模拟信号是用连续变化的数值来表示要说明的信息;数字信号是用有限个“0”和“1”的代码来表示信息中某一个字符,当很多字符组合起来时,才能表达完整的信息。

1.1.2 AD/DA基础知识介绍

1.1.2.1 AD/DA介绍

在这里插入图片描述

1.1.2.2 硬件电路模型

在这里插入图片描述
AD转DA的过程(下图左边部分),模拟量(电阻的阻值0-5V)经过AD转换后,和数字量(数字0-255)一一对应,成正比关系的;对于DA转AD的过程(下图右边部分),数字量(数字0-255)和模拟量(电阻的阻值0-5V)也是一一对应成正比关系的;如下图所示

在这里插入图片描述

硬件电路

在这里插入图片描述

1.1.2.3 介绍运算放大器

在这里插入图片描述
运算放大器的特性:
1、运算放大器的输入阻抗非常大;就当于桐乡输入端和反向输入端既不流入电流,也不流出电流;
2、因为运放内部有功率输出,所以输出端是有驱动能力;
3、调节放大倍数的方法:加一个负反馈,则内部的放大系数由负反馈决定
在这里插入图片描述

下面介绍运算放大器的四个经典电路:

1.1.2.3.1 电压比较器

在这里插入图片描述

电压比较器会比较同向输入端和反向输入端两个输入端电压的差值,当正向输入端的电压高于反向输入端电压时,OUT输出VCC(即最高电压);反之,当反向输入端的电压高于正向输入端电压时,OUT输出GND(0);

1.1.2.3.2 反向放大器

在这里插入图片描述
在反向放大器中,输出OUT和输入IN之间的关系如上图公式所示;放大系数就是R2与R1的比值的相反数;

其内部实现原理如下:

在这里插入图片描述

假如输入的电压IN是0.1V,由于电压比较器的性质,最终负极和正极最终都会稳定的0V左右,像是短路了一样,称为虚短;另外由于正极和负极是无法通过电流的,像断路一样,称为虚断;看上图,电阻R1左边的电压为0.1V,即IN;电阻R1右边的电压为0V;所以流过R1的的电流I(0.1-0)/ R1,由于虚断的性质,负极那里是断开的,则流过电阻R2的电流也为I,所以R2两端的电压就为IR2,也就是(0.1-0)/ R1 * R2,R2左边是正极,右边是负极,而R2左边电压是0V,所以右边电压就是0 -(0.1-0)/ R1 * R2;最终经过化简,可以得到公式V_out=-R2/R1 *V_IN

因为反向放大器最终输出的电压时反向放大的,比如输入时正电压,则输出就是放大后的负电压;有时候很不方便,为了使其输入正电压,可以接上双电源;
在这里插入图片描述
或者使用下面一种电路:同向放大器;

1.1.2.3.3 同向放大器

在这里插入图片描述
图中可以看到最终结论:V_out=(1+R2/R1)* V_IN

其原理推理过程如下:

在这里插入图片描述

可以看到上图的正向放大电路也是负反馈电路,满足虚短和虚断的机制,正极+的输入电压为V_IN,由虚短原理,+-之间是短路的,则正极+负极-的电压是相同的,所以负极-的电压也是V_IN;R1左侧是GND,电压为0,右侧的电压是IN,所以流过R1的电流I就是(V_IN-0)/ R1;由虚断可知,负极-正极+之间是断开的,则R2的电流也是I,所以R2两端的电压就是I*R2 也就是 (V_IN-0)/ R1 * R2;而R2的左侧是负极,右侧是正极,所以R2两侧的电压为右-左,右边是OUT,左边是负极-的电压也就是IN,所以V_OUT - V_IN = (V_IN-0)/ R1 * R2;化简后就是V_out=(1+R2/R1)* V_IN

同向发达器的优点就是,放大的方向是同向的,即如果IN是正电压,则OUT也是正电压;很方便;

1.1.2.3.4 电压跟随器

在这里插入图片描述

电压跟随器的特点就是输入电压等于输出电压;虽然电压没有变化,但是驱动能力会增强;

1.1.2.4 AD/DA的原理

DA的原理

在这里插入图片描述

DA转换器就是将数字信号转换为模拟信号;那么上述电路实现的功能就是将输入的8位数字量电压转换为模拟电压信号输出;

上述公式中(D7~D0)表示输入的8位二进制组成的最终数字转换成十进制;D7为最高位,D0为最低位;

具体原理写起来不方便,直接参考视频:

https://www.bilibili.com/video/BV1Mb411e7re?p=35&vd_source=e2638d12685eef84cda913d9d67be0a9第50分钟位置;

PWM型的DA转换器原理

在这里插入图片描述
优点是比较节省i/o口,一个输入一个输出就可以;且精度比较高;缺点是比较消耗单片机资源;

AD的原理
在这里插入图片描述

上述公式中(D7~D0)表示输出的结果取整后的十进制数转换成8位二进制;D7为最高位,D0为最低位;

具体原理写起来不方便,直接参考视频:

https://www.bilibili.com/video/BV1Mb411e7re?p=35&vd_source=e2638d12685eef84cda913d9d67be0a9第1小时08分钟的位置;

1.1.2.5 AD/DA性能指标

在这里插入图片描述

1.2 XPT2046

XPT2046 也是一款AD转换器;电阻式触摸屏控制器;

在这里插入图片描述

XPT2046 时序

在这里插入图片描述

1.3 本节目标

目标1:AD模数转换
LCD1602上分别显示可调电阻、热敏电阻和光敏电阻的AD值,如下图所示
在这里插入图片描述

三个硬件在开发板上的位置如下图:
在这里插入图片描述

调节可调电阻时,LCD1602上显示的可调电阻的发声变化,最小0,最大255:,如下图

在这里插入图片描述

在这里插入图片描述

同样的,热敏电阻和光敏电阻的阻值发生变化时,LCD1602上显示的也发生变化;

目标2:DA数模转换

使开发板上DA输出的LED灯呈现呼吸灯的状态:

在这里插入图片描述

二、AD模数转换

代码路径:51单片机入门教程资料课件及程序源码程序源码KeilProject16-1 AD模数转换

具体代码:

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

unsigned int ADValue;

void main(void)
{
	LCD_Init();
	LCD_ShowString(1,1,"ADJ  NTC  GR");
	while(1)
	{
		ADValue=XPT2046_ReadAD(XPT2046_XP);		//读取AIN0,可调电阻
		LCD_ShowNum(2,1,ADValue,3);				//显示AIN0
		ADValue=XPT2046_ReadAD(XPT2046_YP);		//读取AIN1,热敏电阻
		LCD_ShowNum(2,6,ADValue,3);				//显示AIN1
		ADValue=XPT2046_ReadAD(XPT2046_VBAT);	//读取AIN2,光敏电阻
		LCD_ShowNum(2,11,ADValue,3);			//显示AIN2
		Delay(100);
	}
}

XPT2046.c:

#include <REGX52.H>
#include <INTRINS.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;
	XPY2046_CS=0;
	for(i=0;i<8;i++)
	{
		XPY2046_DIN=Command&(0x80>>i);
		XPY2046_DCLK=1;
		XPY2046_DCLK=0;
	}
	for(i=0;i<16;i++)
	{
		XPY2046_DCLK=1;
		XPY2046_DCLK=0;
		if(XPY2046_DOUT){Data|=(0x8000>>i);}
	}
	XPY2046_CS=1;
	return Data>>8;
}

三、DA数模转换

代码路径:51单片机入门教程资料课件及程序源码程序源码KeilProject16-2 DA数模转换

具体代码:

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

sbit DA=P2^1;

unsigned char Counter,Compare;	//计数值和比较值,用于输出PWM
unsigned char i;

void main()
{
	Timer0_Init();
	while(1)
	{
		for(i=0;i<100;i++)
		{
			Compare=i;			//设置比较值,改变PWM占空比
			Delay(10);
		}
		for(i=100;i>0;i--)
		{
			Compare=i;			//设置比较值,改变PWM占空比
			Delay(10);
		}
	}
}

void Timer0_Routine() interrupt 1
{
	TL0 = 0x9C;		//设置定时初值
	TH0 = 0xFF;		//设置定时初值
	Counter++;
	Counter%=100;	//计数值变化范围限制在0~99
	if(Counter<Compare)	//计数值小于比较值
	{
		DA=1;		//输出1
	}
	else				//计数值大于比较值
	{
		DA=0;		//输出0
	}
}
风语者!平时喜欢研究各种技术,目前在从事后端开发工作,热爱生活、热爱工作。