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