搜索
bottom↓
回复: 16
打印 上一主题 下一主题

PCF8591驱动

[复制链接]

出0入0汤圆

跳转到指定楼层
1
发表于 2011-1-3 17:31:40 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
=======================================================H文件===========================================================

#ifndef __8591_h
#define __8591_h

#include "delay.h"

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

#define READ8591  0x01
#define WRITE8591 0x00
#define IIC_8591  0x90


/******* 控制字定义 *******/
/* 模拟信号输出开关 */
  #define anlog_output_off  0        //禁止模拟输出
  #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_on  1  //禁止通道自动增量  
/* 模拟转换通道设置 */
  #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)


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

阿莫论坛20周年了!感谢大家的支持与爱护!!

曾经有一段真挚的爱情摆在我的面前,我没有珍惜,现在想起来,还好我没有珍惜……

出0入0汤圆

2
发表于 2011-4-15 11:57:59 | 只看该作者
Thank you.I need that.

出0入0汤圆

3
发表于 2011-4-15 12:59:33 | 只看该作者
请问这个程序适合PCF8576吗?

出0入0汤圆

4
 楼主| 发表于 2011-4-18 11:03:48 | 只看该作者
回复【2楼】mcu131368
-----------------------------------------------------------------------

PCF8576不清楚,未玩过

出0入0汤圆

5
发表于 2011-4-18 11:36:55 | 只看该作者
请教一下楼主:
PCF8591的AD值读出来是什么值啊?应该如何转换呢?
我在网上找的数值转换代码
(1)
void show_value(unsigned char ad_data)
{
  dis[2] = ad_data / 51; //AD值转换为3位BCD码,最大为5.00V。
  dis[2] = dis[2] + 0x30; //转换为ACSII码
  dis[3] = ad_data % 51; //余数暂存
  dis[3] = dis[3] *10; //计算小数第一位
  dis[1] = dis[3] / 51;
  dis[1] = dis[1] + 0x30; //转换为ACSII码
  dis[3] = dis[3] % 51;
  dis[3] = dis[3] *10; //计算小数第二位
  dis[0] = dis[3] / 51;
  dis[0] = dis[0] + 0x30; //转换为ACSII码
}

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

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

数据处理部分:
     LedOut[0]=Disp_Tab[D[1]%10000/1000];
     LedOut[1]=Disp_Tab[D[1]%1000/100];
     LedOut[2]=Disp_Tab[D[1]%100/10]|0x80;
     LedOut[3]=Disp_Tab[D[1]%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值到底是什么样子?

出0入0汤圆

6
发表于 2011-4-18 12:12:38 | 只看该作者
mark

出0入0汤圆

7
发表于 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[2]=Buffer/51+'0';//整数部分,相当于Buffer/51+0x30
    Tmp=Buffer%51*10;// 第一位小数
    Dis[1]=Tmp/51+'0';//第二位小数
    Tmp=Tmp%51*10;
    Dis[0]=Tmp/51+'0'; //第三位小数

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

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

出0入0汤圆

8
发表于 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.


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

出0入0汤圆

9
发表于 2011-9-8 15:09:23 | 只看该作者
回复【7楼】arm7tdmi
-----------------------------------------------------------------------

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

出0入0汤圆

10
发表于 2012-8-8 15:13:37 | 只看该作者
谢谢分享……

出0入0汤圆

11
发表于 2012-8-25 20:16:37 | 只看该作者
arm7tdmi 发表于 2011-4-18 17:53
折腾的要吐了,总算是总结出来了。

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

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

出0入0汤圆

12
发表于 2013-3-28 21:52:24 | 只看该作者
arm7tdmi 发表于 2011-4-18 17:53
折腾的要吐了,总算是总结出来了。

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

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

出0入0汤圆

13
发表于 2013-3-29 10:02:46 来自手机 | 只看该作者
顶一下!

出0入0汤圆

14
发表于 2013-6-4 21:53:55 | 只看该作者
谢谢分享           

出0入0汤圆

15
发表于 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 ...

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

出0入0汤圆

16
发表于 2014-8-21 10:45:53 | 只看该作者
解决了,多采几次样!!!
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片。注意:要连续压缩2次才能满足要求!!】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-8-26 02:01

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表