基于AT89C51单片机的多功能自行车测速计程器(含文档、源码与proteus仿真,以及系统详细介绍)

本篇文章论述的是基于AT89C51单片机的多功能自行车测速计程器的详情介绍,如果对您有帮助的话,还请关注一下哦,如果有资源方面的需要可以联系我。

目录

选题背景

原理图

PCB图

仿真图

代码

系统论文

资源下载


选题背景

美丽的夜晚,骑着单车刷内环,既浪漫又可以锻炼身体,但是我们到底骑了多少米,我们的车速是多少,我们并不知道。自行车已经不仅仅是普通的代步、运输工具,而是成为人们娱乐、休闲、锻炼的首选。自行车简易数字里程表能够满足人们最基本的需求,让人们能清楚地知道当前的速度、里程等物理量。

关键字里程/速度;霍尔元件;单片机;LCD显示;超声波测距;震动防盗;人体感控;

原理图


PCB图


仿真图


代码


复制代码
#include<reg52.h>

#define uchar unsigned char
#define uint unsigned int

#include "Data.h"
#include "DS1302.h"
#include "AT24C02.h"

sbit COUNT_IN=P3^2;

//定义1602相关管脚
sbit rs=P1^4;
sbit en=P1^0;

//键盘定义
sbit K1=P3^4;	//设置时间
sbit K3=P3^6;	//减按键
sbit K2=P3^5;	//加按键
sbit K4=P3^7;	//设置半径安全距离
sbit BEEP=P3^0;

uint count;
unsigned long Velocity,Mileage;

uchar code tab1[]={"  /  /     :    "}; //14/09/10 16:34 3   	
uchar code tab2[]={"  0.000km 00km/h"};	//000.000km 00km/h
uchar code tab3[]={"Wheel Radius  cm"};
uchar code tab4[]={"Safe Speed  km/h"};
uchar code tab5[]={"Sec :           "};
			   			
uchar Mode=0;
uchar bike_set=0;
uchar a;
char RADIUS,SAFE_SPEED;
bit LED_SEC;
uchar before_sec;	

//自定义字符
uchar code num[]={
						0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x00,//1	 
						0x1f,0x01,0x01,0x1f,0x10,0x10,0x1f,0x00,//2
						0x1f,0x01,0x01,0x1f,0x01,0x01,0x1f,0x00,//3	 
						0x11,0x11,0x11,0x1f,0x01,0x01,0x01,0x00,//4
						0x1f,0x10,0x10,0x1f,0x01,0x01,0x1f,0x00,//5	 
						0x1f,0x10,0x10,0x1f,0x11,0x11,0x1f,0x00,//6
						0x1f,0x01,0x01,0x01,0x01,0x01,0x01,0x00,//7 	
};
void READS();
void SETS();
void delay(uint x)
{
	uint i,j;
	for(i=0;i<x;i++)
	for(j=0;j<110;j++);
}
void init()
{
	IT0=1;	//INT0负跳变触发	
    TMOD=0x01;//定时器工作于方式1
	TH0=0x3c;	  //50ms
	TL0=0xb0;
	EA=1; //CPU开中断总允许
	ET0=1;//开定时中断
	EX0=1;//开外部INTO中断
    TR0=1;//启动定时
}
/********液晶写入指令函数与写入数据函数,以后可调用**************/

void write_1602com(uchar com)//****液晶写入指令函数****
{
	rs=0;//数据/指令选择置为指令
	P0=com;//送入数据
	delay(1);
	en=1;//拉高使能端,为制造有效的下降沿做准备
	delay(1);
	en=0;//en由高变低,产生下降沿,液晶执行命令

}


void write_1602dat(uchar dat)//***液晶写入数据函数****
{
	rs=1;//数据/指令选择置为数据
	P0=dat;//送入数据
	delay(1);
	en=1; //en置高电平,为制造下降沿做准备
	delay(1);
	en=0; //en由高变低,产生下降沿,液晶执行命令
}
//自定义字符集
void Lcd_ram()      
{ 
	uint i,j,k=0,temp=0x40; 
	for(i=0;i<7;i++)
	{
	   for(j=0;j<8;j++)
	   {
	    write_1602com(temp+j);
	    write_1602dat(num[k]);
	    k++;
	   }
	   temp=temp+8;
	}
}

