16.1 模數(shù)轉(zhuǎn)換(A/D)、數(shù)模轉(zhuǎn)換(D/A)芯片 PCF8591 簡(jiǎn)介
PCF8591 是一款單電源供電的 8 位 CMOS 數(shù)據(jù)采集芯片,具有 4 個(gè)模擬信號(hào)輸入通道、一個(gè)模擬信號(hào)輸出通道以及一個(gè) I2C 總線通信接口。與前面講解的 I2C 芯片相同,通過管腳 A0、A1 和 A2 來配置芯片硬件地址,因此,在同一 I2C 總線上最多可同時(shí)連接 8 個(gè) PCF8591 芯片。主機(jī)與該芯片的地址、控制和數(shù)據(jù)信息的通信都是通過 I2C 總線接口來實(shí)現(xiàn)的。芯片引腳定義及芯片封裝如下圖所示。該芯片有兩種封裝形式:一種雙列直插式 DIP16、另一種貼片 SOP16 模式,兩種封裝的管腳順序是一樣的。
引腳 1-4 為四個(gè)數(shù)模(A/D)轉(zhuǎn)換通道的模擬數(shù)據(jù)輸入端,名稱分別為 AIN0~AIN3。引腳 5-7 為芯片硬件地址配置引腳 A0-A2。引腳 16、8 分別為芯片電源正負(fù)極 VDD 和 VSS,供電電壓范圍為 2.5V-6V。引腳 9、10 分別為 I2C 總線數(shù)據(jù)、時(shí)鐘引腳 SDA 和 SCL。管腳 11 為晶振輸入/輸出端口 OSC,管腳 12 為外部或內(nèi)部晶振選擇端口 EXT,EXT 接地時(shí)芯片選擇內(nèi)部時(shí)鐘,EXT 連接 VDD 時(shí),芯片選擇 OSC 引腳的外部時(shí)鐘。管腳 15、13 分別為數(shù)模(D/A)轉(zhuǎn)換的模擬輸出端 AOUT 和模擬地 AGND。管腳 14 為芯片轉(zhuǎn)換的基準(zhǔn)電壓輸入引腳 VREF。RY-51 開發(fā)板 PCF8591 原理圖設(shè)計(jì)如下圖所示:
PCF8591 地址格式如下圖所示:
8 位地址由固定值和可編程部分組成。高 4 位為固定值“1001”,緊接著 3 位為可配置位 A2-A0,最后一位為讀寫方向位,0 表示讀,1 表示寫。原理圖中將 A2-A0 直接接地,因此,寫操作時(shí)地址為 0x91,讀操作時(shí)地址為 0x90。
PCF8591 控制寄存器如下圖所示,bit1-bit0 為 A/D 通道選擇為 00-11 分別表示通道 0-通道 3。Bit2 為通道自動(dòng)累加選擇位,為 1 時(shí)選擇自動(dòng)累加。Bit3 為系統(tǒng)功能預(yù)留位,常設(shè)為 0。Bit5-bit4 為單端或差分輸入選擇位,如下圖所示。Bit6 為模擬輸出選擇位,為 1 時(shí)選擇模擬輸出。
PCF8591 數(shù)字量轉(zhuǎn)模擬量(DAC)數(shù)據(jù)寄存器以及計(jì)算公式如下圖所示:
DAC 寄存器為 8 位,數(shù)字量取值范圍為 0~255,模擬通道模擬量輸出公式如上圖所示。RY-51 開發(fā)板設(shè)計(jì)原理圖中將 VAGND 接地,VREF 接 5V,因此,模擬通道最大輸出為 255/256 x 5V,最小輸出為 0。主機(jī)將相應(yīng)的數(shù)字量通過 I2C 總線寫入 DAC 數(shù)據(jù)寄存器后,PCF8951 通過相應(yīng)的算法轉(zhuǎn)換成模擬量輸出。DAC轉(zhuǎn)換通信協(xié)議如下:
如上圖所示 DAC 轉(zhuǎn)換步驟如下:
1. I2C 起始信號(hào);
2. 主機(jī)發(fā)送器件地址,方向?yàn)椤皩憽保?br /> 3. 主機(jī)發(fā)送控制字節(jié)數(shù)據(jù);
4. 主機(jī)發(fā)送 DAC 字節(jié)數(shù)據(jù) 1~N;
5. 停止信號(hào)。
如上圖所示,在發(fā)送 DAC 數(shù)據(jù)的同時(shí),模擬通道 VAOUT 輸出為前一次 DAC 數(shù)據(jù)寄存器的數(shù)值。DAC 函數(shù)如下所示:
//數(shù)字量轉(zhuǎn)模擬量函數(shù),val為待轉(zhuǎn)換的數(shù)字量,模擬量從Vout引腳輸出
void DAC(unsigned char val)
{
Start_I2C();//啟動(dòng)I2C總線
//尋址PCF8591,方向?yàn)椤睂憽保缥错憫?yīng),則停止并返回
if(Wr_I2C(0x48< 1)) {Stop_I2C();return;}
Wr_I2C(0x40);//寫入控制字,使能模擬輸出
Wr_I2C(val); //發(fā)送DAC字節(jié)
Stop_I2C(); //結(jié)束I2C總線
}
模擬量轉(zhuǎn)數(shù)字量(ADC)工作原理如下:
將 0-5V 電壓轉(zhuǎn)換為 8 位的數(shù)字量,數(shù)字量范圍為 0-255,將 5V 電壓均分為 256 等份,當(dāng)輸入電壓落在幾等分處,則轉(zhuǎn)換的數(shù)字量為幾。當(dāng)輸入電壓為 0-1/256 * 5V 時(shí),轉(zhuǎn)換的數(shù)字量為 1,當(dāng)輸入電壓為 1/256 * 5V-2/256 * 5V 時(shí),轉(zhuǎn)換的數(shù)字量為 2,依次類推,當(dāng)輸入電壓為 254/256 * 5V-255/256 * 5V 時(shí),轉(zhuǎn)換的數(shù)字量為 255。ADC 轉(zhuǎn)換時(shí)序如下圖所示,首先為尋址 PCF8951,方向?yàn)樽x,然后讀取數(shù)據(jù)。加上 PCF8951 設(shè)置等相關(guān)語句,ADC 轉(zhuǎn)換 I2C 通信步驟如下:
1. I2C 起始信號(hào);
2. 主機(jī)發(fā)送器件地址,方向?yàn)椤皩憽保?br /> 3. 主機(jī)發(fā)送控制字節(jié)數(shù)據(jù),并設(shè)置相應(yīng)通道;
4. 重新發(fā)送 I2C 起始信號(hào);
5. 主機(jī)發(fā)送器件地址,方向?yàn)椤白x”;
6. 讀取轉(zhuǎn)換數(shù)據(jù),并拋棄;
7. 再次讀取數(shù)據(jù),并返回;
8. 停止信號(hào)。
ADC 轉(zhuǎn)換時(shí)序如下圖所示:
上述步驟中 1-5 很好理解,6、7 的出現(xiàn)是什么原理,第六條語言為讀取當(dāng)前轉(zhuǎn)換值,如上圖所示,由于芯片的 AD 轉(zhuǎn)換是需要時(shí)間的,當(dāng)前返回值為上一次的轉(zhuǎn)換值,當(dāng)前的轉(zhuǎn)換值會(huì)在下一次讀數(shù)據(jù)時(shí)出現(xiàn),因此,第 7 條語句讀到的數(shù)據(jù)是寫第 6 條語句時(shí)的轉(zhuǎn)換值,因此將第 7 條語句的值返回。ADC 函數(shù)如下圖所示:
//模擬量轉(zhuǎn)數(shù)字量函數(shù),將通道chn的值轉(zhuǎn)換為數(shù)字量val,并返回val
unsigned char ADC(unsigned char chn)
{
unsigned char val;//數(shù)字量存儲(chǔ)變量
Start_I2C();//啟動(dòng)I2C總線
//尋址PCF8591,方向?yàn)椤睂憽?,如未響?yīng),則停止并返回0
if(Wr_I2C(0x48< 1)){Stop_I2C();return 0;}
Wr_I2C(0x40|chn);//寫入控制字并選擇轉(zhuǎn)換通道chn的數(shù)據(jù)
Start_I2C();//重新啟動(dòng)I2C總線
Wr_I2C((0x48< 1)|0x01);//尋址PCF8591,方向?yàn)椤弊x”
RdACK_I2C();//讀一次數(shù)據(jù)并拋棄,下一次數(shù)據(jù)才是轉(zhuǎn)換的數(shù)據(jù)
val = RdNAK_I2C();//讀數(shù)據(jù)并返回
return val;
}
按照慣例,驅(qū)動(dòng)文件完整代碼如下,"Drive_PCF8591.h"代碼:
#ifndef __PCF8591_H__
#define __PCF8591_H__
//數(shù)字量轉(zhuǎn)模擬量函數(shù),val為待轉(zhuǎn)換的數(shù)字量,模擬量從Vout引腳輸出
extern unsigned char ADC(unsigned char chn);
//模擬量轉(zhuǎn)數(shù)字量函數(shù),將通道chn的值轉(zhuǎn)換為數(shù)字量val,并返回val
extern void DAC(unsigned char val);
#endif
"Drive_PCF8591.c"代碼:
#include< reg52.h >
#include"Drive_I2C.h"
//數(shù)字量轉(zhuǎn)模擬量函數(shù),val為待轉(zhuǎn)換的數(shù)字量,模擬量從Vout引腳輸出
void DAC(unsigned char val)
{
Start_I2C();//啟動(dòng)I2C總線
//尋址PCF8591,方向?yàn)椤睂憽?,如未響?yīng),則停止并返回
if(Wr_I2C(0x48< 1)) {Stop_I2C();return;}
Wr_I2C(0x40);//寫入控制子,使能模擬輸出
Wr_I2C(val); //發(fā)送DAC字節(jié)
Stop_I2C(); //結(jié)束I2C總線
}
//模擬量轉(zhuǎn)數(shù)字量函數(shù),將通道chn的值轉(zhuǎn)換為數(shù)字量val,并返回val
unsigned char ADC(unsigned char chn)
{
unsigned char val;//數(shù)字量存儲(chǔ)變量
Start_I2C();//啟動(dòng)I2C總線
//尋址PCF8591,方向?yàn)椤睂憽?,如未響?yīng),則停止并返回0
if(Wr_I2C(0x48< 1)){Stop_I2C();return 0;}
Wr_I2C(0x40|chn);//寫入控制字并選擇轉(zhuǎn)換通道chn的數(shù)據(jù)
Start_I2C();//重新啟動(dòng)I2C總線
Wr_I2C((0x48< 1)|0x01);//尋址PCF8591,方向?yàn)椤弊x”
RdACK_I2C();//讀一次數(shù)據(jù)并拋棄,下一次數(shù)據(jù)才是轉(zhuǎn)換的數(shù)據(jù)
val = RdNAK_I2C();//讀數(shù)據(jù)并返回
return val;
}
下面我們進(jìn)行簡(jiǎn)單的應(yīng)用,大家都知道,熱敏電阻和光敏電阻這兩種元器件。熱敏電阻的特性為溫度不一樣時(shí)電阻值不一樣,光敏電阻的特性為光照強(qiáng)度不一樣則電阻不一樣。因此,可以用ADC轉(zhuǎn)換器去采集這兩種元器件的電阻值便可以知道溫度和光照強(qiáng)度是多少了。
16.2 熱敏電阻
熱敏電阻器是敏感元件的一類,按照溫度系數(shù)不同分為正溫度系數(shù)熱敏電阻器(PTC)和負(fù)溫度系數(shù)熱敏電阻。熱敏電阻器的典型特點(diǎn)是對(duì)溫度敏感,不同的溫度下表現(xiàn)出不同的電[阻值。正溫度系數(shù)熱敏電阻在溫度越高時(shí)電阻值越大,負(fù)溫度系數(shù)熱敏電阻在溫度越高時(shí)電阻值越低,它們同屬于半導(dǎo)體器件。
16.3 光敏電阻
光敏電阻(photoresistor or light-dependent resistor,后者縮寫為 ldr)或光導(dǎo)管,常用的制作材料為硫化鎘,另外還有硒、硫化鋁、硫化鉛和硫化鉍等材料。這些制作材料具有在特定波長(zhǎng)的光照射下,其阻值迅速減小的特性。這是由于光照產(chǎn)生的載流子都參與導(dǎo)電,在外加電場(chǎng)的作用下作漂移運(yùn)動(dòng),電子奔向電源的正極,空穴奔向電源的負(fù)極,從而使光敏電阻器的阻值迅速下降。光敏電阻是用硫化鎘或硒化鎘等半導(dǎo)體材料制成的特殊電阻器,其工作原理是基于內(nèi)光電效應(yīng)。光照愈強(qiáng),阻值就愈低,隨著光照強(qiáng)度的升高,電阻值迅速降低,亮電阻值可小至 1K Ω以下。光敏電阻對(duì)光線十分敏感,其在無光照時(shí),呈高阻狀態(tài),暗電阻一般可達(dá) 1.5M Ω。光敏電阻的特殊性能,隨著科技的發(fā)展將得到極其廣泛應(yīng)用。
16.4 綜合試驗(yàn)
如電路原理圖所示,我們分別在ADC器件的通道A0-A3連接可變電阻,固定電壓,熱敏電阻、光敏電阻,并將四個(gè)通道采集到的電壓值顯示在1602液晶顯示器上,嘗試改變電阻,溫度以及光照強(qiáng)度,觀察4通道的電壓變化。主程序如下所示:
#include< reg52.h >
#include"Drive_1602.h"
#include"Drive_PCF8591.h"
#define uchar unsigned char
#define uint unsigned int
#define FOSC 11059200 //單片機(jī)晶振頻率
#define T_1ms (65536 - FOSC/12/1000) //定時(shí)器初始值計(jì)算
sbit DU = P2^7;//數(shù)碼管段選、位選引腳定義
sbit WE = P2^6;
uchar str[10]=0;
uchar T_flag = 0;
uchar val = 0;
void ValueToString(unsigned char *str,unsigned char val);
void main()
{
Init_1602();//1602初始化
P0 = 0xff;//關(guān)閉所有數(shù)碼管
WE = 1;
WE = 0;
TMOD = 0x01; //定時(shí)器工作模式配置
TL0 = T_1ms; //裝載初始值
TH0 = T_1ms >?>8;
TR0 = 1; //啟動(dòng)定時(shí)器
ET0 = 1; //允許定時(shí)器中斷
EA = 1; //開總中斷
Disp_1602_str(1,1,"A0 A1 A2 A3 ");//顯示通道初始化
while(1)
{
if(T_flag)
{
T_flag = 0;
val = ADC(0);
DAC(val);//將通道零采集到的數(shù)據(jù)DA輸出
ValueToString(str,val);
Disp_1602_str(2,1,str);//顯示通道0電壓
val = ADC(1);
ValueToString(str,val);
Disp_1602_str(2,5,str);//顯示通道1電壓
val = ADC(2);
ValueToString(str,val);
Disp_1602_str(2,9,str);//顯示通道2電壓
val = ADC(3);
ValueToString(str,val);
Disp_1602_str(2,13,str);//顯示通道3電壓
}
}
}
//將AD采樣數(shù)值轉(zhuǎn)化成字符串
void ValueToString(unsigned char *str,unsigned char val)
{
//電壓=采樣值*5V/255
val = (val*50)/255; //放大了10倍
str[0] = (val/10) + '0';//整數(shù)位
str[1] = '.';//小數(shù)點(diǎn)
str[2] = (val%10) + '0';//小數(shù)位
}
//定時(shí)器0中斷子程序,定時(shí)1ms
void timer0() interrupt 1
{
static uint T_500ms = 0;
TL0 = T_1ms;//重裝初始值
TH0 = T_1ms >?>8;
T_500ms++;
if(T_500ms >=500)//500ms,置位T_flag
{
T_500ms = 0;
T_flag = 1;
}
}
16.5本章小結(jié)
本章詳細(xì)介紹了AD/DA器件PCF8591的工作原理,通信時(shí)序,以及驅(qū)動(dòng)程序的編寫,并完成了簡(jiǎn)單的應(yīng)用。
評(píng)論
查看更多