【PROTEUS仿真】AT89C51实现PCF8591的AD采样及DA输出

本文详细介绍了使用51单片机实现I2C通信的过程,包括初始化、数据发送与接收等关键函数的实现。同时,通过实例展示了如何利用PCF8591芯片进行ADC模数转换,以及如何将转换结果通过串口输出。

原理图及运行演示

源代码

#include<reg52.h>
#include <stdio.h>
#include<intrins.h>
#define uchar unsigned char
#define uint unsigned int

sbit I2C_SCL=P1^7;                            //I2C时钟引脚
sbit I2C_SDA=P1^6;                            //I2C数据输入输出引脚
sbit KEY=P2^0;

unsigned char ADC_Value;
char DispBuf[30];		//用来存放打印的数据

void delay(unsigned int t)
{
    while(t--);
}

////////////////////////////串口函数及定义区域
void InitUART(void)
{
    TMOD = 0x20;
    SCON = 0x40;
    TH1 = 0xFD;
    TL1 = TH1;
    PCON = 0x00;
    TR1 = 1;
}

void SendOneByte(unsigned char c)
{
    SBUF = c;
    while(!TI);
    TI = 0;
}

void SendStr(unsigned char *p)
{
    while(*p!= '\0')
    {
        SendOneByte(*p);
        p++;
    }
}

////////////////////////IIC 函数定义区域

#define DELAY()	 {_nop_();_nop_();_nop_();}
#define TRUE	1
#define FALSE	0
char I2CErr=0;

/*--------------------------------------------------------------------
函数名称:I2C Stop
--------------------------------------------------------------------*/
void I2C_Stop(void)
{
    I2C_SCL=0;
    I2C_SDA=0;
    DELAY();
    I2C_SCL=1;
    DELAY();
    I2C_SDA=1;
    //EA=1;
}
/*--------------------------------------------------------------------
函数名称:I2C Wait Ack
--------------------------------------------------------------------*/
char  I2C_WaitAck(void)
{
    unsigned char  times=255;			//避免故障,设定错误次数

    I2C_SDA=1;
    I2C_SCL=1;
    while(I2C_SDA)
    {
        times--;
        if(!times)				//超时值为255
        {
            I2C_Stop();
            I2CErr=TRUE;
            return FALSE;
        }
    }
    I2C_SCL=0;
    I2CErr=FALSE;
    return TRUE;
}
/*--------------------------------------------------------------------
函数名称:I2C Start
--------------------------------------------------------------------*/
void I2C_Start(void)
{
    //EA=0;
    I2C_SDA=1;
    I2C_SCL=1;
    DELAY();
    I2C_SDA=0;
    DELAY();
    I2C_SCL=0;
}
/*--------------------------------------------------------------------
函数名称:I2C Send Ack
--------------------------------------------------------------------*/
void I2C_SendAck(void)
{
    I2C_SDA=0;
    DELAY();
    I2C_SCL=1;
    DELAY();
    I2C_SCL=0;
}
/*--------------------------------------------------------------------
函数名称:I2C Send No Ack
--------------------------------------------------------------------*/
void I2C_SendNoAck(void)
{
    I2C_SDA=1;
    DELAY();
    I2C_SCL=1;
    DELAY();
    I2C_SCL=0;
}
/*--------------------------------------------------------------------
函数名称:I2C发送数据
--------------------------------------------------------------------*/
void I2C_SendByte(unsigned char  dat)
{
    unsigned char  i;

    for(i=0; i<=7; i++)
    {
        if((dat&0x80)==0x80)
            I2C_SDA=1;
        else
            I2C_SDA=0;
        dat<<=1;
        I2C_SCL=1;
        DELAY();
        I2C_SCL=0;
    }
    I2C_WaitAck();
}
/*--------------------------------------------------------------------
函数名称:I2C接收数据
--------------------------------------------------------------------*/
void I2C_RcvDat(unsigned char  *pRdDat)
{
    unsigned char  i;

    I2C_SDA=1;
    for(i=0; i<=7; i++)
    {
        I2C_SCL=1;
        DELAY();
        *pRdDat<<=1;
        *pRdDat|=I2C_SDA;
        I2C_SCL=0;
        DELAY();
    }
}
/*--------------------------------------------------------------------
函数名称:I2C接收数据且不产生应答
--------------------------------------------------------------------*/
void I2C_RcvAckDat(unsigned char  *pRdDat)
{
    I2C_RcvDat(pRdDat);
    I2C_SendAck();
}
/*--------------------------------------------------------------------
函数名称:I2C接收数据且产生应答
--------------------------------------------------------------------*/
void I2C_RcvNAckDat(unsigned char  *pRdDat)
{
    I2C_RcvDat(pRdDat);
    I2C_SendNoAck();
}
/*--------------------------------------------------------------------
函数名称:I2C写器件,写一个数据
--------------------------------------------------------------------*/
void I2C_Write(unsigned char  wrDAdr,unsigned char  wordAdr,unsigned char  dat)
{
    I2C_Start();
    I2C_SendByte(wrDAdr);
    I2C_SendByte(wordAdr);
    I2C_SendByte(dat);
    I2C_Stop();
}

/*--------------------------------------------------------------------
函数名称:I2C读器件,读一个数据
--------------------------------------------------------------------*/
void I2C_Read(unsigned char  wrDAdr,unsigned char  wordAdr,
              unsigned char  rdDAdr,unsigned char  *pRdDat)
{
    I2C_Start();
    I2C_SendByte(wrDAdr);
    I2C_SendByte(wordAdr);
    I2C_Start();
    I2C_SendByte(rdDAdr);
    I2C_RcvNAckDat(pRdDat);
    I2C_Stop();
}

/////////////////////////////////////PCF8591定义
#define WR_DADR		0x90	//write device-address
#define RD_DADR		0x91	//read device-address
#define MODE0 	0x00	//Channel0 = AIN0;
//Channel1 = AIN1;
//Channel2 = AIN2;
//Channel3 = AIN3;
#define MODE1 	0x10	//Channel0 = AIN3-AIN0;
//Channel1 = AIN3-AIN1
//Channel2 = AIN3-AIN2;
#define MODE2 	0x20	//Channel0 = AIN0;
//Channel1 = AIN1;
//Channel2 = AIN3-AIN2;
#define MODE3 	0x30	//Channel0 = AIN1-AIN0;
//Channel1 = AIN3-AIN2;

#define CHNL0 	0		//Using Channel0
#define CHNL1 	1		//Using Channel1
#define CHNL2 	2		//Using Channel2
#define CHNL3 	3		//Using Channel3

#define DAouputEn	0x40


void PCF8591_getAD(unsigned char mode,unsigned char chan,unsigned char *pRdDat)
{
    I2C_Read(WR_DADR,mode|chan,RD_DADR,pRdDat);
}

void PCF8591_setDA(unsigned char val)
{
    I2C_Write(WR_DADR,DAouputEn,val);
}

//主程序
void main()
{
    uchar i;
    InitUART();
    if(KEY==1)
    {
        while(1)
        {
            for(i=0; i<255; i++)
                PCF8591_setDA(i);
            for(i=255; i>0; i--)
                PCF8591_setDA(i);
        }
    }
    else
    {
		PCF8591_getAD(MODE0,CHNL0,&ADC_Value);
		sprintf(DispBuf,"ADC:%d Voltage:%d mV\r\n",(unsigned int)ADC_Value,(unsigned int)196*ADC_Value/10);
		SendStr(DispBuf);
        delay(40000);
    }
}


评论 7
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值