I2C总线是Philips公司推出的串行总线,整个系统仅靠数据线(SDA)和时钟线(SCL)实现完善的全双工数据传输,即CPU与各个外围器件仅靠这两条线实现信息交换。I2C总线系统与传统的并行总线系统相比具有结构简单、可维护性好、易实现系统扩展、易实现模块化标准化设计、可靠性高等优点。
在一个完整的单片机系统中,A/D转换芯片往往是必不可少的。PCF8591是一种具有I2C总线接口的A/D转换芯片。在与CPU的信息传输过程中仅靠时钟线SCL和数据线SDA就可以实现。
2、芯片介绍
PCF8591是具有I2C总线接口的8位A/D及D/A转换器。有4路A/D转换输入,1路D/A模拟输出。这就是说,它既可以作A/D转换也可以作D/A转换。A/D转换为逐次比较型。引脚图如图1所示。结构图如图2所示。电源电压典型值为5V。
AIN0~AIN3:模拟信号输入端。
A0~A3:引脚地址端。
VDD、VSS:电源端。(2.5~6V)
SDA、SCL:I2C总线的数据线、时钟线。
OSC:外部时钟输入端,内部时钟输出端。
EXT:内部、外部时钟选择线,使用内部时钟时EXT接地。
AGND:模拟信号地。
AOUT:D/A转换输出端。
VREF:基准电源端。
3 应用
3.1 器件总地址
PCF8591采用典型的I2C总线接口器件寻址方法,即总线地址由器件地址、引脚地址和方向位组成。飞利蒲公司规定A/D器件地址为1001。引脚地址为A2A1A0,其值由用户选择,因此I2C系统中最多可接23=8个具有I2C总线接口的A/D器件。地址的最后一位为方向位R/ ,当主控器对A/D器件进行读操作时为1,进行写操作时为0。总线操作时,由器件地址、引脚地址和方向位组成的从地址为主控器发送的第一字节。
3.2 控制字节
控制字节用于实现器件的各种功能,如模拟信号由哪几个通道输入等。控制字节存放在控制寄存器中。总线操作时为主控器发送的第二字节。其格式如下所示:
其中:D1、D0两位是A/D通道编号:00通道0,01通道1,10通道2,11通道3
D2 自动增益选择(有效位为1)
D5、D4模拟量输入选择:00为四路单数入、01为三路差分输入、10为单端与差分配合输入、11为模拟输出允许有效。
当系统为A/D转换时,模拟输出允许为0。模拟量输入选择位取值由输入方式决定:四路单端输入时取00,三路差分输入时取01,单端与差分输入时取10,二路差分输入时取11。最低两位时通道编号位,当对0通道的模拟信号进行A/D转换时取00,当对1通道的模拟信号进行A/D转换时取01,当对2通道的模拟信号进行A/D转换时取10,当对3通道的模拟信号进行A/D转换时取11。
在进行数据操作时,首先是主控器发出起始信号,然后发出读寻址字节,被控器做出应答后,主控器从被控器读出第一个数据字节,主控器发出应答,主控器从被控器读出第二个数据字节,主控器发出应答…一直到主控器从被控器中读出第n个数据字节,主控器发出非应答信号,最后主控器发出停止信号。
PCF8591 AD及D/A转换器的应用程序
[日期:2009-07-06 ] [来源:东哥单片机学习网 作者:admin] [字体:大 中 小] (投递新闻)
PCF8591 AD及D/A转换器的应用程序
//-----------------------函数声明,变量定义--------------------------------------------------------
#include #include sbit SDA=P1^0; // 将p1.0口模拟数据口 sbit SCL=P1^1; // 将p1.1口模拟时钟口 #define delayNOP(); {_nop_();_nop_();_nop_();_nop_();}; bit bdata SystemError; // 从机错误标志位 //-----------------------PCF8591专用变量定义-------------------------------------------------------- #define PCF8591_WRITE 0x92 #define PCF8591_READ 0x93 #define NUM 4 // 接收和发送缓存区的深度 unsigned char idata receivebuf[NUM]; // 数据接收缓冲区 //-------------------------------------------------------------------------------------------------- // 函数名称: iic_start() // 函数功能: 启动I2C总线子程序 //-------------------------------------------------------------------------------------------------- void iic_start(void) { EA=0; //时钟保持高,数据线从高到低一次跳变,I2C通信开始 SDA = 1; SCL = 1; delayNOP(); // 延时5us SDA = 0; delayNOP(); SCL = 0; } //-------------------------------------------------------------------------------------------------- // 函数名称: iic_stop() // 函数功能: 停止I2C总线数据传送子程序 //-------------------------------------------------------------------------------------------------- void iic_stop(void) { SDA = 0; //时钟保持高,数据线从低到高一次跳变,I2C通信停止 SCL = 1; delayNOP(); SDA = 1; delayNOP(); SCL = 0; } //-------------------------------------------------------------------------------------------------- // 函数名称: slave_ACK // 函数功能: 从机发送应答位子程序 //-------------------------------------------------------------------------------------------------- void slave_ACK(void) { SDA = 0; SCL = 1; delayNOP(); SDA = 1; SCL = 0; } //-------------------------------------------------------------------------------------------------- // 函数名称: slave_NOACK // 函数功能: 从机发送非应答位子程序,迫使数据传输过程结束 //-------------------------------------------------------------------------------------------------- void slave_NOACK(void) { SDA = 1; SCL = 1; delayNOP(); SDA = 0; SCL = 0; } //-------------------------------------------------------------------------------------------------- // 函数名称: check_ACK // 函数功能: 主机应答位检查子程序,迫使数据传输过程结束 //-------------------------------------------------------------------------------------------------- void check_ACK(void) { SDA = 1; // 将p1.0设置成输入,必须先向端口写1 SCL = 1; F0 = 0; if(SDA == 1) // 若SDA=1表明非应答,置位非应答标志F0 F0 = 1; SCL = 0; } //-------------------------------------------------------------------------------------------------- // 函数名称: IICSendByte // 入口参数: ch // 函数功能: 发送一个字节 //-------------------------------------------------------------------------------------------------- void IICSendByte(unsigned char ch) { unsigned char idata n=8; // 向SDA上发送一位数据字节,共八位 while(n--) { if((ch&0x80) == 0x80) // 若要发送的数据最高位为1则发送位1 { SDA = 1; // 传送位1 SCL = 1; delayNOP(); SDA = 0; SCL = 0; } else { SDA = 0; // 否则传送位0 SCL = 1; delayNOP(); SCL = 0; } ch = ch<<1; // 数据左移一位 } } //-------------------------------------------------------------------------------------------------- // 函数名称: IICreceiveByte // 返回接收的数据 // 函数功能: 接收一字节子程序 //-------------------------------------------------------------------------------------------------- unsigned char IICreceiveByte(void) { unsigned char idata n=8; // 从SDA线上读取一上数据字节,共八位 unsigned char tdata; while(n--) { SDA = 1; SCL = 1; tdata = tdata<<1; // 左移一位,或_crol_(temp,1) if(SDA == 1) tdata = tdata|0x01; // 若接收到的位为1,则数据的最后一位置1 else tdata = tdata&0xfe; // 否则数据的最后一位置0 SCL=0; } return(tdata); } //-------------------------------------------------------------------------------------------------- // 函数名称: DAC_PCF8591 // 入口参数: slave_add从机地址,n要发送的数据个数 // 函数功能: 发送n位数据子程序 //-------------------------------------------------------------------------------------------------- void DAC_PCF8591(unsigned char controlbyte,unsigned char wdata) { iic_start(); // 启动I2C IICSendByte(PCF8591_WRITE); // 发送地址位 check_ACK(); // 检查应答位 if(F0 == 1) { SystemError = 1; return; // 若非应答表明器件错误或已坏,置错误标志位SystemError } IICSendByte(controlbyte&0x77); //Control byte check_ACK(); // 检查应答位 if(F0 == 1) { SystemError = 1; return; // 若非应答表明器件错误或已坏,置错误标志位SystemError } IICSendByte(wdata); //data byte check_ACK(); // 检查应答位 if(F0 == 1) { SystemError = 1; return; // 若非应答表明器件错误或已坏,置错误标志位SystemError } iic_stop(); // 全部发完则停止 delayNOP(); delayNOP(); delayNOP(); delayNOP(); } //-------------------------------------------------------------------------------------------------- // 函数名称: ADC_PCF8591 // 入口参数: controlbyte控制字 // 函数功能: 连续读入4路通道的A/D转换结果到receivebuf //-------------------------------------------------------------------------------------------------- void ADC_PCF8591(unsigned char controlbyte) { unsigned char idata receive_da,i=0; iic_start(); IICSendByte(PCF8591_WRITE); //控制字 check_ACK(); if(F0 == 1) { SystemError = 1; return; } IICSendByte(controlbyte); //控制字 check_ACK(); if(F0 == 1) { SystemError = 1; return; } iic_start(); //重新发送开始命令 IICSendByte(PCF8591_READ); //控制字 check_ACK(); if(F0 == 1) { SystemError = 1; return; } while(i<4) { receive_da=IICreceiveByte(); receivebuf[i++]=receive_da; slave_ACK(); // 收到一个字节后发送一个应答位 } slave_NOACK(); // 收到最后一个字节后发送一个非应答位 iic_stop(); } //-------------------------------------------------------------------------------------------------- // 函数名称: main // 函数功能: 主程序 //-------------------------------------------------------------------------------------------------- main() { DAC_PCF8591(0x40,0); //控制字为0100 0000,允许模拟量输出 //零值点输出测试 DAC_PCF8591(0x40,0xff); //控制字为0100 0000,允许模拟量输出 //满值点输入测试 ADC_PCF8591(0x40); }