⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 060305.c

📁 基于单片机的自行车计时
💻 C
字号:
//几点说明:关机可以让单片机真正休眠进入真正低功耗状态,但是由于液晶一直有电供应且不知其功耗,故能省多少电并不知道,当然可以通过一个管脚通过
//控制三极管的基极来给液晶供电,关机时给其断电
#include <at89x52.h>
#include"LCD1602.h"
#include"I2C.h"
sfr  P1Port		= 0x90;
sbit led1=P3^7;
sbit led2=P3^6;
sbit led3=P3^5;
sbit led4=P3^4;
sbit lcd_on=P2^7;//P2^7控制lcd的开关
//######################################################################################################################################
//I2C程序
//######################################################################################################################################
unsigned char  wheel_radi;
unsigned short sec_add1;
unsigned char  second1;
unsigned char  minute;
unsigned char  hour;
unsigned short sec_add2;  //ms
unsigned int  cal_sec_add2;	//
unsigned int  mil_temp;
unsigned int   miles;			//最大值为65536,即655.36km
unsigned int   speed;
unsigned int   max_speed;
unsigned int   time_round;   //保存一个时间里面包含了几个36ms
unsigned int   temp_radi;
unsigned int   totalmile=0;
unsigned int   wspeed;//存放圈速度
unsigned char  butt_down;
bit speedflag;
bit firstime_flag;//消除速度第一次效应
unsigned char timearray[]={0x30,0x30,0x3a,0x30,0x30,0x3a,0x30,0x30,0xff};
unsigned char speedarray[]={0x30,0x30,0x2e,0x30,0x6b,0x6d,0x2f,0x68,0xff};
unsigned char milesarray[]={0x30,0x30,0x30,0x2e,0x30,0x30,0x6b,0x6d,0xff};
unsigned char wspeedarray[]={0x30,0x30,0x30,0x72,0x2f,0x6d,0x69,0x6e,0xff};
void Delay1ms(unsigned char count)
{
	unsigned char i,j;
	for(i=0;i<count;i++)
	for(j=0;j<33;j++);
}
void inttial_reg()
	{
	 max_speed=0;
	 speedflag=0;
	 firstime_flag=0;
     sec_add1=0;
	 second1=0;
	 minute=0;
	 hour=0;		  //时、分、秒、毫秒计数器,用来寄存行驶时间
	 sec_add2=0;
	 cal_sec_add2=0;
	 mil_temp=0;
	 miles=0;
	 speed=0;
	 time_round=0;
     temp_radi=180*wheel_radi;
	}    
void initiall()
{	
	 //warm up 延时
	 lcd_on=1;
	 Delay1ms(60);
	 sta();
	 wri_one_char(0xa0);
	 ack();
  	 wri_one_char(0x02);
	 ack();
	 sta();
	 wri_one_char(0xa1);
	 ack();
	 wheel_radi=read();
	 no_ack();	
	 stop();
	 inttial_reg();
	 TMOD=0x11;
	 TL0=0xb0;
	 TH0=0x3c;
	 TL1=0x30;
	 TH1=0xf8;			//打开外中断0,定时器0和定时器1、总中断的中断允许
	 TCON=0x01;			//将外中断0设置为跳变触发方式
//下面从外部存储器中读入车轮周长的值
//将中断设为下降沿,定时器模式设为1
//将定时器0用来计时,定时器1用来计相邻脉冲的时间间隔
//如果下一脉冲还没有到来而已经经过很长时间,则可以将速度置零
//$$$%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
	 LCD_Initial();
}
void timer0 (void) interrupt 1				   //计时程序,时间数据输出到LCD上
{
	 TL0=0xb0;
	 TH0=0x3c;
	 if (sec_add1==19)						   //定时时长50ms
		{
		   sec_add1=0;
		      if (second1==59)
			     {
			      second1=0;
					  if (minute==59)
					     {
					      minute=0;
						       if (hour==9)
							      {
								   hour=0;
								   }
							   else
							      {
								  hour++;
								  }
						  }
					  else
					     {
						  minute++;
						 }
			      }
		   else
		       {
			    second1++;
				}
		}
	 else
	     {  
		  sec_add1++;	   
		  }
}
void timer1 (void) interrupt 3			  //定时器1的中断,对转一圈的时间进行计时
{
	TL1=0x30;
	TH1=0xf8;								//定时时长2ms
	sec_add2++;
	if(sec_add2>2500){speed=0;wspeed=0;speedflag=1;}
	else{speedflag=0;}
}
void pulse_in (void) interrupt 0
{	
//将当前寄存器数值保存并置零,同时开启定时器
	//Delay1ms(100);
	mil_temp+=wheel_radi;	  //因为wheel_radi是以厘米为单位的,而且我们的显示精度到0.01km(即10m),故要和1000进行比较
	   if (mil_temp>=1000)
	      {
		   mil_temp-=1000;
		   miles++;			 //这里miles也是取的整数,单位也是10m,尽管最后在lcd上显示的是km/s
		  }
	cal_sec_add2=sec_add2;
	sec_add2=0;
	if(speedflag==0)			                             
	  {
	   speed=temp_radi/cal_sec_add2;
	   wspeed=30000/cal_sec_add2;
	   }							   //*************#########################*******************由于简化运算,这里的精度不可能很高,
	else {
			speed=0;
			wspeed=0;
		 }		   //这里速度的单位是:百米/小时
	if(firstime_flag==0){firstime_flag=1;speed=0;wspeed=0;}//消除速度第一次效应
	if(speed>max_speed) max_speed=speed;
	IE0=0; //清中断标志
}
//时间格式:   hour(1bit)  :  minute (int)  :  second1 (int)
//速度:	   speed(3bits)	  百米/小时------->**.*
//里程:	   miles   十米------>km   .**
//这里很重要的一件事情就是将数据形式转换为可以送去显示的形式
void display()
{
	timearray[1]=hour+0x30;
	timearray[3]=minute/10+0x30;
	timearray[4]=minute%10+0x30;
	timearray[6]=second1/10+0x30;
	timearray[7]=second1%10+0x30;
	speedarray[0]=speed/100+0x30;
	speedarray[1]=(speed/10)%10+0x30;
	speedarray[3]=speed%10+0x30;
	milesarray[0]=miles/10000+0x30;
	milesarray[1]=(miles/1000)%10+0x30;
	milesarray[2]=(miles/100)%10+0x30;
	milesarray[4]=(miles/10)%10+0x30;
	milesarray[5]=miles%10+0x30;
	wspeedarray[0]=wspeed/100+0x30;
	wspeedarray[1]=(wspeed/10)%10+0x30;
	wspeedarray[2]=wspeed%10+0x30;
}
unsigned int cal_total_miles()
	{
	unsigned int stoa=0;
	sta();
	wri_one_char(0xa0);
	ack();
	wri_one_char(0x00);
	ack();
	sta();
	wri_one_char(0xa1);
	ack();
	stoa=read();
	no_ack();	
	stop();
	stoa=stoa<<8;
	sta();
	wri_one_char(0xa0);
	ack();
	wri_one_char(0x01);
	ack();
	sta();
	wri_one_char(0xa1);
	ack();
	stoa+=read();
	no_ack();	
	stop();
	stoa+=(miles/10);
	return stoa;
	}
