欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

PCF8591芯片以及AD学习

程序员文章站 2022-04-01 21:49:41
...

由于要测多路AD,本身使用的芯片通道不够,差几路决定使用外置ADC完成,后决定使用PCF8591,带IIC后期很好管理,这是参考的一篇博文。


博文来源:https://blog.csdn.net/cow825/article/details/50412657


AD的主要参数:

1、AD的位数:表明这个AD共有2^n个刻度,8位AD,输出的刻度是0~255。 (255=2^8-1)

2、分辨率:就是AD能够分辨的最小的模拟量变化,假设5.10V的系统用8位的AD采样,那么它能分辨的最小电压就是5.10/255=0.02V。

3、INL:Interger NONliner 积分非线性度,表示了ADC器件在所有的数值点上对应的模拟值,和真实值之间误差最大的那一点的误差值。也就是,输出数值偏离线性最大的距离。单位是LSB(即最低位所表示的量)。比如12位ADC:TLC2543,INL值为1LSB。那么,如果基准4.095V,测某电压得的转换结果是1000,那么,真实电压值可能分布在0.999~1.001V之间。这里是这样这样计算得来的,12位ADC最小分辨率是1/4095。在这里即为4.095*(1/4095)=0.001V。那么1LSB就为0.001V,。转换结果为1000即为1V。

4、DNL:Differencial NonLiner-差分非线性度,理论上说,模数器件相邻量个数据之间,模拟量的差值都是一样的。就相一把疏密均匀的尺子。但实际并不如此。一把分辨率1毫米的尺子,相邻两刻度之间也不可能都是1毫米整。那么,ADC相邻两刻度之间最大的差异就叫差分非线性值(Differencial NonLiner)。DNL值如果大于1,那么这个ADC甚至不能保证是单调的,输入电压增大,在某个点数值反而会减小。这种现象在SAR(逐位比较)型ADC中很常见。

5、基准源:有内部基准源、外部基准源等等。

6、转换速率:也就是转换周期的倒数,转换周期就是完成一次AD转换所需的时间

二.PCF8591芯片

1.电路连接图和引脚功能如下:

PCF8591芯片以及AD学习PCF8591芯片以及AD学习

(1).PCF8591是具有I2C总线借口的8位AD/DA转换芯片,内部为单一电源供电(2.5~6V),典型值为5V,CMOS工艺。PCF8591有4路AD输入,属逐次比较型,内含采样保持电路;1路8位DA输出,内含DAC数据寄存器。AD/DA转换的最大速率约为11KHz。
(2).Philips规定AD器件高四位地址为1001,低三位地址为引脚地址A0,A1,A2,由硬件电路决定。
(3).控制寄存器:


PCF8591芯片以及AD学习

PCF8591芯片以及AD学习


3.控制流程。

 看器件手册可以知道:
      在IICa总线中,器件地址必须是起始条件后作为第一个字节发送。发送给PCF8591的第二个字节被存储在控制寄存器,用于控制寄存器的功能。发送给PCF8591的第三个字节被存储到DAC数据寄存器。并使用片上D/A转换成相应的模拟电压。
 
    一个A/D转换周期总是开始于发送一个有效读模式地址给PCF8591之后。A/D转换周期在应答时钟脉冲的后沿被触发。
操作分四步:
(1)、发送地址字节,选择该器件。
(2)、发送控制字节,选择相应通道。               //
(3)、重新发送地址字节,选择该器件。
(4)、接收目标通道的数据。
这次的程序流程是:AD采样,循环执行。

程序如下:

<span style="font-size:18px;">/*
项目名称:PCF8591实现AD转换
项目内容:A/D转换,并把转换的数字信号送给P0口控制LED灯
,调节电位器时观察LED的变化
作者:YUAN
*/

#include <reg52.h>
#include <intrins.h>	//_nop_()延时头文件
typedef unsigned char uChar8;
typedef unsigned int uInt16;
sbit SDA = P1^0;
sbit SCL = P1^1;
#define PCF8591Add 0x90	//PCF8591的器件地址和写操作

//延时函数
void DelayMS(uInt16 lValMS);
void Delay5us(void);
//IIC操作的几个函数
void IICInit(void);		//IIC初始化
void IICStart(void);	//起始信号
void IICStop(void);		//停止信号
void IICAck(void);		//应答信号
void IICReadAck(void);	//读应答信号
void IICWriteOneByte(uChar8 lByteVal);					//写一个字节
uChar8 IICReadOneByte(void);		//读一个字节
void PCF8591WriteRegulate(uChar8 lREGVal);	//Regulate控制器,这里写控制函数
uChar8  ReadDataPCF8591(void); 
								
