蓝桥杯---第八届省赛试题-基于单片机的电子钟程序设计与调试

杂谈

经过几个小时的奋战,我终于又把蓝桥杯的第八届省赛的题给做出来了!开心!
不过呢我已经做出来几天了,只是一直没有贴在博客里。今天刚好无聊我就贴上来了!
话不多说,我们进入正题

题目

我们先来看下题目吧。

一、基本要求

1.1 使用 CT107D 单片机竞赛板,完成“电子钟”功能的程序设计与调试;
1.2 设计与调试过程中,可参考组委会提供的“资源数据包”;
1.3 Keil 工程文件以准考证号命名,完成设计后,提交完整、可编译的 Keil工程文件到服务器。

二、硬件框图

蓝桥杯---第八届省赛试题-基于单片机的电子钟程序设计与调试_第1张图片

三、功能描述

3.1 初始化

1)关闭蜂鸣器、继电器等无关外设;
2)设备初始化时钟为 23 时 59 分 50 秒,闹钟提醒时间 0 时 0 分 0 秒。

3.2 显示功能

蓝桥杯---第八届省赛试题-基于单片机的电子钟程序设计与调试_第2张图片

3.3 按键功能

1)按键 S7 定义为“时钟设置”按键,通过该按键可切换选择待调整的时、分、秒,当前选择的显示单元以 1 秒为间隔亮灭,时、分、秒的调整需注意数据边界属性。
蓝桥杯---第八届省赛试题-基于单片机的电子钟程序设计与调试_第3张图片

2)按键 S6 定义为“闹钟设置”按键,通过该按键可进入闹钟时间设置功能,数码管显示当前设定的闹钟时间。
3)按键 S5 定义为“加”按键,在“时钟设置”或“闹钟设置”状态下,每次按下该按键当前选择的单元(时、分或秒)增加 1 个单位。
4)按键 S4 定义为“减”按键,在“时钟设置”或“闹钟设置”状态下,每次按下该按键当前选择的单元(时、分或秒)减少 1 个单位。
5)按键功能说明:按键 S4、S5 的“加”、“减”功能只在“时钟设置”或“闹钟设置”状态下有效;在 “时钟显示”状态下,按下 S4 按键,显示温度数据,松开按键,返回“时钟显示”界面。

3.4 闹钟提示功能

1)指示灯 L1 以 0.2 秒为间隔闪烁,持续 5 秒钟;
2)闹钟提示状态下,按下任意按键,关闭闪烁提示功能。

思路

在这里我大致说一下我的思路。

1、初始化

这个很简单的。时间显示23:59:50
这里时间芯片用的DS13B02,这款芯片我就不用多说了,大家都知道怎么个用法。
时钟的初始化我们需要把23:59:50先写入DS18B20,然后才能正常的从所设置的时间开始显示。
然后就是闹钟的初始化,我们这里直接在定义闹钟的变量的时候就直接给他赋值为0。

2、温度显示

我们在这里用到的温度芯片是DS18B20,关于这款芯片我就不多说了,请大家看我的下面这篇文章。

赶紧点我吧!

3、按键检测

按键识别我这里用到的是状态机扫描。关于状态机扫描的话大家也可以参考我下面这篇文章

赶快点我阅读吧

4、数码管显示

数码管显示,我相信在座各位都掌握得如火纯情了。我也就不多说了!

难点汇总

在这里我分享一下我在设计、和码代码的过程中所遇到的难点。

1、状态机扫描

由于我也很少用状态机扫描来搞键盘,都是最近才用起来的,用过几次就感觉领悟了其中的奥秘了。下面我说一下几个注意事项。

Step.1

我们在判断状态的时候一定要判断完!不要写到一半就开跑了。并且,该清零的时候就要清零。

Step.2

把键盘的程序放定时器中断里,每隔10ms执行一次。

2、温度读取

