基于51单片机的汽车远近光灯自动照明系统仿真

仿真图:

在这里插入图片描述

芯片/模块的特点:

ADC0832特点:

8位分辨率:ADC0832可以将模拟输入信号转换为8位数字输出。这意味着它可以将模拟信号划分为256个不同的离散电平,提供相对较低的分辨率。

双通道输入:ADC0832具有两个模拟输入通道,使其能够同时转换两个模拟信号。这对于需要同时测量多个信号的应用非常有用。

内部参考电压源:ADC0832提供了一个内部的参考电压源,它可以用作模拟输入信号的参考电压。这样可以简化外部电路设计,并提供更稳定和准确的参考电压。

串行输出:ADC0832通过串行接口(SPI或I2C)输出转换结果。这种串行输出形式使其与微控制器或其他数字设备的通信变得更加简单和方便。

低功耗:ADC0832具有较低的功耗特性,适合在低功耗应用中使用。

可编程时钟频率:ADC0832的转换速度可以通过控制输入时钟频率进行编程。这使得可以根据应用的需求调整转换速度,并平衡转换精度和速度。

内部自校准:ADC0832具有内部自校准电路,可以降低转换误差,并提供更准确的转换结果。

HC-SR04特点:

  1. 非接触式测距:HC-SR04利用超声波技术进行测距,可以在不接触测量目标物的情况下获取距离信息。这种非接触式的特性使得它在许多应用中非常有用。
  2. 宽测量范围:HC-SR04可以测量的距离范围较广,通常为2厘米到400厘米。这使得它可以满足许多测量需求,从近距离到远距离的测量都可以应对。
  3. 高精度:HC-SR04测量距离的精度相对较高,可以达到3毫米左右。这对于需要较精确距离测量的应用是非常有益的。
  4. 易于使用:HC-SR04的使用非常简单,只需要提供一个触发信号,然后等待接收到回波信号,并通过计算来确定距离。它使用简单的电平触发和回波检测机制。
  5. 快速测量响应:HC-SR04可以快速地对目标进行测量并提供准确的结果。它的测量响应时间通常在几十毫秒的范围内。
  6. 低功耗:HC-SR04的功耗相对较低,适合在需要长时间运行或使用电池供电的应用中使用。

主程序:

#include <reg52.h>
#include "LCD1602.H"
#include "eeprom52.H"
#include "adc0832.H"			

uint time=0;

int S=0;	  //测量距离
sbit  echo=P2^2;				   //超声波接口定义
sbit  trig=P2^3;	
bit ir_ok=0;		//定时测量标志位
sbit led1=P2^0;//自动灯接口定义
sbit led2=P2^1;	  //手动LED指示灯接口定义
sbit LED_1=P1^6;//远光灯控制定义
sbit LED_2=P1^7; //近光灯控制定义
sbit key1=P3^3;	 //设置
sbit key2=P3^4;	 //增加
sbit key3=P3^6;	 //减小
sbit key4=P3^5;	 //手动/自动
sbit key5=P3^7;	 //远光	 //近光
sbit key6=P3^2;	 //手动关灯

bit key1_flag=0;
bit key2_flag=0;
bit key3_flag=0;
bit key4_flag=0;
bit key5_flag=0;
bit key6_flag=0;	//按键标志位

uchar sec1=0,sec2=0,ms=0; //sec1、sec2按键长按标志位,ms定时自加变量
uchar light_set=50,S_set=30,state;	//光照设置值,距离设置值,设置变量
bit s0;	 //液晶闪烁效果标志位
bit memory_flag=0; //存储标志位
uchar light=0,ad_count;	  //光照值,滤波用累加变量
uint ad_dat=0;	  //ad数据
uchar beam;//0关闭 1近光 2远光
bit A_M=0;//0手动

uchar count; //中断累加变量
long int distance; //测量所得距离

void memory()  //存储函数
 {
   SectorErase(0x2000);	 //清扇区
   byte_write(0x2000,S_set/256);
   byte_write(0x2001,S_set%256);  //往扇区存设置距离
   byte_write(0x2002,light_set);  //往扇区存设置光强
 } 
void read_memory()	//读存储函数
 {
  S_set=byte_read(0x2000)*256+byte_read(0x2001);  //将存的数据读出来
  light_set=byte_read(0x2002); 		//
  if(S_set>400||light_set>100)	//判断数据不正常,重新赋值
   {
     S_set=30;
	 light_set=50;
   }
 }
