复试项目1--蓝桥杯&电子钟

项目描述:

使用51单片机为MCU,外设模块有DS18B20、DS1302、数码管和LED灯。通过按键设置和切换时间、日期,同时具有闹钟和温度检测功能。

责任描述:

负责编写并调试代码,并负责硬件电路的焊接,电路焊接完成后对电路的各个外设模块分别进行调试,然后系统地调试代码并下载到51单片机中,直到完成整个功能。

 

一、硬件框图:

                              复试项目1--蓝桥杯&电子钟_第1张图片

 

二、功能描述:

1、初始化

(1)关闭蜂鸣器、继电器等无关外设;

(2)设备初始化时钟为23时59分50秒,闹钟提醒时间0时0分0秒。

2、显示功能

(1)时间显示格式

(2)温度显示格式

3、按键功能

(1)按键S7定义为“时钟设置按键”,通过该按键可切换选择待调整的时、分、秒,当前选择的显示单元以1秒为间隔亮灭,时、分、秒的调整需注意数据的边界属性。

复试项目1--蓝桥杯&电子钟_第2张图片

(2)按键S6定义为“闹钟设置”按键,通过该按键可进入闹钟时间设置功能,数码管显示当前设置的闹钟时间。

复试项目1--蓝桥杯&电子钟_第3张图片

(3)按键S5定义为“加”按键,在“时钟设置”或“闹钟设置”状态下,每次按下当前选择的单元(时、分或秒)增加1个单位。

(4)按键S4定义为“减”按键,在“时钟设置”或“闹钟设置”状态下,每次按下当前选择的单元(时、分或秒)减少1个单位。

(5)按键功能说明:

按键S4、S5的“加”、“减”功能只在“时钟设置”或“闹钟设置”状态下有效;

在“时钟显示”状态下,按下S4按键,显示温度数据,松下按键,返回“时钟显示”界面。

4、闹钟提醒功能

(1)指示灯L1以0.2秒为间隔闪烁,持续5秒钟;

(2)闹钟提示状态,按下任意按键,关闭闪烁提示功能。

 

三、分析以及解决方案

在所有的分析开始之前,先来说说本设计所用的底层芯片,分别是DS1302和DS18B20,看看两者的用法。

1、DS1302

(1)自己懒得总结,找了篇好文章。。。       ==》DS1302总结

(2)关于DS1302是否为SPI接口还是IIC接口   ==》接口方式

(3)初始化时间

2、DS18B20

关于DS18B20,又找了几篇总结文章。。。

==》DS18B20基本操作

==》DS18B20进阶操作

==》DS18B20详细原理

3、操作分析

(1)关于通过S7按键可切换选择待调整的时、分、秒,当前选择的显示单元以1秒为间隔亮灭,时、分、秒的调整需注意数据的边界属性

复试项目1--蓝桥杯&电子钟_第4张图片

运用标志位,就可以让按键具有设置时分秒的功能。

 

                          复试项目1--蓝桥杯&电子钟_第5张图片

由于当初始化时间设置完成后,时间就会1秒1秒地走,以秒为依据,将秒除以2,如果能整除,就显示时、分或秒;如果不能整除,就让数码管熄灭。这样看起来,当前选择的单元以1秒为间隔亮灭。

 

(2)关于通过S6按键设置闹钟

            复试项目1--蓝桥杯&电子钟_第6张图片

与设置时钟类似,这里要特别注意一下标志位的设置。

 

(3)关于S5按键“加”,S4按键“减”

首先要注意这个问题,就是在时间设置上,准备两个数组,一个数组用来初始化时间,一个数组用来设置时间。

                              复试项目1--蓝桥杯&电子钟_第7张图片

以加为例,要注意时间设置的边界值,另外,当时间设置好后,注意初始化。

 

(4)在“时钟显示”状态下,按下S4按键,显示温度数据,松下按键,返回“时钟显示”界面。

