简述
PCF8591是一款单芯片、单电源、低功耗、8位CMOS数 据采集器件,具有四路模拟输入、一路模拟输出和一个 串行I2C总线接口。 通过I2C总线的串行输入/输出
原理图:
引脚定义:
SYMBOL | PIN | DESCRIPTION | 译文 | AIN0 | 1 | analog inputs (A/D converter) | 模拟输入 | AIN1 | 2 | AIN2 | 3 | AIN3 | 4 | A0 | 5 | hardware address | 硬件地址 | A1 | 6 | A2 | 7 | VSS | 8 | negative supply voltage | 负电压 | SDA | 9 | I2C-bus data input/output | IIC数据线 | SCL | 10 | I2C-bus clock input | IIC时间线 | OSC | 11 | oscillator input/output | 振荡器输入输出 | EXT | 12 | external/internal switch for oscillator input | 振荡器输入的外部/内部开关 | AGND | 13 | analog ground | 模拟接地 | VREF | 14 | voltage reference input | 基准电压(已经接了VCC) | AOUT | 15 | analog output (D/A converter) | 模拟输出 | VDD | 16 | positive supply voltage | 正电压 |
相关地址
IIC寻址设备地址
前四位固定为1001,根据原理图可以知道A2、A1、A0都是接地低电平0;所以PCF8591的写地址为 0X90,读地址为 0X91 ;
控制地址
bit0-bit1:通道选择,00为AIN0通道,01为AIN1通道,10为AIN2通道,11为AIN3通道。根据蓝桥杯单片机开发板,其中AIN0接在J3排针的外部A/D输入通道,AIN1接在光敏电阻,AIN3接在RB2电位器(可调电阻)。 bit3:自动增量使能位(1有效): 如果自动增量(auto-increment)标志置1,每次A/D 转换后通道号将自动增加。 bit5-bit6:输入模式选择位:00为单端输入,01为三个差分输入,10为单端和差分混合输入,11为两个差分输入;一般设置为为单端输入00 bit7:运行模拟电压输入位,进行转换是需要置1;
IIC时序分析
写操作:
起始(START)——>设备地址(Device Address)<写操作的地址>——>PCF8591的应答信号(ACK)——>写入控制字(Control Byte)——>PCF8591的应答信号(ACK)——>写入数据字(DATA)——>PCF8591应答信号(ACK)
读操作: 单字节读取 :起始(START)——>设备地址(Device Address)<读操作的地址>——>PCF8591的应答信号(ACK)——>读取数据(Data Byte)——>主机的的应答信号(ACK)——>停止
数模转换D/A
将总线上接收到的数字量转换成模拟量在AOUT输出,主要利用IIC的写操作来实现数据写入,进而输出对应的模拟电压。 计算公式:
V
O
U
T
=
255
×
D
A
T
A
V
R
E
F
{V}_{OUT}=255\times \frac {DATA} {{V}_{REF}}
VOUT?=255×VREF?DATA?
模数转换公式
将AINx端口输入的模拟电压转换成数字量并发送到总线,主要利用IIC的读操作来实现数据读取,进而显示对应的模拟电压。 数模转换公式:
代码:
一:光敏电阻和可变电阻的AD转换,S4控制模式的切换
#include "reg52.h"
#include "iic.h"
sbit S4 = P3^3;
unsigned char Rd1 = 0;
unsigned char Rd2 = 0;
unsigned char status = 0;
unsigned char SMG_NoDot[19] = {0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0x88,0x80,0xc6,0xc0,0x86,0x8e,0xbf,0x7f,0xff};
void Delay(unsigned int t)
{
while(t--);
}
void Delay500us()
{
unsigned char i, j;
i = 6;
j = 211;
do
{
while (--j);
} while (--i);
}
void Digital_Tube(unsigned char Position,unsigned char Typeface)
{
unsigned char Bit[8]={0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80};
P2 = P2 & 0x1f | 0xc0;
P0=Bit[Position];
P2 = P2 & 0x1f | 0xe0;
P0=Typeface;
Delay500us();
P0=0XFF;
P2 = P2 & 0x1f ;
}
void Display_PCF8591(unsigned char channel,unsigned char dat)
{
Digital_Tube(0,SMG_NoDot[16]);
Digital_Tube(1,SMG_NoDot[channel]);
Digital_Tube(2,SMG_NoDot[16]);
Digital_Tube(3,0xff);
Digital_Tube(4,0xff);
Digital_Tube(5,SMG_NoDot[dat/100]);
Digital_Tube(6,SMG_NoDot[dat/10%10]);
Digital_Tube(7,SMG_NoDot[dat%10]);
}
void Read_Rd1_Data(void)
{
IIC_Start();
IIC_SendByte(0x90);
IIC_WaitAck();
IIC_SendByte(0x01);
IIC_WaitAck();
IIC_Stop();
Display_PCF8591(1,Rd1);
IIC_Start();
IIC_SendByte(0x91);
IIC_WaitAck();
Rd1 = IIC_RecByte();
IIC_SendAck(1);
IIC_Stop();
Display_PCF8591(1,Rd1);
}
void Read_Rd2_Data(void)
{
IIC_Start();
IIC_SendByte(0x90);
IIC_WaitAck();
IIC_SendByte(0x03);
IIC_WaitAck();
IIC_Stop();
Display_PCF8591(3,Rd2);
IIC_Start();
IIC_SendByte(0x91);
IIC_WaitAck();
Rd2 = IIC_RecByte();
IIC_SendAck(1);
IIC_Stop();
Display_PCF8591(3,Rd2);
}
void Key_Tackle(void)
{
if(S4 == 0)
{
Delay(20);
if(S4 == 0)
{
if(status == 0)
{
status = 1;
while(S4 == 0)
{
Display_PCF8591(1,Rd1);
}
}
else if(status == 1)
{
status = 0;
while(S4 == 0)
{
Display_PCF8591(3,Rd2);
}
}
}
}
}
void main(void)
{
Read_Rd1_Data();
while(1)
{
Key_Tackle();
if(status == 0)
{
Read_Rd1_Data();
}
else
{
Read_Rd2_Data();
}
}
}
二:输出定量的模拟电压
在开发板右侧排针D/A引脚输出模拟电压,输出的电压跟芯片的基准电压相关,可能会比实际小一点,需要自己微调。
#include "reg52.h"
#include "iic.h"
void Analog_Out(unsigned char DATA)
{
IIC_Start();
IIC_SendByte(0x90);
IIC_WaitAck();
IIC_SendByte(0X40);
IIC_WaitAck();
IIC_SendByte(DATA);
IIC_WaitAck();
IIC_Stop();
}
void main(void)
{
while(1)
{
Analog_Out(255*3/5);
}
}
|