对于温度的读取。这个真的是玄学问题。在我单独弄他的时候,必须把中断关了才能让他执行,不然温度读取不了,但是我放在这个大程序里却不用关中断都没问题!真的是玄学问题!

问题应该只有以上这些了,下面我就贴出来代码。有不懂得可以给我留言哟!

代码分享

在这里我分享的是主程序,其他导入的模块我就不分享了,网上都能找到的。

#include 
#include 
#include 
#include 
#include 

#define uint unsigned int
#define uchar unsigned char
	
#define smg_wei XBYTE[0xc000]
#define smg_duan XBYTE[0xe000]
#define buzz XBYTE[0xa000]
#define LED XBYTE[0x8000]

sbit S4 = P3^3;
sbit S5 = P3^2;
sbit S6 = P3^1;
sbit S7 = P3^0;
	
//数码管段码存储
uchar code duan[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0xff};
//数码管位码存储
uchar code wei[]={0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80};
//数码管显示缓存
uchar smg_count[]={0xff,0xff,0xbf,0xff,0xff,0xbf,0xff,0xff};
//时间缓存
uchar time_count[]={0x23,0x59,0x50};
//温度缓存
uchar team_count[]={0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xc6};
//调整时间数字缓存
uchar set_time_count[]={0x00,0x00,0x00};
	
uchar flag_S7 = 0,g = 0,flag_set_time = 0,flag_S6 = 0,i = 0;
uint flag_time = 0;
bit flag_alarm = 0;
uint flag_LED_time = 0;
uchar flag_LED1 = 0,flag1_alarm = 0;

//延迟1ms程序
void Delay1ms(uint t)		//@12.000MHz
{
	unsigned char i, j;
	while(t--)
	{
		i = 12;
		j = 169;
		do
		{
			while (--j);
		} while (--i);
	}
}

//定时器初始化程序
void Timer0Init(void)		//1毫秒@12.000MHz
{
	AUXR |= 0x80;		//定时器时钟1T模式
	TMOD &= 0xF0;		//设置定时器模式
	TL0 = 0x20;		//设置定时初值
	TH0 = 0xD1;		//设置定时初值
	TF0 = 0;		//清除TF0标志
	//TR0 = 1;		//定时器0开始计时
	ET0 = 1;    //开启定时器0中断
	EA = 1;     //打开总中断
}

//数码管显示
void smg_display()
{
	static uchar i = 0;
	
	smg_duan = 0xff;
	
	smg_wei = wei[i];
	smg_duan = *(smg_count + i);
	
	if(++i == 8)
		i = 0;
}

//时间取值
void read_time()
{
	uchar *p;
	p = read_ds1302();
	
	smg_count[0] = duan[(time_count[0] = *p)>>4];
	smg_count[1] = duan[time_count[0]&0x0f];
	smg_count[3] = duan[(time_count[1] = *(p + 1))>>4];
	smg_count[4] = duan[time_count[1]&0x0f];
	smg_count[6] = duan[(time_count[2] = *(p + 2))>>4];
	smg_count[7] = duan[time_count[2]&0x0f];
	smg_count[2] = smg_count[5] = 0xbf;
}

//读取当前温度值以及处理
uint flag_team = 0;
void read_team()
{
	static uchar team;
	if(flag_team >= 100)
	{
		//TR0 = 0;
		team = rd_temperature();
		//TR0 = 1;
		flag_team = 0;
	}
	smg_count[0] = smg_count[1] = smg_count[2] = smg_count[3] = smg_count[4] = 0xff;
	smg_count[7] = team_count[7];
	if(team == 85 || team == 0)
	{
		smg_count[5] = 0xbf;
		smg_count[6] = 0xbf;
		return;
	}
	smg_count[5] = team_count[5] = duan[team/10];
	smg_count[6] = team_count[6] = duan[team%10];
	
	
	//strcpy(smg_count,team_count);
}

