qq335702318 发表于 2011-1-3 17:31:40

PCF8591驱动

=======================================================H文件===========================================================

#ifndef __8591_h
#define __8591_h

#include "delay.h"

sbit SDA=P1^2;       //定义总线连接端口
sbit SCL=P1^1;
sbit WP=P1^0;      

#define READ85910x01
#define WRITE8591 0x00
#define IIC_85910x90


/******* 控制字定义 *******/
/* 模拟信号输出开关 */
#define anlog_output_off0        //禁止模拟输出
#define anlog_output_on   1        //允许模拟输出
/* 模拟输入模式设置 */
#define anlog_model_0   0x00        //四输入
#define anlog_model_1   0x01        //共差分输入
#define anlog_model_2          0x02        //双直通单差分输入
#define anlog_model_3          0x03        //双差分输入
/* 通道自动增量设置 */
#define auto_increment_off 0//禁止通道自动增量
#define auto_increment_on1//禁止通道自动增量
/* 模拟转换通道设置 */
#define anlog_channel_0 0x00//通道0
#define anlog_channel_1 0x01        //通道1
#define anlog_channel_2 0x02//通道2
#define anlog_channel_3 0x03        //通道3

static unsigned char Control_Key;

/**函数声明**/
void start_8591(void);                                                            
void stop_8591(void);
void send_8591(unsigned char Data);
unsigned char receive_8591(void);
void write_8591(unsigned char slave_addr,unsigned char Control_Key,unsigned char Data);
unsigned char read_8591(unsigned char slave_addr,unsigned char rom_addr);
void ack_8591(void);
void no_ack_8591(void);
bit check_ack_8591(void);
void model_set(bit anlog_sw,unsigned char input_model,bit auto_increment,unsigned char AD_channel);

#endif


=======================================================C文件===========================================================

#include "8591.h"

/* -------------
功能:开始
备注:
内容:
--------------- */
void start_8591(void)
{
SDA=1;
_nop_ ();
SCL=1;
_nop_ ();
SDA=0;
_nop_ ();
SCL=0;
_nop_ ();
}


/* -------------
功能:结束
备注:结束后10ms无法写
内容:
--------------- */
void stop_8591()
{
SDA=0;
_nop_ ();
SCL=1;
_nop_ ();
SDA=1;
_nop_ ();
SCL=0;
}


/* -------------
功能:发送数据
备注:输入:Data 要发送的数据
内容:
--------------- */
void send_8591(unsigned char Data)
{
unsigned char temp;
unsigned char s;
temp=Data;
for(s=0;s<8;s++)
{
SCL=0;
_nop_ ();
if((temp&0x80)==0x80)
{
SDA=1;
}
else
{
SDA=0;
};
_nop_ ();
SCL=1;
temp<<=1;
_nop_ ();
};
SCL=0;
}


/* -------------
功能:接收数据
备注:返回值:接收到的数据
内容:
--------------- */
unsigned char receive_8591(void)
{
unsigned char Data=0;
unsigned char s=0;
SDA=1;
for(s=0;s<8;s++)
    {
       unsigned char d;
   SCL=0;
   _nop_ ();
   SCL=1;
   Data<<=1;
   _nop_ ();
       d=SDA;
       Data|=d;
    };
        SCL=0;
return(Data);
}


/* -------------
功能:应答
备注:
内容:
--------------- */
void ack_8591(void)
{
SDA=0;
_nop_ ();
SCL=1;
_nop_ ();
SCL=0;
_nop_ ();
}


/* -------------
功能:无应答
备注:
内容:
--------------- */
void no_ack_8591(void)
{
SDA=1;
_nop_ ();
SCL=1;
_nop_ ();
SCL=0;
_nop_ ();
}


/* -------------
功能:查询应答
备注:返回值:应答信号error
内容:接收器每成功接收1bit数据都要把SDA拉低,以示接收成功
--------------- */
bit check_ack_8591(void)
{
bit error=0;
SCL=0;
SCL=1;
_nop_ ();
error=SDA;
return(error);
}



/* -------------
功能:写8591一字节数据
备注:返回值:无
      输入值:slave_addr 器件地址
                control 控制字
                          Data   要写入的数据
内容:写1byte数据到rom_addr地址
--------------- */
void write_8591(unsigned char slave_addr,unsigned char Control_Key,unsigned char DA_Data)
{
start_8591();
send_8591(IIC_8591|slave_addr|WRITE8591);
ack_8591();
send_8591(Control_Key);
ack_8591();
send_8591(DA_Data);
ack_8591();
stop_8591();
//delay_nms(10);
}


