蓝桥杯单片机赛道第十三届省赛真题Ⅰ

难点在于:

        1.长按显示分秒,松开恢复时分

        2.定义一个变量同步继电器状态

代码如下

unsigned char Time_Sub_Monde = 0;	//0-显示时分,1-显示分秒

/* 在时间显示界面下,S17长按显示分、秒,短按显示时、分 */
		if(Seg_Disp_Mode == 1)	//在时间显示界面下有效
		{
			if(Key_Down == 17)	//产生下降沿
				Key_Flag = 1;	//拉高标志位,系统开始计时
			
			//在500毫秒以内,短按处理
			if(Key_Time_600ms < 500 && Key_Up == 17)
			{
					Time_Sub_Monde = 0;	//切换子状态
					Key_Time_600ms = Key_Flag = 0;	//复位
			}
			//在500毫秒以外,长按处理
			else	
			{
				if(Key_Old == 17)	//仍按住
					Time_Sub_Monde = 1;	//显示分秒
				if(Key_Up == 17)	//识别到松开S17
					Key_Time_600ms = Key_Flag = Time_Sub_Monde = 0;	//复位
			}
		}	

/* 时间显示界面 */
		case 1:
			if(Time_Sub_Monde == 0)	//显示时分
			{
				Seg_Buf[0] = 11;	//U
				Seg_Buf[1] = Seg_Disp_Mode + 1;	//界面编号1
				Seg_Buf[3] = ucRtc[0] / 16 % 16;	//时的十位
				Seg_Buf[4] = ucRtc[0] % 16;	//时的个位
				Seg_Buf[5] = 12;	//-
				Seg_Buf[6] = ucRtc[1] / 16 % 16;	//分的十位
				Seg_Buf[7] = ucRtc[1] % 16;	//分的个位
				Seg_Point[6] = 0;	//第7位小数点不使能
			}
			else	//显示分秒
			{
				Seg_Buf[0] = 11;	//U
				Seg_Buf[1] = Seg_Disp_Mode + 1;	//界面编号1
				Seg_Buf[3] = ucRtc[1] / 16 % 16;	//分的十位
				Seg_Buf[4] = ucRtc[1] % 16;	//分的个位
				Seg_Buf[5] = 12;	//-
				Seg_Buf[6] = ucRtc[2] / 16 % 16;	//秒的十位
				Seg_Buf[7] = ucRtc[2] % 16;	//秒的个位
				Seg_Point[6] = 0;	//第7位小数点不使能
			}		
		break;

/* 继电器 */
void Beep_Disp(unsigned char enable)	 
{
	static unsigned char temp = 0x00;	
	static unsigned char temp_Old = 0xff;
	
	if(enable)
		temp |= 0x40;
	else
		temp  &= ~0x40;
	
	g_beep_status = enable;
	
	if(temp != temp_Old)
	{
		P0 = temp;
		P2 = P2 & 0x1f | 0xa0;	//打开锁存器
		P2 = P2 & 0x1f;	//关闭锁存器
		temp_Old = temp;
	}
}

/* L3 */
		if(g_beep_status == 0)
			ucLed_enable[2] = Star_Flag ? 0 : 1;
		else if(g_beep_status == 1)
			ucLed_enable[2] = 0;

本代码已通过4t测试,唯一bug在于继电器开启和关闭有一定问题,目前正在调试,其余部分无问题,可参考

main.c

/* 头文件声明区域 */
#include <STC15F2K60S2.H>
#include <Init.h>
#include <Led.h>
#include <Key.h>
#include <Seg.h>
#include "ds1302.h"
#include "onewire.h"

/* 变量声明区域 */
unsigned char Key_Val,Key_Old,Key_Down,Key_Up;	//按键专用变量
unsigned char Key_Slow_Down_10ms;	//按键减速专用变量
unsigned int Seg_Slow_Down_500ms;	//数码管减速专用变量
unsigned char Seg_Pose = 0; //数码管扫描专用变量
unsigned char Seg_Buf[8] = {10,10,10,10,10,10,10,10};	//数码管显示数据专用存放数组
unsigned char Seg_Point[8] = {0,0,0,0,0,0,0,0};	//数码管小数点专用存放数组
unsigned char ucLed_enable[8] = {0,0,0,0,0,0,0,0};	//Led使能专用数组
unsigned char ucRtc[3] = {0x23,0x59,0x55};	//时钟数据存放数组
float Temperature;	//实时温度专用变量
unsigned char Seg_Disp_Mode = 0;	//数码管显示模式专用变量 0--温度显示界面 1--时间显示界面 2--参数设置界面
unsigned char	Temperature_parameters = 23;	//温度参数专用变量
bit Work_Mode = 0;	//工作模式专用变量 0--温度控制 1--时间控制
bit Key_Flag = 0;	//系统计时标志位
bit Star_Flag = 0;	//闪烁标志位
unsigned char Timer_100ms = 0;	//100毫秒
unsigned int Key_Time_600ms = 0;	//系统计时变量
unsigned char Time_Sub_Monde = 0;	//0-显示时分,1-显示分秒
unsigned char g_beep_status = 0;

