51单片机的A/D转换总结(XPT2046、PCF8591、内部集成AD转换器)

目录

一、A/D转换的介绍

二、基于XPT2046的AD转换(SPI通信)

三、基于PCF8591的A/D转换(IIC通信)

四、内部集成AD转换器

 五、总结


一、A/D转换的介绍

AD转换即模拟信号转换为数字信号的过程,全称为模拟-数字转换(Analog-to-Digital Conversion)。在电子、通信和控制领域等方面,模拟信号是人能直接识别的形式,如音频、视频、温度、压力、力度等,但是它们需要经过处理(传输、存储、处理)时必须转换成数字信号,以便于数字设备进行数字化处理,如滤波、放大、压缩、编码等。因此, AD转换是将模拟信号通过一个特定的电路处理,将其转化为数字信号的过程,换言之,就是将连续时间上(analog)的信号转化为离散时间上(digital)的信号的过程。这个数字信号可以用计算机进行处理、传输、存储。常见的AD转换器包括逐次逼近型、窗口型、积分型等。在很多电子产品中,如手机、数码相机、音响设备等,都使用到了AD转换器。AD转换(Analog-to-Digital Conversion)的意义在于将模拟信号转换为数字信号,以便于数字系统的处理和分析。在实际应用中,例如传感器采集、仪器控制、音频处理等领域,模拟信号是无法直接处理和存储的,必须先进行AD转换将其转换为数字信号。因此,AD转换是数字系统中非常重要的一环,同时也是电子工程技术中的基础知识之一。

51单片机的ADC(Analog to Digital Converter)模块,可以将模拟信号转换为相应的数字信号,方便单片机进行数字运算和处理。在单片机应用中,ADC模块广泛应用于模拟量采集、传感器信号处理、电压检测等方面。51单片机的ADC模块通常有8位或10位的分辨率,采样速度也有快、中、慢三种模式,可以根据实际应用需求进行设置。

ADC模块工作流程如下:

1. 选定通道:通过寄存器配置选择要转换的模拟信号通道。

2. 启动转换:设置ADC启动位或者转换启动模式,让ADC开始转换模拟信号。

3. 转换过程:在启动转换后,ADC从模拟信号输入端口采样模拟信号,将其转化为一个数字量,通过数据总线传输给单片机。

4. 数据获取:单片机通过数据总线获取ADC转换后的数字数据,进行处理。

5. 中断处理:ADC转换结果可能通过中断的方式向单片机发送,单片机在中断服务程序中获取ADC数据。

不同的单片机的ADC模块是不同的,在使用前需要仔细阅读相关的芯片手册和数据手册,并根据实际情况进行配置和调试。

二、基于XPT2046的AD转换(SPI通信)

在使用XPT2046之前,我们首先要了解什么是SPI通信协议:

SPI(Serial Peripheral Interface)是一种同步串行通信协议,其使用了4根线实现全双工的通信。SPI协议包含四个时钟信号:SCK(时钟线)、MOSI(主机输出从机输入线)、MISO(主机输入从机输出线)和SS(片选线)。

在SPI通信中,主机通过SS信号对从机进行选择,然后通过SCK时钟信号同步发送和接收数据。主机和从机的数据传输是通过MOSI和MISO两根线进行的。

SPI通信的协议由以下几个方面组成:

1. 传输时序:SPI通信需要对时钟信号进行同步控制,通信方按同样的时钟转换数据,即轮流传输数据位。

2. 数据长度:可以按照需要设定数据位的个数。SPI通信每次传输的数据最大位数由从机还是主机确定,通常在一个字节到数千个字节之间。

3. 传输数据的时钟极性和相位:SPI通信的时钟极性和相位是可以设定的,以确保不能出错。通常SPI设备的数据都在沿时刻传输给SPI总线(也许是上升沿或下降沿),并且总线上下降沿总是发生在每个字节或数据位之间。

4. 确定状态:SPI通信中还需要一个确定通讯状态的控制信号,它可以是用于连接器的一个独立引脚或者SPI数据流中的一个特定字节,通常SPI设备的数据流中,最后一个字节会包含控制选项和CRC等特殊字节。