这句话该怎么理解呢,这里涉及到一个长按键的思想

                                                 

                          复试项目1--蓝桥杯&电子钟_第8张图片

                                        复试项目1--蓝桥杯&电子钟_第9张图片

                      从代码可知,长按键的思想就是先设置一个阈值,也就是 timestr[ ] 里面设置的1000,然后再设置一个因按键而改变的变量,也就是这里的 keydowntime[ ], 当按键按下后,keydowntime[ ] 一次增加200,如果 keydowntime[ ] 里面的数值没有超过设置的阈值1000,那么就执行按键的动作;如果   keydowntime[ ]   里面的数值超过设置的阈值1000,那么从超过阈值那刻开始,按键的动作照样执行,阈值也开始增加,但是阈值增加速度远远小于设置的变量的增加速度,这样,因按键产生的动作也会一直执行。

(5)细节问题

                                                                   复试项目1--蓝桥杯&电子钟_第10张图片

DS1302输出数据为十六进制,要转化为十进制。

 

用上文来记叙当时刚进实验室考核所做的实物-电子钟,以及19年参加蓝桥杯所准备的题目-电子钟。

下面附加上蓝桥杯整个源代码:

                                                            复试项目1--蓝桥杯&电子钟_第11张图片

main.c代码:

#include "system.h"
#include "seg.h"
#include "key.h"
#include "ds18b20.h"
#include "ds1302.h"

extern u8 yi,er,san,si,wu,liu,qi,ba,time[7],set=0;
extern bit clock_set=0;
extern bit clock_show=1;	//时钟显示标志位
extern bit alarm_show=0;	//闹钟显示标志位
extern u8 alarm_set=0;	//闹钟设置时分秒标志位
u8 alarm[7];	//闹钟设置
bit led1=0;		//提示闹钟的时间到了
bit led_shanshuo=0;	//led闪烁
bit led_flag=0;	//限制指示灯持续5秒后的其他动作
bit wendu_flag=0;	//温度读取标志位
bit wendu_show=0;	//温度显示标志位

u8 temperature;

void Timer0Init(void)		//2毫秒@11.0592MHz
{
	AUXR |= 0x80;		//定时器时钟1T模式
	TMOD &= 0xF0;		//设置定时器模式
	TL0 = 0x9A;		//设置定时初值
	TH0 = 0xA9;		//设置定时初值
	TF0 = 0;		//清除TF0标志
	TR0 = 1;		//定时器0开始计时
	EA=1;
	ET0=1;
}


void main()
{
	All_Init();
	Timer0Init();
	Ds1302_Init();
	while(1)
	{
		ledshow();
		keydriver();
		readtime();
		if(wendu_flag==1)
		{
			wendu_flag=0;
			temperature=temperature_change();
		}
		
		if(time[2]==alarm[2] && time[1]==alarm[1] && time[0]==alarm[0])
		{
			if(led_flag==0)	//该标志位的作用是放置闹钟过了5秒之后还有其他的动作
			{
				led1=1;
			}
		}
		
		if(clock_show==1 && wendu_show==0)
		{
		if(clock_set==0)
		{
			yi=time[2]/10;er=time[2]%10;san=10;
			si=time[1]/10;wu=time[1]%10;liu=10;
			qi=time[0]/10;ba=time[0]%10;
		}
		
		else if(clock_set==1)
		{
			if(set==0)
			{
				if(time[0]%2 == 0)
				{
					yi=time[2]/10;er=time[2]%10;san=10;
					si=time[1]/10;wu=time[1]%10;liu=10;
					qi=time[0]/10;ba=time[0]%10;
				}
				else if(time[0]%2 != 0)
				{
					yi=11;er=11;san=10;
					si=time[1]/10;wu=time[1]%10;liu=10;
					qi=time[0]/10;ba=time[0]%10;
				}
			}
			
			else if(set==1)
			{
				if(time[0]%2 == 0)
				{
					yi=time[2]/10;er=time[2]%10;san=10;
					si=time[1]/10;wu=time[1]%10;liu=10;
					qi=time[0]/10;ba=time[0]%10;
				}
				else if(time[0]%2 != 0)
				{
					yi=time[2]/10;er=time[2]%10;san=10;
					si=11;wu=11;liu=10;
					qi=time[0]/10;ba=time[0]%10;
				}
			}
			
			else if(set==2)
			{
				if(time[0]%2 == 0)
				{
					yi=time[2]/10;er=time[2]%10;san=10;
					si=time[1]/10;wu=time[1]%10;liu=10;
					qi=time[0]/10;ba=time[0]%10;
				}
				else if(time[0]%2 != 0)
				{
					yi=time[2]/10;er=time[2]%10;san=10;
					si=time[1]/10;wu=time[1]%10;liu=10;
					qi=11;ba=11;
				}
			}
			}
		}
		
		else if(alarm_show==1 && wendu_show==0)
		{
			if(alarm_set==1)
			{
				if(time[0]%2 == 0)
				{
					yi=alarm[2]/10;er=alarm[2]%10;san=10;
					si=alarm[1]/10;wu=alarm[1]%10;liu=10;
					qi=alarm[0]/10;ba=alarm[0]%10;
				}
				else if(time[0]%2 != 0)
				{
					yi=11;er=11;san=10;
					si=alarm[1]/10;wu=alarm[1]%10;liu=10;
					qi=alarm[0]/10;ba=alarm[0]%10;
				}
			}
			
			else if(alarm_set==2)
			{
				if(time[0]%2 == 0)
				{
					yi=alarm[2]/10;er=alarm[2]%10;san=10;
					si=alarm[1]/10;wu=alarm[1]%10;liu=10;
					qi=alarm[0]/10;ba=alarm[0]%10;
				}
				else if(time[0]%2 != 0)
				{
					yi=alarm[2]/10;er=alarm[2]%10;san=10;
					si=11;wu=11;liu=10;
					qi=alarm[0]/10;ba=alarm[0]%10;
				}
			}
			
			else if(alarm_set==3)
			{
				if(time[0]%2 == 0)
				{
					yi=alarm[2]/10;er=alarm[2]%10;san=10;
					si=alarm[1]/10;wu=alarm[1]%10;liu=10;
					qi=alarm[0]/10;ba=alarm[0]%10;
				}
				else if(time[0]%2 != 0)
				{
					yi=alarm[2]/10;er=alarm[2]%10;san=10;
					si=alarm[1]/10;wu=alarm[1]%10;liu=10;
					qi=11;ba=11;
				}
			}
		}
		
		else if(wendu_show==1)
		{
			yi=11;er=11;san=11;si=11;wu=11;
			liu=temperature/10;qi=temperature%10;ba=12;
		}
	}
}

void Timer0() interrupt 1
{
	static u16 led1_count=0,lednum_count=0;
	static wendu_count=0;
	wendu_count++;
	if(wendu_count==100)
	{
		wendu_count=0;
		wendu_flag=1;
	}
	
	else if(led1==1)
	{
		led1_count++;
		lednum_count++;
		if(led1_count==100)
		{
			led1_count=0;
			if(led_shanshuo==0)
			{
				led_shanshuo=1;
				P2=(P2&0x1f)|0x80;
				P0=0xfe;
				P2&=0x1f;
			}
			else if(led_shanshuo==1)
			{
				led_shanshuo=0;
				P2=(P2&0x1f)|0x80;
				P0=0xff;
				P2&=0x1f;
			}
			if(lednum_count==2500)
			{
				lednum_count=0;
				led_flag=1;
				led1=0;
				P2=(P2&0x1f)|0x80;
				P0=0xff;
				P2&=0x1f;
			}
		}
	}
	ledscan();
	keyscan();
}

system.c代码: 

#include"system.h"
void All_Init()
{
	P2=(P2&0x1f)|0xa0;     //关闭继电器、蜂鸣器
	P0=0x00;
	P2=(P2&0x1f)|0xe0;     //关闭数码管
	P0=0xff;
	P2=(P2&0x1f)|0x80;     //关闭LED灯
	P0=0xff;
	P2&=0x1f;
}

seg.c代码: 

#include "seg.h"

u8 yi,er,san,si,wu,liu,qi,ba;
u8 code ledchar[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0xbf,0xff,0xc6}; //0-9,-,灭,C
u8 ledbuff[]={0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff};

