PCF8591是一个单片集成、单独供电、低功耗、8-bit CMOS数据获取器件。PCF8591具有4个模拟输入、1个模拟输出和1个串行I²C总线接口。在90c51上PCF8591的4个引脚AIN0, AIN1,AIN2和AIN3可接注入光敏电阻,滑变电阻器之类的原件。在PCF8591器件上输入输出的地址、控制和数据信号都是通过双线双向I2C总线以串行的方式进行传输。2条双向串行线,一条数据线SDA,一条时钟线SCL。
A/D实现:诸如光敏电阻将模拟量转化为电压连在AIN1口,而PCF将电压转化为数字由数据线SDA输出。
工作原理:
首先说PCF使用的I2C总线协议
以下来自一位大佬的http://blog.csdn.net/subkiller/article/details/6854910
1. I2C开始和结束信号
开始信号:SCL为高电平时,SDA由高电平向低电平跳变,开始传送数据。
结束信号:SCL为高电平时,SDA由低电平向高电平跳变,结束传送数据。
c51代码:
忽略<>里的东西
void I2C_start()
{
SCL = 1;
SDA = 1;
delay5us();
SDA = 0;
delay5us();
SCL = 0;
}
代码
void I2C_write(uchar dat)
{
uchar i;
for(i=0; i<8; i++)
{
SCL = 0;
delay5us();
SDA = dat & 0x80;
delay5us();
SCL = 1;
dat <<= 1;
delay5us();
}
SCL = 0;
}
3. I2C应答信号
uchar I2C_WaitAck()
{
uint i = 0;
SDA = 1;
delay5us();
SCL = 1;
delay5us();
while(SDA == 1 && i < 300)
i++;
if(SDA)
{
SCL = 0;
I2C_stop();
return 0;
}
else
{
SCL = 0;
return 1;
}
}
返回1有回应
接下来就是读取数据
代码
uchar I2C_read()
{
uchar i;
uchar byte;
SCL = 0;
delay5us();
SDA = 1;
for(i=0; i<8; i++)
{
SCL = 1;
byte <<= 1;
delay5us();
if(SDA)
byte |= 0x01;
SCL = 0;
delay5us();
}
return byte;
}
每次赋值在byte的第一位,之后byte位移。
关于PCF8591的读写
写入数据时:起始信号->器件地址->应答信号->控制字节->写入的数据->应答信号(从机)->写入的数据->应答信号(从机)。。。。->停止信号
读取数据时:起始信号->器件地址(写)->应答信号(从机)->控制字节->应答信号(从机)->停止信号(这个前提是设置读取的是哪一个通道,采用的哪种模 式) 接着再是:起始信号->器件地址(读)->读取的字节->非应答信号(主机)->停止信号
下面来自另一位大佬 http://www.cnblogs.com/whik/p/6650955.html
PCF8591的操作和AT24C02非常类似,只不过AT24C02是写入或读出数据,而PCF8591是AIN端口输入模拟电压,然后PCF8591将转换后的数字量通过IIC总线发送给单片机,或是单片机通过IIC总线给一个数字量,然后PCF8591通过AOUT端口将模拟电压输出.
最高位默认为0
第6位是选择是否允许模拟电压输出,在DA转换时设置为1,AD转换时设置为0或1均可
第5/4位是选择模拟电压输出方式,一般选择00单端输入方式,其他的几种方式如下图所示
第3位默认为0
第2位是自动增量使能位,如果自动增量(auto-increment)标志置1,每次A/D 转换后通道号将自动增加。
第1/0为是在AD转换时选择哪一个通道输入的电压转换为数字量.
由之前的图可以得知,如果显示光敏电阻的变化,那么通道输入0000 0001即可,就是0x01
下面说器件地址
每一个IIC器件都有一个器件地址,来区分不同的IIC设备,下面是PCF8591的地址
它的地址是由1001和A2A1A0组成的,在原理图中可以看出,A2A1A0均为0,所以器件地址为0x90/0x91,最后一位是读写方向位,0表示下一个字节往总线上写数据,1表示下一个字节从总线上读取数据.
代码
完整的代码,烧录在51上后显示的是前三位为滑变电阻器变化值,后三位显示光敏电阻,数码管通过中断控制,尽管我将周期写得很短很短了,它还是闪烁的我眼都要瞎了,只能说可以看清数字
#include
#include "intrins.h"
#define uint unsigned int
#define uchar unsigned char
sbit SCL = P2^0;
sbit SDA = P2^1;
void delay5us();
void I2C_start();
void I2C_write(uchar dat);
uchar I2C_read();
uchar I2C_WaitAck();
void I2C_Ack(uchar ackbit);
void I2C_stop();
void PCF8591_init();
uchar ADC_PCF8591();
#define uint unsigned int
#define uchar unsigned char
uchar code tab[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0xff};
uchar dspbuf[]={10,10,10,10,10,10,10,10};
uchar dspcom = 0;
sfr AUXR = 0x8E;
void close_buzz()
{
P2 = (P2 & 0x1f)|0xa0;
P0 &= 0xbf;
P2 &= 0x1f;
}
void Timer1Init(void)
{
AUXR |= 0x40;
TMOD &= 0x0F;
TH1=(65535-65000)/256;
TL1=(65535-65000)%256;
TF1 = 0;
TR1 = 1;
ET1 = 1;
EA = 1;
}
void delay5us()
{
uchar i;
_nop_();
i = 11;
while (--i);
}
void I2C_start()
{
SCL = 1;
SDA = 1;
delay5us();
SDA = 0;
delay5us();
SCL = 0;
}
void I2C_write(uchar dat)
{
uchar i;
for(i=0; i<8; i++)
{
SCL = 0;
delay5us();
SDA = dat & 0x80;
delay5us();
SCL = 1;
dat <<= 1;
delay5us();
}
SCL = 0;
}
uchar I2C_WaitAck()
{
uint i = 0;
SDA = 1;
delay5us();
SCL = 1;
delay5us();
while(SDA == 1 && i < 300)
i++;
if(SDA)
{
SCL = 0;
I2C_stop();
return 0;
}
else
{
SCL = 0;
return 1;
}
}
void I2C_Ack(uchar ackbit)
{
SCL = 0;
if(ackbit)
SDA = 0;
else
SDA = 1;
delay5us();
SCL = 1;
delay5us();
SCL = 0;
SDA = 1;
delay5us();
}
uchar I2C_read()
{
uchar i;
uchar byte;
SCL = 0;
delay5us();
SDA = 1;
for(i=0; i<8; i++)
{
SCL = 1;
byte <<= 1;
delay5us();
if(SDA)
byte |= 0x01;
SCL = 0;
delay5us();
}
return byte;
}
void I2C_stop()
{
SCL = 0;
SDA = 0;
delay5us();
SCL = 1;
delay5us();
SDA = 1;
}
uchar ADC_PCF8591_AIN3()
{
uchar val;
I2C_start();
I2C_write(0x90);
I2C_WaitAck();
I2C_write(0x03);
I2C_WaitAck();
I2C_start();
I2C_write(0x91);
I2C_WaitAck();
val = I2C_read();
I2C_Ack(0);
I2C_stop();
// val = (val*50)/255;
return val;
}
uchar ADC_PCF8591_AIN1()
{
uchar val;
I2C_start();
I2C_write(0x90);
I2C_WaitAck();
I2C_write(0x01);
I2C_WaitAck();
I2C_start();
I2C_write(0x91);
I2C_WaitAck();
val = I2C_read();
I2C_Ack(0);
I2C_stop();
// val = (val*50)/255;
return val;
}
void display()
{
P2 = (P2 & 0x1f)|0xE0;
P0 = ~0xff;
P2 &= 0x1f;
P2 = (P2 & 0x1f)|0xC0;
P0 = ~(1 << dspcom);
P2 &= 0x1f;
P2 = (P2 & 0x1f)|0xE0;
P0 = ~tab[dspbuf[dspcom]];
P2 &= 0x1f;
if(++dspcom == 8)
dspcom = 0;
}
void main()
{
uchar val_AIN1,val_AIN3;
close_buzz();
Timer1Init();
while(1)
{
val_AIN1 = ADC_PCF8591_AIN1();
val_AIN3 = ADC_PCF8591_AIN3();
dspbuf[0] = val_AIN1/100;
dspbuf[1] = val_AIN1/10%10;
dspbuf[2] = val_AIN1%10;
dspbuf[5] = val_AIN3/100;
dspbuf[6] = val_AIN3/10%10;
dspbuf[7] = val_AIN3%10;
}
}
void Timer1() interrupt 3
{
display();
}
刚看完什么什么特工2,极限特工2?