SPI通信的流程如下:

1. 由主设备发起传输请求,选择从设备并拉低片选(CS)信号;
2. 主设备通过时钟信号(SCK)来同步数据传输,将数据通过MOSI(Master Output Slave Input)引脚传给从设备;
3. 从设备在下降沿时读取MOSI引脚上的数据,并将自己的应答数据通过MISO(Master Input Slave Output)引脚返回给主设备;
4. 主设备在下降沿时读取MISO引脚上的数据,等待从设备的应答,然后拉高片选信号,传输完成。

信号和数据的传输是在时钟信号的同步下完成的,可以通过SPI的时钟极性和相位来确定数据的读取和传输顺序。SPI通信的时序图如下图所示: 

 而XPT2046是基于SPI通信的一种设备,对于XPT2406来说,它的时序图为:

 参照时序图我们便可以编写XPT2046的AD转换函数:

#include <REGX52.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;
	XPT2046_CS = 0;
	for(i = 0;i < 8;i++)
	{
		XPT2046_DIN = Command & (0x80 >> i);
		XPT2046_DCLK = 1;
		XPT2046_DCLK = 0;
	}
	for(i = 0;i < 16;i++)
	{
		XPT2046_DCLK = 1;
		XPT2046_DCLK = 0;
		if(XPT2046_DOUT){ADValue |= (0x8000 >> i);}
	}
	XPT2046_CS = 1;
	if(Command & 0x08)
	{
		return (ADValue >> 8);
	}
	else
	{
		return (ADValue >> 4);
	}
}

 需要注意的是这里要判断是8分辨模式还是12分辨模式,8分辨模式需要将读取到的数据右移八位,12位模式要右移4位,因为我们读取到的数据是16位的二进制数据。

#ifndef __XPT2046__H__
#define __XPT2046__H__

#define XPT2406_XP_8			0x9C//0x8C//8分辨率模式
#define XPT2406_YP_8			0xDC
#define XPT2406_VBAT_8		0xAC
#define XPT2406_AUX_8			0xEC

#define XPT2406_XP_12			0x94//0x84//12分辨率模式
#define XPT2406_YP_12			0xD4
#define XPT2406_VBAT_12		0xA4
#define XPT2406_AUX_12		0xE4

unsigned int XPT2046_ReadAD(unsigned char Command);

#endif

有了这个函数,我们就可以读取任意通道的模拟量并将模拟量转化为数字量:

#include <REGX52.H>
#include "Nixie.h"
#include "XPT2046.h"
#include "Delay.h"
unsigned int ADValue;

void main()
{
	
	while(1)
	{
//		ADValue = XPT2046_ReadAD(XPT2406_XP_8);//读滑动电阻
//		Nixie(1,ADValue/100);
//		Nixie(2,ADValue/10%10);
//		Nixie(3,ADValue%10);
//		ADValue = XPT2046_ReadAD(XPT2406_YP_8);//读热敏电阻
//		Nixie(1,ADValue/100);
//		Nixie(2,ADValue/10%10);
//		Nixie(3,ADValue%10);
		ADValue = XPT2046_ReadAD(XPT2406_VBAT_8);//读光敏电阻
		Nixie(1,ADValue/100);
		Nixie(2,ADValue/10%10);
		Nixie(3,ADValue%10);
		Delay(5);
	}
}

三、基于PCF8591的A/D转换(IIC通信)

PCF8591使用的IIC通信协议为另一种通信协议:

IIC(Inter-Integrated Circuit)通信协议,也被称作I2C(Inter-IC)通信协议。它是一种串行通信协议,由飞利浦公司(现已更名为恩智浦公司)在1980年代开发,用于各种数字芯片之间进行通信。IIC通信协议只需要两根线,即SDA(数据线)和SCL(时钟线),即可实现多个芯片之间的通信。

在IIC通信协议中,总线上通信的设备分为两类,一类是主设备,一类是从设备。主设备是控制总线,发送IIC通信命令和数据的设备。从设备只能在主设备允许的情况下回复命令和数据。

