4.8 PCF8591(ADC/DAC)轉換芯片
4.8.1 原理圖
當前實驗板上沒有PCF8591芯片,這里采用外接模塊的形式使用,

圖4-8-1 PCF8591模塊實物圖

圖4-8-2 原理圖
通過原理圖得到的重要資訊: PCF8591芯片地址線全部接GND,也就是當前模塊的地址固定為: 1001000
4.8.2 PCF8591模塊功能介紹
在一個完整的單片機系統中,A/D轉換芯片往往是必不可少的;PCF8591是一款具有I2C總線介面的A/D轉換芯片,在與CPU的資訊傳輸程序中僅靠時鐘線SCL和資料線SDA就可以實作,
PCF8591具有8位AD/DA轉換器,有4個模擬輸入口、1個模擬輸出口和1個串行I2C總線介面,PCF8591的3個地址引腳A0, A1和A2可用于硬體地址編程,飛利浦公司規定A/D轉換芯片的內部器件地址為1001,這樣就允許在同個I2C總線上接入8個PCF8591器件,而無需額外的硬體,在PCF8591器件上輸入輸出的地址、控制和資料信號都是通過雙線雙向I2C總線以串行的方式進行傳輸,
I2C總線是Philips(飛利浦)公司推出的串行總線,整個系統僅靠資料線(SDA)和時鐘線(SCL)實作完善的全雙工資料傳輸,即CPU與各個外圍器件僅靠這兩條線實作資訊交換,I2C總線系統與傳統的并行總線系統相比具有結構簡單、可維護性好、易實作系統擴展、易實作模塊化標準化設計、可靠性高等優點,

圖4-8-3 PCF8591內部框架圖

圖4-8-4 芯片引腳圖
PCF8591的電源電壓典型值為5V,所有輸入信號的電壓值都不能超過 VCC,即+5V,否則可能會損壞 ADC 芯片,
引腳功能介紹:
(1)、AIN0~AIN3:模擬信號輸入端,
(2)、A0~A3:引腳地址端,
(3)、VDD、VSS:電源端,(2.5~6V)
(4)、SDA、SCL:I2C總線的資料線、時鐘線,
(5)、OSC:外部時鐘輸入端,內部時鐘輸出端,
(6)、EXT:內部、外部時鐘選擇線,使用內部時鐘時EXT接地,
(7)、AGND:模擬信號地,
(8)、AOUT:D/A轉換輸出端,
(9)、VREF:基準電源端
PCF8591的ADC是逐次逼近型的,轉換速率算是中速,它的速度瓶頸在 I2C 通信上,由于 I2C 通信速度較慢,所以最終的 PCF8591 的轉換速度,直接取決于 I2C 的通信速率,由于 I2C 速度的限制,所以 PCF8591 算是個低速的 AD 和 DA 的集成,主要應用在一些轉換速度要求不高,希望成本較低的場合,比如電池供電設備,測量電池的供電電壓,電壓低于某一個值,報警提示更換電池等類似場合,
4.8.3 PCF8591暫存器介紹
PCF8591遵循標準IIC協議,編程肯定符合這個協議的,
單片機對 PCF8591 進行初始化,一共發送三個位元組即可;第一個位元組和 EEPROM 類似,是器件地址位元組,其中 7 位代表地址, 1 位代表讀寫方向,地址高 4位固定是 0b1001,低三位是 A2, A1, A0,這三位在模塊電路上都接了 GND,因此也就是 0b000 (這里0b是二進制的前綴),
(1). PCF8591的設備地址

圖4-8-5 設備地址
其中:
高位是器件固定的地址:1001
低位A2 A1 A0 由硬體電路決定
R/W是讀寫位:1表示讀 0表示寫
本模塊的硬體地址固定為: 0 0 0 ,得出PCF8591的地址:0x91(讀方向) 0x90(寫方向)
(2). PCF8591的控制位元組
發送到 PCF8591 的第二個位元組將被存盤在控制暫存器,用于控制 PCF8591 的功能,
其中第 3 位和第 7 位是固定的 0,另外 6 位各自有各自的作用,

圖4-8-6 控制位元組
控制位元組的第6位是DAC使能位,這一位置1表示 DAC 輸出引腳使能,會產生模擬電壓輸出功能,
第 4位和第 5位可以實作把 PCF8591的 4路模擬輸入配置成單端模式和差分模式,具體的配置可以看下面圖片,

