蓝桥杯单片机第八届初赛程序设计——“电子钟程序设计与调试”设计任务书

程序设计流程

  • 综述
    • 模板搭建
    • 程序设计
      • ds1302和ds18b20
      • 上升沿按键
      • 系统设计

综述

第八届初赛赛题除了基础的独立按键、数码管显示、继电器和蜂鸣器的控制、LED灯的控制以外,难度增加的部分体现在ds18b20和ds1302的调用。

本解析不代表标准答案或官方答案,仅做分享。若有不足或是更好的写法,望在评论区进行指正!

模板搭建

基础的功能:
1、独立按键
2、数码管显示

可以独立于赛题,提前写好,适用于各类赛题,仅做修改即可。

模板部分代码与解释在第三届赛题分享中 模板代码

程序设计

ds1302和ds18b20

ds1302的调用参考第四届赛题 链接
ds18b20的调用参考第五届赛题 链接

上升沿按键

第八届赛题要求,在时钟显示模式下,按下S4键显示温度界面,而松开时恢复时钟显示。
(按键默认高电平,当输入电平为0时为按键被按下)
实际上这里要求对按键代码进行一定修改,因为很多朋友习惯的按键写法各不相同,如果习惯下降沿开关写法的朋友这个时候可能要进行调整。但我在第三届的赛题解析中就声明了我的模板中选择上升沿按键的原因。所以这个地方我们无需进行修改。
开的两个数组——keyPressFlag[i]的值为1时,表示该按键被按下。keyPress[i]的值为1时,表示该按键经历了被按下与松开的一个过程。所以当keyPressFlag[i]的值为1时显示温度界面,keyPress[i]的值被清零时回到时钟显示界面。

代码:

void keyScan(){
	uchar i;
	for(i = 0; i < 4; i ++) keyPress[i] = 0;
	if((P3 & 0x0f) != 0x0f){
		Delay5ms();
		if((P3 & 0x0f) != 0x0f){
			switch(P3 & 0x0f){
				case 0x0e:keyPressFlag[0] = 1;break;
				case 0x0d:keyPressFlag[1] = 1;break;
				case 0x0b:keyPressFlag[2] = 1;break;
				case 0x07:keyPressFlag[3] = 1;break;
			}
		}
	}
	for(i = 0; i < 4; i ++){
		if(keyPressFlag[i] != 0){
			if((P3 & 0x0f) == 0x0f){
				keyPress[i] = 1;
				keyPressFlag[i] = 0;
			}
		}
	}
}

系统设计

在系统设计的时候,尽量避免对P2的重复操作。第三届系统设计示例

此题的系统设计可以理解为 时钟显示、时钟设置、闹钟设置 三种模式间的切换。
难点在于闹钟被触发之后的操作。

主函数代码:

#include 
#include 
#include 
#include 

#define uchar unsigned char

uchar keyPress[4] = {0, 0, 0, 0};
uchar keyPressFlag[4] = {0, 0, 0, 0};

uchar code shapeOfNum[12] = {0xc0, 0xf9, 0xa4, 0xb0, 0x99, 0x92, 0x82, 0xf8, 0x80, 0x90, 0xbf, 0xc6};
uchar numGrp[8] = {11, 0, 5, 0, 0, 0, 0, 0};

uchar oriTime[7] = {50, 59, 23, 1, 1, 1, 1};
uchar nowTime[7] = {0, 0, 0, 0, 0, 0, 0};
uchar alarmTime[7] = {0, 0, 0, 1, 1, 1, 1};

int count = 0, count_alarm = 0;
uchar num = 0, alarm = 0, sec = 0, L1 = 0;

void Delay1ms(){
	unsigned char i, j;

	_nop_();
	_nop_();
	_nop_();
	i = 11;
	j = 190;
	do
	{
		while (--j);
	} while (--i);
}

void Delay5ms(){
	unsigned char i, j;

	i = 54;
	j = 199;
	do
	{
		while (--j);
	} while (--i);
}

void openP2(uchar num){
	P2 &= 0x1f;
	P2 |= (num << 5);
}


