1、PCF8591模块简介
PCF8591是一个单片集成、单独供电、低功耗、8-bit CMOS数据获取器件。PCF8591具有4个模拟输入、1个模拟输出和1个串行I²C总线接口。
在PCF8591器件上输入输出的地址、控制和数据信号都是通过双线双向I2C总线以串行的方式进行传输。
2、电路连接图
PCF8591电路连接图
AIN0~AIN3:模拟信号输入端。
A0~A2:器件地址的低3位。
VSS:电源负极。
SDA、SCL:I2C 总线的数据线、时钟线。
OSC:外部时钟输入端,内部时钟输出端。
EXT:内部/外部时钟选择线,使用内部时钟时EXT 接地。
AGND:模拟信号地。
VREF:基准电源端。
AOUT:D/A 转换输出端。
VDD:电源端。(2.5~6V)
AINI外接了一个光敏电阻和一个定值电阻,读取的是定值电阻两端的电压,因此,光照越强,光敏电阻阻值越小,即电压越小,然后R31电压增大,所以总的来看,读取到的电压是随光照增加而增大的。
AIN3外接一个电位器RB2,读取到的是AIN3向接地部分的电阻,因此是随电阻增大,电压减小
这里J3的18、19两根引脚,一个AIN0是ADC读取,一个OUT是DAC输出,都是可以外接设备的,通过跳线帽连接,可以读取out输出值。
3、器件地址
与AT24C0D相同,PCF8591的3个地址引脚A0, A1和A2可用于硬件地址编程,也就是编写器件地址第2、3、4位。最后一位地址的最后一位为方向位R/W ,当主控器对A/D 器件进行读操作时为1,进行写操作时为0。前四位固定为1001,因此允许在同个I2C总线上接入8个PCF8591器件,而无需额外的硬件。
即0X90——写操作地址+器件地址
0X91——读操作地址+器件地址
4、DA转换功能
①启动IIC
②发送器件地址+写:0x90
③发送通道选择命令:0x40-0x43 (0x00-0x03 )
④重新启动IIC
⑤发送器件地址+读:0x91
⑥读取转换数据
unsigned char read_rb(unsigned char channel)//选择通道,取值0、1、2、3
{
unsigned char dat;
IIC_Start();
IIC_SendByte(0x90); //写
IIC_WaitAck();
IIC_SendByte(40+channel);
IIC_WaitAck();
IIC_Start();
IIC_SendByte(0x91); //读
IIC_WaitAck();
dat = IIC_RecByte();
IIC_SendAck(1);
IIC_Stop();
return dat;
}
5、AD转换功能
读取的第一个字节是上一次转换的结果。读取上一个字节后,才开始进行这次转换的采样,所以读取的第二个字节才是这次的转换结果。所以读取转换结果的步骤是:发送转换命令,将上次的结果读走,然后等一会儿,然后读取结果。
①启动
②发送器件地址+写:0x90
③发送DAC使能:0x40
④发送数字信号值:X
void write_DAC(unsigned char x)
{
IIC_Start();
IIC_SendByte(0x90); //写
IIC_WaitAck();
IIC_SendByte(0x43); //允许输出
IIC_WaitAck();
IIC_SendByte(x);
IIC_WaitAck();
IIC_Stop();
}
6、IIC通信
#include "reg52.h"
#include "intrins.h"
#define DELAY_TIME 5
#define SlaveAddrW 0xA0
#define SlaveAddrR 0xA1
//总线引脚定义
sbit SDA = P2^1; /* 数据线 */
sbit SCL = P2^0; /* 时钟线 */
void IIC_Delay(unsigned char i)
{
do{_nop_();}
while(i--);
}
//总线启动条件
void IIC_Start(void)
{
SDA = 1;
SCL = 1;
IIC_Delay(DELAY_TIME);
SDA = 0;
IIC_Delay(DELAY_TIME);
SCL = 0;
}
//总线停止条件
void IIC_Stop(void)
{
SDA = 0;
SCL = 1;
IIC_Delay(DELAY_TIME);
SDA = 1;
IIC_Delay(DELAY_TIME);
}
//发送应答
void IIC_SendAck(bit ackbit)
{
SCL = 0;
SDA = ackbit; // 0:应答,1:非应答
IIC_Delay(DELAY_TIME);
SCL = 1;
IIC_Delay(DELAY_TIME);
SCL = 0;
SDA = 1;
IIC_Delay(DELAY_TIME);
}
//等待应答
bit IIC_WaitAck(void)
{
bit ackbit;
SCL = 1;
IIC_Delay(DELAY_TIME);
ackbit = SDA;
SCL = 0;
IIC_Delay(DELAY_TIME);
return ackbit;
}
//通过I2C总线发送数据
void IIC_SendByte(unsigned char byt)
{
unsigned char i;
for(i=0; i<8; i++)
{
SCL = 0;
IIC_Delay(DELAY_TIME);
if(byt & 0x80) SDA = 1;
else SDA = 0;
IIC_Delay(DELAY_TIME);
SCL = 1;
byt <<= 1;
IIC_Delay(DELAY_TIME);
}
SCL = 0;
}
//从I2C总线上接收数据
unsigned char IIC_RecByte(void)
{
unsigned char i, da;
for(i=0; i<8; i++)
{
SCL = 1;
IIC_Delay(DELAY_TIME);
da <<= 1;
if(SDA) da |= 1;
SCL = 0;
IIC_Delay(DELAY_TIME);
}
return da;
}