/* 按键处理函数 */
void Key_Proc()
{
	//按键减速专用程序
	if(Key_Slow_Down_10ms) return;
	Key_Slow_Down_10ms = 1;
	
	//读取键码值
	Key_Val = Key_Read();
	Key_Down = Key_Val & (Key_Old ^ Key_Val);
	Key_Up = ~Key_Val & (Key_Old ^ Key_Val);
	Key_Old = Key_Val;
	
	/* 在时间显示界面下,S17长按显示分、秒,短按显示时、分 */
		if(Seg_Disp_Mode == 1)	//在时间显示界面下有效
		{
			if(Key_Down == 17)	//产生下降沿
				Key_Flag = 1;	//拉高标志位,系统开始计时
			
			//在500毫秒以内,短按处理
			if(Key_Time_600ms < 500 && Key_Up == 17)
			{
					Time_Sub_Monde = 0;	//切换子状态
					Key_Time_600ms = Key_Flag = 0;	//复位
			}
			//在500毫秒以外,长按处理
			else	
			{
				if(Key_Old == 17)	//仍按住
					Time_Sub_Monde = 1;	//显示分秒
				if(Key_Up == 17)	//识别到松开S17
					Key_Time_600ms = Key_Flag = Time_Sub_Monde = 0;	//复位
			}
		}	
	
	switch(Key_Down)
	{
		/* 切换按键 */
		case 12:
			if(++Seg_Disp_Mode == 3)
				Seg_Disp_Mode = 0;
		break;
			
		/* 模式按键 */
		case 13:
			Work_Mode ^= 1;
		break;
		
		/* 加按键 */
		case 16:
			if(Seg_Disp_Mode == 2)	//仅在参数设置界面下有效
			{
				if(++Temperature_parameters == 100)	//上限值为99℃
					Temperature_parameters = 99;
			}
		break;  

		/* 减按键 */
		case 17:
			if(Seg_Disp_Mode == 2)	//在参数设置界面下有效
			{
				if(--Temperature_parameters == 9)	//下限值为10℃
					Temperature_parameters = 10;
			}
		break;  
	}
}
/* 数码管显示函数 */
void Seg_Proc()
{
	unsigned char i = 3;	//For循环专用变量
	
	//数码管减速专用程序
	if(Seg_Slow_Down_500ms) return;
	Seg_Slow_Down_500ms = 1;
	
	//实时读取数据
	Temperature = rd_temperature();	//实时读取当前温度值
	Read_Rtc(ucRtc);	//实时读取当前时钟值
	//数码管显示区域
	switch(Seg_Disp_Mode)
	{
		/* 温度显示界面 */
		case 0:
			Seg_Buf[0] = 11;	//U
			Seg_Buf[1] = Seg_Disp_Mode + 1;	//界面编号1
			Seg_Buf[3] = Seg_Buf[4] = 10;	//重置使熄灭
			Seg_Buf[5] = (unsigned char)Temperature / 10 % 10;	//温度十位
			Seg_Buf[6] = (unsigned char)Temperature % 10;	//温度个位
			Seg_Buf[7] = (unsigned int)(Temperature * 10) % 10;	//温度第一位小数
			Seg_Point[6] = 1;	//第7位小数点使能
		break;
		
		/* 时间显示界面 */
		case 1:
			if(Time_Sub_Monde == 0)	//显示时分
			{
				Seg_Buf[0] = 11;	//U
				Seg_Buf[1] = Seg_Disp_Mode + 1;	//界面编号1
				Seg_Buf[3] = ucRtc[0] / 16 % 16;	//时的十位
				Seg_Buf[4] = ucRtc[0] % 16;	//时的个位
				Seg_Buf[5] = 12;	//-
				Seg_Buf[6] = ucRtc[1] / 16 % 16;	//分的十位
				Seg_Buf[7] = ucRtc[1] % 16;	//分的个位
				Seg_Point[6] = 0;	//第7位小数点不使能
			}
			else	//显示分秒
			{
				Seg_Buf[0] = 11;	//U
				Seg_Buf[1] = Seg_Disp_Mode + 1;	//界面编号1
				Seg_Buf[3] = ucRtc[1] / 16 % 16;	//分的十位
				Seg_Buf[4] = ucRtc[1] % 16;	//分的个位
				Seg_Buf[5] = 12;	//-
				Seg_Buf[6] = ucRtc[2] / 16 % 16;	//秒的十位
				Seg_Buf[7] = ucRtc[2] % 16;	//秒的个位
				Seg_Point[6] = 0;	//第7位小数点不使能
			}		
		break;
			
		/* 参数设置界面 */
		case 2:
			Seg_Buf[0] = 11;	//U
			Seg_Buf[1] = Seg_Disp_Mode + 1;	//界面编号1
			for(i=3;i<6;i++)
				Seg_Buf[i] = 10;	//数码管4--6全部熄灭
			Seg_Buf[6] = Temperature_parameters / 10 % 10;	//温度参数的十位
			Seg_Buf[7] = Temperature_parameters % 10;	//温度参数的个位
		break;
	}
	
}
/* 其他显示函数 */
void Led_Proc()
{
	/* 关闭蜂鸣器 */
		Relay_Disp(1);
	
	/* 继电器控制功能区域 */
	if(Seg_Disp_Mode == 0)
	{
		if(Temperature > Temperature_parameters)
			Beep_Disp(0);	//打开继电器
		else
			Beep_Disp(1);	//关闭继电器
	}
	else if(Seg_Disp_Mode == 1)
	{
		if(ucRtc[1] / 16 % 16 == 0 && ucRtc[1] % 16 == 0 && ucRtc[2] / 16 % 16 == 0 && ucRtc[2] % 16 == 0)
			Beep_Disp(0);	//打开继电器
		if(ucRtc[2] % 16 == 5)
			Beep_Disp(1);	//关闭继电器
	}
	
	/* Led指示灯控制功能区域 */
		/* L1 */
		if(ucRtc[1] / 16 % 16 == 0 && ucRtc[1] % 16 == 0 && ucRtc[2] / 16 % 16 == 0 && ucRtc[2] % 16 == 0)
			ucLed_enable[0] = 1;	//整点时,L1点亮
		if(ucRtc[2] % 16 == 5)	//5秒后
			ucLed_enable[0] = 0;
		/* L2 */
			ucLed_enable[1] = !Work_Mode;
		/* L3 */
		if(g_beep_status == 0)
			ucLed_enable[2] = Star_Flag ? 0 : 1;
		else if(g_beep_status == 1)
			ucLed_enable[2] = 0;
}

