蓝桥杯第十三届单片机省赛真题(IAP15F2K61S2)解析

一、题目

二、题目分析

1、难点(笔者个人认为)

(1)s17按键短按和长按的设置不同,界面不同

s17短按在参数界面需要把温度参数-1;

s17长按在时间界面需要显示分,秒界面;

所以笔者这里把两个数码管显示分两个函数

void Nixie_Show()//数码管显示函数
{
	Nixie_pos_num(1,16);
	Nixie_pos_num(3,17);
	if(flag_s12 == 0)//温度显示界面
	{
		Temp = Read_DS18B20_Temp();
		Nixie_pos_num(2,1);
		Nixie_pos_num(4,17);
		Nixie_pos_num(5,17);
		Nixie_pos_num(6,Temp/1000);
		Nixie_Dian_pos_num(7,Temp/100%10);
		Nixie_pos_num(8,Temp/10%10);
	}
	if(flag_s12 == 1)//时间显示界面
	{
		Nixie_pos_num(2,2);
		Nixie_pos_num(4,Time[2]/16);
		Nixie_pos_num(5,Time[2]%16);
		Nixie_pos_num(6,18);
		Nixie_pos_num(7,Time[1]/16);
		Nixie_pos_num(8,Time[1]%16);
	}
	if(flag_s12 == 2)//参数显示界面
	{
		Nixie_pos_num(2,3);
		Nixie_pos_num(4,17);
		Nixie_pos_num(5,17);
		Nixie_pos_num(6,17);
		Nixie_pos_num(7,Temp_C/10);
		Nixie_pos_num(8,Temp_C%10);
	}
}

void Nixie_Time_S17()//在时间显示界面下,长按s17显示界面
{
	if(flag_s12 == 1)
	{
		Read_Ds1302_Time(Time);
		Nixie_pos_num(1,16);
		Nixie_pos_num(2,2);
		Nixie_pos_num(3,17);
		Nixie_pos_num(4,Time[1]/16);
		Nixie_pos_num(5,Time[1]%16);
		Nixie_pos_num(6,18);
		Nixie_pos_num(7,Time[0]/16);
		Nixie_pos_num(8,Time[0]%16);
	}
	
}

分别显示不同的界面,避免界面冲突。当然这里也可以通过switch语句进行界面选择,读者可以自己调整

(2)出现两个不同时间产生不同状态,L1点亮,5秒熄灭,L3要0.1秒交替闪烁

这里直接使用Delay是有问题的,LED灯和数码管显示会频闪。笔者这里用到是定时器

void Timer0Init(void)		//50毫秒@12MHz
{
	TMOD = 0x01;
	TL0 = (65535 - 50000) % 256;		//设置定时初值
	TH0 = (65535 - 50000) / 256;		//设置定时初值
	TR0 = 1;		//定时器0开始计时
	EA = 1;
	ET0 = 1;
}

void Timer0Init_Time() interrupt 1
{
	TL0 = (65535 - 50000) % 256;		//设置定时初值
	TH0 = (65535 - 50000) / 256;		//设置定时初值
	count++;
	if(count % 5 == 0)//计时100ms
	{
		flag_L3 = ~flag_L3;
	}
	if(count == 100)//计时5s
	{
		flag_timer_relay = 0;
		flag_L1 = 0;
		count = 0;
	}
}

让定时器到点发起中断,产生效果

(3)、温度浮点数处理

在上一篇笔记笔者已经提到,有兴趣的读者可以到这里的四、2、第十五届蓝桥杯单片机模拟II(IAP15F2K61S2)-CSDN博客

这里就不过多阐述

三、代码(仅供参考)

1、头文件

#include <STC15F2K60S2.H>
#include <ds1302.H>
#include <onewire.H>

2、变量声明

sbit K1 = P3^5;
sbit K2 = P3^4;
sbit K3 = P3^3;
sbit K4 = P3^2;

sbit L1 = P0^0;
sbit L2 = P0^1;
sbit L3 = P0^2;
//==================数组定义===================
code unsigned char Seg_Table[] = {0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0x88,0x83,0xc6,0xa1,0x86,0x8e,0xc1,0xff,0xbf};//数码管不带小数点 16:0xc1:U 18:0xbf:-
code unsigned char Seg_Dian_Table[] = {0x40,0x79,0x24,0x30,0x19,0x12,0x02,0x78,0x00,0x10,0x08,0x03,0x46,0x21,0x06,0x0e};//数码管带小数点
unsigned char Time[3]={0x55,0x59,0x07};//秒,分,时
//==================变量定义===================
unsigned char flag_s12;//按键s12按下三种状态
unsigned char flag_s13;//按键s13按下两种状态
unsigned char flag_relay = 0;//继电器两种状态
unsigned char Temp_C = 23;//温度参数
unsigned char count;//定时器计时参数
unsigned char flag_L3;//L3灯状态
unsigned char flag_L1;//L1灯状态
unsigned char flag_timer_relay;//时间控制模式下继电器状态
unsigned int Temp;//温度变量