IIC通信协议的传输方式是字节传输,每个字节都由8个比特位组成。数据传输时,从设备需要在时钟线的上升沿之前准备好数据,主设备正好在时钟线上升沿时读取数据。通过控制位来表示数据的读写方向,实现数据的传输和通信。

I2C通信的基本流程:

1. 主设备发送起始信号(Start signal):主设备发送一个低电平脉冲信号,告诉所有从设备I2C总线现在被占用了。

2. 主设备发送从设备地址和读写模式:主设备将目标从设备的地址发送到I2C总线上,告诉从设备他想要读还是写。

3. 从设备响应:目标从设备响应主设备,并发送一个“应答信号”(ACK)回来。

4. 主设备发送要读/写的数据:主设备将要写入从设备或要读出来的数据发送到I2C总线上。

5. 从设备响应:从设备发送一个ACK回复主设备,确认数据已经处理。

6. 如果主设备想再进行读/写数据操作,重复步骤4和5。

7. 主设备发送停止信号(Stop signal):主设备发送一个高电平脉冲信号,告诉所有从设备I2C总线现在空闲了。

有了这个流程我们是不是可以用它来编写我们需要的读写和转换程序:

#include "PCF8591.h"
/**
  * @brief	AD转换
  * @param	Commend 通道
  * @retval	Value 转换后的值
  */
unsigned char ADGet(unsigned char Commend)
{
	unsigned char Value;
	IIC_Start();
	IIC_SendByte(0x90);
	IIC_WaitAck();
	IIC_SendByte(Commend);
	IIC_WaitAck();
	IIC_Stop();
	
	IIC_Start();
	IIC_SendByte(0x91);
	IIC_WaitAck();
	Value = IIC_RecByte();
	IIC_SendAck(1);
	IIC_Stop();
	return Value;
}
/**
  * @brief	DA转换
  * @param	Commend 
  * @retval	无
  */
//void DAGet(unsigned char Commend)
//{	
//	IIC_Start();
//	IIC_SendByte(0x90);
//	IIC_WaitAck();
//	IIC_SendByte(0x40);
//	IIC_WaitAck();
//	IIC_SendByte(Commend);
//	IIC_WaitAck();
//	IIC_Stop();
//}

PCF8591的地址字节为:

1001A2A1A0R/W

其中前四位为固定位,后四位为可编程部分,对照原理图可知,A2、A1、A0接地,则这三位为0,如图:

 因为首先我们要读取通道的模拟量,所以PCF8591的地址字节为1001 0000既0x90;

PCF的控制字节为:

D7D6D5D4D3D2D1D0

控制字节控制着PCF所有的功能

其中:

D3、D7:固定为0;

D1、D0:4路AD通道编号,AIN0~AIN3,00、01、10、11分别对应通道0、1、2、3;

D2:自动增量标志位,1表示在采集完0通道数据后继续采集通道1、2、3;单路采集时置0即可。

D4,D5:模拟量输入模式选择:00、01、10、11分别表示:四路单端输入、三路差分输入、单端与差分配合输入、两路差分输入。

D6:DA转换使能控制位:1表示DA转换,0表示AD转换。

所以我们的主函数要怎么写呢

#include <STC15F2K60S2.H>
#include "PCF8591.h"
#include "buzzer.h"
#include "Nixie.h"
#include "Delay.h"

void main()
{
	unsigned char Value = 0;
	Buzzer_Init();
	while(1)
	{
		Value = ADGet(AIN3);
		Nixie_C(1,Value/100);
		Nixie_C(2,Value/10%10);
		Nixie_C(3,Value%10);
	}
}
#ifndef __PCF8591__H__
#define __PCF8591__H__
#include "iic.h"

#define AIN0 0x00
#define AIN1 0x01 //光敏电阻
#define AIN2 0x02
#define AIN3 0x03 //滑动变阻

unsigned char ADGet(unsigned char Commend);
#endif

四、内部集成AD转换器

STC15系列单片机内部集成有高速10位AD转换器,只需要对相关寄存器进行配置,就可以采集AD转换数据,我们参照STC15单片机的手册:

 

 

 

 