void lcd_init()//***液晶初始化函数****
{
	Lcd_ram();
	write_1602com(0x38);//设置液晶工作模式,意思:16*2行显示,5*7点阵,8位数据
	write_1602com(0x0c);//开显示不显示光标
	write_1602com(0x06);//整屏不移动,光标自动右移
	write_1602com(0x01);//清显示

	write_1602com(0x80);//显示固定符号从第一行第1个位置之后开始显示
	for(a=0;a<16;a++)
	{
		write_1602dat(tab1[a]);//向液晶屏写固定符号部分
	}
	write_1602com(0x80+0x40);//显示固定符号写入位置,从第2个位置后开始显示
	for(a=0;a<16;a++)
	{
		write_1602dat(tab2[a]);//写显示固定符号
	}
}

void display()
{
	//			1km/h=100m/0.1h	  	 360s
	//			10km/h=100m/0.01h 	 36s
	//			100km/h=100m/0.001h  3.6s
	if(Mode==0&&bike_set==0)
	{
		//读时间
			Ds1302_Read_Time();
			//显示时间
			write_1602com(0x80);
			write_1602dat(0x30+time_buf1[1]/10);
			write_1602dat(0x30+time_buf1[1]%10);
			write_1602com(0x80+3);
			write_1602dat(0x30+time_buf1[2]/10);
			write_1602dat(0x30+time_buf1[2]%10);
			write_1602com(0x80+6);
			write_1602dat(0x30+time_buf1[3]/10);
			write_1602dat(0x30+time_buf1[3]%10);
			write_1602com(0x80+9);
			write_1602dat(0x30+time_buf1[4]/10);
			write_1602dat(0x30+time_buf1[4]%10);
			write_1602com(0x80+12);
			write_1602dat(0x30+time_buf1[5]/10);
			write_1602dat(0x30+time_buf1[5]%10);
			write_1602com(0x80+15);
			write_1602dat(time_buf1[7]-1);		

			if(before_sec!=time_buf1[6])
			{
				before_sec=time_buf1[6];
				write_1602com(0x80+11);
				write_1602dat(':');
				LED_SEC=1;
			}
			if(LED_SEC==0)
			{
				write_1602com(0x80+11);
				write_1602dat(' ');	
			}

			write_1602com(0x80+0x40);
			if(Mileage/1000000==0)
			write_1602dat(' ');
			else
			write_1602dat(0x30+Mileage/1000000);//数字+0x30得到该数字的LCD1602显示码
			if(Mileage%1000000/100000==0)
			write_1602dat(' ');
			else	
			write_1602dat(0x30+Mileage%1000000/100000);//数字+0x30得到该数字的LCD1602显示码
			write_1602dat(0x30+Mileage%1000000%100000/10000);//数字+0x30得到该数字的LCD1602显示码 
			write_1602com(0x80+0x40+4);
			write_1602dat(0x30+Mileage%1000000%100000%10000/1000);//数字+30得到该数字的LCD1602显示码
			write_1602dat(0x30+Mileage%1000000%100000%10000%1000/100);//数字+30得到该数字的LCD1602显示码
			write_1602dat(0x30+Mileage%1000000%100000%10000%1000%100/10);//数字+30得到该数字的LCD1602显示码
			SETS();
	
			write_1602com(0x80+0x40+10);
			write_1602dat(0x30+Velocity/10);
			write_1602dat(0x30+Velocity%10);//数字+30得到该数字的LCD1602显示码
	}
	else if(Mode!=0)
	{
		switch(Mode)
		{
			case 1:	
				write_1602com(0x80+0x40);//显示固定符号写入位置
				for(a=0;a<16;a++)
				{
					write_1602dat(tab5[a]);//写显示固定符号
				}
				write_1602com(0x80+0x40+14);
				write_1602dat(0x30+time_buf1[6]/10);
				write_1602dat(0x30+time_buf1[6]%10);	
				write_1602com(0x0F);	 //打开闪烁
				write_1602com(0x80+1);
				break;						  
			case 2:
				write_1602com(0x80+4);
				break;
			case 3:
				write_1602com(0x80+7);
				break;
			case 4:
				write_1602com(0x80+10);
				break;
			case 5:
				write_1602com(0x80+13);
				break;
			case 6:
				write_1602com(0x80+0x40+15);
				break;
			case 7:
				write_1602com(0x80+15);
				break;
			case 8:
				write_1602com(0x0c);
				write_1602com(0x80);//显示固定符号从第一行第1个位置之后开始显示
				for(a=0;a<16;a++)
				{
					write_1602dat(tab1[a]);//向液晶屏写固定符号部分
				}
				write_1602com(0x80+0x40);//显示固定符号写入位置,从第2个位置后开始显示
				for(a=0;a<16;a++)
				{
					write_1602dat(tab2[a]);//写显示固定符号
				}
				break;
		}
	}
	else if(bike_set!=0)
	{
		switch(bike_set)
		{
			case 1:	
				write_1602com(0x80);//显示固定符号写入位置
				for(a=0;a<16;a++)
				{
					write_1602dat(tab3[a]);//写显示固定符号
				}
				write_1602com(0x80+0x40);//显示固定符号写入位置
				for(a=0;a<16;a++)
				{
					write_1602dat(tab4[a]);//写显示固定符号
				}
				write_1602com(0x80+12);
				write_1602dat(0x30+RADIUS/10);		   //车轮半径
				write_1602dat(0x30+RADIUS%10);
				write_1602com(0x80+0x40+10);
				write_1602dat(0x30+SAFE_SPEED/10);		   //安全速度
				write_1602dat(0x30+SAFE_SPEED%10);	
				write_1602com(0x0F);	 //打开闪烁
				write_1602com(0x80+13);
				break;						  
			case 2:
				write_1602com(0x80+0x40+11);
				break;
			case 3:
				write_1602com(0x0c);
				write_1602com(0x80);//显示固定符号从第一行第1个位置之后开始显示
				for(a=0;a<16;a++)
				{
					write_1602dat(tab1[a]);//向液晶屏写固定符号部分
				}
				write_1602com(0x80+0x40);//显示固定符号写入位置,从第2个位置后开始显示
				for(a=0;a<16;a++)
				{
					write_1602dat(tab2[a]);//写显示固定符号
				}
				break;
		}
	}	
}

