专注电子技术学习与研究
当前位置:单片机教程网 >> MCU设计实例 >> 浏览文章

PCF8591(AD-DA)芯片-51单片机程序

作者:佚名   来源:本站原创   点击数:  更新时间:2013年10月29日   【字体:
注:
     PCF8591  是8位AD-DA芯片   转换数据0---5  对应 0--255
    通信协议IIC
    模拟量输出值和电压的关系:   输出电压=(参考电压-基点电位)/255
 
//以下是源码如果在网页上显示格式错乱可以从这里下载: http://www.51hei.com/f/8591c.rar
//12MHZ晶振
#include <reg51.h>
#include <intrins.h>
#define uchar unsigned char
#define uint unsigned int
#include "IIC.h"  //i2c库函数
code uchar seg[]={0x28,0x7e,0xa2,0x62,0x74,0x61,0x21,0x7a,0x20,0x60};    //数码管码表
code uchar tab[]={0x7f,0xbf,0xdf,0xef,0xf7,0xfb,0xfd,0xfe};      //数码管位选
sbit bz=P3^3;   //喇叭位
uchar outdata; //模拟量输出值
sbit k1=P1^2 ;   //模拟量输出者增加
sbit k2=P1^1;   //模拟量输出者减少 
void delay(uint k)    //延时子函数
{
while(k--);
}
  
void key1()    //模拟输出值增加
{
if(k1==0)
{
delay(1000);
if(k1==0)
outdata++;
}
 }
void key2()     //模拟输出值减少
{
if(k2==0)
{
delay(1000);
if(k2==0)
outdata--;
}
 }

void ADCinshow(uchar dd)   //模拟量输入值显示
{
   P0=seg[dd/100];
   P2=tab[7];
   delay(8);
   P0=0xff;                             //显示消影
   P2=0xff;
   P0=seg[dd%100/10];
   P2=tab[6];
   delay(8);
   P0=0xff;
   P2=0xff;
   P0=seg[dd%10];
   P2=tab[5];
   delay(8);
   P0=0xff;
   P2=0xff;
}
 
void ADCoutshow(uchar k)    //模拟量输出值显示
{
 P0=seg[k/100];
 P2=tab[2];
 delay(8);
 P0=0xff;
 P2=0xff;
 P0=seg[k%100/10];
 P2=tab[1];
 delay(8);
 P0=0xff;
 P2=0xff;
 P0=seg[k%10];
 P2=tab[0];
 delay(8);
 P0=0xff;
 P2=0xff;
 }
//------------------主函数----------------
void main()
{
   uchar val;      //模拟量读取值变量 
   uint cnt=0;             //设置喇叭报警延时变量  
   while(1)
   {   key1();
       key2();
      val=readADC(3);   //读取通道3的转换值
   ADCinshow(val);
     if(writeDAC(outdata)!=0);    //模拟量输出值
   ADCoutshow(outdata);
      if(val>200)      //模拟量输入值超过200  喇叭报警
   {
  cnt++;
  if(cnt>2)
  {
  bz=~bz;
   cnt=0;
  }
    }
    else
    bz=1;
   }
}
 
//IIC库函数---------------------------------------------------------------

sbit scl=P3^0;    //IIC 时钟线
sbit sda=P3^1;    //IIC 数据线
uchar ack;     //应答位

void delay_nop()  //延时约5us
{
 _nop_(); _nop_(); _nop_(); _nop_(); _nop_();
}
void iic_start()   //启动IIC总线
{
   sda=1;
   _nop_();
   scl=1;    //时钟线高电平期间,数据线下降沿产生启动信号
   delay_nop();    //5us延时
   sda=0;
  delay_nop(); 
   scl=0;      //释放总线开始准备接受/发送数据
    _nop_();
  _nop_();
}
void iic_stop()     //停止IIC总线
{
   sda=0;
   _nop_();     //时钟线高电平期间,数据线上升沿产生停止信号
   scl=1;
    delay_nop(); 
   sda=1;
   delay_nop(); 
}
void iic_sendbyte(uchar byte)    //IIC发送一个字节命令
{
  uchar i;
  for(i=0;i<8;i++)
  {
 if((byte<<i)&0x80)sda=1;    //把发送字节最高位放入数据线
 else sda=0;      //发送字节中数据左移一位
 _nop_();      
 scl=1;          //时钟线至高位 ,数据保持稳定
  delay_nop(); 
 scl=0;          //释放开始下一个数据发送
  }
  sda=1;           //发送完,释放数据线开始接受应答
  _nop_();
  _nop_();
  scl=1;         //时钟线至高位
  _nop_();
  _nop_();
  _nop_();
  if(sda==1)ack=0;         //应答判断
  else ack=1;
  scl=0;
  _nop_();
  _nop_();
 }
 
uchar iic_receive()  //IIC接受一个字节
{
   uchar i;
   uchar byte=0;
   sda=1;                        //数据线释放开始接受
   for(i=0;i<8;i++)
   {
   scl=0;        //时钟线置低开始接受数据
   delay_nop(); 
   scl=1;          //时钟线置高,接受数据
    _nop_(); _nop_();
    byte=byte<<1;       
   if(sda==1)byte=byte+1;     //数据左移1位      
   _nop_();
   _nop_();
 }
 scl=0;        //接受完释放总线
 _nop_();
 _nop_();
 return byte;       //返回接受值
}
void iic_noack()  //非应答
{
 sda=1;
 _nop_();
 _nop_();
  _nop_();
 scl=1;
  delay_nop(); 
 scl=0;
 _nop_();
 _nop_();
}
uchar readADC(uchar chl)    //ADC转换子函数 选择通道chl
{
 uchar value;
 iic_start();
 iic_sendbyte(0x90);    //发送写方向
 if(ack==0)return 0;
 iic_sendbyte(0x40|chl);    //控制命令
 if(ack==0)return 0;
 iic_start();
 iic_sendbyte(0x91);     //发送读方向
 if(ack==0)return 0;
 value=iic_receive();     //接受转换数据
 iic_noack();
 iic_stop();
 return value;         //返回转换值
 }

uchar writeDAC(uchar da)    //模拟量输出值函数
{
  iic_start();
  iic_sendbyte(0x90);
  if(ack==0)return 0;
  iic_sendbyte(0x40);
  if(ack==0)return 0;
  iic_sendbyte(da);
  if(ack==0)return 0;
  iic_stop();
  return 1;         //正常输出返回值1  异常返回值0
}
 
//--------------------------------------------------------------------

 
关闭窗口

相关文章