51单片机大作业 停车场管理系统

记录一下单片机大作业,
项目介绍:
在这里插入图片描述

我们小组在经过了半个学期的计算机系统设计的学习后,并结合了平时停车场的管理模式,使用C51单片机和各个模块完成了一个停车场的管理系统。该套系统模拟了当汽车进入停车时的收费提示液晶屏,我们这里使用了16个按键来模拟停车位,主要由以下功能:
(1)该系统可以提醒管理员该停车场是否剩余停车位;
(2)当汽车停入汽车位时开始计算停车时间,并显示车位占用量和余量;
(3)当汽车离开停车位时在液晶屏上显示期间该车停车的总时间与停车费,重置车位的状态,并显示车位占用量和余量。
(4)温度传感器测温(一直测温的状态,超过温度的时候响)
在这里插入图片描述
使用液晶屏用到的函数调用
在这里插入图片描述
流程图:
在这里插入图片描述
源码:

#include <reg52.h>
#include <intrins.h>
#include <stdio.h>
#define uchar unsigned char
#define uint  unsigned int
#define LCDDATA P0
sbit led_red = P2^4;		 //红色led引脚定义
sbit led2_green = P2^3;		 //绿色led引脚定义
sbit led3_red = P3^4;		 //火警控制灯

//LCD1602引脚定义
//采用8位并行方式,DB0~DB7连接至LCDDATA0~LCDDATA7
sbit RS=P2^0;  //数据指令控制
sbit RW=P2^1;	//读写选择(0写1读)
sbit CS=P2^2;	//使能信号
uchar code KeyCodeTable[]={
    
    0x11,0x12,0x14,0x18,0x21,0x22,0x24,0x28,0x41,0x42,0x44,0x48,0x81,0x82,0x84,0x88};// 设定键值
uchar i_,j_;

static int a[16];
unsigned int n;
static int timeStart[16];
//static int timeStop[16];  无需此数组 
static int  timeCount = 0;
static uchar  timer = 0;

static uint temp;//测得温度
sbit buzzer=P3^3;//蜂鸣器引脚
sbit DQ=P3^7;//ds18b20 端口

//功能:延时1毫秒
//说明:当晶振为12M时,j<112;当晶振为11.0592M时,j<122
void Delay_xms(uint x)
{
    
    
  uint i,j;
  for(i=0;i<x;i++)
    for(j=0;j<112;j++);
}
//功能:12us延时
//STC89C52为1T单片机,即1个时钟/机器周期,速度为AT89C52的12倍
void Delay_xus(uint t)	  		 		
{
    
     
  for(;t>0;t--)
   {
    
    
	 _nop_();		//_nop_(); 指令的延迟时间为 1us。可以较为精确得控制延迟时间。
   }
}
uchar Keys_Scan()		  //按键扫描函数
{
    
    
 	uchar sCode,kCode,i,k;	 //定义变量
	P1 = 0xf0;				  //P1口接按键,P1口赋值0xf0表示屏蔽低四位
	if((P1&0xf0)!=0xf0)		   //判断高四位是否有按键按下
	{
    
    
	 	Delay_xus(200);			  
		if((P1&0xf0)!=0xf0)		  //消抖 再判断
		{
    
    
		 	sCode = 0xfe;
			for(k=0;k<4;k++)
			{
    
    
			 	P1 = sCode;
				if((P1&0xf0)!=0xf0)		//判断高四位是否有按键按下
				{
    
    
				 	kCode = ~P1;			//将P1口取反后的值赋给变量
					for(i=0;i<16;i++)		 //循环16次进行判断
					{
    
    
					 	if(kCode == KeyCodeTable[i])	 //判断变量是数组中的第几个,并返回序号值
							return i;
					}
				}
				else 
					sCode = _crol_(sCode,1);			 //变量左移一位并在左边补1,_cror_代表右移
			}
		}
	}
	return -1;			//返回无效值
}

//定时器的初始化,并开启计时
void Timer0_init(){
    
    
	TMOD = 0x01; //定时选择模式一 
	TF0 = 1;	 //溢出标志位 
	TR0 = 1;	 //启动定时器 
	TH0=0xFC;	 //定时器高八位 
	TL0=0x17;	 //定时器低八位 
	ET0=1;		 //51单片机的定时器0允许中断
	EA=1;		 //总中断开关 
	PT0=0;		 //中断优先级 
}

//温度感应初始化
void Init_DS18B20(void)
{
    
    
	uchar x=0;
	DQ = 1;    //拉高总线,等待
 	Delay_xms(8);
 	DQ = 0;    //单片机将DQ拉低
 	Delay_xms(80); //精确延时 大于 480us
 	DQ = 1;    //拉高总线,等待
 	Delay_xms(10);
 	x=DQ;      //稍做延时后 如果x=0则初始化成功 x=1则初始化失败
 	Delay_xms(5);
 }

 uchar ReadOneChar(void)	// DS18B20读一个字节
{
    
    
	uchar i=0;
	uchar dat = 0;
	for (i=8;i>0;i--)
 	{
    
    
  		DQ = 0; // 给脉冲信号
  		dat>>=1;   //右移一位
  		DQ = 1; // 给脉冲信号,主机在读时隙期间必须释放总线
  		if(DQ)
   		dat|=0x80;//补最高位为1
  		Delay_xms(5);
 	}
 	return(dat);
}
 
 
/*DS18B20写一个字节*/
void WriteOneChar(uchar dat) //DS18B20写一个字节
{
    
    
 	uchar i=0;
 	for (i=8; i>0; i--)
 	{
    
    
  		DQ = 0;
  		DQ = dat&0x01;//取最低位
  		Delay_xms(5);
  		DQ = 1;
  		dat>>=1;//左移
 	}
	Delay_xms(5);
}
 

/*DS18B20读取温度*/
uint ReadTemperature(void) //DS18B20读取温度
{
    
    
	uchar a=0;
	uint b=0;
	uint t=0;
	Init_DS18B20();//DS18B20初始化
	WriteOneChar(0xCC); // 跳过读序号列号的操作
	WriteOneChar(0x44); // 启动温度转换
	Delay_xms(200);       //延时以求信号的稳定
	Init_DS18B20();    //DS18B20再次初始化
	WriteOneChar(0xCC); //跳过读序号列号的操作 
	WriteOneChar(0xBE); //读取温度寄存器等(共可读9个寄存器) 前两个就是温度
	a=ReadOneChar();   //低位
	b=ReadOneChar();   //高位
	b<<=8;  //b左移8位
	t=a+b;  //把a与b结合,放在16位的t中   
	return(t);
}

//控制LCD写时序
void LCD_en_write(void)       
{
    
    
    CS=1;//高电平激活,使能信号打开 
    Delay_xus(20);
    CS=0;//关闭使能信号   
	//Delay_xus(200);	//每个单元字符显示的时间间隔
}
//写指令函数,控制显示位置
void Write_Instruction(uchar command)
{
    
    
  RS=0;//数据选择(高电位位置的选择)
  RW=0;
  LCDDATA=command;
  LCD_en_write();//写入指令数据
}

//写数据函数
void Write_Data(uchar Wdata)
{
    
    
  RS=1;
  RW=0;
  LCDDATA=Wdata;
  LCD_en_write();//写入数据
}

//初始地址设置函数
void LCD_SET_XY(uchar Y,uchar X)
{
    
    
  uchar address;
  if(Y==0)
    address=0x80+X;//Y=0,表示在第一行显示,地址基数为0x80
  else 
    address=0xc0+X;//Y非0时,表时在第二行显示,地址基数为0xC0 0x80+0x40
  Write_Instruction(address);//写指令,设置显示初始地址
}

//写入单片机操作(同时设置地址,以及数值)
void LCD_write_char(uchar X,uchar Y,uchar Wdata)
{
    
    
  LCD_SET_XY(X,Y);//写地址
  Write_Data(Wdata);//写入当前字符并显示
}

//清屏函数
void LCD_clear(void)
{
    
    
  Write_Instruction(0x01);//清除DDRAM的所有单元(清屏),光标移动到屏幕左上角 
  Delay_xms(5);	//等待一段时间,等待液晶传入指令到寄存器并执行 
} 

//液晶屏初始化函数
void LCD_init(void) 
{
    
    	
	Write_Instruction(0x38);	//8位总线 双行显示 5*7点阵(最常用的模式) 
	Delay_xms(15);	

	Write_Instruction(0x01);	//清屏
	Delay_xms(15);

	Write_Instruction(0x0C);	//开显示,光标、闪烁都关闭

}
//设置液晶屏初始值,LCD1602初始化显示“Welcome! My car park”
void Display_init(void)				
{
    
    
	uchar txt1[]="Welcome!";
	uchar txt2[]="My car park";
	
	for(i_=4;i_<=11;i_++){
    
    
		LCD_write_char(0,i_,txt1[i_-4]);
	}
	for(i_=3;i_<=13;i_++){
    
    
		LCD_write_char(1,i_,txt2[i_-3]);
	}
}
void Display_page0(){
    
    
	uchar table[]={
    
    "Time:"};
	uchar table1[]={
    
    "Temprature:"};
	for(i_=0;i_<5;i_++){
    
    
		LCD_write_char(0,i_,table[i_]);	
	}
	for(i_=0;i_<11;i_++){
    
    
		LCD_write_char(1,i_,table1[i_]);	
	}
}