//键盘处理程序
uchar flag2_but = 0;
void button()
{
	if(flag_alarm == 0)
	{
		static uchar flag1_but = 0;
		uchar x = P3;
		x = x & 0x0f;
		switch(flag1_but)
		{
			case 0:
				if(x != 0x0f)
				{
					flag1_but = 1;
				}
				else
				{
					//P3 = 0xff;
					flag1_but = 0;
				}
				break;
			case 1:
				if(x != 0x0f)
				{
					switch(x)
					{
						case 0x07:
							switch(flag_S7)                      //时钟设置
							{
								case 1:
									if(flag_S7)
									{
										if(time_count[0] == 0x00)
										{
											time_count[0] = 0x24;
										}
										time_count[0]--;
										if((time_count[0]&0x0f) == 0x0f)
										{
											time_count[0] &= 0xf0;
											time_count[0] |= 0x09;
										}
										
									}
									break;
								case 2:
									if(time_count[1] == 0x00)
									{
										time_count[1] = 0x60;
									}
									time_count[1]--;
									if((time_count[1]&0x0f) == 0x0f)
									{
										time_count[1] &= 0xf0;
										time_count[1] |= 0x09;
									}
									break;
								case 3:
									if(time_count[2] == 0x00)
									{
										time_count[2] = 0x60;
									}
									time_count[2]--;
									if((time_count[2]&0x0f) == 0x0f)
									{
										time_count[2] &= 0xf0;
										time_count[2] |= 0x09;
									}
							}
							switch(flag_S6)                  //闹钟设置键盘处理
							{
								case 1:
									if(flag_S6)
									{
										if(set_time_count[0] == 0x00)
										{
											set_time_count[0] = 0x24;
										}
										set_time_count[0]--;
										if((set_time_count[0]&0x0f) == 0x0f)
										{
											set_time_count[0] &= 0xf0;
											set_time_count[0] |= 0x09;
										}
										
									}
									break;
								case 2:
									if(set_time_count[1] == 0x00)
									{
										set_time_count[1] = 0x60;
									}
									set_time_count[1]--;
									if((set_time_count[1]&0x0f) == 0x0f)
									{
										set_time_count[1] &= 0xf0;
										set_time_count[1] |= 0x09;
									}
									break;
								case 3:
									if(set_time_count[2] == 0x00)
									{
										set_time_count[2] = 0x60;
									}
									set_time_count[2]--;
									if((set_time_count[1]&0x0f) == 0x0f)
									{
										set_time_count[2] &= 0xf0;
										set_time_count[2] |= 0x09;
									}
							}
							g = 4;break;
						case 0x0b:
							switch(flag_S7)
							{
								case 1:
									time_count[0]++;
									if((time_count[0]&0x0f) >= 0x0a)
									{
										time_count[0] += 0x10;
										time_count[0] &= 0xf0;
									}
									if(time_count[0] == 0x24)
										time_count[0] = 0x00;
									break;
								case 2:
									time_count[1]++;
									if((time_count[1]&0x0f) >= 0x0a)
									{
										time_count[1] += 0x10;
										time_count[1] &= 0xf0;
									}
									if(time_count[1] == 0x60)
										time_count[1] = 0x00;
									break;
								case 3:
									time_count[2]++;
									if((time_count[2]&0x0f) >= 0x0a)
									{
										time_count[2] += 0x10;
										time_count[2] &= 0xf0;
									}
									if(time_count[2] == 0x60)
										time_count[2] = 0x00;
							}
							switch(flag_S6)
							{
								case 1:
									set_time_count[0]++;
									if((set_time_count[0]&0x0f) >= 0x0a)
									{
										set_time_count[0] += 0x10;
										set_time_count[0] &= 0xf0;
									}
									if(set_time_count[0] == 0x24)
										set_time_count[0] = 0x00;
									break;
								case 2:
									set_time_count[1]++;
									if((set_time_count[1]&0x0f) >= 0x0a)
									{
										set_time_count[1] += 0x10;
										set_time_count[1] &= 0xf0;
									}
									if(set_time_count[1] == 0x60)
										set_time_count[1] = 0x00;
									break;
								case 3:
									set_time_count[2]++;
									if((set_time_count[2]&0x0f) >= 0x0a)
									{
										set_time_count[2] += 0x10;
										set_time_count[2] &= 0xf0;
									}
									if(set_time_count[2] == 0x60)
										set_time_count[2] = 0x00;
							}
							g = 5;break;
						case 0x0d:
							if(flag_S7 == 0)
							{
								g = 6;
								flag_S6++;
							}
							break;
						case 0x0e:if(flag_S6 == 0)
						{
							g = 7;
							flag_S7++;
						}
						break;
						default:g = 0;break;
					}
					flag1_but = 2;
				}
				else
					{flag1_but = 0;break;}
				case 2:
					if(x == 0x0f)
					{
						flag1_but = 0;
					}
					break;
		}
	}
	//flag2_but = 0;
}

