目录
前言
本篇要介绍的是电子硬件中最重要的手段之一——AD/DA,即模数转换/数模转换,这是单片机进行信号采集的重要途径之一。
在开发板的AD/DA模块上可以实现对光敏电阻,热敏电阻和旋转拨码器的数据读取。
一、AD/DA简介
AD(Analog to Digital):模拟-数字转换,将模拟信号转换为计算机可操作的数字信号。
DA (Digital to Analog):数字-模拟转换,将计算机输出的数字信号转换为模拟信号。
AD/DA转换打开了计算机与模拟信号的大门,极大的提高了计算机系统的应用范围,也为模拟信号数字化处理提供了可能。
AD转换通常有多个输入通道,用多路选择开关连接至AD转换器以实现AD多路复用的目的,提高硬件利用率AD/DA与单片机数据传送可使用并口 (速度快、原理简单),也可使用串口(接线少、使用方便)可将AD/DA模块直接集成在单片机内,这样直接写入/读出寄存器就可进行AD/DA转换,单片机的IO口可直接复用为AD/DA的通道。
可以这样通俗的理解,AD就是电压表,它可以把模拟电压量化成数值,DA就是可调电源,可以根据输入的数值输出相应的电压。相较而言,AD的应用范围要远大于DA,日常开发中也是AD用的更频繁。
二、XPT2046型ADC
以普中51单片机开发板为例,DAC其实就是在配置了PWM的引脚P2^1后面接了电压跟随器等驱动电路,输出的结果会反映到DA1这颗LED灯珠上,还可以通过J52引脚输出。
它的AD模组使用的是这颗XPT2046的ADC芯片。XPT2046 是一款 4 线制电阻式触摸屏控制器,内部集成了一个12 位分辨率125KHz速率的逐次逼近型ADC。
简单介绍下开发板ADC模块的原理图,左边是一个就是ADC芯片XPT2046,它有四个模拟信号输入引脚也就是AN0、AN1、AN2、AN3,可以输入四路模拟信号。芯片连接到单片机的3^4、P3^5、P3^6、P3^7引脚上,这里用的是SPI的通信方式,分别对应SPI的四根通信线,用SPI与单片机进行信息交流,单片机发送指令给XPT2046,后者把转换后的数字信号交给单片机处理。
右边是AD转换采集的模拟量来源,AN0通道上是一个旋转编码器,通过转动旋转编码器改变内部阻值可以输出不同大小的电压,AN1通道上是一个热敏电阻,AN2通道上是一个光敏电阻,二者的模拟输入分别由10k和100k的电阻分压得到。
电阻式DA的原理:
这是个8位T型电阻网DA转换器,D0~D7分别是他的位权,数字量的输入范围是0~127,输出的模拟量取决于电流的大小,这样就可以对电压进行128等分量化,这就是DA的基本原理,之前的篇章里有介绍过PWM,其实PWM世界上也是DA的过程。
逐次逼近型AD转换器:
逐次逼近型的ADC内部需要一个DAC做衡量,简单来说就是,用比较器对ADC输入的电压值与DAC的各个位权电压做比较,逐步逼近目标的电压值。
三、代码
DA的代码和之前介绍的PWM很相似,需要先配置一个定时器,设置好初值、重装载值和救计数方式,就会输出PWM波从而驱动LED灯亮暗变化。
#include <REGX52.H>
#include "Delay.h"
#include "Timer0.h"
//定义引脚
sbit DA=P2^1;
unsigned char i;
unsigned char Counter,Compare; //计数值和比较值,用于输出PWM
void Timer0_Init(void);
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
}
}
void Timer0_Init(void) //定时器0初始化
{
TMOD &= 0xF0; //设置定时器模式
TMOD |= 0x01; //设置定时器模式
TL0 = 0x9C; //设置定时初值
TH0 = 0xFF; //设置定时初值
TF0 = 0; //清除TF0标志
TR0 = 1; //定时器0开始计时
ET0=1;
EA=1;
PT0=0;
}
AD部分代码,将三路ADC的值分别存入缓存区再输出到LCD屏上,就可以得到温度,亮度和旋转编码器的旋转角度。
#include <REGX52.H>
#include <INTRINS.H>
//SPI引脚定义
sbit XPY2046_DIN=P3^4; //DIN
sbit XPY2046_CS=P3^5; //CS
sbit XPY2046_DCLK=P3^6; //SCLK
sbit XPY2046_DOUT=P3^7; //DOUT
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;
}
#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);
}
}
总结
51单片机AD/DA
关于这个AD和DA的详细原理不是三两句能说得清的,我理解的也不够深,只要知道它们的作用就好。