基于51單片機(jī)的PCF8591電壓測(cè)量這個(gè)筆記記錄好久了,。因?yàn)橄胪黄艫DS1115在STC89下的使用,但一直沒(méi)有太清晰的眉目和充裕的時(shí)間,。不知道為什么各種資料里,,ADS1115很少有介紹差分的,而都是單端的,。這幾天忙時(shí)也無(wú)暇琢磨,,于是輪到了PCF8591。
STC89系列芯片不能直接測(cè)電壓,,也就是這個(gè)系列的芯片沒(méi)有AD/DA轉(zhuǎn)換的本領(lǐng),。想測(cè)量電壓,就必須得借助PCF8591來(lái)幫忙,。這一點(diǎn)上STC89跟ATTiny沒(méi)法比,,實(shí)際ATTiny13/85都可以直接AD轉(zhuǎn)換。不過(guò)STC后期的STC8/12/15系列都自帶ADC引腳,,可以直接使用的,,價(jià)格可能也要貴一些。
在STC89系列下使用PCF8591本質(zhì)就是IIC讀寫,,然后轉(zhuǎn)換,。但是說(shuō)起來(lái),實(shí)現(xiàn)起來(lái)也不容易,。 接線圖: 代碼很混亂,,不拆分,也不依賴外部其他文件,,但是對(duì)PCF8591的使用流程則一目了然: #include<reg52.h> #include<intrins.h> #include <stdio.h> #include <stdlib.h>
#define uchar unsigned char #define uint unsigned int uchar dat[8]; uchar code char_temp[8] = {'\r', '\n'};
sbit SCL = P2 ^ 0; sbit SDA = P2 ^ 1;
void IIC_Start(void) { SDA = 1; SCL = 1; _nop_(); _nop_(); SDA = 0; _nop_(); _nop_(); SCL = 0; } void IIC_Stop(void) { SDA = 0; SCL = 1; _nop_(); _nop_(); SDA = 1; } void IIC_Ack(unsigned char ackbit) { if(ackbit) { SDA = 0; } else { SDA = 1; }
_nop_(); _nop_(); SCL = 1; _nop_(); _nop_(); SCL = 0; SDA = 1; _nop_(); _nop_(); }
bit IIC_WaitAck(void) { SDA = 1; _nop_(); _nop_(); SCL = 1; _nop_(); _nop_();
if(SDA) { SCL = 0; IIC_Stop(); return 0; } else { SCL = 0; return 1; } }
void IIC_SendByte(unsigned char byt) { unsigned char i;
for(i = 0; i < 8; i++) { if(byt & 0x80) { SDA = 1; } else { SDA = 0; }
_nop_(); _nop_(); SCL = 1; byt <<= 1; _nop_(); _nop_(); SCL = 0; }
}
unsigned char IIC_RecByte(void) { unsigned char da; unsigned char i;
for(i = 0; i < 8; i++) { SCL = 1; _nop_(); _nop_(); da <<= 1;
if(SDA) da |= 0x01; SCL = 0; _nop_(); _nop_(); } return da; }
void init_pcf8591(void) { IIC_Start(); IIC_SendByte(0x90); //PCF8591里的地址 IIC_WaitAck(); IIC_SendByte(0x00); //選擇ADC通道,,0x00電位器,0x01光敏,0x02熱敏 IIC_WaitAck(); IIC_Stop(); }
//接收PCF8591轉(zhuǎn)換過(guò)的采樣電壓值 unsigned char adc_pcf8591(void) { unsigned char temp; IIC_Start(); IIC_SendByte(0x91); IIC_WaitAck(); temp = IIC_RecByte(); IIC_Ack(0); IIC_Stop(); return temp; }
/** * 串口初始化函數(shù) * 波特率為9600 */ void UartConfigurationInit() { TMOD = 0x20; //設(shè)置定時(shí)器1工作方式為方式2 TH1 = 0xfd; //波特率9600 TL1 = 0xfd; TR1 = 1; //啟動(dòng)定時(shí)器1 SM0 = 0; SM1 = 1; //串口方式1 REN = 1; //允許接收 PCON = 0x00; //關(guān)倍頻 ES = 1; //開(kāi)串口中斷 EA = 1; //開(kāi)總中斷 }
/** * 延時(shí)函數(shù) * 延時(shí)count毫秒 */
void delay(uint count) { uint cycle; while(count) { cycle = 120; while(cycle > 0) cycle--; count--; } }
/** * 字符發(fā)送函數(shù) */ void PostChar(uchar character) { SBUF = character; //發(fā)送單個(gè)字符 while(!TI); TI = 0; //發(fā)送完成標(biāo)志 }
/** * 字符串發(fā)送函數(shù) * 通過(guò)調(diào)用字符發(fā)送函數(shù)來(lái)實(shí)現(xiàn) */ void PostString(uchar *p) { while(*p) //若指針指向的地址為空,,則跳出循環(huán) { PostChar(*p); //指針第一次默認(rèn)指向首地址 delay(20); //延時(shí),,作用為提高發(fā)送準(zhǔn)確度 p++; } }
void main() { uint adNum; float value; UartConfigurationInit(); //初始化串口
while(1) { init_pcf8591(); PostString(char_temp); //發(fā)送字符串 adNum = adc_pcf8591(); value = adNum * 0.01953; //轉(zhuǎn)為電壓值 adNum = value * 100; //保留兩位小數(shù) dat[0] = adNum / 1000 + '0'; //加上'0'是表示數(shù)字轉(zhuǎn)換成字符 dat[1] = adNum % 1000 / 100 + '0'; dat[2] = '.'; dat[3] = adNum % 100 / 10 + '0'; dat[4] = adNum % 10 + '0'; dat[5] = 'V'; PostString(dat); //發(fā)送字符串 delay(1000); } }
|