3、函数声明

//==================函数声明===================
void Nixie_Show();//数码管显示函数
void Scan_Key();//按键控制函数
void Nixie_Time_S17();//在时间显示界面下,长按s17显示
void Relay();//继电器控制函数
void LED();//LED灯控制函数
//=============================================

四、函数模块

1、其他函数

void delay(unsigned char i)
{
	while(i--);
}

void hc(unsigned char n)//通道选择
{
	switch(n)
	{
		case 0:
			P2 = P2 & 0x1f;
			break;
		case 4:
			P2 = (P2 & 0x1f) | 0x80;//LED
			break;
		case 5:
			P2 = (P2 & 0x1f) | 0xa0;//蜂鸣器,继电器
			break;
		case 6:
			P2 = (P2 & 0x1f) | 0xc0;//数码管位选
			break;
		case 7:
			P2 = (P2 & 0x1f) | 0xe0;//数码管段选
			break;
	}
}

void System_Init()//系统初始化
{
	hc(4);
	P0 = 0xFF;
	hc(5);
	P0 = 0x00;
	hc(0);
}

2、数码管

void Nixie_pos_num(unsigned char pos,num)//数码管(不带小数点)位置,显示数字
{
	hc(6);
	P0 = 0x01 << (pos-1);
	hc(7);
	P0 = Seg_Table[num];
	delay(500);
	P0 = 0xFF;
	hc(0);
}

void Nixie_Dian_pos_num(unsigned char pos,num)//数码管(带小数点)位置,显示数字
{
	hc(6);
	P0 = 0x01 << (pos-1);
	hc(7);
	P0 = Seg_Dian_Table[num];
	delay(500);
	P0 = 0xFF;
	hc(0);
}

void Nixie_Show()//数码管显示函数
{
	Nixie_pos_num(1,16);
	Nixie_pos_num(3,17);
	if(flag_s12 == 0)//温度显示界面
	{
		Temp = Read_DS18B20_Temp();
		Nixie_pos_num(2,1);
		Nixie_pos_num(4,17);
		Nixie_pos_num(5,17);
		Nixie_pos_num(6,Temp/1000);
		Nixie_Dian_pos_num(7,Temp/100%10);
		Nixie_pos_num(8,Temp/10%10);
	}
	if(flag_s12 == 1)//时间显示界面
	{
		Nixie_pos_num(2,2);
		Nixie_pos_num(4,Time[2]/16);
		Nixie_pos_num(5,Time[2]%16);
		Nixie_pos_num(6,18);
		Nixie_pos_num(7,Time[1]/16);
		Nixie_pos_num(8,Time[1]%16);
	}
	if(flag_s12 == 2)//参数显示界面
	{
		Nixie_pos_num(2,3);
		Nixie_pos_num(4,17);
		Nixie_pos_num(5,17);
		Nixie_pos_num(6,17);
		Nixie_pos_num(7,Temp_C/10);
		Nixie_pos_num(8,Temp_C%10);
	}
}

void Nixie_Time_S17()//在时间显示界面下,长按s17显示界面
{
	if(flag_s12 == 1)
	{
		Read_Ds1302_Time(Time);
		Nixie_pos_num(1,16);
		Nixie_pos_num(2,2);
		Nixie_pos_num(3,17);
		Nixie_pos_num(4,Time[1]/16);
		Nixie_pos_num(5,Time[1]%16);
		Nixie_pos_num(6,18);
		Nixie_pos_num(7,Time[0]/16);
		Nixie_pos_num(8,Time[0]%16);
	}
	
}

3、按键

void Scan_Key()//按键控制函数
{
	K2 = K3 = K4 = 1;K1 = 0;
	if(K3 == 0 || K4 == 0)
	{
		delay(100);
		if(K3 == 0)//s12按键按下
		{
			flag_s12 = (flag_s12 + 1) % 3;
			while(K3 == 0)
			{
				Nixie_Show();
			}
		}
		if(K4 == 0)//s13按键按下
		{
			flag_s13 = (flag_s13 + 1) % 2;
			while(K4 == 0)
			{
				Nixie_Show();
				LED();
			}
		}
	}
	if(flag_s12 == 2)//在参数设置界面关于s16,s17控制
	{
		K1 = K3 = K4 = 1;K2 = 0;
		if(K3 == 0 || K4 == 0)
		{
			delay(100);
			if(K3 == 0)//s16按键按下
			{
				Temp_C++;
				if(Temp_C >= 90)
				{
					Temp_C = 90;
				}
				while(K3 == 0)
				{
					Nixie_Show();
				}
			}
			if(K4 == 0)//s17按键按下
			{
				Temp_C--;
				if(Temp_C <= 10)
				{
					Temp_C = 10;
				}
				while(K4 == 0)
				{
					Nixie_Show();
				}
			}
		}
	}
	if(flag_s12 == 1)//在时间显示界面关于s17控制
	{
		K1 = K3 = K4 = 1;K2 = 0;
		if(K4 == 0)
		{
			delay(100);
			if(K4 == 0)
			{
				while(K4 == 0)
				{
					Nixie_Time_S17();
				}
			}
		}
	}
}

4、LED

void LED()//LED灯控制函数
{
	//L1灯控制
	if(Time[0]==0x00&&Time[1]==0x00)
	{
		if(flag_L1 == 0)
		{
			hc(4);
			L1 = 0;
			hc(0);
		}
		else
		{
			hc(4);
			L1 = 1;
			hc(0);
		}
	}
	else
	{
		hc(4);
		L1 = 1;
		hc(0);
	}
	//L2灯控制
	if(flag_s13 == 0)
	{
		hc(4);
		L2 = 0;
		hc(0);
	}
	else
	{
		hc(4);
		L2 = 1;
		hc(0);
	}
	//L3灯控制
	if(flag_relay == 1)//在继电器吸合状态
	{
		if(flag_L3 == 0)
		{
			hc(4);
			L3 = 0;
			hc(0);
		}
		else
		{
			hc(4);
			L3 = 1;
			hc(0);
		}
	}
	else
	{
		hc(4);
		L3 = 1;
		hc(0);
	}
}

5、继电器

void Relay()//继电器控制函数
{
	if(flag_s13 == 0)//温度控制模式
	{
		if(Temp>Temp_C*100)
		{
			hc(5);
			P0 = 0x10;
			hc(0);
			flag_relay = 1;
		}
		else
		{
			hc(5);
			P0 = 0x00;
			hc(0);
			flag_relay = 0;
		}
	}
	if(flag_s13 == 1)//时间控制模式
	{
		if(Time[0]==0x00&&Time[1]==0x00)
		{
			hc(5);
			P0 = 0x10;
			hc(0);
			flag_relay = 1;
			flag_timer_relay = 1;
		}
		else
		{
			hc(5);
			P0 = 0x00;
			hc(0);
			flag_relay = 0;
		}
	}
}

6、main

void main()
{
	System_Init();
	Timer0Init();
	Temp = Read_DS18B20_Temp();
	Write_Ds1302_Time(Time);
	while(1)
	{
		Read_Ds1302_Time(Time);
		Temp = Read_DS18B20_Temp();
		Nixie_Show();
		Scan_Key();
		LED();
		Relay();
	}
}

7、onewrie

unsigned int Read_DS18B20_Temp()
{
	unsigned char LSB,MSB;
	unsigned int Temp;
	init_ds18b20();
	Write_DS18B20(0xcc);
	Write_DS18B20(0x44);
	init_ds18b20();
	Write_DS18B20(0xcc);
	Write_DS18B20(0xbe);
	
	LSB = Read_DS18B20();
	MSB = Read_DS18B20();
	
	Temp = (MSB << 8) | LSB;
	Temp = Temp >> 4;
	Temp = Temp * 100;
	Temp =  Temp + (LSB & 0x0f) * 0.0625 * 100;
	return Temp;
}

8、ds1302

code unsigned char Write_Time[3]={0x80,0x82,0x84};
code unsigned char Read_Time[3]={0x81,0x83,0x85};
void Write_Ds1302_Time(unsigned char *time)
{
	unsigned char i;
	Write_Ds1302_Byte(0x8e,0x00);
	for(i = 0;i < 3;i++)
	{
		Write_Ds1302_Byte(Write_Time[i],time[i]);
	}
	Write_Ds1302_Byte(0x8e,0x00);
}

void Read_Ds1302_Time(unsigned char *time)
{
	unsigned char i;
	for(i = 0;i < 3;i++)
	time[i]=Read_Ds1302_Byte(Read_Time[i]);
}

五、演示

六、总结

注意:本代码只是提供读者参考,给读者提供一个方法。

蓝桥杯第十三届单片机省赛的题难度不大,但是要处理的细节比较多,需要细心看题,认真思考。

作者:Same_chen

物联沃分享整理
物联沃-IOTWORD物联网 » 蓝桥杯第十三届单片机省赛真题(IAP15F2K61S2)解析

发表评论