蓝桥杯第十三届单片机省赛:CT107D——IAP15F2K61S2 真题
文章目录
前言
相关说明:
开发板:CT107D (IAP15F2K61S2)
开发环境:Keil5
涉及题目:第十三届蓝桥杯单片机省赛真题
主要函数代码及说明:
一、代码相关定义、声明
1.头文件声明
#include "stdio.h"
#include "timer.h"
#include "init.h"
#include "key.h"
#include "seg.h"
#include "led.h"
#include "onewire.h"
#include "ds1302.h"
2.变量声明
unsigned char Screen_Display_No;//0-温度显示,1-时间显示,2-参数设置
unsigned char Sys_Mode;//0-温度控制,1-时间控制
unsigned char Temp_Compare = 23;//温度参数值 初始化为23
unsigned char Time_Disp_Mode;//时间显示的一种模式,0-时分,1-分秒
unsigned char Rtc[3] = {23,59,55};//设置初始时刻23:59:55
float Temp_Value;//温度数据
unsigned char seg_buf[8] = {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF};//数码管显示数组 上电熄灭
unsigned char pos;//数码管索引
unsigned char ucLed;//LED显示参数
unsigned long ms_Tick = 0;//滴答定时器变量
unsigned int Key_Slow_Down;//按键减速变量
unsigned int Seg_Slow_Down;//数码管减速变量
unsigned int Led_Slow_Down;//LED减速变量
unsigned long Relay_ms_Tick = 0;//继电器工作时间计时
unsigned long LED_ms_Tick = 0;//LED点亮时间计时
unsigned long relay_flag;// 0继电器断开 1继电器吸合
3.函数声明
void Key_Proc(void);
void Seg_Proc(void);
void Led_Proc(void);
void Delay750ms();//用来消除85°C显示
二、主要函数
1.main函数
void main(void)
{
Cls_Peripheral();//关闭LED/继电器/蜂鸣器
Timer1Init();//定时器1初始化
EA = 1;//打开总中断
Set_Rtc(Rtc);//设置初始时间
rd_temperature();//读取温度
Delay750ms();//用来消除85°C显示
while(1)
{
Key_Proc();
Seg_Proc();
Led_Proc();
}
}
2.按键扫描
void Key_Proc(void)
{
static unsigned char Key_Old;
unsigned char Key_Down,Key_Value;
if(Key_Slow_Down) return;
Key_Slow_Down = 1;
Key_Value = Key_Read();
Key_Down = Key_Value & (Key_Old ^ Key_Value);
Key_Old = Key_Value;
switch(Key_Down)
{
case 12:
if(++Screen_Display_No == 3) //0-温度显示,1-时间显示,2-参数设置
Screen_Display_No = 0;//限制为3个界面循环显示
break;
case 13:
Sys_Mode^=1;//0-温度控制,1-时间控制
P0 = 0X00;//继电器断开
P2 = P2 & 0X1F | 0xA0;
P2 &= 0X1F;
relay_flag= 0;//继电器断开标志置0
break;
}
if(Screen_Display_No == 2)//参数设置界面
{
switch(Key_Down)
{
case 16:
if(++Temp_Compare == 100)//温度参数+1
Temp_Compare = 99;//限定最大值为99
break;
case 17:
if(--Temp_Compare == 9) //温度参数-1
Temp_Compare = 10;//限定最小值为10
break;
}
}
if(Screen_Display_No == 1)//时间显示界面
{
if(Key_Old == 17)//按下S17 时分显示
Time_Disp_Mode = 1;
else if(Key_Old == 0)//松开S17 分秒显示
Time_Disp_Mode = 0;
}
}
3.数码管显示、继电器控制
void Seg_Proc(void)
{
unsigned char seg_string[10];
if(Seg_Slow_Down) return;
Seg_Slow_Down = 1;
Temp_Value = rd_temperature()/16.0;//读取温度数据
Read_Rtc(Rtc); //读取当前时间
if(Screen_Display_No == 0)//温度显示界面
sprintf(seg_string,"U1 %4.1f",Temp_Value);
else if(Screen_Display_No == 1)//时间显示界面
{
if(Time_Disp_Mode == 0)//按时分显示
sprintf(seg_string,"U2 %02d-%02d",(unsigned int)Rtc[0],(unsigned int)Rtc[1]);
else//按分秒显示
sprintf(seg_string,"U2 %02d-%02d",(unsigned int)Rtc[1],(unsigned int)Rtc[2]);
}
else if(Screen_Display_No == 2)//参数界面
sprintf(seg_string,"U3 %02d",(unsigned int)Temp_Compare);
if(Sys_Mode == 0)//温度控制
{
if((unsigned int)(Temp_Value*10) > (unsigned int)(Temp_Compare*10))//当前温度>温度参数
{
P0 = 0X10;//继电器吸合
P2 = P2 & 0X1F | 0xA0;//beep relay
P2 &= 0X1F;
relay_flag= 1;//继电器吸合标志置1
}
else//当前温度<=温度参数
{
P0 = 0X00;//继电器断开
P2 = P2 & 0X1F | 0xA0;//beep relay
P2 &= 0X1F;
relay_flag= 0;//继电器断开标志置0
}
}
else//时间控制
{
if((Rtc[1] == 0)&&(Rtc[2] == 0))//整点
{
P0 = 0X10;//继电器吸合
P2 = P2 & 0X1F | 0xA0;//beep relay
P2 &= 0X1F;
Relay_ms_Tick = ms_Tick;//继电器工作开始计时
relay_flag= 1; //继电器吸合标志置1
}
if((ms_Tick - Relay_ms_Tick) >= 5000)//经过5秒
{
P0 = 0X00;//继电器断开
P2 = P2 & 0X1F | 0xA0;//beep relay
P2 &= 0X1F;
relay_flag= 0;//继电器断开标志置0
}
}
Seg_Tran(seg_string, seg_buf);//数码管数组转换函数
}
4.LED显示
void Led_Proc(void)
{
if(Led_Slow_Down) return;
Led_Slow_Down = 1;
if((Rtc[1] == 0)&&(Rtc[2] == 0))//整点
{
ucLed |= 0x01;//点亮LED1
LED_ms_Tick = ms_Tick;//开始计时
}
if((ms_Tick - LED_ms_Tick) >= 5000)//5秒过后
ucLed &= (~0x01);//熄灭LED1
if(Sys_Mode == 0)//温度显示界面
ucLed |= 0x02;//点亮LED2
else//时间、参数显示界面
ucLed &= (~0x02);//熄灭LED2
if(relay_flag== 1)//继电器吸合
ucLed ^= 0x04;//LED3 0.1秒间隔闪烁
else
ucLed &= (~0x04);//LED3熄灭
}
5.定时器中断
void tm1_isr() interrupt 3//每1毫秒发生一次中断
{
ms_Tick++;//滴答定时器
if(++Key_Slow_Down == 10) Key_Slow_Down = 0;//减速变量
if(++Seg_Slow_Down == 100) Seg_Slow_Down = 0;//减速变量
if(++Led_Slow_Down == 100) Led_Slow_Down = 0;//减速变量 同时用于LED0.1秒间隔闪烁
Seg_Disp(seg_buf, pos);//数码管显示函数
if(++pos == 8)//数码管显示数组索引+1
pos = 0;//限定pos范围为0~7
Led_Disp(ucLed);//LED显示函数
}
6.消除85°C显示
void Delay750ms() //@12.000MHz 用来消除85°C显示
{
unsigned char i, j, k;
_nop_();
_nop_();
i = 35;
j = 51;
k = 182;
do
{
do
{
while (--k);
} while (--j);
} while (--i);
}
三、总结经验
今年我参加的是嵌入式,比赛当天晚上整理了代码并进行了发布。今天突然心血来潮,想发布一下今年第十三届的单片机组的省赛真题。
由于今年没有参加,所以自己写了一份,并进行了验证,功能全部实现,底层代码没有发布,提供了代码的逻辑流程,有助于同学们提升逻辑能力和为第二场做准备。
省赛和国赛的题目最起码要做过一遍。主要训练逻辑思路,可以先用自己写好的各个模块驱动代码。比赛前几天全部代码都要重新写,包括新建工程开始,到各个驱动模块代码。比赛的时候,我是先写好大模板和各个模块的代码,然后才开始做按要求去实现功能的,功能由简单到难。