void stoa_miles()
	{
	unsigned int stoa=0;
	unsigned char stob;
	stoa=cal_total_miles();
//上面程序将数据从存储器中读出加上当前里程,下面将数据回存到存储器中
	sta();
	wri_one_char(0xa0);
	ack();
	wri_one_char(0x01);
	ack();
	stob=stoa&0x00ff;
	wri_one_char(stob);
	ack();
	stop();
	Delay1ms(100);
	//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
	sta();
	wri_one_char(0xa0);
	ack();
	wri_one_char(0x00);
	ack();
	stob=stoa>>8;
	wri_one_char(stob);
	ack();
	stop();
	Delay1ms(100);
	}
void disp_MILES_MSpeed()		  //显示最大速度以及总里程
	{
	 unsigned int  MilTemp;
	 unsigned char chartemp[9];
	 LCD_Write(LCD_COMMAND,LCD_CLEAR_SCREEN);   //清屏
	 MilTemp=cal_total_miles();
	 chartemp[8]=0xff;
	 chartemp[4]=0x2e;
	 chartemp[6]=0x6b;
	 chartemp[7]=0x6d;
	 chartemp[5]=MilTemp%10+0x30;
	 MilTemp/=10;
	 chartemp[3]=MilTemp%10+0x30;
	 MilTemp/=10;
	 chartemp[2]=MilTemp%10+0x30;
	 MilTemp/=10;
	 chartemp[1]=MilTemp%10+0x30;
	 MilTemp/=10;
	 chartemp[0]=MilTemp%10+0x30;
	 GotoXY(4,0);
	 Print(chartemp);
//上面一段显示了总里程,下面一段将显示行驶中的最大速度
	 Delay1ms(100);
	 MilTemp=max_speed;
	 chartemp[8]=0xff;
	 chartemp[2]=0x2e;
	 chartemp[4]=0x6b;
	 chartemp[5]=0x6d;
	 chartemp[6]=0x2f;
	 chartemp[7]=0x68;
	 chartemp[3]=MilTemp%10+0x30;
	 MilTemp/=10;
	 chartemp[1]=MilTemp%10+0x30;
	 MilTemp/=10;
	 chartemp[0]=MilTemp%10+0x30;
	 GotoXY(4,1);
	 Print(chartemp);
	}