void KEY()
{	
	if(bike_set==0&&K1==0)
	{
		delay(20);
		if(bike_set==0&&K1==0)
		{
			BEEP=0;
			delay(50);
			BEEP=1;
			Mode++;
			display();
			if(Mode>=8)
			{
				Mode=0;
				Ds1302_Write_Time();
			}
		}
		while(bike_set==0&&K1==0);
	}
	if(K4==0&&Mode==0)
	{
		delay(20);
		if(K4==0&&Mode==0)
		{
			BEEP=0;
			delay(50);
			BEEP=1;
			bike_set++;
			display();
			if(bike_set>=3)
			{
				bike_set=0;
				SETS();
			}
		}
		while(Mode==0&&K4==0);
	}

	//+
	if(K2==0&&(Mode!=0||bike_set!=0))
	{
		delay(20);
		//调时
		if(K2==0&&(Mode!=0||bike_set!=0))
		{
			BEEP=0;
			delay(50);
			BEEP=1;	
			switch(Mode)
			{
				case 1:
					time_buf1[1]++;
					if(time_buf1[1]>=100)
						time_buf1[1]=0;
					write_1602com(0x80);
					write_1602dat(0x30+time_buf1[1]/10);
					write_1602dat(0x30+time_buf1[1]%10);
					write_1602com(0x80+1);
					break;
				case 2:
					time_buf1[2]++;
					if(time_buf1[2]>=13)
						time_buf1[2]=1;
					write_1602com(0x80+3);
					write_1602dat(0x30+time_buf1[2]/10);
					write_1602dat(0x30+time_buf1[2]%10);
					write_1602com(0x80+4);
					break;
				case 3:
					time_buf1[3]++;
					if(time_buf1[3]>=YDay(time_buf1[1],time_buf1[2])+1)
						time_buf1[3]=1;
					write_1602com(0x80+6);
					write_1602dat(0x30+time_buf1[3]/10);
					write_1602dat(0x30+time_buf1[3]%10);
					write_1602com(0x80+7);
					break;
				case 4:
					time_buf1[4]++;
					if(time_buf1[4]>=24)
						time_buf1[4]=0;
					write_1602com(0x80+9);
					write_1602dat(0x30+time_buf1[4]/10);
					write_1602dat(0x30+time_buf1[4]%10);
					write_1602com(0x80+10);
					break;
				case 5:
					time_buf1[5]++;
					if(time_buf1[5]>=60)
						time_buf1[5]=0;
					write_1602com(0x80+12);
					write_1602dat(0x30+time_buf1[5]/10);
					write_1602dat(0x30+time_buf1[5]%10);
					write_1602com(0x80+13);
					break;
				case 6:
					time_buf1[6]++;
					if(time_buf1[6]>=60)
						time_buf1[6]=0;
					write_1602com(0x80+0x40+14);
					write_1602dat(0x30+time_buf1[6]/10);
					write_1602dat(0x30+time_buf1[6]%10);
					write_1602com(0x80+0x40+15);
					break;
				case 7:
					time_buf1[7]++;
					if(time_buf1[7]>=8)
						time_buf1[7]=1;
					write_1602com(0x80+15);
					write_1602dat(time_buf1[7]-1);
					write_1602com(0x80+15);
					break;
			}
			switch(bike_set)
			{
				case 1:
					RADIUS++;
					if(RADIUS>=71)
					RADIUS=0;
					write_1602com(0x80+12);
					write_1602dat(0x30+RADIUS/10);
					write_1602dat(0x30+RADIUS%10);
					write_1602com(0x80+13);
					break;
				case 2:
					SAFE_SPEED++;
					if(SAFE_SPEED>=100)
					SAFE_SPEED=0;
					write_1602com(0x80+0x40+10);
					write_1602dat(0x30+SAFE_SPEED/10);
					write_1602dat(0x30+SAFE_SPEED%10);
					write_1602com(0x80+0x40+11);
					break;
			}
		}
		while(K2==0);
	}

	//-
	if(K3==0&&(Mode!=0||bike_set!=0))
	{
		delay(20);
		//调时
		if(K3==0&&(Mode!=0||bike_set!=0))
		{
			BEEP=0;
			delay(50);
			BEEP=1;
			switch(Mode)
			{
				case 1:
					time_buf1[1]--;
					if(time_buf1[1]<0)
						time_buf1[1]=99;
					write_1602com(0x80);
					write_1602dat(0x30+time_buf1[1]/10);
					write_1602dat(0x30+time_buf1[1]%10);
					write_1602com(0x80+1);
					break;
				case 2:
					time_buf1[2]--;
					if(time_buf1[2]<=0)
						time_buf1[2]=12;
					write_1602com(0x80+3);
					write_1602dat(0x30+time_buf1[2]/10);
					write_1602dat(0x30+time_buf1[2]%10);
					write_1602com(0x80+4);
					break;
				case 3:
					time_buf1[3]--;
					if(time_buf1[3]<=0)
						time_buf1[3]=YDay(time_buf1[1],time_buf1[2]);
					write_1602com(0x80+6);
					write_1602dat(0x30+time_buf1[3]/10);
					write_1602dat(0x30+time_buf1[3]%10);
					write_1602com(0x80+7);
					break;
				case 4:
					time_buf1[4]--;
					if(time_buf1[4]<0)
						time_buf1[4]=23;
					write_1602com(0x80+9);
					write_1602dat(0x30+time_buf1[4]/10);
					write_1602dat(0x30+time_buf1[4]%10);
					write_1602com(0x80+10);
					break;
				case 5:
					time_buf1[5]--;
					if(time_buf1[5]<0)
						time_buf1[5]=59;
					write_1602com(0x80+12);
					write_1602dat(0x30+time_buf1[5]/10);
					write_1602dat(0x30+time_buf1[5]%10);
					write_1602com(0x80+13);
					break;
				case 6:
					time_buf1[6]--;
					if(time_buf1[6]<0)
						time_buf1[6]=59;
					write_1602com(0x80+0x40+14);
					write_1602dat(0x30+time_buf1[6]/10);
					write_1602dat(0x30+time_buf1[6]%10);
					write_1602com(0x80+0x40+15);
					break;
				case 7:
					time_buf1[7]--;
					if(time_buf1[7]<1)
						time_buf1[7]=7;
					write_1602com(0x80+15);
					write_1602dat(time_buf1[7]-1);
					write_1602com(0x80+15);
					break;
			}
			switch(bike_set)
			{
				case 1:
					RADIUS--;
					if(RADIUS<0)
					RADIUS=70;
					write_1602com(0x80+12);
					write_1602dat(0x30+RADIUS/10);
					write_1602dat(0x30+RADIUS%10);
					write_1602com(0x80+13);
					break;
				case 2:
					SAFE_SPEED--;
					if(SAFE_SPEED<0)
					SAFE_SPEED=99;
					write_1602com(0x80+0x40+10);
					write_1602dat(0x30+SAFE_SPEED/10);
					write_1602dat(0x30+SAFE_SPEED%10);
					write_1602com(0x80+0x40+11);
					break;
			}
		}
		while(K3==0);
	}	
	if(K2==0&&K3==0&&Mode==0&bike_set==0)
	{
		BEEP=0;
		delay(100);
		BEEP=1;
		delay(100);
		BEEP=0;
		delay(100);
		BEEP=1;
		delay(100);
		Mileage=0;
		SETS();
		while(K2==0&&K3==0);
	}
}
void BJ_SAFE()
{
	if(Velocity>SAFE_SPEED)
	{
		BEEP=0;
	}
	else
	{
		BEEP=1;
	}
}

