這個筆記記錄好久了。因為想突破ADS1115在STC89下的使用,但一直沒有太清晰的眉目和充裕的時間。不知道為什么各種資料里,ADS1115很少有介紹差分的,而都是單端的。這幾天忙時也無暇琢磨,于是輪到了PCF8591。
STC89系列芯片不能直接測電壓,也就是這個系列的芯片沒有AD/DA轉(zhuǎn)換的本領(lǐng)。想測量電壓,就必須得借助PCF8591來幫忙。這一點上STC89跟ATTiny沒法比,實際ATTiny13/85都可以直接AD轉(zhuǎn)換。不過STC后期的STC8/12/15系列都自帶ADC引腳,可以直接使用的,價格可能也要貴一些。
在STC89系列下使用PCF8591本質(zhì)就是IIC讀寫,然后轉(zhuǎn)換。但是說起來,實現(xiàn)起來也不容易。
接線圖:
代碼很混亂,不拆分,也不依賴外部其他文件,但是對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)換過的采樣電壓值
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è)置定時器1工作方式為方式2
TH1 = 0xfd; //波特率9600
TL1 = 0xfd;
TR1 = 1; //啟動定時器1
SM0 = 0;
SM1 = 1; //串口方式1
REN = 1; //允許接收
PCON = 0x00; //關(guān)倍頻
ES = 1; //開串口中斷
EA = 1; //開總中斷
}
/**
* 延時函數(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ā)送單個字符
while(!TI);
TI = 0; //發(fā)送完成標(biāo)志
}
/**
* 字符串發(fā)送函數(shù)
* 通過調(diào)用字符發(fā)送函數(shù)來實現(xiàn)
*/
void PostString(uchar *p)
{
while(*p) //若指針指向的地址為空,則跳出循環(huán)
{
PostChar(*p); //指針第一次默認(rèn)指向首地址
delay(20); //延時,作用為提高發(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);
}
}
聯(lián)系客服