一.AD转换的概念
AD转换的功能是把模拟量电压转换为数字量电压。DA转换的功能正好相反,就是将数字量转换位模拟量。
二.芯片PCF8591介绍
PCF8591是一个单片集成、单独供电、低功耗、8-bit CMOS数据获取器件。PCF8591具有4个模拟输入、1个模拟输出和1个串行I²C总线接口。PCF8591的3个地址引脚A0, A1和A2可用于硬件地址编程,允许在同个I2C总线上接入8个PCF8591器件,而无需额外的硬件。在PCF8591器件上输入输出的地址、控制和数据信号都是通过双线双向I²C总线以串行的方式进行传输。
PCF8591 是具有I2C 总线接口的8 位A/D 及D/A 转换器。有4 路A/D 转换输入,1 路D/A 模拟输出。这就是说,它既可以作A/D 转换也可以作D/A 转换。A/D 转换为逐次比较型。电源电压典型值为5V。
AIN0~AIN3:模拟信号输入端。
A0~A3:引脚地址端。
VSS:电源负极。
SDA、SCL:I2C 总线的数据线、时钟线。
OSC:外部时钟输入端,内部时钟输出端。
EXT:内部、外部时钟选择线,使用内部时钟时EXT 接地。
AGND:模拟信号地。
VREF:基准电源端。
AOUT:D/A 转换输出端。
VDD:电源端。(2.5~6V)
模块原理图
PCF8591的器件地址:
PCF8591 采用典型的I2C 总线接口器件寻址方法,即总线地址由器件地址、引脚地址和方向位组成。飞利蒲公司规定A/D 器件地址为1001。引脚地址A2A1A0,其值由用户选择,因此I2C 系统中多可接2^3=8 个具有I2C 总线接口的A/D 器件。地址的后一位为方向位R/w ,当主控器对A/D 器件进行读操作时为1,进行写操作时为0。总线操作时,由器件地址、引脚地址和方向位组成的从地址为主控器发送的第一字节。
D7~D4:1001
D3~D1:分别是A2、A1、A0的电平,我们原理图上面是全部接地,所以为000。
D0:为方向设置,当为1时进行读操作,当为0时进行写操作。
PCF8591的控制寄存器
D1、D0:AD通道选择00通道0,01通道1,10通道2,11通道3
D2:自动增益选择(有效位为1)
D5、D4:输入模式选择:00四路单数输入;01三路差分输入;10单端与差分配合输入;11为模拟输入有效
D6:模拟输出使能位。(时能为1)
I2C总线的数据传送
起始、终止、应答信号时序图
主机可以采用不带I2C总线接口的单片机,如80C51、AT89C2051等单片机,利用软件实现I2C总线的数据传送,即软件与硬件结合的信号模拟。为了保证数据传送的可靠性,标准的I2C总线的数据传送有严格的时序要求。I2C总线的起始信号、终止信号、发送“0”及发送“1”的模拟时序 :
起始信号程序:
void Start_I2c()
{
sda=1; /*发送起始条件的数据信号*/
_nop_();
scl=1;
_nop_(); /*起始条件建立时间大于4.7us,延时*/
_nop_(); _nop_(); _nop_(); _nop_();
sda=0; /*发送起始信号*/
_nop_(); /* 起始条件锁定时间大于4μs*/
_nop_(); _nop_(); _nop_(); _nop_();
scl=0; /*开启I2C总线,准备发送或接收数据 */
_nop_(); _nop_();
}
终止信号程序:
void Stop_I2c()
{
sda=0; /*发送结束条件的数据信号*/
_nop_(); /*发送结束条件的时钟信号*/
scl=1; /*结束条件建立时间大于4μs*/
_nop_(); _nop_(); _nop_(); _nop_(); _nop_();
sda=1; /*发送I2C总线结束信号*/
_nop_(); _nop_(); _nop_(); _nop_();
}
应答信号程序:
void Ack_I2c(bit a)
{
if(a==0)sda=0; /*在此发出应答或非应答信号 */
else sda=1;
_nop_(); _nop_(); _nop_();
scl=1;
_nop_(); /*时钟低电平周期大于4μs*/
_nop_(); _nop_(); _nop_(); _nop_();
scl=0; /*清时钟线,开启I2C总线以便继续接收*/
_nop_(); _nop_();
}
PCF8591的写入
第一个字节是器件地址和读写控制
第二个字节被存到控制寄存器,用于控制器件功能。
第三个字节被存储到DAC数据寄存器,并使用片上D/A转换器转换成对应的模拟电压。(所以不输入D/A时,可以不用输入。)
PCF8591发送一个字节的程序
bit PCF8591_SendByte(unsigned char addr,unsigned char channel)
{
Start_I2c(); //启动总线
I2C_SendByte(addr); //发送器件地址
if(ack==0)return(0);
I2C_SendByte(0x40|channel); //发送控制字节
if(ack==0)return(0);
Stop_I2c(); //结束总线
return(1);
}
PCF8591的读取
读取的第一个字节是包含上一次转换结果。将上一个字节读取时,才开始进行这次转换的采样。读取的第二个字节才是这次的转换结果。所以读取转换结果的步骤是:发送转换命令,将上次的结果读走,然后等一会儿,然后读取结果。
PCF8591读取一个字节的程序:
unsigned char PCF8591_RcvByte(unsigned char addr)
{ unsigned char dat;
Start_I2c(); //启动总线
I2C_SendByte(addr+1); //发送器件地址
if(ack==0)return(0);
dat=I2C_RcvByte(); //读取数据
Ack_I2c(1); //发送非应答信号
Stop_I2c(); //结束总线
return(dat);
}
PCF8591发送一次转换的程序:
bit Pcf8591_DaConversion(unsigned char addr,unsigned char channel, unsigned char Val)
{
Start_I2c(); //启动总线
I2C_SendByte(addr); //发送器件地址
if(ack==0)return(0);
I2C_SendByte(0x40|channel); //发送控制字节
if(ack==0)return(0);
I2C_SendByte(Val); //发送DAC的数值
if(ack==0)return(0);
Stop_I2c(); //结束总线
return(1);
}