参照这些寄存器我们来编写函数来采集通道7的模拟量:

void ADC_init()
{
	P1ASF |= P1ASF_7; //选择通道7
	ADC_RES = 0;    //ADC_RES[7:0]存放高八位数据,ADC_RESL存放低两位数据
	ADC_CONTR = 0x80;//打开电源
	Delay(1);
}

unsigned int ADC_GetResult(unsigned char ch)
{
	unsigned int ADC_Value;
	ADC_CONTR = 0x88|ch;//打开电源选择要采集的模拟量通道
	Delay(1);
	while(!(ADC_CONTR&ADC_FLAG));//等待转换完成
	ADC_CONTR = 0x80;//清楚转换完成标志位
	ADC_Value = ADC_RES;//ADC_RES[7:0]存放高八位数据
	ADC_Value = (ADC_Value << 2) | ADC_RESL;//ADC_RESL存放低两位数据并将数据合并
	return ADC_Value;
}

 采集数据后转化并显示在LCD1602上:

#include <STC15F2K60S2.H>
#include "LCD1602.h"
#include "ADGET.h"
#include "Delay.h"

unsigned int ADCTemp;
unsigned int ADCVoltage;
void main()
{
	unsigned char temp = 0;
	IO_init();
    ADC_init();
	LCD_Init();
	LCD_ShowString(1,1,"ADJ");
	while(1)
	{
		 ADCTemp = ADC_GetResult(0x07);	
         ADCVoltage = (unsigned int)(((ADCTemp*5)/1024.000)*1000);

		
		 temp=ADCTemp/1000; LCD_ShowChar(2,1,temp+'0');	
		 temp=(ADCTemp%1000)/100; LCD_ShowChar(2,2,temp+'0');		
		 temp=(ADCTemp%100)/10; LCD_ShowChar(2,3,temp+'0'); 
		 temp=ADCTemp%10; LCD_ShowChar(2,4,temp+'0');	
		
	
		 temp=ADCVoltage/1000; LCD_ShowChar(2,9,temp+'0');	
		 LCD_ShowChar(2,10,'.');	
		 temp=(ADCVoltage%1000)/100; LCD_ShowChar(2,11,temp+'0');			
		 temp=(ADCVoltage%100)/10; LCD_ShowChar(2,12,temp+'0');	 
		 temp=ADCVoltage%10; LCD_ShowChar(2,13,temp+'0');	
		 LCD_ShowChar(2,14,'V');	
		 Delay(10);
	}
}

 五、总结

本文着重介绍了使用XPT2046、PCF8591、内部集成AD转换器进行AD转换,介绍过程中,对SPI通信协议和IIC通信协议进行了简单的介绍和使用方法的说明。