void showNum(){
	uchar i;
	for(i = 0; i < 8; i ++){
		if(numGrp[i] != 12){
			openP2(6);P0 = (0x01 << i);
			openP2(7);P0 = shapeOfNum[numGrp[i]];
			Delay1ms();
		}
	}
	openP2(6);P0 = 0x00;
}

void keyScan(){
	uchar i;
	for(i = 0; i < 4; i ++) keyPress[i] = 0;
	if((P3 & 0x0f) != 0x0f){
		Delay5ms();
		if((P3 & 0x0f) != 0x0f){
			switch(P3 & 0x0f){
				case 0x0e:keyPressFlag[0] = 1;break;
				case 0x0d:keyPressFlag[1] = 1;break;
				case 0x0b:keyPressFlag[2] = 1;break;
				case 0x07:keyPressFlag[3] = 1;break;
			}
		}
	}
	for(i = 0; i < 4; i ++){
		if(keyPressFlag[i] != 0){
			if((P3 & 0x0f) == 0x0f){
				keyPress[i] = 1;
				keyPressFlag[i] = 0;
			}
		}
	}
}

void writeTime(){
	uchar i, dat, add = 0x80;
	for(i = 0; i < 7; i ++){
		dat = ((oriTime[i] / 10) << 4) | (oriTime[i] % 10);
		Write_Ds1302(add + (i * 2),dat);
	}
}

void readTime(){
	uchar i, dat, add = 0x81;
	for(i = 0; i < 7; i ++){
		dat = Read_Ds1302 (add + (i * 2));
		nowTime[i] = (dat >> 4) * 10 + (dat & 0x0f);
	}
}


void Timer0Init(void){
	AUXR |= 0x80;		//定时器时钟1T模式
	TMOD &= 0xF0;		//设置定时器模式
	TL0 = 0xCD;		//设置定时初值
	TH0 = 0xD4;		//设置定时初值
	TF0 = 0;		//清除TF0标志
	TR0 = 1;		//定时器0开始计时
}

void timer0() interrupt 1{
	if(count == 999){
		count = 0;
		num = !num;
		sec ++;
	}
	if(count_alarm == 199){
		count_alarm = 0;
		alarm = !alarm;
	}
	count ++;
	count_alarm ++;
}

uchar alarmJudge(){
	if((nowTime[2] == alarmTime[2]) && (nowTime[1] == alarmTime[1]) && (nowTime[0] == alarmTime[0]))
		return 1;
	else
		return 0;
}

uchar getTemp(){
	uchar high, low;
	init_ds18b20();
	Write_DS18B20(0xcc);
	Write_DS18B20(0x44);
	Delay_OneWire(20);
	
	init_ds18b20();
	Write_DS18B20(0xcc);
	Write_DS18B20(0xbe);
	low = Read_DS18B20();
	high = Read_DS18B20();
	
	return ((high << 4) | (low >> 4));
}