//数码管闪烁以及调整时间
void tiao_time()
{
	static uchar cc1 = 0,cc2 = 0;
	switch(flag_S7)
	{
		case 1:
			if(flag_time <= 1000)
			{
				smg_count[0] = 0xff;
				smg_count[1] = 0xff;
			}
			if(flag_time > 1000 && flag_time < 2000)
			{
				smg_count[0] = duan[time_count[0]>>4];
				smg_count[1] = duan[time_count[0]&0x0f];
			}
			if(flag_time > 2000)
				flag_time = 0;
			break;
		case 2:
			if(cc1 == 0)
			{
				smg_count[0] = duan[time_count[0]>>4];
				smg_count[1] = duan[time_count[0]&0x0f];
				cc1++;
			}
			if(flag_time <= 1000)
			{
				smg_count[3] = 0xff;
				smg_count[4] = 0xff;
			}
			if(flag_time > 1000 && flag_time < 2000)
			{
				smg_count[3] = duan[time_count[1]>>4];
				smg_count[4] = duan[time_count[1]&0x0f];
			}
			if(flag_time > 2000)
				flag_time = 0;
			break;
		case 3:
			if(cc2 == 0)
			{
				smg_count[3] = duan[time_count[1]>>4];
				smg_count[4] = duan[time_count[1]&0x0f];
				cc2++;
			}
			if(flag_time <= 1000)
			{
				smg_count[6] = 0xff;
				smg_count[7] = 0xff;
			}
			if(flag_time > 1000 && flag_time < 2000)
			{
				smg_count[6] = duan[time_count[2]>>4];
				smg_count[7] = duan[time_count[2]&0x0f];
			}
			if(flag_time > 2000)
				flag_time = 0;
			break;
		default:
			set2_ds1302(time_count[0],time_count[1],time_count[2]);
			cc1 = cc2 = 0;
			flag_S7 = 0;
	}
}

//进入闹钟程序时闪烁程序
void set_tiao_time()
{
	static uchar cc1 = 0,cc2 = 0;
	switch(flag_S6)
	{
		case 1:
			if(flag_time <= 1000)
			{
				smg_count[0] = 0xff;
				smg_count[1] = 0xff;
			}
			if(flag_time > 1000 && flag_time < 2000)
			{
				smg_count[0] = duan[set_time_count[0]>>4];
				smg_count[1] = duan[set_time_count[0]&0x0f];
			}
			if(flag_time > 2000)
				flag_time = 0;
			break;
		case 2:
			if(cc1 == 0)
			{
				smg_count[0] = duan[set_time_count[0]>>4];
				smg_count[1] = duan[set_time_count[0]&0x0f];
				cc1++;
			}
			if(flag_time <= 1000)
			{
				smg_count[3] = 0xff;
				smg_count[4] = 0xff;
			}
			if(flag_time > 1000 && flag_time < 2000)
			{
				smg_count[3] = duan[set_time_count[1]>>4];
				smg_count[4] = duan[set_time_count[1]&0x0f];
			}
			if(flag_time > 2000)
				flag_time = 0;
			break;
		case 3:
			if(cc2 == 0)
			{
				smg_count[3] = duan[set_time_count[1]>>4];
				smg_count[4] = duan[set_time_count[1]&0x0f];
				cc2++;
			}
			if(flag_time <= 1000)
			{
				smg_count[6] = 0xff;
				smg_count[7] = 0xff;
			}
			if(flag_time > 1000 && flag_time < 2000)
			{
				smg_count[6] = duan[set_time_count[2]>>4];
				smg_count[7] = duan[set_time_count[2]&0x0f];
			}
			if(flag_time > 2000)
				flag_time = 0;
			break;
		default:
			//set2_ds1302(time_count[0],time_count[1],time_count[2]);
			flag_set_time = 0;
			g = 0;
			i = 0;
			cc1 = cc2 = 0;
			flag_S6 = 0;
	}
}