void main()
{
	//初始化
	Ds1302_Init();
	lcd_init();
	initeeprom();
	//读取初始参数
	READS();
	//定时器初始化
//	InitTimer0();
	init();
	lcd_init();
	before_sec=time_buf1[6];
	while(1)
	{
		if(Mode==0&&bike_set==0)
		{
			display();
			BJ_SAFE();
		}
		KEY();
	}
}

void EXINT0() interrupt 0
{
	count++;
}

void time0() interrupt 1
{
	uchar m,n;
	TH0=0x3c;
	TL0=0xb0;	 //50ms
	m++;
	if(LED_SEC==1)
	{
		n++;
		if(n>=10)
		{
			n=0;
			LED_SEC=0;
		}
	}
	
	if(m>=10)
	{
		m=0;
		Mileage=Mileage+10*(Velocity/3.6)/2;		 //里程m=里程+速度km/h/3.6/2
		Velocity=count *2*3.14*RADIUS /100000*2*3600  /40;//将500ms的距离经过运算得到km/h,将速度/100,方便显示
		count=0;	
	}
}

//读初值
void READS()
{
	uchar Mileage_H,Mileage_M,Mileage_L;
	delay(10);
	RADIUS=read_add(0x01);
	delay(10);
	SAFE_SPEED=read_add(0x02);

	delay(10);
	Mileage_H=read_add(0x03);
	delay(10);
	Mileage_M=read_add(0x04);
	delay(10);
	Mileage_L=read_add(0x05);

	Mileage=Mileage_H*100000+Mileage_M*1000+Mileage_L*10;
}

