PCF8591 應(yīng)用程序
PCF8591 的通信接口是 I2C,那么編程肯定是要符合這個(gè)協(xié)議的。單片機(jī)對 PCF8591 進(jìn)行初始化,一共發(fā)送三個(gè)字節(jié)即可。第一個(gè)字節(jié),和 EEPROM 類似,是器件地址字節(jié),其中7位代表地址,1位代表讀寫方向。地址高4位固定是 0b1001,低三位是 A2,A1,A0,這三位我們電路上都接了 GND,因此也就是 0b000,如圖17-5所示。
圖17-5 PCF8591 地址字節(jié)
發(fā)送到 PCF8591 的第二個(gè)字節(jié)將被存儲在控制寄存器,用于控制 PCF8591 的功能。其中第3位和第7位是固定的0,另外6位各自有各自的作用,如圖17-6所示,我逐一介紹。
圖17-6 PCF8591 控制字節(jié)
控制字節(jié)的第6位是 DA 使能位,這一位置1表示 DA 輸出引腳使能,會產(chǎn)生模擬電壓輸出功能。第4位和第5位可以實(shí)現(xiàn)把 PCF8591 的4路模擬輸入配置成單端模式和差分模式,單端模式和差分模式的區(qū)別,我們在17.5節(jié)有介紹,這里大家只需要知道這兩位是配置 AD 輸入方式的控制位即可,如圖17-7所示。
圖17-7 PCF8591 模擬輸入配置方式
控制字節(jié)的第2位是自動(dòng)增量控制位,自動(dòng)增量的意思就是,比如我們一共有4個(gè)通道,當(dāng)我們?nèi)渴褂玫臅r(shí)候,讀完了通道0,下一次再讀,會自動(dòng)進(jìn)入通道1進(jìn)行讀取,不需要我們指定下一個(gè)通道,由于 A/D 每次讀到的數(shù)據(jù),都是上一次的轉(zhuǎn)換結(jié)果,所以同學(xué)們在使用自動(dòng)增量功能的時(shí)候,要特別注意,當(dāng)前讀到的是上一個(gè)通道的值。為了保持程序的通用性,我們的代碼沒有使用這個(gè)功能,直接做了一個(gè)通用的程序。
控制字節(jié)的第0位和第1位就是通道選擇位了,00、01、10、11代表了從0到3的一共4個(gè)通道選擇。
發(fā)送給 PCF8591 的第三個(gè)字節(jié) D/A 數(shù)據(jù)寄存器,表示 D/A 模擬輸出的電壓值。D/A 模擬我們一會介紹,大家知道這個(gè)字節(jié)的作用即可。我們?nèi)绻麅H僅使用 A/D 功能的話,就可以不發(fā)送第三個(gè)字節(jié)。
下面我們用一個(gè)程序,把 AIN0、AIN1、AIN3 測到的電壓值顯示在液晶上,同時(shí)大家可以轉(zhuǎn)動(dòng)電位器,會發(fā)現(xiàn) AIN0 的值發(fā)生變化。 /*Lcd1602.c 文件程序源代碼***/ (此處省略,可參考之前章節(jié)的代碼) /*I2C.c 文件程序源代碼***/ (此處省略,可參考之前章節(jié)的代碼)
/*****************************main.c文件程序源代碼******************************/#includebitflag300ms=1;//300ms定時(shí)標(biāo)志unsignedcharT0RH=0;//T0重載值的高字節(jié)unsignedcharT0RL=0;//T0重載值的低字節(jié)voidConfigTimer0(unsignedintms);unsignedcharGetADCValue(unsignedcharchn);voidValueToString(unsignedchar*str,unsignedcharval);externvoidI2CStart();externvoidI2CStop();externunsignedcharI2CReadACK();externunsignedcharI2CReadNAK();externbitI2CWrite(unsignedchardat);externvoidInitLcd1602();externvoidLcdShowStr(unsignedcharx,unsignedchary,unsignedchar*str);voidmain(){unsignedcharval;unsignedcharstr[10];EA=1;//開總中斷ConfigTimer0(10);//配置T0定時(shí)10msInitLcd1602();//初始化液晶LcdShowStr(0,0,"AIN0AIN1AIN3");//顯示通道指示while(1){if(flag300ms){flag300ms=0;//顯示通道0的電壓val=GetADCValue(0);//獲取ADC通道0的轉(zhuǎn)換值ValueToString(str,val);//轉(zhuǎn)為字符串格式的電壓值LcdShowStr(0,1,str);//顯示到液晶上//顯示通道1的電壓val=GetADCValue(1);ValueToString(str,val);LcdShowStr(6,1,str);//顯示通道3的電壓val=GetADCValue(3);ValueToString(str,val);LcdShowStr(12,1,str);}}}/*讀取當(dāng)前的ADC轉(zhuǎn)換值,chn-ADC通道號0~3*/unsignedcharGetADCValue(unsignedcharchn){unsignedcharval;I2CStart();if(!I2CWrite(0x48<<1)){//尋址PCF8591,如未應(yīng)答,則停止操作并返回0I2CStop();return0;}I2CWrite(0x40"chn);//寫入控制字節(jié),選擇轉(zhuǎn)換通道I2CStart();I2CWrite((0x48<<1)|0x01);//尋址PCF8591,指定后續(xù)為讀操作I2CReadACK();//先空讀一個(gè)字節(jié),提供采樣轉(zhuǎn)換時(shí)間val=I2CReadNAK();//讀取剛剛轉(zhuǎn)換完的值I2CStop();returnval;}/*ADC轉(zhuǎn)換值轉(zhuǎn)為實(shí)際電壓值的字符串形式,str-字符串指針,val-AD轉(zhuǎn)換值*/voidValueToString(unsignedchar*str,unsignedcharval){//電壓值=轉(zhuǎn)換結(jié)果*2.5V/255,式中的25隱含了一位十進(jìn)制小數(shù)val=(val*25)/255;str[0]=(val/10)+'0';//整數(shù)位字符str[1]='.';//小數(shù)點(diǎn)str[2]=(val%10)+'0';//小數(shù)位字符str[3]='V';//電壓單位str[4]='