/* 继电器 */
void Beep_Disp(unsigned char enable)	 
{
	static unsigned char temp = 0x00;	
	static unsigned char temp_Old = 0xff;
	
	if(enable)
		temp |= 0x40;
	else
		temp  &= ~0x40;
	
	g_beep_status = enable;
	
	if(temp != temp_Old)
	{
		P0 = temp;
		P2 = P2 & 0x1f | 0xa0;	//打开锁存器
		P2 = P2 & 0x1f;	//关闭锁存器
		temp_Old = temp;
	}
}

/* 定时器0初始化函数 */
void Timer0_Init(void)		//1毫秒@12.000MHz
{
	AUXR &= 0x7F;			//定时器时钟12T模式
	TMOD &= 0xF0;			//设置定时器模式
	TL0 = 0x18;				//设置定时初始值
	TH0 = 0xFC;				//设置定时初始值
	TF0 = 0;				//清除TF0标志
	TR0 = 1;				//定时器0开始计时
	ET0 = 1;
	EA = 1;
}

/* 定时器0中断服务函数 */
void Timer0_Server() interrupt 1
{
	if(++Key_Slow_Down_10ms == 10) Key_Slow_Down_10ms = 0; //按键减速专用程序
	if(++Seg_Slow_Down_500ms == 500) Seg_Slow_Down_500ms = 0; //数码管减速专用程序
	if(++Seg_Pose == 8) Seg_Pose = 0;
		Seg_Disp(Seg_Pose,Seg_Buf[Seg_Pose],Seg_Point[Seg_Pose]); //数码管显示程序
		Led_Disp(Seg_Pose,ucLed_enable[Seg_Pose]);	//Led显示程序
	if(Key_Flag == 1)
	{
		if(++Key_Time_600ms == 600)
			Key_Time_600ms = 600;
	}
	if(++Timer_100ms == 100)
	{
		Timer_100ms = 0;
		Star_Flag ^= 1;
	}
}

/* 750ms延时函数 */
void Delay750ms(void)	//@12.000MHz
{
	unsigned char data i, j, k;

	i = 35;
	j = 51;
	k = 182;
	do
	{
		do
		{
			while (--k);
		} while (--j);
	} while (--i);
}

/* Main */
void main()
{
	Set_Rtc(ucRtc);
	rd_temperature();
	Delay750ms();
	System_Init();
	Timer0_Init();
	while(1)
	{
		Key_Proc();
		Seg_Proc();
		Led_Proc();
	}
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值