系统论文(部分)


引 言

自行车被发明及使用到现在已有两百多年的历史,这两百年间人类在不断的尝试与研发过程中,将玩具式的木马车转换到今日各式新颖休闲运动自行车,自行车发展的目的也从最早的交通代步的工具转换成休闲娱乐运动的用途。

随着居民生活水平的不断提高,自行车不再仅仅是普通的运输、代步的工具,而是成为人们娱乐、休闲、锻炼的首选。因此,人们希望自行车的功用更强大,能给人们带来更多的方便。自行车简易数字里程表作为自行车的一大辅助工具也随着这个需求而面世,其功能也逐渐从单一的里程显示发展到速度、时间显示。本设计采用51系列单片机设计一种体积小、操作简单的便携式自行车的速度里程表,它能自动地显示当前自行车行驶的里程及速度,并且具有测距防盗功能。

这次主要任务是利用霍尔元件、单片机、超声波发射、震动传感器等部件设计一个可用1602液晶显示里程、速度、防盗和测距的自行车速度里程表。本文主要介绍了自行车的速度里程表的设计思想、电路原理和元件的选择等内容,整体上分为硬件部分设计和软件部分设计。

本文首先扼要对该课题的任务进行方案论证,包括硬件方案和软件方案的设计;继而具体介绍了自行车的速度里程表的硬件设计,包括单片机的选择、传感器的选择、显示电路的设计;然后简要阐述了自行车的速度里程表的软件设计思路;最后针对仿真过程遇到的问题进行了说明与分析,对本次设计进行了系统的总结。

具体的硬件电路包括STC89C52单片机的外围电路以及液晶显示电路等。

软件设计包括:芯片的初始化程序、定时中断子程序、显示子程序等,用keil软件采用C语言编写。

第一部分 设计任务

1.1 设计要求

(1)用1602显示屏显示速度,路程,时间。

(2)若超过预设的速度,则蜂鸣器报警

(3)报警临界速度可调

(4)使用震动传感器设计防盗系统

(5)使用超声波模块测距

(6)选择合适的调试模型

1.2 方案设计

采用单片机实现:用霍尔传感器将所测转速转变为数字脉冲信号,然后再将数字脉冲信号数据传输于核心单片机处理,单片机将根据设计程序计算在一定时间内数字脉冲的频率,再由计数值最终得到里程数并通过终端显示设备显示出来。且附加报警功能,在速度超过某一个固定值后,蜂鸣器响,提示需要减速。当震动传感器震动频率超出设置频率时,蜂鸣器发出响声报警,数码管可显示路面的距离。

第三部分 系统软件的设计与实现

3.1 主程序流程图

图9 主程序流程图

3.2 显示流程图

该子程序用LCD动态扫描显示方式。先将单片机的P2.2口连接使能端口E。接着将单片机的P2.0口连接数据/命令选择端RS,P0口连接数据端D0~D7,然后将要显示的数字的值发送给P0口。然后调用延时,接着将P2.2口置0,P2.0口置1,写指令,将P2.2口置1,P2.0口置1,写数据,直到要显示的数字全部显示在液晶上。显示流程图如图10所示。

图10 显示流程图

3.3 速度处理流程图

3.4 电路仿真

3.4.1 仿真软件简介

Proteus是世界上著名的EDA工具,从原理图布图、代码调试到单片机与外围电路协同仿真,一键切换到PCB设计,真正实现了从概念到产品的完整设计。是目前世界上唯一将电路仿真软件、PCB设计软件和虚拟模型仿真软件三合一的设计平台,其处理器模型支持8051、HC11、PIC10/12/16/18/24/30/DsPIC33、AVR、ARM、8086和MSP430等,2010年又增加了Cortex和DSP系列处理器,并持续增加其他系列处理器模型。在编译方面,

它也支持IAR、Keil和MPLAB等多种编译器

3.4.2 仿真结果

仿真结果如图12所示。

图12


资源下载


如果有需要这个系统的源码、仿真、论文等资源的可以私信我。感谢你的阅读~

相关推荐
无畏jh13 分钟前
TLE5012B磁阻芯片解读
嵌入式硬件·汽车嵌入式·磁阻芯片
培林将军21 分钟前
Altium Designer 22的安装与汉化
嵌入式硬件·ad工具安装
idcardwang23 分钟前
xl9555-IO拓展芯片
stm32·单片机·嵌入式硬件
Y1rong27 分钟前
STM32之EXTI
stm32·单片机·嵌入式硬件
兆龙电子单片机设计32 分钟前
【STM32项目开源】STM32单片机智能语音家居控制系统
stm32·单片机·嵌入式硬件·物联网·开源·自动化
TaidL1 小时前
茂捷M1020电感式编码器芯片赋能工业智能升级,适用于工业及机器人等领域的各种应用场景
单片机·嵌入式硬件
意法半导体STM321 小时前
【官方原创】SAU对NSC分区的影响 LAT1578
stm32·单片机·嵌入式硬件·mcu·信息安全·trustzone·stm32开发
SmartRadio1 小时前
MK8000(UWB射频芯片)与DW1000的协议适配
c语言·开发语言·stm32·单片机·嵌入式硬件·物联网·dw1000
LDR0061 小时前
芯片电路的引脚标识代表什么?
stm32·单片机·嵌入式硬件
恒锐丰小吕2 小时前
屹晶微 EG3116 600V高压、2A/2.5A驱动、双高有效输入逻辑的半桥栅极驱动芯片技术解析
嵌入式硬件·硬件工程