这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » 高校专区 » 毕业设计专区 » 【用声音传感器和超声波传感器控制LED】程序看不懂,请大神指教

共6条 1/1 1 跳转至

【用声音传感器和超声波传感器控制LED】程序看不懂,请大神指教

菜鸟
2017-04-29 14:40:07     打赏

#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);
	}
}

 



菜鸟
2017-04-29 14:42:08     打赏
2楼
电路图

菜鸟
2017-04-29 14:43:14     打赏
3楼
具有2种工作模式:(1)LED光柱的高度能随着用户音量的大小的改变而相应地改变,即音量越大、光柱越高,反之同理;(2)LED光柱的高度能随着用户手掌与传感器之间距离大小的改变而相应地改变,即距离越大、光柱越高,反之同理。

专家
2017-04-30 08:40:01     打赏
4楼
谢谢楼主分析。

专家
2017-04-30 13:17:33     打赏
5楼
我也不会

专家
2017-05-01 22:46:05     打赏
6楼

百度了一些资料:

超声波测量的基本原理是:
由超声探头发出的超声脉冲信号,
在气体中传播,遇到被测界面后被反射,
接收到回波信号后计算其超声波往返的传播时间,
即可换算出距离。

例如:超声波传感器的工作频率为40kHz。
由发射传感器发出超声波脉冲,
传到被测面经反射后返回接收传感器,
测出超声波脉冲从发射到接收到所需的时间,
根据媒质中的声速,就能得到从传感器到被测面之间的距离,
考虑到环境温度对超声波传播速度的影响,
通过温度补偿的方法对传播速度予以校正,
以提高测量精度。计算公式为:
V=331.5+0.607T 
式中:V为超声波在空气中传播速度;T为环境温度。

S=V ×t/2=V×(t1-t0)/2 
式中:
S为被测距离;
t为发射超声脉冲与接收其回波的时间差;
t1为超声回波接收时刻;
t0为超声脉冲发射时刻。
利用MCU的捕获功能可以很方便地测量t0时刻和t1时刻,
根据以上公式,用软件编程即可得到被测距离S。


共6条 1/1 1 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册 ]