AD转换显示电压值和DA转换实现呼吸灯

这个实验的内容是:通过PCF8591芯片读取滑动变阻器的电压值,然后转换成数字信号在数码管上显示。通过对PCF8591芯片进行写入数字信号,然后转换成模拟信号(即电压值),来控制LED灯呼吸(由暗慢慢变亮,再由亮慢慢变暗,循环往复),并在Proteus上仿真。

Proteus图:

AD转换显示电压值和DA转换实现呼吸灯_第1张图片

I2C总线基本的时序信号图:

AD转换显示电压值和DA转换实现呼吸灯_第2张图片

具体实现方式请看下面的程序:

#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 
	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 
	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 	
	void timer0_init();	
	
#endif

你可能感兴趣的:(单片机)