“MPX4115型壓力傳感器+PCF8591型AD+模擬IIC總線”的Proteus仿真

一、MPX4115型壓力傳感器介紹

1.1 引腳說明

即:1引腳爲模擬量輸出,2引腳接地,三引腳接電源,4、5、6引腳空

 

1.2 輸出特性圖

選擇典型曲線,我們可以得知轉換公式:壓力值=(電壓值/5.1+0.095)/0.009。

 

二、模擬IIC總線

因爲本例子採用的爲51單片機,因此需要自己模擬IIC總線協議。

2.1 IIC總線工作時序如下

 

2.2 根據上圖所示IIC總線工作協議進行IIC工作模擬

2.2.1 IIC總線啓動

void I2c_start()
{
	sda=1;
	scl=1;
	Delay1(DELAY_TIME);
	sda=0;
	Delay1(DELAY_TIME);
	scl=0;
}

2.2.2 IIC發送一個字節

void I2c_sendbyte(uchar byt)
{
	uchar i;
    for(i=0;i<8;i++)
	{
        scl=0;
        Delay1(DELAY_TIME);
        if(byt&0x80)
		{
            sda=1;
        }
        else
		{
            sda=0;
        }
        Delay1(DELAY_TIME);
        scl=1;
        byt <<= 1;
       Delay1(DELAY_TIME);
    }
    scl=0;
}

2.2.3 IIC等待響應

uchar I2c_waitack()
{
	uchar ackbit;
	sda=1;//釋放數據線
	Delay1(DELAY_TIME);
	scl=1;
	Delay1(DELAY_TIME);
	ackbit=sda;//獲取響應信號,低電平爲有效
	scl=0;
	Delay1(DELAY_TIME);
	return sda;
}

2.2.4 IIC接收一個字節

uchar I2c_receivebyte()
{
	uchar da;
	uchar i;
	for(i=0;i<8;i++)
	{
		scl=1;
		Delay1(DELAY_TIME);
		da<<=1;
		if(sda)
		{
			da|=0x01;
		}
		scl=0;
		Delay1(DELAY_TIME);
	}
	return da;
}

2.2.5 IIC發送響應

void I2c_sendack(uchar ackbit)
{
	
    scl=0;
    sda=ackbit;  //0:發送應答信號;1:發送非應答信號
    Delay1(DELAY_TIME);
    scl=1;
    Delay1(DELAY_TIME);
    scl=0;
    sda=1;
    Delay1(DELAY_TIME);
}

2.2.6 IIC總線結束

void I2c_stop()
{
    sda=0;
    scl=1;
    Delay1(DELAY_TIME);
    sda=1;
    Delay1(DELAY_TIME);
}

 

三、PCF8591型AD介紹

3.1 介紹

PCF8591 是單電源,低功耗8 位CMOS 數據採集器件,具有4 個模擬輸入、一個輸出和一個串行I2C 總線接口。3 個地址引腳A0、A1 和A2 用於編程硬件地址,允許將最多8 個器件連接至I2C總線而不需要額外硬件。PCF8591由於其使用的簡單方便和集成度高,在單片機應用系統中得到了廣泛的應用。

 

3.2 引腳說明

 

3.3 器件地址說明

每一個IIC器件都有一個器件地址,來區分不同的IIC設備,下面是PCF8591的地址格式

在本例子中,我將A0、A1、A2全部接地,因此寫地址爲0x90,讀地址爲0x91。

 

3.4 控制字說明

在該例子中我們進行的是AD轉換,因此第6位爲0,不允許模擬電壓輸出;採用單端輸入,因此第5、4位爲0、0;該例子中只進行一個模擬輸入量的AD轉換,因此關閉自動增量使能,即第2位爲0;模擬輸入通道選擇AIN3,因此第1位與第0位爲1、1。因此,控制字爲0x30。

 

3.5 輸出特性曲線

在該例子中,我們讓Vagnd=0V,Vref=5V。因此可得轉換公式爲:電壓值=(5.0/256.0)*AD模塊的讀數。

 

四、Proteus仿真電路

五、完整例程(例程均爲自己編寫且在仿真中測試通過)

使用單片機爲AT89C52,工作頻率爲12MHz

#include<reg52.h>
#include<intrins.h>

typedef unsigned char uchar;
typedef unsigned int  uint;

#define DELAY_TIME 5

sbit scl = P2^0;//時鐘總線接口
sbit sda = P2^1;//數據總線接口 
sbit w2=P2^2;//位選2 
sbit w3=P2^3;//位選3 
sbit w4=P2^4;//位選4 

void I2c_start(void);//IIC總線啓動條件
void I2c_stop(void);//IIC總線結束條件
void I2c_sendbyte(uchar byt);//IIC總線發送一個字節
uchar I2c_receivebyte(void);//IIC總線接收一個字節
void I2c_sendack(uchar ackbit);//IIC總線發送應答
void Delay1(uchar t);//讀寫操作中的延時
void Delay2(uchar t);//等待初始化子函數
void Init_pcf8591(void);//PCF8951初始化
uchar I2c_waitack(void);//IIC等待迴應子函數
uchar Read_value(void);//讀取AD值
void Show(uchar Out);//顯示壓力值

void main()
{
	uchar G_value;//AD值
	float V_value,P_value;//電壓值,壓力值
	uchar Out;//對壓力值進行四捨五入後的輸出值 
	Read_value();
	G_value=Read_value();
	V_value=(5.0/256.0)*G_value;
	P_value=(V_value/5.1+0.095)/0.009;
	Out=P_value;//進行四捨五入
	if(P_value-Out>=0.5)
	{
		Out+=1;
	}
	Show(Out);
}
/****************************讀取AD值******************************************/
uchar Read_value(void)
{
	uchar result;
	Init_pcf8591();
	I2c_start();
	I2c_sendbyte(0x91);//進行讀操作(A0、A1、A2均接地)
	I2c_waitack();
	result=I2c_receivebyte();
	I2c_sendack(1);
	I2c_stop();	
	return result;
}
/**********************PCF8591初始化函數*************************************/
void Init_pcf8591(void)
{
	I2c_start();
	I2c_sendbyte(0x90);//進行寫操作(A0、A1、A2均接地)
	I2c_waitack();
	I2c_sendbyte(0x03); //選擇通道AIN3進行轉化
	I2c_waitack();
	I2c_stop();
	Delay2(10);
}
/**********************IIC總線啓動*************************************/
void I2c_start()
{
	sda=1;
	scl=1;
	Delay1(DELAY_TIME);
	sda=0;
	Delay1(DELAY_TIME);
	scl=0;
}
/********************IIC發送一個字節***********************************/
void I2c_sendbyte(uchar byt)
{
	uchar i;
    for(i=0;i<8;i++)
	{
        scl=0;
        Delay1(DELAY_TIME);
        if(byt&0x80)
		{
            sda=1;
        }
        else
		{
            sda=0;
        }
        Delay1(DELAY_TIME);
        scl=1;
        byt <<= 1;
       Delay1(DELAY_TIME);
    }
    scl=0;
}
/********************IIC等待迴應***********************************/
uchar I2c_waitack()
{
	uchar ackbit;
	sda=1;//釋放數據線
	Delay1(DELAY_TIME);
	scl=1;
	Delay1(DELAY_TIME);
	ackbit=sda;//獲取響應信號,低電平爲有效
	scl=0;
	Delay1(DELAY_TIME);
	return sda;
}
/********************IIC接收一個字節******************************/
uchar I2c_receivebyte()
{
	uchar da;
	uchar i;
	for(i=0;i<8;i++)
	{
		scl=1;
		Delay1(DELAY_TIME);
		da<<=1;
		if(sda)
		{
			da|=0x01;
		}
		scl=0;
		Delay1(DELAY_TIME);
	}
	return da;
}
/********************IIC發送迴應***********************************/
void I2c_sendack(uchar ackbit)
{
	
    scl=0;
    sda=ackbit;  //0:發送應答信號;1:發送非應答信號
    Delay1(DELAY_TIME);
    scl=1;
    Delay1(DELAY_TIME);
    scl=0;
    sda=1;
    Delay1(DELAY_TIME);
}
/**********************IIC總線結束*************************************/
void I2c_stop()
{
    sda=0;
    scl=1;
    Delay1(DELAY_TIME);
    sda=1;
    Delay1(DELAY_TIME);
}
/**********************IIC中延時函數*************************************/
void Delay1(uchar t)
{
	do
    {
        _nop_();
    }
    while(t--);
}
/**************************等待初始化延時***************************************/
void Delay2(uchar t)
{
	unsigned char i;

	while(t--)
	{
		for(i=0; i<112; i++);
	}
}

/**********************顯示函數*************************************/
void Show(uchar Out)
{
	char code duan[10]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90};//段碼
	while(1)
	{
		w4=0;//顯示第百位
		w3=0;
		w2=1;
		Delay2(5);
		P1=duan[(Out/100)%10];
		Delay2(15);
		P1=0xff;
		w4=0;//顯示第十位
		w3=1;
		w2=0;
		Delay2(5);
		P1=duan[(Out/10)%10];
		Delay2(15);
		P1=0xff;
		w4=1;//顯示第個位
		w3=0;
		w2=0;
		Delay2(5);
		P1=duan[Out%10];
		Delay2(15);
		P1=0xff;
		

	}
}

 

 

左肩理想,右肩擔當。君子不怨永遠不會停下腳步!

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章