<think>嗯,用户现在问的是51单片机AD模块。首先,我需要确认用户的问题到底是什么。AD模块通常指的是模数转换模块,也就是将模拟信号转换成数字信号的部分。51单片机其实指的是Intel的8051系列单片机,但原生的8051是没有内置AD模块的,所以用户可能指的是带有AD功能的增强型51兼容单片机,比如STC89C52的一些变种或者STC12、STC15系列,或者其他厂商的兼容型号。 接下来,我需要考虑用户可能的背景。用户可能刚开始接触单片机,或者在做项目时需要用到AD转换,但不太清楚具体怎么操作。他们可能想知道如何选择带有AD模块的51单片机,或者如何外接AD芯片,以及编程方法。 用户的问题比较广泛,所以回答需要覆盖几个方面:内置AD模块的常见51单片机型号、外置AD转换芯片的方法、以及基本的代码示例。同时,要澄清原生8051没有AD模块,避免混淆。 需要检查用户之前的问题历史,之前他们问过XPT2046,这是一个触摸屏控制器,可能他们现在在做触摸屏或者需要AD转换相关的项目。可能需要关联之前的回答,确保信息的一致性。 另外,用户可能对AD转换的基本原理不太清楚,比如分辨率、采样率、参考电压等参数,所以需要简要解释这些概念。同时,开发注意事项比如参考电压稳定性、抗干扰措施也很重要,避免他们在实际应用中遇到问题。 还要考虑用户可能的误区,比如直接使用原生8051单片机而没有AD模块,导致无法进行模数转换。这时候需要提醒他们选择正确的型号或者外接芯片。 最后,给出示例代码,并注明是伪代码,需要根据具体型号调整,这样用户可以根据自己的硬件进行修改。同时,提供替代方案,比如使用外置AD芯片,如ADC0804、PCF8591,或者集成模块,帮助他们扩展思路。 总结回答的结构:先说明原生51的情况,再介绍内置AD的增强型号,然后讲外置AD的方案,接着是开发要点,最后代码示例和替代方案。这样结构清晰,用户能逐步了解如何实现AD转换功能。</think>--- ### 一、51单片机AD模块的关系 **核心结论**: - **原生8051单片机(如AT89C51)无内置AD模块**,需通过外接ADC芯片或选择增强型51内核单片机(如STC12/15系列)。 - **AD模块作用**:将模拟信号(如温度、电压)转换为数字信号,供单片机处理。 --- ### 二、实现AD转换的两种方案 #### 方案1:外接独立ADC芯片(适用于基础51单片机) 1. **常用芯片** - **ADC0804**(8位分辨率,并行输出) - **PCF8591**(8位分辨率,I²C接口) - **XPT2046**(12位分辨率,SPI接口,兼容电阻触摸屏) 2. **典型电路连接** ```c // 以ADC0804为例(51单片机连接) sbit ADC_CS = P2^0; // 片选 sbit ADC_RD = P2^1; // 读信号 sbit ADC_WR = P2^2; // 写信号 sbit ADC_INTR= P2^3; // 转换完成中断 ``` #### 方案2:选择内置AD的增强型51单片机 1. **推荐型号** - **STC12C5A60S2**:8通道10位ADC,速度约$100kHz$ - **STC15W4K32S4**:8通道12位ADC,支持差分输入 - **C8051F系列**:高精度16位ADC(如C8051F350) 2. **关键参数对比** | 型号 | 分辨率 | 采样率 | 接口类型 | |---------------|--------|---------|---------------| | STC12C5A60S2 | 10位 | 100kHz | 并行控制 | | STC15W4K32S4 | 12位 | 500kHz | 寄存器配置 | | C8051F350 | 16位 | 1MHz | SPI/I²C | --- ### 三、AD模块开发要点 1. **硬件设计** - **参考电压**:需稳定(如使用TL431提供$V_{\text{ref}}=2.5V$) - **信号调理**:添加RC滤波电路(如$R=1k\Omega$, $C=0.1\mu F$) - **接地隔离**:模拟地与数字地单点连接 2. **软件流程**(以STC15系列为例) ```c void ADC_Init() { P1ASF = 0x01; // 启用P1.0作为ADC输入 ADC_RES = 0; // 清空结果寄存器 ADC_CONTR = 0x80; // 开启ADC电源 Delay_ms(1); // 等待稳定 } uint16_t ADC_Read(uint8_t ch) { ADC_CONTR = 0x80 | (ch << 3); // 选择通道 _nop_(); _nop_(); // 等待切换 ADC_START = 1; // 启动转换 while (!ADC_FLAG); // 等待完成 return (ADC_RES << 2) | ADC_RESL; // 合并10/12位数据 } ``` --- ### 四、常见问题与优化 1. **精度提升** - 多次采样取平均(如16次采样) - 公式:$$ V_{\text{avg}} = \frac{1}{N} \sum_{i=1}^{N} V_{\text{sample}} $$ 2. **噪声抑制** - 添加屏蔽层(对模拟信号线) - 避免高频数字信号与ADC线路并行走线 --- ### 五、替代方案建议 - **集成模块**:可直接采购ADC模块(如ADS1115,I²C接口,16位精度) - **电压频率转换**:通过LM331将模拟量转为频率信号,用单片机计数器测量 --- 若需特定型号的完整代码或电路图,请提供具体单片机型号(如STC12C5A60S2),将为您补充详细实现方案。
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

FightingLod

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

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

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

打赏作者

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

抵扣说明:

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

余额充值