PCF8591芯片以及AD學習(一)

一.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學習(一) - 元寶 - 元寶的世界

(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).控制寄存器:

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>


 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章