第十五届蓝桥杯单片机模拟考试|
目录
一、基本要求
1、将IAP15F2K61S2单片机内部振荡器频率设定为12MHZ。 2、键盘工作模式跳线J5配置为KBD矩阵按键模式。 3、扩展方式跳线J13配置为I0模式
二、硬件框图
三、功能描述
3.1基本功能描述
1)通过读取DS1302 RTC芯片,获取时间数据;
2)通过EEPROM实现数据记录功能;
3)通过LED指示灯完成试题要求的状态指示功能;
4)通过数码管、按键完成试题要求的数据显示和界面切换功能;
3.2显示功能
1)时间界面 时间界面如图2所示,显示内容包括时、分、秒数据和间隔符"”时、分、秒数据固定占2 位显示宽度,不足2 位补 0。
2)输入界面
输入界面如图3所示,由标识符(C)和一个4位数据组成,4位数据通过4位数码管显示,每输入一位数据,数码管显示向左移动一位,直到完成4位数据的输入。
3)记录界面
记录界面如图4所示,由标识符(E)和输入4位数据的起始时和分数据以及时、分数据的间隔符(-)。
4)显示要求
按照题目要求的界面格式和切换方式进行设计。数码管显示无重影、闪烁、过暗、亮度不均匀等严重影响显示效果的缺陷。
3.3按键功能
1)功能说明
① S4:定义为“切换”,按下S4按键,切换“时间界面”、“输入界面”和“记录界面”。
② S5:定义为“清除”,在输入界面下,按下S5,清除当前输入的数据,显示输入数据的4位数码管全部熄灭。
③ S6、S10、S14、S18、S9、S13、S17、S8、S12、S16分别对应数值“0-9”,在“输入界面”下,按下对应按键,实现一位对应数据的输入,显示格式及要求如图3所。若当前4位数据输入完成,按键继续输入不影响当前已输入完成的4位数据。
2)按键要求
按键应做好消抖处理,避免出现一次按键动作导致功能多次触发。 按键动作不影响数码管显示等其他功能。 按键 S5、S6、S10、S14、S18、S9、S13、S17、S8、S12、S16仅在"输入界面”有效。
3.4记录功能
每次进入记录界面时,将4位数据和输入数据的起始时间保存到E2PROM,存储位置要求如下:
输入数据起始时间(时):E2PROM内部地址0:
输入数据起始时间(分):E2PROM内部地址1;
输入数据(高字节):E2PROM内部地址2;
输入数据(低字节):E2PROM内部地址3; 注意: E2PROM写入操作发生在切换到记录界面时,其它时间不写入。
输入数据以HEX编码写入E2PROM,例如数据数据为1234,E2PROM内部地址2中应保存04H,内部地址3中保存D2H。
3.5LED指示灯功能
1、界面指示灯
1)时间界面下,指示灯L1 点亮,否则指示灯 L1 熄灭。
2)输入界面下,指示灯 L2 点亮,否则指示灯 L2 熄灭。
3)记录界面下,指示灯 L3 点亮,否则指示灯 L3 熄灭。
2、记录指示灯 若本次记录的4位数据较上一次记录的4位数据大,则指示灯L4点亮,否则指示灯熄灭。
3.6初始状态
请严格按照以下要求设计作品的上电初始状态。 1)处于时间界面。
2)指示灯L1点亮,其余指示灯熄灭。
四、代码示例
// Header:
// File Name:
// Author:
// Date:
/********************预编译、宏和变量********************************************/
#include "main.h"
#include <stdio.h>
#include "key.h"
#include "ds1302.h"
#include "iic.h"
/*************************************************************
宏定义区域
**************************************************************/
#define CONTROL(x,y) P0=y;P2=x;P2=0 //为锁存器的引脚操作封装一个带参宏
enum PERIPHERAL
{
LED = 0x80,
DEVICE = 0xa0,
BIT = 0xc0,
SEG = 0xe0
};
/*******************************************************************************
变量定义
********************************************************************************/
/********************模板驱动变量****************************/
//控制LED0~7的开关量,正逻辑
bit LED0, LED1, LED2, LED3, LED4, LED5, LED6, LED7;
//控制蜂鸣器的自定义变量,正逻辑
bit Buzzer;
//控制继电器的自定义变量,正逻辑
bit Relay;
//Dsp_Bit是数码管显示的字符串数组,考虑到小数点的同位显示,所以字符串长度最长为16
uchar Dsp_Bit[16] = {0};
//数码管显示的各位段码内容,由 Dsp_Bit 通过函数Seg_Tran转换更新
uchar Dsp_Code[8] = {0};
//定时器计数
uint Tick;
/********************中断区域***************************************************/
/*******************************************************************************
函数名程: void Timer_2Init(void)
函数功能: 定时器T2 中断 1ms 配置
参数列表:
返回值 :
*******************************************************************************/
void Timer_2Init(void) //1000微秒@12.000MHz
{
AUXR |= 0x04; //定时器时钟1T模式
T2L = 0x20; //设置定时初值
T2H = 0xD1; //设置定时初值
AUXR |= 0x10; //定时器2开始计时
IE2 |= 0x04; //ET2 = 1;
EA = 1;
}
/*******************************************************************************
函数名程: void Timer2_Service() interrupt 12
函数功能: 定时器T2 中断 1ms 中断处理
参数列表:
返回值 :
*******************************************************************************/
void Timer2_Service() interrupt 12
{
static uchar dsp_com;
//定时任务
Tick++;
/***********控制外设的引脚操作*****/
//更新LED的引脚操作
CONTROL(LED,~((uchar)LED0|(uchar)LED1<<1|(uchar)LED2<<2|(uchar)LED3<<3|(uchar)LED4<<4|(uchar)LED5<<5|(uchar)LED6<<6|(uchar)LED7<<7));
//更新蜂鸣器、继电器的引脚操作
CONTROL(DEVICE,(uchar)Buzzer<<6|(uchar)Relay<<4);
//更新一位数码管的引脚操作
CONTROL(BIT,0); //消影
CONTROL(SEG,Dsp_Code[dsp_com]); //放入要显示的数字到段选锁存
CONTROL(BIT,1 << (dsp_com)); //选择对应的位选锁存
if(++dsp_com > 7) //显示完一次后自增位选,位选到8之后回到1
dsp_com = 0;
}
/*******************************************************************************
函数名程: void Seg_Tran(void)
函数功能: 将Dsp_Bit[]的内容,转换成对应的段码放入Dsp_Code[];
参数列表:
返回值 :
*******************************************************************************/
void Seg_Tran(void)
{
unsigned char i, j=0, temp;
for (i=0; i<8; i++, j++)
{
switch (Dsp_Bit[j])
{ // 低电平点亮段,段码[MSB...LSB]对应码顺序为[dp g f e d c b a]
case '0': temp = 0xc0; break;
case '1': temp = 0xf9; break;
// case '1': temp = 0xcf; break;
case '2': temp = 0xa4; break;
case '3': temp = 0xb0; break;
// case '3': temp = 0x86; break;
case '4': temp = 0x99; break;
// case '4': temp = 0x8b; break;
case '5': temp = 0x92; break;
case '6': temp = 0x82; break;
// case '6': temp = 0x90; break;
case '7': temp = 0xf8; break;
// case '7': temp = 0xc7; break;
case '8': temp = 0x80; break;
case '9': temp = 0x90; break;
// case '9': temp = 0x82; break;
case 'A': temp = 0x88; break;
case 'B': temp = 0x83; break;
case 'C': temp = 0xc6; break;
case 'D': temp = 0xA1; break;
case 'E': temp = 0x86; break;
case 'F': temp = 0x8E; break;
case 'H': temp = 0x89; break;
case 'L': temp = 0xC7; break;
case 'N': temp = 0xC8; break;
case 'P': temp = 0x8c; break;
case 'U': temp = 0xC1; break;
case '-': temp = 0xbf; break;
case ' ': temp = 0xff; break;
case '^': temp = 0xfe; break; // 1 1 1 1 1 1 1 0
case '_': temp = 0xf7; break; // 1 1 1 1 0 1 1 1
default: temp = 0xff;
}
if (Dsp_Bit[j+1] == '.')
{
temp = temp&0x7f; // 点亮小数点
j++;
}
Dsp_Code[i] = temp;
}
}
/********************应用层变量****************************/
//两个参数
char KeyNum;
//界面
uchar Page;
//起始时间
uchar Time[6]={2,3,0,9,5,9};
//输入的值
uint Value,Last_Value,Pre_Value;
//记录的时和分
uchar Hour,Min;
/*******************************************************************************
函数名程: void Display_Task(void)
函数功能: 显示内容执行任务,0.5s刷新一次显示内容
参数列表:
返回值 :
*******************************************************************************/
void Display_Task(void)
{
static uint Display_Tick;
if((Tick - Display_Tick) > 500)
{
Display_Tick = Tick;
switch (Page)
{
case 0://时间界面
LED0=1;LED1=0;LED2=0;
sprintf(Dsp_Bit, "%02bd-%02bd-%02bd",Time[0]*10+Time[1], Time[2]*10+Time[3],Time[4]*10+Time[5]);
break;
case 1://输入界面
LED0=0;LED1=1;LED2=0;
if(Value)
sprintf(Dsp_Bit, "C %4hu", Value);
else
sprintf(Dsp_Bit, "C ");
break;
case 2://记录界面
LED0=0;LED1=0;LED2=1;
sprintf(Dsp_Bit, "E %02bd-%02bd", Hour,Min);
break;
default:
break;
}
//sprintf(Dsp_Bit, "%9.2f", (float)KeyNum);
}
Seg_Tran();
}
/*******************************************************************************
函数名程: void Key_Task(void)
函数功能: 按键执行任务,每2ms执行一次
参数列表:
返回值 :
*******************************************************************************/
void Key_Task(void)
{
static uint Key_Tick;
char Key_Value;
if((Tick - Key_Tick) > 2)
{
Key_Tick = Tick;
Key_Value = MatKeyScan_4x4();
switch (Page)
{
case 0://时间界面
switch (Key_Value)
{
case 4://切换到输入界面
Page=1;
break;
default:
break;
}
break;
case 1://输入界面
switch (Key_Value)
{
case 4://切换到记录界面
Page=2;
Hour=Time[0]*10+Time[1];
Min=Time[2]*10+Time[3];
Last_Value=Pre_Value;
//记录
AT24C02_WriteBuffer(&Hour,0, 1);
AT24C02_WriteBuffer(&Min,1, 1);
AT24C02_WriteBuffer((unsigned char*)&Value,2, 2);
LED3 = (Value > Pre_Value) ? 1 : 0;
Pre_Value=Value;
//LED3=(Last_Value>Pre_Value)?1:0;//若本次记录的4位数据较上一次记录的4位数据大,则指示灯L4点亮,否则指示灯熄灭。
break;
case 5://清除按键
Value=0;
break;
case 6://显示0
Value=(Value>999)?Value:(Value*10+0);
break;
case 10://显示1
Value=(Value>999)?Value:(Value*10+1);
break;
case 14://显示2
Value=(Value>999)?Value:(Value*10+2);
break;
case 18://显示3
Value=(Value>999)?Value:(Value*10+3);
break;
case 9://显示4
Value=(Value>999)?Value:(Value*10+4);
break;
case 13://显示5
Value=(Value>999)?Value:(Value*10+5);
break;
case 17://显示6
Value=(Value>999)?Value:(Value*10+6);
break;
case 8://显示7
Value=(Value>999)?Value:(Value*10+7);
break;
case 12://显示8
Value=(Value>999)?Value:(Value*10+8);
break;
case 16://显示9
Value=(Value>999)?Value:(Value*10+9);
break;
default:
break;
}
break;
case 2://记录界面
switch (Key_Value)
{
case 4://切换到时间界面
Page=0;
break;
default:
break;
}
break;
default:
break;
}
}
}
/*******************************************************************************
函数名程: void Data_Task(void)
函数功能: 定时处理数据的采集、处理、传输任务
参数列表:
返回值 :
*******************************************************************************/
void Data_Task(void)
{
static uint Data_Tick;
if((Tick - Data_Tick) > 500)
{
Data_Tick = Tick;
Ds1302_ReadTime(Time);
}
}
/*******************************************************************************
函数名程: void Data_Task(void)
函数功能: 定时按一定逻辑执行任务
参数列表:
返回值 :
*******************************************************************************/
void Logic_Task(void)
{
static uint Logic_Tick;
if((Tick - Logic_Tick) > 500)
{
Logic_Tick = Tick;
}
}
/*******************************************************************************
函数名程: void P_Init(void)
函数功能: 外设初始化
参数列表:
返回值 :
*******************************************************************************/
void P_Init(void) //外设初始化
{
CONTROL(LED,0xff); //初始化LED熄灭
CONTROL(DEVICE,0x00); //初始化所有外设不工作
CONTROL(BIT,0x00); //初始化数码管位选无效
CONTROL(SEG,0xff); //初始化数码管段选无效
//定时器T2时基1ms初始化
Timer_2Init();
}
/*************************************************************
主函数
**************************************************************/
void main(void)
{
/********************初始化********************************************/
P_Init();
AT24C02_ReadBuffer(&Hour,0, 1);
AT24C02_ReadBuffer(&Min,1, 1);
AT24C02_ReadBuffer((unsigned char*)&Value,2, 2);
Ds1302_SetTime(Time);
/********************功能函数*******************************************/
while(1)
{
Display_Task();
Key_Task();
Data_Task();
Logic_Task();
}
}