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) Thank you.I need that. 请问这个程序适合PCF8576吗? 回复【2楼】mcu131368
-----------------------------------------------------------------------
PCF8576不清楚,未玩过 请教一下楼主:
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值到底是什么样子? mark 还有一个帖子
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路就不行了。 折腾的要吐了,总算是总结出来了。
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.
在程序调试的时候,有时会注释掉语句,结果值总是变,总也搞不懂为嘛,这芯片太扯蛋了。 回复【7楼】arm7tdmi
-----------------------------------------------------------------------
请问楼主知不知道PCF8591的差分输入啊??是不是只要改控制字为0x70就可以了啊我一直没有调出差分输入来不知道是什么原因?多谢楼主赐教 谢谢分享…… 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寄存器等待下一次读取;想上来确认一下,果然如此哈,呵呵 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 ...
上面网址变了,给个新的链接 顶一下! 谢谢分享 arm7tdmi 发表于 2011-4-18 17:53
折腾的要吐了,总算是总结出来了。
http://www.ourdev.cn/bbs/bbs_content.jsp?bbs_sn=4300389&bbs_page_n ...
兄弟我也遇到这样的问题,怎么办呢?{:handshake:} 解决了,多采几次样!!!
页:
[1]