void trigger()	   //测量启动函数
{
	trig=0;
	_nop_();   //空语句,用来占用时间
	_nop_();
	_nop_();
	_nop_();
	_nop_();
	_nop_();
	_nop_();
	_nop_();
	_nop_();
	_nop_();
	_nop_();
	_nop_();
	_nop_();
	_nop_();
	_nop_();
	_nop_();
	_nop_();
	_nop_();
	_nop_();
	_nop_();
	_nop_();
	trig=1; 
}
void delayt(uint x)	//延时函数
{
	uchar j;
	while(x-- > 0)
	{
		for(j = 0;j < 125;j++)
		{
			;
		}
	}
}
void init_measuring()
{
	trig=1;
	echo=1;
	count=0;
}
void measuring() 		      //启动测距信号
{
	uchar l;
	uint h,y;
	TR0 = 1;
	while(echo==1)
	{
	;
	} 
	TR0 = 0;
	l = TL0;
	h = TH0;
	y = (h << 8) + l;
	y = y - 0xfc66;//us部分
	distance = y + 1000 * count;//计算总时间,单位是微秒
	TL0 = 0x66;
	TH0 = 0xfc;
	delayt(30);
	S = 3453* distance / 200000;//原始为:(0.34毫米/us)*时间/2// 
}

void interrupt_int()  //定时器初始化
 {
   TMOD=0x11;		//定时器0,定时器1都用模式1
   TH0=0x00;
   TL0=0x00;	  //定时器0赋初值0
   ET0=1;		   //使能定时器0
   TR0=0;		  //先不打开定时器0

   TH1=0x3c;
   TL1=0xb0;	//定时器1赋值50ms
   ET1=1;
   TR1=1;	   //打开定时器1
  
   EA=1;	 //打开总中断
 }

void display()	//显示函数
 {
   if(state==0)	   //如果是非设置状态
   {
	   LCD1602_write(0,0x80); //第一行
	   LCD1602_writebyte("Distance:"); //显示距离
	   if(S>99) LCD1602_write(1,0x30+S/100%10);
	   else LCD1602_writebyte(" ");
	   if(S>9) LCD1602_write(1,0x30+S/10%10);
	   else LCD1602_writebyte(" ");
	   LCD1602_write(1,0x30+S%10);
	   LCD1602_writebyte("cm   ");
	
	   LCD1602_write(0,0xC0);		//第二行
	   LCD1602_writebyte("Light:");	 //显示光照强度
	   if(light>99) LCD1602_write(1,0x30+light/100%10);
	   else LCD1602_writebyte(" ");
	   if(light>9) LCD1602_write(1,0x30+light/10%10);
	   else LCD1602_writebyte(" ");
	   LCD1602_write(1,0x30+light%10);
	   LCD1602_writebyte("%        ");
   }
   else	  //设置状态
   {
   	   LCD1602_write(0,0x80);  //第一行
	   LCD1602_writebyte("dis_set:");  //设置距离
	   if(state==1&&s0)	LCD1602_writebyte("   ");	//闪烁效果
	   else
	   {
		   if(S_set>99) LCD1602_write(1,0x30+S_set/100%10);
		   else LCD1602_writebyte(" ");
		   if(S_set>9) LCD1602_write(1,0x30+S_set/10%10);
		   else LCD1602_writebyte(" ");
		   LCD1602_write(1,0x30+S_set%10);
	   }
	   LCD1602_writebyte("cm   ");
	
	   LCD1602_write(0,0xC0);	
	   LCD1602_writebyte("lig_set:"); //设置光照
	   if(state==2&&s0)	LCD1602_writebyte("   ");
	   else
	   {
		   if(light_set>99) LCD1602_write(1,0x30+light_set/100%10);
		   else LCD1602_writebyte(" ");
		   if(light_set>9) LCD1602_write(1,0x30+light_set/10%10);
		   else LCD1602_writebyte(" ");
		   LCD1602_write(1,0x30+light_set%10);
	   }
	   LCD1602_writebyte("%        ");
   }
 }

void AD_dispose()	 //光照处理
{
	if(ad_count<10)		//读十次光照数据,取平均值,起到滤波的作用
	{
		ad_dat+=A_D(1);
		ad_count++;
	}
	else
	{
	   light=ad_dat/10;
	   light=(light*100)/255; //最大是255,所以这里扩大100倍除以255,可以得到百分比数据
	   ad_count=0;
	   ad_dat=0;
	}
}