void main()
{
	IICInit();
	while(1)
	{	 
		/*写入控制字00,即模拟量输出关闭,选择通道0,
		不自动增加通道,模拟量输入围方式0*/
	 	 PCF8591WriteRegulate(0x00);
		 P0 = ReadDataPCF8591(); 
		 DelayMS(10);
	}
}

void DelayMS(uInt16 lValMS)	//延时函数
{
	uInt16 luiVal,lujVal;
	for(luiVal = 0; luiVal < lValMS; luiVal++)
		for(lujVal = 0; lujVal < 113; lujVal++);
}
void Delay5us(void)
{
	_nop_();_nop_();_nop_();
	_nop_();_nop_();_nop_();
}
//IIC总线空闲时均为高电平
void IICInit(void)		//IIC初始化
{
  	SCL = 0;
	SDA=1;
	Delay5us();
	SCL=1;
}
//SCL高电平期间SDA由高到低的变化为起始信号
void IICStart(void)	//起始信号
{
	SCL = 0;
	Delay5us();
	SDA = 1;
	Delay5us();
	SCL = 1;
	Delay5us();
	SDA = 0;
	Delay5us();
	//防止接下来SDA数据变化导致IIC总线误判	
	SCL = 0;	 
}
//SCL高电平期间SDA由低到高的变化为终止信号
void IICStop(void)		//停止信号
{
	SCL = 0;
	Delay5us();
	SDA = 0;
	Delay5us();
	SCL = 1;
	Delay5us();
	SDA = 1;
	Delay5us();
	//防止接下来SDA数据变化导致IIC总线误判	
	SCL = 0;
}
//一个脉冲期间,SDA为低电平为应答
void IICAck(void)		//应答信号
{
	SCL = 0;
	Delay5us();
	SDA = 0;
	Delay5us();
	SCL = 1;
	Delay5us();
	SCL = 0; 		
}
/*cpu读应答信号,如果应答了则
继续传输数据,否则在一定时间里,
默认已经应答,继续传数据
*/
void IICReadAck(void)	//读应答信号
{
	uChar8 li = 0;
	SCL = 0;
	SDA = 1;  //确保读出的值为0,因此先送1
	Delay5us();
	SCL = 1;
	Delay5us();
	//如果没有应答或时间没有超过预定时间则停在此处
	while((1 == SDA)&&(li<255))li++;
	SCL = 0;
	Delay5us();		
	SDA = 1;			
}
/*
	写1个字节,先写高位。
*/
void IICWriteOneByte(uChar8 lByteVal)					//写一个字节
{
	uChar8 li,liVal;
	liVal = lByteVal;

	for(li=0;li<8;li++)	  
	{
		
		SCL = 0; 
		Delay5us();	
		SDA = (bit)(liVal&0x80);	//把数据准备好等待传送
		Delay5us();	
		SCL = 1;
		Delay5us();
		liVal <<= 1;
	} 
	SCL = 0; 
	Delay5us();	
	SDA = 1;
}
/*
读取一个字节并把读到的值返回
*/
uChar8 IICReadOneByte(void)
{
	uChar8 li,liVal;
	SCL = 0;
	SDA = 1;
	for(li=0;li<8;li++)
	{
		liVal <<= 1;
		SCL = 0;
		Delay5us();
		SCL = 1;
		Delay5us();
		liVal = (liVal|SDA);
	}
	SCL = 0; 
	return liVal;
}	
//Regulate控制器,这里写控制函数
void PCF8591WriteRegulate(uChar8 lREGVal)
{
	IICStart();
	IICWriteOneByte(PCF8591Add); 	//PCF8591的地址,写控制
	IICReadAck();
	IICWriteOneByte(lREGVal);		//写入控制字
	IICReadAck();
	IICStop();
}	
uChar8  ReadDataPCF8591(void)
{
	uChar8 liVal;
	IICStart();
	IICWriteOneByte(PCF8591Add|0x01); 	//PCF8591的地址,读控制	
	liVal = IICReadOneByte();
	IICAck();
	IICStop();
	return liVal; 	
} 
</span>

相关标签: 硬件 ADC 电源