#include "STC89.h"
	#include "intrins.h"
	#include "process.h"
	#define CycleTime_Ultrasonic 10
	 
	#define TR_Ultrasonic TR0
	#define TH_Ultrasonic TH0
	#define TL_Ultrasonic TL0
	#define ET_Ultrasonic ET0
	#define TMOD_Ultrasonic TMOD
	 
	sbit FrontTrig=P2^2;
	sbit FrontEcho=P3^2;//accord to the selected timer, timer 0-->P32  timer 1--->P33
	 
	void InitDistance(void);
	float GetDistance(void);
	 
	void StartCheckDistance(void);
	#define AddWr 0x90   //写数据地址 PCF8591 bit321为地址A0 A1 A2
	#define AddRd 0x91   //读数据地址 PCF8591
	 
	sbit SDA_PCF8591=P2^6;
	sbit SCL_PCF8591=P2^7;
	 
	unsigned char ReadADC(unsigned char Chl);
	 
	unsigned char SysTime;
	unsigned char SoundAdc;
	unsigned int LedShowData;
	unsigned char NumToShow=6;
	unsigned int DistanceData;
	 
	sbit Key0=P0^4;
	unsigned char OldKey0,DisMode=0;
	 
	 
	void InitTimer2(void)
	{
	    T2MOD = 0;
	T2CON = 0;
	RCAP2H = 0xFC;
	    RCAP2L = 0x17;
	 	EA=1;             				//总中断打开
	 	ET2=1;            				//定时器T2允许中断
	 	TR2=1;            				//定时器T2开始工作
	}
	 
	void et2(void) interrupt 5 using 0
	{
	    TF2=0;
	SysTime++;
	}
	 
	bit ack;	              //应答标志位
	 
	/*------------------------------------------------
	                    启动总线
	------------------------------------------------*/
	void Start_I2c()
	{
	  SDA_PCF8591=1;   //发送起始条件的数据信号
	  _nop_();
	  SCL_PCF8591=1;
	  _nop_();    //起始条件建立时间大于4.7us,延时
	  _nop_();
	  _nop_();
	  _nop_();
	  _nop_();    
	  SDA_PCF8591=0;     //发送起始信号
	  _nop_();    //起始条件锁定时间大于4μ
	  _nop_();
	  _nop_();
	  _nop_();
	  _nop_();       
	  SCL_PCF8591=0;    //钳住I2C总线,准备发送或接收数据
	  _nop_();
	  _nop_();
	}
	/*------------------------------------------------
	                    结束总线
	------------------------------------------------*/
	void Stop_I2c()
	{
	  SDA_PCF8591=0;    //发送结束条件的数据信号
	  _nop_();   //发送结束条件的时钟信号
	  SCL_PCF8591=1;    //结束条件建立时间大于4μ
	  _nop_();
	  _nop_();
	  _nop_();
	  _nop_();
	  _nop_();
	  SDA_PCF8591=1;    //发送I2C总线结束信号
	  _nop_();
	  _nop_();
	  _nop_();
	  _nop_();
	}
	 
	 
	 
	 
	/*----------------------------------------------------------------
	                 字节数据传送函数               
	函数原型: void  SendByte(unsigned char c);
	功能:  将数据c发送出去,可以是地址,也可以是数据,发完后等待应答,并对
	     此状态位进行操作.(不应答或非应答都使ack=0 假)     
	     发送数据正常,ack=1; ack=0表示被控器无应答或损坏。
	------------------------------------------------------------------*/
	void  SendByte(unsigned char c)
	{
	 unsigned char BitCnt;
	 
	 for(BitCnt=0;BitCnt<8;BitCnt++)  //要传送的数据长度为8位
	    {
	     if((c<<BitCnt)&0x80)SDA_PCF8591=1;   //判断发送位
	       else  SDA_PCF8591=0;                
	     _nop_();
	     SCL_PCF8591=1;               //置时钟线为高,通知被控器开始接收数据位
	      _nop_();
	      _nop_();             //保证时钟高电平周期大于4μ
	      _nop_();
	      _nop_();
	      _nop_();         
	     SCL_PCF8591=0;
	    }
	    
	    _nop_();
	    _nop_();
	    SDA_PCF8591=1;               //8位发送完后释放数据线,准备接收应答位
	    _nop_();
	    _nop_();   
	    SCL_PCF8591=1;
	    _nop_();
	    _nop_();
	    _nop_();
	    if(SDA_PCF8591==1)ack=0;     
	       else ack=1;        //判断是否接收到应答信号
	    SCL_PCF8591=0;
	    _nop_();
	    _nop_();
	}
	 
	 
	/*----------------------------------------------------------------
	                 字节数据传送函数               
	函数原型: unsigned char  RcvByte();
	功能:  用来接收从器件传来的数据,并判断总线错误(不发应答信号),
	     发完后请用应答函数。  
	------------------------------------------------------------------*/
	unsigned char  RcvByte()
	{
	  unsigned char retc;
	  unsigned char BitCnt;
	  
	  retc=0;
	  SDA_PCF8591=1;             //置数据线为输入方式
	  for(BitCnt=0;BitCnt<8;BitCnt++)
	      {
	        _nop_();           
	        SCL_PCF8591=0;       //置时钟线为低,准备接收数据位
	        _nop_();
	        _nop_();      //时钟低电平周期大于4.7us
	        _nop_();
	        _nop_();
	        _nop_();
	        SCL_PCF8591=1;       //置时钟线为高使数据线上数据有效
	        _nop_();
	        _nop_();
	        retc=retc<<1;
	        if(SDA_PCF8591==1)retc=retc+1; //读数据位,接收的数据位放入retc中
	        _nop_();
	        _nop_();
	      }
	  SCL_PCF8591=0;    
	  _nop_();
	  _nop_();
	  return(retc);
	}
	 
	 
	/*----------------------------------------------------------------
	                     非应答子函数
	原型:  void NoAck_I2c(void);
	 
	----------------------------------------------------------------*/
	void NoAck_I2c(void)
	{
	  
	  SDA_PCF8591=1;
	  _nop_();
	  _nop_();
	  _nop_();      
	  SCL_PCF8591=1;
	  _nop_();
	  _nop_();              //时钟低电平周期大于4μ
	  _nop_();
	  _nop_();
	  _nop_();  
	  SCL_PCF8591=0;                //清时钟线,钳住I2C总线以便继续接收
	  _nop_();
	  _nop_();    
	}
	 
	/*------------------------------------------------
	             读AD转值程序
	输入参数 Chl 表示需要转换的通道,范围从0-3
	返回值范围0-255
	------------------------------------------------*/
	unsigned char ReadADC(unsigned char Chl)
	 {
	   unsigned char Val;
	   Start_I2c();               //启动总线
	   SendByte(AddWr);             //发送器件地址
	     if(ack==0)return(0);
	   SendByte(0x00|Chl);            //发送器件子地址
	     if(ack==0)return(0);
	   Start_I2c();
	   SendByte(AddRd);
	      if(ack==0)return(0);
	   Val=RcvByte();
	   NoAck_I2c();                 //发送非应位
	   Stop_I2c();                  //结束总线
	   Start_I2c();
	   SendByte(AddRd);
	      if(ack==0)return(0);
	   Val=RcvByte();
	   NoAck_I2c();                 //发送非应位
	   Stop_I2c();                  //结束总线
	  return(Val);
	 }
	 void InitDistance(void)		 //使用EX0口
	{
	    TMOD_Ultrasonic |= 0x09;//打开GATE0 内部时钟计数模式
	    ET_Ultrasonic=0;
	    FrontTrig = 0;
	}
	 
	void Delay(void)
	{
	unsigned i=10;
	while(i--)
	_nop_( );
	}
	 
	void StartCheckDistance(void)
	{
	    FrontTrig = 1;
	TH_Ultrasonic = 0;
	    TL_Ultrasonic = 0;
	    Delay();
	TR_Ultrasonic=1;
	FrontTrig = 0;
	}
	 
	 
	 
	float GetDistance(void)//always return value ,unit:mm
	{
	static unsigned char DisTestStep,DisDelayTime;
	unsigned int FrontTime;
	static float DistanceData=0;
	 
	switch(DisTestStep)
	{
	case 0:
	{
	StartCheckDistance();
	DisTestStep = 1;
	break;
	}
	case 1:
	{
	DisDelayTime++;
	if(DisDelayTime >= 30/CycleTime_Ultrasonic)
	{
	DisDelayTime = 0;
	DisTestStep = 2;
	}
	break;
	}
	case 2:
	{
	 
	TR0 = 0;
	FrontTime = TH_Ultrasonic;
	FrontTime = FrontTime<<8;
	FrontTime = FrontTime+TL_Ultrasonic;
	DistanceData = FrontTime;
	DistanceData = DistanceData*0.17;
	DisTestStep = 3;
	 
	break;
	}
	case 3:
	{
	DisDelayTime++;
	if(DisDelayTime >= 300/CycleTime_Ultrasonic)
	{
	DisDelayTime = 0;
	DisTestStep = 0;
	}
	break;
	}
	}
	return DistanceData;
	}
	 
	 
	 
	 
	main()
	{
	InitTimer2();
	//InitSci();
	InitDistance();
	for(;;)
	{
	StartPro(0);
	SoundAdc = ReadADC(3);
	DistanceData = GetDistance();
	 
	if((OldKey0==0)&&(Key0==1))
	{
	DisMode = ~DisMode;
	}
	OldKey0 = Key0;
	 
	if(DisMode == 0)
	{
	P25 = 0;
	if(DistanceData < 200)
	{
	NumToShow = 0;
	}
	else if(DistanceData > 800)
	{
	NumToShow = 12;
	}
	else
	{
	NumToShow = (DistanceData-200)/50;
	}
	}
	else
	{
	P25 = 1;
	if(SoundAdc < 62)
	{
	NumToShow = 0;
	}
	else if(SoundAdc > 110)
	{
	NumToShow = 12;
	}
	else
	{
	NumToShow = (SoundAdc-62)>>2;
	}
	}
	LedShowData = (0x0FFF>>NumToShow);
	P36 = LedShowData>>11;
	P35 = LedShowData>>10;
	P34 = LedShowData>>9;
	P33 = LedShowData>>8;
	P10 = LedShowData>>7;
	P11 = LedShowData>>6;
	P12 = LedShowData>>5;
	P13 = LedShowData>>4;
	P14 = LedShowData>>3;
	P15 = LedShowData>>2;
	P16 = LedShowData>>1;
	P17 = LedShowData;
	
	 
	EndPro(10);
	}
	}