圖4-8-7 模式配置
控制位元組的第 2 位是自動增量控制位,如果此位為1,就使用自動增量;自動增量的意思就是,比如一共有 4 個通道,當4個通道全部使用的時候,讀完了通道 0,下一次再讀,會自動進入通道 1 進行讀取,不需要指定下一個通道,由于 A/D 每次讀到的資料,都是上一次的轉換結果,所以在使用自動增量功能的時候,要特別注意,當前讀到的是上一個通道的值,
控制位元組的第 0 位和第 1 位是通道選擇位, 00、 01、 10、 11 代表了從 0 到 3 的一共4 個通道選擇,

圖4-8-8 通道選擇
如果使用通道0為單端輸入,采集ADC轉換的資料,那么控制位元組就為: 0000 0000 -->0x00
如果使用通道1為單端輸入,采集ADC轉換的資料,那么控制位元組就為: 0000 0001 -->0x01
如果使用通道2為單端輸入,采集ADC轉換的資料,那么控制位元組就為: 0000 0010 -->0x02
如果使用通道3為單端輸入,采集ADC轉換的資料,那么控制位元組就為: 0000 0011 -->0x03
如果使用DAC輸出功能,那么控制位元組就為: 0100 0000 -->0x40
4.8.4 讀寫時序介紹
(1) 設定PCF8591轉換通道讀取ADC轉換資料的時序

圖4-8-9
示例代碼:
/*
函式功能: 設定ADC轉換通道,并回傳采集的資料值
ch的范圍:0x00 0x01 0x02 0x03 分別代表通道0~3
*/
u8 PCF8591_GetADC_CHx(u8 ch)
{
u8 dat;
IIC_SendStart();//起始信號
IIC_SendOneByte(PCF8591_WRITE_ADDR);//發送設備地址
IIC_GetAck();//獲取應答
IIC_SendOneByte(ch); //發送控制位元組
IIC_GetAck();//獲取應答
IIC_SendStart();//起始信號
IIC_SendOneByte(PCF8591_READ_ADDR);//發送設備地址
IIC_GetAck();//獲取應答
dat=IIC_RecvOneByte();//讀取資料
IIC_SendAck(1); //發送非應答
IIC_SendStop(); //停止信號
return dat;
}
(2). 設定DAC通道輸出資料時序

圖4-8-10
示例代碼:
/*
函式功能:設定DAC通道輸出的值
*/
void PCF8591_SetDAC_Data(u8 val)
{
IIC_SendStart();//起始信號
IIC_SendOneByte(PCF8591_WRITE_ADDR);//發送設備地址
IIC_GetAck();//獲取應答
IIC_SendOneByte(0x40); //發送控制位元組
IIC_GetAck();//獲取應答
IIC_SendOneByte(val); //設定AD值
IIC_GetAck();//獲取應答
IIC_SendStop();//停止信號
}
4.8.9 PCF8591完整示例代碼
PCF8591模塊接在實驗板P2.1(SCL)和P2.0(SDA)口上,在主函式里按照順序讀取4個通道ADC值,列印到串口終端,并且使用其中一個ADC通道檢測的輸入值,作為DAC通道的輸出值,用以測驗DAC通道功能,

圖 4-8-11
(硬體平臺說明:CPU是STC90C516RD 、晶振頻率12MHZ 、作業在12T模式下、一個機器周期為1us時間)
示例代碼:
#include <reg51.h>
/*
硬體連接:
SCL---P2.1
SDA---P2.0
*/
//資料線
sbit IIC_SDA=P2^0;
//時鐘線
sbit IIC_SCL=P2^1;
/*
函式功能: 發送起始信號
當時鐘線為高電平的時候,資料線由高電平變為低電平的程序
*/
void IIC_SendStart(void)
{
u8 i=0;
IIC_SCL=1;
IIC_SDA=1;
IIC_SDA=0;
IIC_SCL=0; //總線開始作業、開始讀寫資料
}
/*
函式功能: 停止信號
當時鐘線為高電平的時候,資料線由低電平變為高電平的程序
*/
void IIC_SendStop(void)
{
u8 i=0;
IIC_SCL=0;
IIC_SDA=0;
IIC_SCL=1;
IIC_SDA=1;
}
/*
函式功能: 獲取應答信號
返 回 值: 0表示獲取到應答 1表示沒有獲取到應答
*/
u8 IIC_GetAck(void)
{
u8 i=0;
IIC_SDA=1; //上拉
IIC_SCL=0;
IIC_SCL=1;
while(IIC_SDA)
{
i++;
if(i>250)return 1; //獲取不到應答
}
IIC_SCL=0;
return 0;
}
/*
函式功能: 發送應答信號
函式引數:0表示應答 1表示非應答
*/
void IIC_SendAck(u8 ack)
{
u8 i=0;
IIC_SCL=0;
if(ack)IIC_SDA=1; //發送非應答
else IIC_SDA=0; //發送應答
IIC_SCL=1;
IIC_SCL=0;
}
/*
函式功能: 發送一個位元組資料
*/
void IIC_SendOneByte(u8 dat)
{
u8 j=0,i=0;
for(j=0;j<8;j++)
{
IIC_SCL=0;
if(dat&0x80)IIC_SDA=1;
else IIC_SDA=0;
IIC_SCL=1;
dat<<=1;
}
IIC_SCL=0;
}
/*
函式功能: 接收一個位元組資料
*/
u8 IIC_RecvOneByte(void)
{
u8 i=0,j=0;
u8 dat=0;
for(j=0;j<8;j++)
{
IIC_SCL=0;
IIC_SCL=1;
dat<<=1; //表示默認收到0
if(IIC_SDA)dat|=0x01;
}
IIC_SCL=0;
return dat;
}
/*
函式功能: 設定ADC轉換通道,并回傳采集的資料值
ch的范圍:0x00 0x01 0x02 0x03 分別代表通道0~3
*/
u8 PCF8591_GetADC_CHx(u8 ch)
{
u8 dat;
IIC_SendStart();//起始信號
IIC_SendOneByte(PCF8591_WRITE_ADDR);//發送設備地址
IIC_GetAck();//獲取應答
IIC_SendOneByte(ch); //發送控制位元組
IIC_GetAck();//獲取應答
IIC_SendStart();//起始信號
IIC_SendOneByte(PCF8591_READ_ADDR);//發送設備地址
IIC_GetAck();//獲取應答
dat=IIC_RecvOneByte();//讀取資料
IIC_SendAck(1); //發送非應答
IIC_SendStop(); //停止信號
return dat;
}
/*
函式功能:設定DAC通道輸出的值
*/
void PCF8591_SetDAC_Data(u8 val)
{
IIC_SendStart();//起始信號
IIC_SendOneByte(PCF8591_WRITE_ADDR);//發送設備地址
IIC_GetAck();//獲取應答
IIC_SendOneByte(0x40); //發送控制位元組
IIC_GetAck();//獲取應答
IIC_SendOneByte(val); //設定AD值
IIC_GetAck();//獲取應答
IIC_SendStop();//停止信號
}
int main()
{
u8 ch0,ch1,ch2,ch3; //存放ADC通道檢測的值
u8 dac_val; //存放DAC輸出的值
UART_Init(); //初始化串口波特率為4800
while(1)
{
/*1. 轉換并讀取通道0的AD值: 模塊上通道0默認接可調0-5v的可變電阻*/
ch0=PCF8591_GetADC_CHx(0x00);//模塊上標注是AIN3
printf("(CH0)可變電阻=%d\r\n",(int)ch0);
/*2. 轉換并讀取通道1的AD值: 模塊上通道1默認接光敏電阻*/
ch1=PCF8591_GetADC_CHx(0x01); //模塊上標注是AIN0
printf("(CH1)光敏電阻=%d\r\n",(int)ch1);
/*3. 轉換并讀取通道2的AD值: 模塊上通道2默認接熱敏電阻*/
ch2=PCF8591_GetADC_CHx(0x02);//模塊上標注是AIN1
printf("(CH2)熱敏電阻=%d\r\n",(int)ch2);
/*4. 轉換并讀取通道3的AD值: 模塊上通道3默認懸空沒有接檢測點*/
ch3=PCF8591_GetADC_CHx(0x03);//模塊上標注是AIN2
printf("(CH3)=%d\r\n",(int)ch3);
printf("---------------------\r\n");
/*5. 設定DAC輸出值*/
PCF8591_SetDAC_Data(ch0); //使用通道1測量的可變電阻值傳給DAC輸出
DelayMs(1000); //延時一段時間
}
}

圖4-8-12
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/392248.html
標籤:其他
上一篇:物聯網(二)
下一篇:智能魔法棒———硬體篇