/* -------------
功能:读取8591
备注:返回值:读取的数据
      输入值:slave_addr 器件地址
                Control    控制字
内容:读取ADC
--------------- */
unsigned char read_8591(unsigned char slave_addr,unsigned char Control)
{
unsigned char Data=0;
start_8591();
send_8591(IIC_8591|WRITE8591|slave_addr);
ack_8591();
send_8591(Control);
ack_8591();
start_8591();
send_8591(IIC_8591|READ8591|slave_addr);
ack_8591();
Data=receive_8591();
SCL=0;
no_ack_8591();
stop_8591();
return(Data);
}


void model_set(bit anlog_sw,unsigned char input_model,bit auto_increment,unsigned char AD_channel)
{
Control_Key=0x00;
if(anlog_sw)
{
Control_Key|=0x40;
};
input_model=input_model<<4;
Control_Key|=input_model;
if(auto_increment)
{
Control_Key|=0x04;
};
Control_Key|=AD_channel;
}


=======================================================资 料===========================================================
程序ourdev_608891EOZM8B.rar(文件大小:37K) (原文件名:PCF8591.rar)


中文手册ourdev_608893O2JHTX.pdf(文件大小:283K) (原文件名:PCF8591中文数据手册.pdf)

http://cache.amobbs.com/bbs_upload782111/files_35/ourdev_608892EH2IUP.jpg
测试。。输出显示4路AD的输入电压占Vref比例 AD位数:8位 (原文件名:4路AD 1路DA.jpg)

arm7tdmi 发表于 2011-4-15 11:57:59

Thank you.I need that.

mcu131368 发表于 2011-4-15 12:59:33

请问这个程序适合PCF8576吗?

qq335702318 发表于 2011-4-18 11:03:48

回复【2楼】mcu131368
-----------------------------------------------------------------------

PCF8576不清楚,未玩过

arm7tdmi 发表于 2011-4-18 11:36:55

请教一下楼主:
PCF8591的AD值读出来是什么值啊?应该如何转换呢?
我在网上找的数值转换代码
(1)
void show_value(unsigned char ad_data)
{
dis = ad_data / 51; //AD值转换为3位BCD码,最大为5.00V。
dis = dis + 0x30; //转换为ACSII码
dis = ad_data % 51; //余数暂存
dis = dis *10; //计算小数第一位
dis = dis / 51;
dis = dis + 0x30; //转换为ACSII码
dis = dis % 51;
dis = dis *10; //计算小数第二位
dis = dis / 51;
dis = dis + 0x30; //转换为ACSII码
}

数据为什么要先/51呢?
我实际试了一下,/51应该是正确的处理(误差0.01V,跟万用表量比较)。
(2)我用的是普中科技的开发板
里面的例子是读出的AD值要乘以2,再进行处理才会接近真实值(误差0.2V,不能接受)
switch(AD_CHANNEL)
   {
   case 0: ISendByte(PCF8591,0x41);
             D=IRcvByte(PCF8591)*2;//ADC0 模数转换1放大2倍显示
                       break;

       case 1: ISendByte(PCF8591,0x42);
             D=IRcvByte(PCF8591)*2;//ADC1模数转换2
                       break;
   }

数据处理部分:
   LedOut=Disp_Tab%10000/1000];
   LedOut=Disp_Tab%1000/100];
   LedOut=Disp_Tab%100/10]|0x80;
   LedOut=Disp_Tab%10];
并且更糟的是ADC0转换应该输入0x40呀,ADC1的转换才是0X41,通道混乱了,不解,头疼。
(3)在网上还找到一个公式:
DAC_PCF8591(0x40,Vol_out);
Vol_ain = ADC_PCF8591(0x40);
Voltage = Visb * Vol_ain * 2;

就是“Voltage = Visb * Vol_ain * 2;”也不知道是不是正确。

恳请楼主帮忙。
从PCF8591里读出的ADC值到底是什么样子?

narutolnq 发表于 2011-4-18 12:12:38

mark

arm7tdmi 发表于 2011-4-18 13:53:01