void key_scan()	  //按键扫描
{

	if(!key1)	  //按键1按下
	{		
		if(key1_flag)  //如果标志位是1
		{
			key1_flag=0;	//清0
			state=(state+1)%3;	   //设置变量自加,%3限制了最大只能是2
		}
	}
	else
	{
		key1_flag=1; 	   //按键松开,才会给标志位置1,这样的话,按键按下只执行一次按键内容,起到了松手检测的作用
	}
	
	if(!key2)
	{		
		if(key2_flag)
		{
			key2_flag=0;
			if(state==1)	//设置距离状态
			{
				if(S_set<400) S_set++;	 //小于400,就自加
			}
			else if(state==2)//设置光照状态
			{
				if(light_set<100) light_set++;	//小于100就自加
			}
		}
		if(sec2==0)	//sec2==0,按键长按
		{
			if(state==1)  //实现连加效果
			{
				if(S_set<400) S_set++;
			}
			else if(state==2)
			{
				if(light_set<100) light_set++;
			}
		} 
		memory_flag=1;	//按键每次按下,存储标志位置1一次,这样只有设置的时候才会存储一次,一直执行存储函数会拖慢程序执行速度
	}
	else
	{
		key2_flag=1; sec2=2; //按键松开,按键标志位置1,按键长按变量赋0,当按键按下时,sec2不会再次赋值2,定时器有他的自减,当减到0,即为按键长按
	}
	
	if(!key3)  //同上
	{		
		if(key3_flag)
		{
			key3_flag=0;
			if(state==1)
			{
				if(S_set>0) S_set--;
			}
			else if(state==2)
			{
				if(light_set>0) light_set--;
			}
		}
		if(sec1==0)
		{
			if(state==1)
			{
				if(S_set>0) S_set--;
			}
			else if(state==2)
			{
				if(light_set>0) light_set--;
			}
		} 
		memory_flag=1;
	}
	else
	{
		key3_flag=1; sec1=2;
	}

	if(!key4)
	{		
		if(key4_flag)
		{
			key4_flag=0;
			A_M=!A_M;	   //手动自动切换
			if(A_M==0) beam=0;	  //如果切换到手动,就把灯关了
		}
	}
	else
	{
		key4_flag=1; 
	}

	if(!key5)
	{		
		if(key5_flag)
		{
			key5_flag=0;
			if(A_M==0)	 //手动状态
			{
				if(beam==1) beam=2;	 //远近光灯切换
				else beam=1;
			} 
			
		}
	}
	else
	{
		key5_flag=1; 
	}
	if(!key6)
	{		
		if(key6_flag)
		{
			key6_flag=0;
			if(A_M==0)		 //手动状态
			{
				beam=0;		//可关闭远近光灯
			} 
			
		}
	}
	else
	{
		key6_flag=1; 
	}
}

void police()  //自动模式处理函数
{
	if(light<light_set)	  //如果光照小于设置值,即天黑
	{
		if(S>S_set) beam=2;	  //如果距离大于设置距离,远光打开
		else beam=1;	 //否则近光打开
	}
	else beam=0;	 //否则光照强,就关闭远近光灯
}

void main()
 {  
   interrupt_int();	//调用定时器初始化函数
   LCD1602_cls();  //调用1602初始化函数
   read_memory();  //调用读存储
   init_measuring(); //调用超声波相应端口初始化
   while(1)
    {
	  display();  //显示函数
	  if(ir_ok)
	   {
	    ir_ok=0;
		 trigger(); //触发超声波启动
		 
		while(echo==0) //等待回声&&TH0<200
		{
		;	
		}	
		measuring(); //进行距离测量
		init_measuring(); //超声波相应端口初始化
		 
	   }
	   if(memory_flag) //如果存储标志位是1
	   {
	   	memory_flag=0;	//清0,
		memory();	   //执行一次存储函数
	   }
	   if(A_M)	  //如果是自动状态
	   {
	   	led1=0;	   //自动模式指示灯点亮
		led2=1;
		police(); //执行自动处理函数
	   }
	   else	  //否则
	   {
	   	led2=0;	 //手动指示灯点亮
		led1=1;
	   }
	   AD_dispose(); //调用AD处理函数
	   switch(beam)	//根据beam的值,切换远近光灯状态
	   {
	   	case 0:LED_1=1;LED_2=1;break;  //关闭
		case 1:LED_1=1;LED_2=0;break;	//近光
		case 2:LED_1=0;LED_2=1;break;  //远光
	   }
	}
 }

 void timer0(void) interrupt 1    //定时器0,用来测距计时
	{	
	   	
	}

 void timer1(void) interrupt 3  //定时器1
	{	
	   TH1=0x3c;		  //重新赋值50ms
	   TL1=0xb0;
	   ms++;
	   key_scan();	   //执行按键扫描函数
	   if(ms%4==0)		//50*4=20ms,执行以下内容
	   {
	   	 ir_ok=1;
		 s0=~s0;
	   }
	   if(ms>=20)	//50*20=1000ms=1s,执行以下内容
	    {
		 ms=0;
		 if(sec1!=0) sec1--;
		 if(sec2!=0) sec2--;

		}	   	
	}







设计文件:

链接:https://pan.baidu.com/s/1HamifzQ_aKLhJJPd6E54mA?pwd=p41n

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值