void main(){
	uchar mod = 0, preMod = 1;
	uchar p = 0, i;
	uchar ala = 0, preAla = 0;
	uchar temp;
	P2 = 0xa0;P0 = 0x00;
	P2 = 0x80;P0 = 0xff;
	Timer0Init();
	EA = 1;ET0 = 0;
	getTemp();
	writeTime();
	while(1){
		keyScan();
		
		if(mod == 0){ //mod为0时表示时钟显示模式
			if(preMod == 1){
				ET0 = 0;
				preMod = 0;
			}
			else if(preMod == 2){
				ET0 = 0;
				preMod = 0;
			}
			readTime();
			temp = getTemp();
			
			if(keyPressFlag[3] == 1){
				//数码管显示
				numGrp[0] = 12;
				numGrp[1] = 12;
				numGrp[2] = 12;
				numGrp[3] = 12;
				numGrp[4] = 12;
				numGrp[5] = temp / 10;
				numGrp[6] = temp % 10;
				numGrp[7] = 11;
			}
			else{
				//数码管显示
				numGrp[0] = nowTime[2] / 10;
				numGrp[1] = nowTime[2] % 10;
				numGrp[2] = 10;
				numGrp[3] = nowTime[1] / 10;
				numGrp[4] = nowTime[1] % 10;
				numGrp[5] = 10;
				numGrp[6] = nowTime[0] / 10;
				numGrp[7] = nowTime[0] % 10;
			}
			
			if(ala == 0){
				if(preAla == 1){
					ET0 = 0;
					openP2(4);P0 = 0xff;openP2(0);
					L1 = 0;
					preAla = 0;
				}
				if(alarmJudge() == 1) ala = 1;
				if(keyPress[0] == 1){
					mod = 1;
				}
				if(keyPress[1] == 1){
					mod = 2;
				}
			}
			else{
				if(preAla == 0){
					Timer0Init();ET0 = 1;
					count = 0;count_alarm = 0;sec = 0;
					preAla = 1;
				}
				if(alarm == 0){
					if(L1 == 1){
						openP2(4);P0 = 0xff;openP2(0);
						L1 = 0;
					}
				}
				else{
					if(L1 == 0){
						openP2(4);P0 = 0xfe;openP2(0);
						L1 = 1;
					}
				}
				for(i = 0; i < 4; i ++){
					if(keyPress[i] == 1) ala = 0;
				}
				if(sec == 5){
					ala = 0;
					sec = 0;
				}
			}
			
			
		}
		else if(mod == 1){ //mod为1时表示时钟设置模式
			if(preMod == 0){
				Timer0Init();ET0 = 1;
				count = 0;count_alarm = 0;sec = 0;
				p = 0;
				preMod = 1;
			}
			
			//数码管显示
			numGrp[0] = nowTime[2] / 10;
			numGrp[1] = nowTime[2] % 10;
			numGrp[2] = 10;
			numGrp[3] = nowTime[1] / 10;
			numGrp[4] = nowTime[1] % 10;
			numGrp[5] = 10;
			numGrp[6] = nowTime[0] / 10;
			numGrp[7] = nowTime[0] % 10;
			if(num == 0){
				numGrp[p * 3] = 12;
				numGrp[p * 3 + 1] = 12;
			}
			
			if(keyPress[3] == 1){
				if(p == 0){
					nowTime[2] = (nowTime[2] + 1) % 24;
				}
				else{
					nowTime[2 - p] = (nowTime[2 - p] + 1) % 60;
				}
			}
			if(keyPress[2] == 1){
				if(p == 0){
					if(nowTime[2] == 0) nowTime[2] = 23;
					else nowTime[2] --;
				}
				else{
					if(nowTime[2 - p] == 0) nowTime[2 - p] = 59;
					else nowTime[2 - p] --;
				}
			}
			if(keyPress[0] == 1){
				if(p == 2){
					p = 0;
					for(i = 0; i < 7; i ++) oriTime[i] = nowTime[i];
					writeTime();
					mod = 0;
				}
				else p ++;
			}
		}
		else if(mod == 2){ //mod为2时表示闹钟设置模式
			if(preMod == 0){
				Timer0Init();ET0 = 1;
				count = 0;count_alarm = 0;sec = 0;
				p = 0;
				preMod = 2;
			}
			
			//数码管显示
			numGrp[0] = alarmTime[2] / 10;
			numGrp[1] = alarmTime[2] % 10;
			numGrp[2] = 10;
			numGrp[3] = alarmTime[1] / 10;
			numGrp[4] = alarmTime[1] % 10;
			numGrp[5] = 10;
			numGrp[6] = alarmTime[0] / 10;
			numGrp[7] = alarmTime[0] % 10;
			if(num == 0){
				numGrp[p * 3] = 12;
				numGrp[p * 3 + 1] = 12;
			}
			
			if(keyPress[3] == 1){
				if(p == 0){
					alarmTime[2] = (alarmTime[2] + 1) % 24;
				}
				else{
					alarmTime[2 - p] = (alarmTime[2 - p] + 1) % 60;
				}
			}
			if(keyPress[2] == 1){
				if(p == 0){
					if(alarmTime[2] == 0) alarmTime[2] = 23;
					else alarmTime[2] --;
				}
				else{
					if(alarmTime[2 - p] == 0) alarmTime[2 - p] = 59;
					else alarmTime[2 - p] --;
				}
			}
			if(keyPress[1] == 1){
				if(p == 2){
					p = 0;
					mod = 0;
				}
				else p ++;
			}			
		}
		showNum();
	}
}

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