//设置液晶初始显示,
//LCD1602显示主界面“The total is:16”
//总数量为:16 “Empt:XX”空车位:XX “Full:XX”满车位:XX
void Display_page1(void)			  
{
    
    
	uchar txt1[]="The total is:16";
	uchar txt2[]="Empt:   Full:";

	for(i_=0;i_<=14;i_++){
    
    
		LCD_write_char(0,i_,txt1[i_]);
	}
	for(i_=0;i_<=13;i_++){
    
    
		LCD_write_char(1,i_,txt2[i_]);
	}
}

//控制led灯的闪烁
void led_init(void)
{
    
    
	led_red=1;led2_green=1;
	Delay_xms(500);
	led_red=0;led2_green=0;
	Delay_xms(500);
	led_red=1;led2_green=1;
	Delay_xms(500);
	led2_green=0;
}
void main()
{
    
    
	unsigned char KeyNO = -1;			 //定义按键状态标志位
	unsigned char k;
	uchar intime;

	

	static uchar i=0,j=0;		 //i:车位使用数量 j:车位剩余数量
	Delay_xms(50);		//这里通过测试需要一个缓冲,也就是一个延迟,来保证程序的稳定
	LCD_init();   		//LCD初始化
	LCD_clear();  		//清屏 
	Display_init();		//初始化显示
	
	
	

	while(1)
	{
    
     
		
		Timer0_init();
	 	KeyNO = Keys_Scan(); //获取当前按钮设置键值
		k=KeyNO;
		if(KeyNO != -1)
		{
    
    
			
		 	for(n=0;n<16;n++){
    
    
				if(n == k){
    
    
					a[n]++;
					if (a[n] == 1)						   //该按键第一次按下,该车位车入库
					{
    
    
						i++;							//车位减一
						timeStart[n]=timer;				//开始收费的时间 
						led_init();						//指示灯闪烁指示入库成功
						temp=ReadTemperature();//读取温度值	
						temp=temp%100;	
						if(temp>20){
    
    
							buzzer=1;
							led3_red=0;
						}else{
    
    
							buzzer=0;
		 					led3_red=1;
						}			
					}
					else if (a[n] == 2)					   //该按键第二次按下,该车位车出库
					{
    
    
						a[n] = 0;							//标志复位
						i--;							//车位加一
						//timeStop[n]=timer;				//停止收费的时间 
						LCD_clear();
						//intime = timeStop[n]-timeStart[n];
						intime = timer - timeStart[n];//获取停的时间 
						Display_page0();	
						LCD_write_char(0,13,intime/10+'0');						 //在LCD1602上显示已停车位数量的十位
						LCD_write_char(0,14,intime%10+'0');
						LCD_write_char(1,13,temp/10+'0');					
						LCD_write_char(1,14,temp%10+'0');
						Delay_xms(50);
						
						
						led_init();						//指示灯闪烁指示出库成功
					}
					break;
				}
			} 
			if(i==16) {
    
    led_red=0;led2_green=1;}					//如果车位停满了,则红灯常亮,绿灯熄灭
			else{
    
    led_red=1;led2_green=0;}						//如果车位还有空余,则绿灯常量,红灯熄灭
			LCD_clear();										//LCD1602清屏
													 
			Display_page1();									 //显示界面一
																//注意这里需要+‘0’,否则无法显示
			LCD_write_char(1,13,i/10+'0');						 //在LCD1602上显示已停车位数量的十位
			LCD_write_char(1,14,i%10+'0');						 //在LCD1602上显示已停车位数量的个位
			j=16-i;												 //计算剩余车位
			LCD_write_char(1,5,j/10+'0');						 //在LCD1602上显示剩余车位数量的十位
			LCD_write_char(1,6,j%10+'0');						 //在LCD1602上显示剩余车位数量的个位

				 
		}
	}
}

//定时器中断 
void Timer0_routine() interrupt 1
{
    
    
	TH0=0xD8;
	TL0=0xEF;
	timeCount++;
	if(timeCount>=10000){
    
    
		timeCount=0;
		timer++;
	}
} 

附上部分资料:在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

最后感谢小组内各个成员的分工与配合!
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/m0_45311187/article/details/121158724
今日推荐