//设置闹钟程序
void alarm_clock()
{
	
	if(i == 0)
	{
		smg_count[0] = duan[set_time_count[0]>>4];
		smg_count[1] = duan[set_time_count[0]&0x0f];
		smg_count[3] = duan[set_time_count[1]>>4];
		smg_count[4] = duan[set_time_count[1]&0x0f];
		smg_count[6] = duan[set_time_count[2]>>4];
		smg_count[7] = duan[set_time_count[2]&0x0f];
		smg_count[2] = smg_count[5] = 0xbf;
		i++;
	}
	set_tiao_time();
}


void main()
{
	
	Timer0Init();
	buzz = 0x00;
	LED = 0xff;
	set_ds1302(23,59,50);
	P3 = 0xff;
	TR0 = 1;
	while(1)
	{
		if(flag_S7 == 0)
			read_time();
		if((set_time_count[0] == time_count[0]) && (set_time_count[1] == time_count[1]) && (set_time_count[2] == time_count[2]))
		{
			flag_alarm = 1;
			flag1_alarm = time_count[2];
		}
//		if(flag_alarm == 1)
//		{
//			if((S4 == 0) || (S5 == 0) || (S6 == 0) || (S7 == 0))
//			{
//			flag_alarm = 0;
//			flag_LED1 = 0;
//			flag_LED_time = 0;
//			LED = 0xff;
//			}
//		}
		if(flag_S7 != 0)
			tiao_time();
		while(g == 4 && S4 == 0 && flag_S7 == 0)
			read_team();
		while(g == 6)
		{
			flag_set_time = 1;
			while(flag_set_time)
				alarm_clock();
		}
		if((flag_alarm == 1) && (flag_LED_time <= 5000))           //(flag_alarm == 1) && (
		{
			if(flag_LED1 <= 20)
			{
				LED = 0xfe;
			}
			else
			{
				LED = 0xff;
			}
		}
	}
}

//定时器0中断服务函数
void timer0() interrupt 1
{
	static uchar flag_but = 0;
	flag_but++;
	flag_team++;
	flag_time++;
	if(flag_alarm == 1)
	{
		flag_LED1++;
		flag_LED_time++;
		if(flag_LED1 >= 41)
		{
			flag_LED1 = 0;
		}
		P3 |= 0x0f;
		if((flag_LED_time >= 5000) || ((P3 &0x0f) != 0x0f))
		{
			flag_alarm = 0;
			flag_LED1 = 0;
			flag_LED_time = 0;
			LED = 0xff;
		}
	}
	if(flag_but == 10)
	{
		P3 |= 0x0f;
		button();
		flag_but = 0;
	}
	smg_display();
}

总结

OK,分享得差不多了,来做个总结吧。这个程序我觉得是我个人一次质的飞跃。为什么呢?
因为这个程序我没有一处用到了延迟程序,这大大得提升了程序的可读性和有效代码的量。这是我很开的一件事。

最后,感谢观看。。。。。

欢迎来我的博客看看哦!
卿枫博客

你可能感兴趣的:(蓝桥杯)