void disp_wheel_radi()
	{
	 unsigned char tempchar2;
	 unsigned char tempchatable[]={0x47,0x52,0x49,0x54,0x48,0x3a,0xff};
	 LCD_Write(LCD_COMMAND,LCD_CLEAR_SCREEN);   //清屏
	 Delay1ms(100);
	 GotoXY(5,0);
	 Print(tempchatable);
	 tempchar2=wheel_radi;
	 tempchatable[2]=tempchar2%10+0x30;
	 tempchar2/=10;
	 tempchatable[1]=tempchar2%10+0x30;
	 tempchar2/=10;
	 tempchatable[0]=tempchar2%10+0x30;
	 tempchatable[3]=0x63;
	 tempchatable[4]=0x6d;
	 tempchatable[5]=0xff;
	 GotoXY(5,1);
	 Print(tempchatable);
	}
void chan_radi()				 //改变车轮周长
	{
	bit changed_flag=0;
	disp_wheel_radi();
//将当前周长显示在lcd上
	EA=0;
	do
		{
		 if(!(P1Port&0x04))//如果发现UP键被按下
		 	{
			 Delay1ms(100);//延时进行前沿消抖
			 if(!(P1Port&0x04))//确认UP键确实被按下一次
			 	{
			 	while(!(P1Port&0x04));//等待UP按键弹起
				Delay1ms(100);//后沿消抖
			 	wheel_radi++; //车轮周长增加1
			 	changed_flag=1;//判断车轮周长变化了的标志
			 	if(wheel_radi>230) wheel_radi=180;
				if(wheel_radi<180) wheel_radi=180;//限制车轮周长在180~230cm之间
			 	disp_wheel_radi();//将车轮周长在lcd上显示出来
			 	}
			 }
		 if(!(P1Port&0x02))//判断MODE键是否被按下 
		 	{
			 Delay1ms(100);
			 led1=1;
			 if(!(P1Port&0x02))
			 	{
				 while(!(P1Port&0x02));
				 Delay1ms(100);
				 break;
				 }
			}
		}while(1);
		if(changed_flag)
		{
		changed_flag=0;
		sta();
		wri_one_char(0xa0);
		ack();
		wri_one_char(0x02);
		ack();
		wri_one_char(wheel_radi);
		ack();
		stop();
		Delay1ms(100);
		miles=0x0000;
		sta();
		wri_one_char(0xa0);
		ack();
		wri_one_char(0x00);
		ack();
		wri_one_char(0x00);
		ack();
		stop();
		Delay1ms(100);
		sta();
		wri_one_char(0xa0);
		ack();
		wri_one_char(0x01);
		ack();
		wri_one_char(0x00);
		ack();
		stop();
		inttial_reg();
		}
		EA=1;
	}
void main (void)
{  
   bit dispflag1;
   bit dispflag2;
   bit MODE2flag;
   unsigned int to_time;	  
   initiall();
   //led1=0;//测试用句
   //led2=0;//测试用句
   //led3=0;//测试用句
   //led4=0;//测试用句
   MODE2flag=0;
   IE=0x8f;	   //开中断
   TR0=1;
   Delay1ms(1);
   TR1=1; 	   
   do{ 
        if(second1%2==0) dispflag1=0;
          else            dispflag1=1;
	      if(dispflag1!=dispflag2)
		     { 
			  dispflag2=dispflag1;
       display();
	   GotoXY(0,0);
	   Print(wspeedarray);
	   GotoXY(8,0);
	   Print(timearray);
	   GotoXY(0,1);
	   Print(speedarray);
	   GotoXY(8,1);
	   Print(milesarray);
	   }
	   butt_down=P1Port;
	   if(!(P1Port&0x01))//关机程序
	   	{
			EA=0;
			for(to_time=6000;to_time>0;to_time--);
			if(P1Port&0x01)break;
			else{
				stoa_miles();
				LCD_Write(LCD_COMMAND,LCD_CLEAR_SCREEN);   //清屏  shut down lcd
				LCD_Write(0x08,1);//显示关
				PCON+=0x02;//进入掉电方式
				}
		}
		else if(!(P1Port&0x02))//判断是否MODE键被按下第一次,若是则进入下一步×××××××××××××××××××××××××
				{
				 Delay1ms(100);//延时10ms,软件消除前沿抖动
				 if(P1Port&0x02)break;//再次判断,若MODE键没有被按下了第一次则退出
				 else{				  //确实MODE键被按下了第一次
				 	  while(!(P1Port&0x02));//等待第一次按键弹起后,再处理
					  Delay1ms(100);//延时10ms,软件消除后沿抖动
				 	  disp_MILES_MSpeed();//显示总里程和本次骑行最大速度
					  for(to_time=120;to_time>0;to_time--)//延时一段时间,同时在本段时间内判断MODE键有没有第二次被按下
					  	{
						 Delay1ms(100);
						 if(!(P1Port&0x02))//这后面的过程基本重复×××××××××××××××××××××××××的过程
						 	{
								Delay1ms(100);
								if(P1Port&0x02)break;
								else{	  //若确实MODE键被按下了第二次
									while(!(P1Port&0x02));//等待第二次按键弹起
									MODE2flag=1;
									Delay1ms(100);//软件消除后沿抖动
									break;
									}
							}
						}
					}
				}
				if(MODE2flag){MODE2flag=0;chan_radi();}
	}while(1);
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -