AD轉換顯示電壓值和DA轉換實現呼吸燈

這個實驗的內容是:通過PCF8591芯片讀取滑動變阻器的電壓值,然後轉換成數字信號在數碼管上顯示。通過對PCF8591芯片進行寫入數字信號,然後轉換成模擬信號(即電壓值),來控制LED燈呼吸(由暗慢慢變亮,再由亮慢慢變暗,循環往復),並在Proteus上仿真。

Proteus圖:

在這裏插入圖片描述

I2C總線基本的時序信號圖:

在這裏插入圖片描述

具體實現方式請看下面的程序:

#include"dac.h"
#include"i2c.h"
#include"timer0.h"

unsigned char dat=0;

void main(){
	timer0_init();  //定時器0初始化
	while(1){		
		dat=PCF8591_Read();  //AD轉換,並通過數碼管顯示電壓值,後面的多次使用的原因是:當電壓變化時能及時地刷新
		PCF8591_Write(255);  //DA轉換,用來實現呼吸燈,寫入的值最大隻能是255
		delay(10000);  
		dat=PCF8591_Read();
		PCF8591_Write(200);
		delay(10000);
		dat=PCF8591_Read();
	  PCF8591_Write(150);
		delay(10000);
		dat=PCF8591_Read();
		PCF8591_Write(100);
		delay(10000);
		dat=PCF8591_Read();
		PCF8591_Write(50);
		delay(10000);
		dat=PCF8591_Read();
		PCF8591_Write(0);
		delay(10000);
		dat=PCF8591_Read();
		PCF8591_Write(50);
		delay(10000);
		dat=PCF8591_Read();
		PCF8591_Write(100);
		delay(10000);
		PCF8591_Write(150);
		delay(10000);
		dat=PCF8591_Read();
		PCF8591_Write(200);
		delay(10000);
		dat=PCF8591_Read();
		PCF8591_Write(255);
		delay(10000);
	}
}

void timer0() interrupt 1{	//定時器中斷函數
	TH0=0xdc;//定時器延時10ms
	TL0=0x00;
	display(dat);  //在數碼管上顯示電壓值
}

#include"i2c.h"								

void delay5us(void)   //5us延時函數
{
    unsigned char a;
    for(a=1;a>0;a--);
}

void I2cStart()  //I2C總線的啓動函數
{
	SDA=1;
	SCL=1;
	delay5us();//建立時間是SDA保持時間>4.7us
	SDA=0;
	delay5us();//保持時間是>4us
	SCL=0;			
	delay5us();		
}
void I2cStop()  //I2C總線的停止函數
{
	SDA=0;
	SCL=1;
	delay5us();//建立時間大於4.7us
	SDA=1;
	delay5us();			
}

unsigned char I2cReadByte()  //I2C總線讀取字節函數
{
  unsigned char a=0,dat=0;
	SDA=1;			//起始和發送一個字節之後SCL都是0
	delay5us();
	for(a=0;a<8;a++)//接收8個字節
	{
		SCL=1;  //保持數據穩定
		delay5us();
		dat<<=1;  
		dat|=SDA;  //讀取SDA的一位數據
		delay5us();
		SCL=0;  //數據改變
		delay5us();
	}
	return dat;	
}
unsigned char I2cSendByte(unsigned char dat)  //I2C總線發送字節函數
{
	unsigned char a=0,b=0;//最大255,一個機器週期爲1us,最大延時255us。		
	for(a=0;a<8;a++)//要發送8位,從最高位開始
	{
		SDA=dat>>7;	 //起始信號之後SCL=0,所以可以直接改變SDA信號
		dat=dat<<1;
		delay5us();
		SCL=1;
		delay5us();//建立時間>4.7us
		SCL=0;
		delay5us();//時間大於4us		
	}
	//時I2C空閒
	SDA=1;
	delay5us();
	SCL=1;
	while(SDA)//等待應答,也就是等待從設備把SDA拉低
	{
		b++;
		if(b>200)	 //如果超過2000us沒有應答發送失敗,或者爲非應答,表示接收結束
		{
			SCL=0;
			delay5us();
			return 0;
		}
	}
	SCL=0;
	delay5us();
 	return 1;		
}
unsigned char PCF8591_Read(void)  //AD轉換
{
	unsigned char num;
	I2cStart();
	I2cSendByte(0x90); //發送寫器件地址,並聲明寫操作
	
	I2cSendByte(0x00); //發送控制字節,採用通道0
	
	I2cStart();
	I2cSendByte(0x91); //發送讀器件地址,並聲明讀操作
	
	num=I2cReadByte(); //讀取數據

	
	I2cStop();
	return num;	
}
unsigned char PCF8591_Write(unsigned char val)  //DA轉換
{
	I2cStart();
	I2cSendByte(0x90);  //發送寫器件地址,並聲明寫操作
    
	I2cSendByte(0x40);  //發送控制字節,打開自動寫控制位
    
    I2cSendByte(val);
    
    I2cStop();
	
	return 1;
}

#ifndef __I2C_H__
#define __I2C_H__

	#include <reg52.h>
	unsigned char PCF8591_Write(unsigned char val);
	unsigned char PCF8591_Read(void);
	
	sbit SDA = P2^0;
	sbit SCL = P2^1;
	 

#endif
#include"dac.h"


unsigned char code smgduan[10]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90};
unsigned char i;
unsigned char voltage[2];

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

void display(unsigned char dat){    	
	    /*數據的量化*/
	float temp = FACTOR * dat;
	if(dat == 255){
		voltage[1]= 5;
		voltage[0] = 0;
	}
	else{ // 分離整數和小數部分
		voltage[1]= (unsigned char)temp;
		voltage[0] = (unsigned char)((temp - voltage[1]) * 10);
	}	
	for(i=0;i<2;i++)
	{
		switch(i){           //位選,選擇點亮的數碼管,            
      case(0): 
        LSA=0;LSB=0;LSC=1;LSD=0; break;//顯示第 1 位 
      case(1): 
        LSA=0;LSB=1;LSC=0;LSD=0; break;//顯示第 2 位           
		}
		if(i==1)
			P0=smgduan[voltage[i]]&0x7f;
		else 
			P0=smgduan[voltage[i]];//發送數據		    
	  delay(100); //間隔一段時間掃描			 
		P0=0xFF;//消隱
  }	  
}
#ifndef __DAC_H__
#define __DAC_H__

	#define FACTOR 0.01953125 // 量化單位(用一個字節來量化表示5V的電壓值,共爲256個量化等級; FACTOR = 5 / 256)
	#include <reg52.h>
	void display(unsigned char dat);
	void delay(unsigned int i);
	sbit LSA=P1^3; 
	sbit LSB=P1^2; 
	sbit LSC=P1^1; 
	sbit LSD=P1^0;

#endif
#include"timer0.h"

void timer0_init(){
	EA=1;
	ET0=1;
	TR0=1;
	TMOD=0x01;//定時器工作模式爲1
	TH0=0xdc;//定時器延時10ms
	TL0=0x00;
}

#ifndef __TIMER0_H__
#define __TIMER0_H__

	#include <reg52.h>	
	void timer0_init();	
	
#endif
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章