还有一个帖子
http://www.ourdev.cn/bbs/bbs_content.jsp?bbs_sn=4300389&bbs_page_no=1&search_mode=1&search_text=pcf8591&bbs_id=9999

/********************
将读出的16进制AD转换值转化为ASCII码
************************/
AD_Convert(Uchar Buffer )
{
   
    Uchar Tmp; //最大值为255,对应5V,255/5=51
    Dis=Buffer/51+'0';//整数部分,相当于Buffer/51+0x30
    Tmp=Buffer%51*10;// 第一位小数
    Dis=Tmp/51+'0';//第二位小数
    Tmp=Tmp%51*10;
    Dis=Tmp/51+'0'; //第三位小数

}
数值处理用这个函数就差不多了。
有空再研究:Voltage = Visb * Vol_ain * 2;”
里面的Uchar Tmp 要换成Uint的,否则误差太大。

目前面临的问题是ADC0和ADC1的通道是反着的,同时开了ADC0,ADC1两路。
发送0x40,显示的是通道0的值,发送0x41是通道1的值。
若是只发送0x40或0x41,一路显示的数据还算正确。同时开2路就不行了。

arm7tdmi 发表于 2011-4-18 17:53:25

折腾的要吐了,总算是总结出来了。

http://www.ourdev.cn/bbs/bbs_content.jsp?bbs_sn=4300389&bbs_page_no=1&search_mode=1&search_text=pcf8591&bbs_id=9999
上面帖子里代码写的还算清楚,但是具体怎么样,没有试。
关于通道选择ADC0,ADC1,ADC2,ADC3.
1.若是单通道,则转换指令正确,ADC0对应0x40,ADC1对应0x41,ADC2对应0x42,ADC3对应0x43.
2.若是两个或两个以上用,指令会往后延一个周期。
比如:
若用ADC0和ADC1,则ADC0对应0x41,ADC1对应0x40.
若用ADC0,ADC1和ADC2,则ADC0对应0x41,ADC1对应0x42,ADC2对应0x40.
若用ADC0,ADC1和ADC2,ADC3,则ADC0对应0x41,ADC1对应0x42,ADC2对应0x43,ADC3对应0x40.


在程序调试的时候,有时会注释掉语句,结果值总是变,总也搞不懂为嘛,这芯片太扯蛋了。

s15200380596 发表于 2011-9-8 15:09:23

回复【7楼】arm7tdmi
-----------------------------------------------------------------------

请问楼主知不知道PCF8591的差分输入啊??是不是只要改控制字为0x70就可以了啊我一直没有调出差分输入来不知道是什么原因?多谢楼主赐教

胡大兴 发表于 2012-8-8 15:13:37

谢谢分享……

changqing 发表于 2012-8-25 20:16:37

arm7tdmi 发表于 2011-4-18 17:53 static/image/common/back.gif
折腾的要吐了,总算是总结出来了。

http://www.ourdev.cn/bbs/bbs_content.jsp?bbs_sn=4300389&bbs_page_n ...

嗯,我也看到要读的通道设置比实际的要大一,后来在修改源程序对比现象,并且认真查看芯片的读时序,第一个读的数据时上次停留在ADC寄存器中的数据,新选择的通道则是在读模式时被触发,但仅仅是转化,当第一个字节被读完后,转化后的数据存入ADC寄存器等待下一次读取;想上来确认一下,果然如此哈,呵呵

孤独将一 发表于 2013-3-28 21:52:24

arm7tdmi 发表于 2011-4-18 17:53 static/image/common/back.gif
折腾的要吐了,总算是总结出来了。

http://www.ourdev.cn/bbs/bbs_content.jsp?bbs_sn=4300389&bbs_page_n ...

上面网址变了,给个新的链接

hamipeter 发表于 2013-3-29 10:02:46

顶一下!

司马朝阳 发表于 2013-6-4 21:53:55

谢谢分享         

牛东 发表于 2014-8-21 10:15:55

arm7tdmi 发表于 2011-4-18 17:53
折腾的要吐了,总算是总结出来了。

http://www.ourdev.cn/bbs/bbs_content.jsp?bbs_sn=4300389&bbs_page_n ...

兄弟我也遇到这样的问题,怎么办呢?{:handshake:}

牛东 发表于 2014-8-21 10:45:53

解决了,多采几次样!!!
页: [1]
查看完整版本: PCF8591驱动