PCF8591是8bit的A/D和D/A芯片,采用i2c接口,它有四路模拟输入口和一个模拟输出口,采样速率取决于i2c的速率。数据传输是高位在前低位在后(不论是主机写入数据,还是主机读取的数据)。
写入数据时:起始信号->器件地址->应答信号->控制字节->写入的数据->应答信号(从机)->写入的数据->应答信号(从机)。。。。->停止信号
读取数据时:起始信号->器件地址(写)->应答信号(从机)->控制字节->应答信号(从机)->停止信号(这个前提是设置读取的是哪一个通道,采用的哪种模式) 接着再是:起始信号->器件地址(读)->读取的字节->非应答信号(主机)->停止信号
下图是AD通道自动增量模式采集数据时的数据格式:
具体指令格式请参考PCF8591的数据手册。
下面是PCF8591的模拟输出和模拟输入的程序:
/************************************************************************ **Describe:PCF85891数模和模数转换 ** Time: 2015.5.20 ** Author: zys *************************************************************************/ #include <reg52.h> #include <intrins.h> sbit SCL = P1^5; sbit SDA = P3^6; #define ADONE 0.0198 //5.06/256V PCF8591的Vref电压是5.06V /***本程序数码管是共阴极的***/ const unsigned char smg_dp_yin[ 16 ] = {0xbf, 0x86, 0xdb, 0xcf, 0xe6, 0xed, 0xfd, 0x87, 0xff, 0xef, 0xf7, 0xfc, 0xb9, 0xde, 0xfb, 0xf1};//0. 1. 2. 3......f. //共阴极,显示小数点 //不显示小数点: smg_dp_yin[x] & 0x7f //共阳极显示小数点: ~smg_dp_yin[x] //共阳极不显示小数点: ~(smg_dp_yin[x] | 0x80) /****数码管的位是通过74LS138控制的****/ const unsigned char smg_8_pos[ 8 ] = { 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff }; //对应P20,P21,P22,高位都为1,则与的时候P2的其他位不变 const unsigned char smg_sum = 8; //8位数码管 void i2c_start( void ); void i2c_stop( void ); void i2c_ack( void ); void master_ack(); void master_notAck(); void i2c_writeByte( unsigned char byte); unsigned char i2c_readByte( void ); void PCF8591_wirteCommand( unsigned char addr, unsigned char command ); void PCF8591_AOUT(unsigned char byte); unsigned char i2c_readADResult( void ); void PCF8591_displayADResult( unsigned int ADResult); void delay( void ); void i2c_delay( void ); void delay_xms(unsigned int ); /******************************************************** ** 函数名: void main( void ) **输入参数:无 **返回参数:无 ********************************************************/ void main( void ) { int i = 0; int ch = 0; while(1) { /*for(i = 0; i <= 255; i++) //DA输出,呼吸灯效果 { PCF8591_AOUT(i); delay(); } for(i = 255; i >= 0; i--) { PCF8591_AOUT(i); delay(); } */ for(ch = 0; ch < 4; ch++) //循环采集四路电压 { PCF8591_wirteCommand(0x90, 0x00+ch); for(i = 0; i < 1000; i++) { PCF8591_displayADResult(i2c_readADResult()); } } } } /******************************************************** ** 函数名: void i2c_start( void ),i2c起始信号 **输入参数:无 **返回参数:无 ********************************************************/ void i2c_start( void ) { SCL = 1; SDA = 1; i2c_delay(); SDA = 0; i2c_delay(); SCL = 0; i2c_delay(); } /******************************************************** ** 函数名: void i2c_stop( void ),i2c停止信号 **输入参数:无 **返回参数:无 ********************************************************/ void i2c_stop( void ) { SDA = 0; i2c_delay(); SCL = 1; i2c_delay(); SDA = 1; i2c_delay(); } /******************************************************** ** 函数名: void i2c_ack( void ),i2c应答信号(从机) **输入参数:无 **返回参数:无 ********************************************************/ void i2c_ack( void ) { int i = 0; SCL = 0; i2c_delay(); SDA = 1; i2c_delay(); SCL = 1; i2c_delay(); while(SDA == 1); /*while((SDA == 1) && ((i++) < 10)) { _nop_(); }*/ } /******************************************************** ** 函数名: void master_ack( void ),主机应答信号,在读取数据时 **输入参数:无 **返回参数:无 ********************************************************/ void master_ack( void ) { SCL = 0; i2c_delay(); SDA = 0; i2c_delay(); SCL = 1; i2c_delay(); SCL = 0; i2c_delay(); SDA = 1; i2c_delay(); } /******************************************************** ** 函数名: void master_notAck( void ),主机非应答信号,在读取数据时 **输入参数:无 **返回参数:无 ********************************************************/ void master_notAck( void ) { SCL = 0; i2c_delay(); SDA = 1; i2c_delay(); SCL = 1; i2c_delay(); // 没下面四句程序读取不正常 SCL = 0; // i2c_delay(); // SDA = 0; // } /******************************************************** ** 函数名: void i2c_writeByte,i2c写一个字节 **输入参数:unsigned char byte **返回参数:无 ********************************************************/ void i2c_writeByte( unsigned char byte ) { char loop; for(loop = 0; loop < 8; loop++) { SCL = 0; i2c_delay(); if((byte<<loop)&0x80) //数据是从高位到低位传输 { SDA = 1; } else { SDA = 0; } i2c_delay(); SCL = 1; i2c_delay(); } } unsigned char i2c_readByte( void ) { int loop = 0; unsigned char temp = 0; unsigned char tempData = 0; //SDA = 0; for(loop = 7; loop >= 0; loop--) { SCL = 0; i2c_delay(); temp = SDA; i2c_delay(); SCL = 1; i2c_delay(); tempData += (temp<<loop); temp = 0; } return tempData; } /******************************************************** ** 函数名: void PCF8591_wirteCommand( unsigned char addr, unsigned char command ),PCF8591写控制指令 **输入参数:unsigned char addr, unsigned char command **返回参数:无 ********************************************************/ void PCF8591_wirteCommand( unsigned char addr, unsigned char command ) { i2c_start(); i2c_writeByte(addr); i2c_ack(); i2c_writeByte(command); i2c_ack(); i2c_delay(); i2c_stop(); } /******************************************************** ** 函数名: unsigned char i2c_readADResult( void ),i2c读出一个字节 **输入参数:无 **返回参数:unsigned char ********************************************************/ unsigned char i2c_readADResult( void ) { unsigned char temp = 0; i2c_start(); i2c_writeByte(0x91); i2c_ack(); temp = i2c_readByte(); master_notAck(); i2c_stop(); return temp; } /******************************************************** ** 函数名: void PCF8591_displayADResult( unsigned int ADResult),显示AD采集的数据 **输入参数:unsigned int ADResult **返回参数:无 ********************************************************/ void PCF8591_displayADResult( unsigned int ADResult) { char loop = 0; unsigned int temp = ADONE * ADResult * 100; //两位小数取出来 unsigned int dec = 1; for(loop = 7; loop >= 5; loop--) { if(loop == 5) { P0 = smg_dp_yin[temp/dec%10]; } else { P0 = smg_dp_yin[temp/dec%10]&0x7f; } P2 = smg_8_pos[loop]; delay_xms(1); dec *= 10; } } /******************************************************** ** 函数名: void PCF8591_AOUT( unsigned char byte ),DA输出 **输入参数:unsigned char byte **返回参数:无 ********************************************************/ void PCF8591_AOUT( unsigned char byte ) { i2c_start(); i2c_writeByte(0x90); i2c_ack(); i2c_writeByte(0x40); //只有模拟输出AOUT i2c_ack(); i2c_writeByte(byte); i2c_ack(); i2c_stop(); } /************************************************************************ **函数名:void i2c_delay( void ),i2c专用延时 ** 功能:无 ** 参数: 无 *************************************************************************/ void i2c_delay( void ) { char loop; for(loop = 0; loop < 5; loop++) { _nop_(); } } /************************************************************************ **函数名:void delay_xms( unsigned int x ) ** 功能:延时xms ** 参数: 无 *************************************************************************/ void delay_xms( unsigned int x ) { unsigned char j = 0; while( x-- ) { while( (j++) < 100 ); j = 0; } } /************************************************************************ **函数名:void delay( void ),在输出DA数据时使用的延时 ** 功能:无 ** 参数: 无 *************************************************************************/ void delay( void ) { unsigned int loop; for(loop = 0; loop < 30; loop++) { _nop_(); } }