void ledscan()
{
	static u8 index=0;
	P2=(P2&0x1f)|0xe0;
	P0=0xff;
	P2=(P2&0x1f)|0xc0;
	P0=0x01<

key.c代码: 

#include "key.h"
#include "ds1302.h"

extern u8 yi,er,san,si,wu,liu,qi,ba;
extern bit clock_set;	//时钟设置标志位
extern bit clock_show;	//时钟显示标志位
extern bit alarm_show;	//闹钟显示标志位
extern bit led1;		//提示闹钟的时间到了
extern bit led_flag;	//限制指示灯持续5秒后的其他动作
extern bit wendu_show;
extern u8 set;	//时钟设置时分秒标志位
extern u8 alarm_set;	//闹钟设置时分秒标志位
extern u8 time[7],time_init[7];	//时钟设置的初始值以及设置值
extern u8 alarm[7];	//闹钟设置
u8 keysta[4]={1,1,1,1};
u8 keycodemap[4]={1,2,3,4};
u8 keydowntime[]={0,0,0,0};

void keydriver()
{
	u8 i;
	static u8 backup[]={1,1,1,1};
	static u8 timestr[]={1000,1000,1000,1000};
	for(i=0;i<4;i++)
	{
		if(keysta[i]!=backup[i])
		{
			if(backup[i] != 0)
			{
				keyaction(keycodemap[i]);
			}
			backup[i]=keysta[i];
		}
		
		else if(keydowntime[i]>timestr[i])
		{
			if(i==3)
			{
				keyaction(keycodemap[i]);
				timestr[i] += 4;
			}
		}
	}
}

void keyscan()
{
	u8 i;
	static u8 keybuff[]={0xff,0xff,0xff,0xff};
	keybuff[0]=(keybuff[0]<<1)|S7;
	keybuff[1]=(keybuff[1]<<1)|S6;
	keybuff[2]=(keybuff[2]<<1)|S5;
	keybuff[3]=(keybuff[3]<<1)|S4;
	for(i=0;i<4;i++)
	{
		if(keybuff[i]==0xff)
		{
			keysta[i]=1;
			keydowntime[i]=0;
			if(i==3)
			{
				wendu_show=0;
			}
		}
		else if(keybuff[i]==0x00)
		{
			keysta[i]=0;
			keydowntime[i] += 200;
		}
		else
		{}
	}
}

void keyaction(u8 keycode)
{
	if(keycode==1)
	{
		if(led1==1)	//闹钟时间到了
		{
			led1=0;
			led_flag=1;
			P2=(P2&0x1f)|0x80;
			P0=0xff;
			P2&=0x1f;
		}
		
		else if(clock_show==1)
		{
			if(clock_set==0)	//如果在非时钟设置界面,切换到时钟设置界面
			{
				clock_set=1;
			}
			else if(clock_set==1)
			{
				if(set==0)	//当前在设置小时,按一下设置分钟
				{
					set=1;
				}
				else if(set==1)	//当前在设置分钟,按一下设置秒
				{
					set=2;
				}
				else if(set==2)	//当前设置秒,按一下设置完成,且标志位指向设置小时
				{
					set=0;
					clock_set=0;
				}
			}
		}
	}
	
	if(keycode==2)
	{
		if(led1==1)	//闹钟时间到了
		{
			led1=0;
			led_flag=1;
			P2=(P2&0x1f)|0x80;
			P0=0xff;
			P2&=0x1f;
		}
		
		else if(clock_set==0)	//如果在非时钟设置界面
		{
			clock_show=0;	//时钟不显示
			alarm_show=1;	//闹钟显示
			if(alarm_set==0)
			{
				alarm_set=1;
			}
			else if(alarm_set==1)
			{
				alarm_set=2;
			}
			else if(alarm_set==2)
			{
				alarm_set=3;
			}
			else if(alarm_set==3)
			{
				alarm_set=0;
				clock_show=1;
				alarm_show=0;
			}
		}
	}
	
	if(keycode==3)
	{
		if(led1==1)	//闹钟时间到了
		{
			led1=0;
			led_flag=1;
			P2=(P2&0x1f)|0x80;
			P0=0xff;
			P2&=0x1f;
		}
		
		else if(clock_show==1)	//在时钟显示界面
		{
			if(clock_set == 1)
			{
				if(set == 0)
				{
					time[2]++;
					if(time[2] == 24)
					{
						time[2]=23;
					}
					time_init[2]=time[2];
					time_init[2]=time[2];
					time_init[2]=time[2];
					Ds1302_Init();
				}
			
			else if(set == 1)
			{
				time[1]++;
				if(time[1] == 60)
				{
					time[1]=59;
				}
				time_init[1]=time[1];
				time_init[1]=time[1];
				time_init[1]=time[1];
				Ds1302_Init();
			}
			
			else if(set == 2)
			{
				time[0]++;
				if(time[0] == 60)
				{
					time[2] = 59;
				}
				time_init[0]=time[0];
				time_init[0]=time[0];
				time_init[0]=time[0];
				Ds1302_Init();
			}
		}
	}
		else if(alarm_show==1)	//在闹钟显示界面
		{
			if(alarm_set==1)
			{
				alarm[2]++;
				if(alarm[2]==24)
				{
					alarm[2]=23;
				}
			}
			
			else if(alarm_set==2)
			{
				alarm[1]++;
				if(alarm[1]==60)
				{
					alarm[1]=59;
				}
			}
			
			else if(alarm_set==3)
			{
				alarm[0]++;
				if(alarm[0]==60)
				{
					alarm[2]=59;
				}
			}
		}
}
	
	if(keycode == 4)
	{
		if(led1==1)	//闹钟时间到了
		{
			led1=0;
			led_flag=1;
			P2=(P2&0x1f)|0x80;
			P0=0xff;
			P2&=0x1f;
		}
		
		if(clock_set==0 && alarm_set==0)
		{
			wendu_show=1;
		}
		
		else if(clock_show==1)
		{
			if(clock_set == 1)
			{
				if(set == 0)
				{
					if(time[2] > 0)
					{
						time[2]--;
					}
					time_init[2]=time[2];
					time_init[2]=time[2];
					time_init[2]=time[2];
					Ds1302_Init();
				}
			
				else if(set == 1)
				{
					if(time[1] > 0)
					{
						time[1]--;
					}
					time_init[1]=time[1];
					time_init[1]=time[1];
					time_init[1]=time[1];
					Ds1302_Init();
				}
			
			else if(set == 2)
			{
				if(time[0] > 0)
				{
					time[0]--;
				}
				time_init[0]=time[0];
				time_init[0]=time[0];
				time_init[0]=time[0];
				Ds1302_Init();
			}
		}
	}
		
	else if(alarm_show==1)
	{
		if(alarm_set == 1)
		{
			if(alarm[2] > 0)
			{
				alarm[2]--;
			}
		}
			
		else if(alarm_set == 2)
		{
			if(alarm[1] > 0)
			{
				alarm[1]--;
			}
		}
			
		else if(alarm_set == 3)
		{
			if(alarm[0] > 0)
			{
				alarm[0]--;
			}
		}
	}
}
}

ds1302.c代码: 

 #include "ds1302.h"

u8 time_init[]={50,59,23,20,3,2,18}; //秒,分钟,小时,日,月,星期,年
u8 time[7];

void Ds1302_Writebyte(u8 dat)
{
	u8 i;
	for(i=0;i<8;i++)
	{
		SCLK=0;
		SDA=dat&0x01;
		SCLK=1;
		dat>>=1;
	}
}

void Ds1302_Write(u8 add,u8 dat)
{
	CE=0;
	SCLK=0;
	CE=1;
	Ds1302_Writebyte(add);
	dat=((dat/10)<<4)|(dat%10);  //把十进制数转化为二进制,将其写入
	Ds1302_Writebyte(dat);
}

u8 Ds1302_Read(u8 add)
{
	u8 i,dat,dat1,dat2;
	CE=0;
	SCLK=0;
	CE=1;
	Ds1302_Writebyte(add);
	for(i=0;i<8;i++)
	{
		SCLK=0;
		dat>>=1;  //dat从高位开始读起
		if(SDA)
		{
			dat|=0x80;
		}
		SCLK=1;
	}
	SDA=0;
	dat1=dat/16;
	dat2=dat%16;
	dat=dat1*10+dat2;
	return dat;
}

void Ds1302_Init()
{
	u8 i,add=0x80;
	Ds1302_Write(0x8e,0x00);   //关闭写保护
	for(i=0;i<7;i++)
	{
		Ds1302_Write(add,time_init[i]);
		add+=2;
	}
	Ds1302_Write(0x8e,0x80);
}

void readtime()
{
	u8 i,add=0x81;
	Ds1302_Write(0x8e,0x00);
	for(i=0;i<7;i++)
	{
		time[i]=Ds1302_Read(add);
		add+=2;
	}
	Ds1302_Write(0x8e,0x00);
}

ds18b20.c代码: 

#include "ds18b20.h"

void Delay100us()		//@11.0592MHz
{
	unsigned char i, j;

	_nop_();
	_nop_();
	i = 2;
	j = 15;
	do
	{
		while (--j);
	} while (--i);
}

void Delay500us()		//@11.0592MHz
{
	unsigned char i, j;

	_nop_();
	_nop_();
	i = 6;
	j = 93;
	do
	{
		while (--j);
	} while (--i);
}

void Ds18b20_Init()
{
	DQ=0;
	Delay500us();
	DQ=1;
	Delay500us();
}

void Ds18b20_Write(u8 dat)
{
	u8 i;
	for(i=0;i<8;i++)
	{
		DQ=0;
		DQ=dat&0x01;
		Delay100us();
		dat>>=1;
		DQ=1;
	}
}

u8 Ds18b20_Read()
{
	u8 i,dat;
	for(i=0;i<8;i++)
	{
		DQ=0;
		dat>>=1;
		DQ=1;
		if(DQ==1)
		{
			dat=dat|0x80;
		}
		Delay100us();
	}
	return dat;
}

u8 temperature_change()
{
	u8 high,lower,temp;
	Ds18b20_Init();
	Ds18b20_Write(0xcc);  //允许总线控制器不用提供64位ROM编码就使用储存器操作命令,
	                      //在单点总线情况下可以节约时间。
	Ds18b20_Write(0x44);  //启动一次温度转换而无需其他数据
	Ds18b20_Init();
	Ds18b20_Write(0xcc);
	Ds18b20_Write(0xbe);  //读取暂存器的内容
	lower=Ds18b20_Read();
	high=Ds18b20_read();
	temp=(high<<4)|(lower>>4);
	return temp;
}

 system.h代码:

#ifndef __SYSTEM_H
#define __SYSTEM_H

#include
#include
typedef unsigned int u16;
typedef unsigned char u8;
void All_Init();

#endif

seg.h代码: 

#ifndef __SEG_H
#define __SEG_H

#include "system.h"

void ledscan();
void ledshow();

#endif

key.h代码:

#ifndef __KEY_H
#define __KEY_H

#include "system.h"

sbit S7=P3^0;
sbit S6=P3^1;
sbit S5=P3^2;
sbit S4=P3^3;

void keydriver();
void keyscan();
void keyaction(u8 keycode);

#endif

ds1302.h代码: 

#ifndef __DS1302_H
#define __DS1302_H

#include "system.h"
sbit SCLK=P1^7;
sbit SDA=P2^3;
sbit CE=P1^3;

void Ds1302_Writebyte(u8 dat);
void Ds1302_Write(u8 add,u8 dat);
u8 Ds1302_Read(u8 add);
void Ds1302_Init();
void readtime();

#endif

ds18b20.h代码: 

#ifndef __DS18B20_H
#define __DS18B20_H

#include "system.h"
sbit DQ=P1^4;
void Delay100us();
void Delay500us();
void Ds18b20_Init();
void Ds18b20_Write(u8 dat);
u8 Ds18b20_read();
u8 temperature_change();

#endif

 

 

你可能感兴趣的:(复试项目回忆)