蓝桥杯单片机-0.基于定时器的时钟程序设计
- 题目
- 小注意点
- 按键三行
- 矩形按键
- 按键功能
- 时间更新
- 显示界面的小数点
- LED灯闪烁
- 其他功能
- 完整代码
链接: 视频搭配视频,这里只是一些笔记,并不完整
题目
小注意点
按键三行
Key_Val = Key_Read();//实时读取键码值
Key_Down = Key_Val & (Key_Old ^ Key_Val);//捕捉按键下降沿
Key_Old = Key_Val;//辅助扫描变量
1.Key_Val = Key_Read();
作用:实时读取按键的当前状态。
Key_Read() 是一个函数,用来读取键盘的当前按键状态,返回的值通常是一个整数或位掩码,每一位代表一个按键的状态(0 表示松开,1 表示按下)。
2.Key_Down = Key_Val & (Key_Old ^ Key_Val);
作用:检测按键的下降沿。
这行代码的目的是捕捉按键的下降沿(即按键从松开状态转变为按下状态的瞬间)。
Key_Old 是之前保存的按键状态(历史状态)。
Key_Old ^ Key_Val 通过异或运算可以得到按键状态的变化情况。如果按键状态有变化(即按键从松开变为按下或从按下变为松开),那么该位会变成 1。
Key_Val & (Key_Old ^ Key_Val) 进一步与 Key_Val(当前按键状态)相与,只保留按键由“松开”变为“按下”的变化(即下降沿)。这样可以排除由按下变为松开的情况。
结果:Key_Down 中的某一位为1,表示该位对应的按键刚刚被按下。
情况 1:按键从“松开”变为“按下”
假设有一个按键从松开(0)变为按下(1),那时:
Key_Old = 0(之前松开)
Key_Val = 1(现在按下)
那么:
Key_Old ^ Key_Val = 0 ^ 1 = 1(变化发生了)
Key_Val & (Key_Old ^ Key_Val) = 1 & 1 = 1(当前状态是按下,且状态发生了变化)
结果:此时结果为 1,表示捕捉到按键从松开到按下的“下降沿”。
情况 2:按键从“按下”变为“松开”
如果按键从按下(1)变为松开(0),那时:
Key_Old = 1(之前按下)
Key_Val = 0(现在松开)
那么:
Key_Old ^ Key_Val = 1 ^ 0 = 1(变化发生了)
Key_Val & (Key_Old ^ Key_Val) = 0 & 1 = 0(当前状态是松开,即 Key_Val 为 0)
结果:此时结果为 0,表示按键从按下到松开的变化被忽略。
情况 3:按键没有变化
如果按键保持不变,无论是持续按下或持续松开,异或运算会得到 0:
Key_Old ^ Key_Val = 0(没有变化)
不管按键是保持按下还是松开:
Key_Val & 0 = 0
结果:结果为 0,表示没有变化发生。
3.Key_Old = Key_Val;
作用:保存当前的按键状态,作为下一次检测的历史状态。
这行代码的目的是更新历史状态变量 Key_Old,将当前的按键状态 Key_Val 保存下来,以便下次检测时可以比较按键状态的变化。
矩形按键
左边是矩阵按键,右边是独立按键。
unsigned char Key_Read()
{
unsigned char temp = 0;
P3_0=0; P3_1 =1; P3_2 = 1; P3_3 = 1;
if(P3_4 == 0) temp = 1;
if(P3_5 == 0) temp = 2;
if(P3_6 == 0) temp = 3;
if(P3_7 == 0) temp = 4;
P3_0=1; P3_1 =0; P3_2 = 1; P3_3 = 1;
if(P3_4 == 0) temp = 5;
if(P3_5 == 0) temp = 6;
if(P3_6 == 0) temp = 7;
if(P3_7 == 0) temp = 8;
P3_0=1; P3_1 =1; P3_2 = 0; P3_3 = 1;
if(P3_4 == 0) temp = 9;
if(P3_5 == 0) temp = 10;
if(P3_6 == 0) temp = 11;
if(P3_7 == 0) temp = 12;
P3_0=1; P3_1 =1; P3_2 = 1; P3_3 = 0;
if(P3_4 == 0) temp = 13;
if(P3_5 == 0) temp = 14;
if(P3_6 == 0) temp = 15;
if(P3_7 == 0) temp = 16;
return temp;
}
按键功能
/* 键盘处理函数 */
void Key_Proc()
{
if(Key_Slow_Down) return;
Key_Slow_Down = 1;//键盘减速程序
Key_Val = Key_Read();//实时读取键码值
Key_Down = Key_Val & (Key_Old ^ Key_Val);//捕捉按键下降沿
Key_Old = Key_Val;//辅助扫描变量
if(Key_Down != 0)
Alarm_Enable_Flag = 0;
switch(Key_Down)
{
case 1:
Clock_Set_Index = 0;
Clock_Set[0] = Clock_Disp[0];
Clock_Set[1] = Clock_Disp[1];
Clock_Set[2] = Clock_Disp[2];
Seg_Disp_Mode = 1;
break;
case 2:
Clock_Set_Index = 0;
Alara_Set[0] = Alara[0];
Alara_Set[1] = Alara[1];
Alara_Set[2] = Alara[2];
Seg_Disp_Mode = 2;
break;
case 3:
if(Seg_Disp_Mode ==1 )
{
Clock_Set_Index++;
if(Clock_Set_Index == 3)
Clock_Set_Index = 0;
}
break;
case 4:
Alarm_Flag ^=1;
break;
case 5:
if(Seg_Disp_Mode == 1)
{
Clock_Set[Clock_Set_Index]++;
if(Clock_Set[Clock_Set_Index] == (Clock_Set_Index==0?24:60))
Clock_Set[Clock_Set_Index] = 0;
}
if(Seg_Disp_Mode == 2)
{
Alara_Set[Clock_Set_Index]++;
if(Alara_Set[Clock_Set_Index] == (Clock_Set_Index==0?24:60))
Alara_Set[Clock_Set_Index] = 0;
}
break;
case 6:
if(Seg_Disp_Mode == 1)
{
Clock_Set[Clock_Set_Index]--;
if(Clock_Set[Clock_Set_Index] == 255)
Clock_Set[Clock_Set_Index] = Clock_Set_Index == 0?23:59;
}
if(Seg_Disp_Mode == 2)
{
Alara_Set[Clock_Set_Index]--;
if(Alara_Set[Clock_Set_Index] == 255)
Alara_Set[Clock_Set_Index] = Clock_Set_Index == 0?23:59;
}
break;
case 7:
if(Seg_Disp_Mode == 1)
{
Clock_Disp[0] = Clock_Set[0];
Clock_Disp[1] = Clock_Set[1];
Clock_Disp[2] = Clock_Set[2];
}
if(Seg_Disp_Mode == 2)
{
Clock_Disp[0] = Alara_Set[0];
Clock_Disp[1] = Alara_Set[1];
Clock_Disp[2] = Alara_Set[2];
}
Seg_Disp_Mode = 0;
break;
case 8:
Seg_Disp_Mode = 0;
break;
}
}
时间更新
Timer_1000Ms++;
if(Timer_1000Ms == 1000)
{
Timer_1000Ms = 0;
Clock_Disp[2]++;
if (Clock_Disp[2]==60)
{
Clock_Disp[2]=0;
Clock_Disp[1]++;
if (Clock_Disp[1]==60)
{
Clock_Disp[1]=0;
Clock_Disp[0]++;
if(Clock_Disp[0]==24)
Clock_Disp[0] = 0;
}
}
}
显示界面的小数点
void Seg_Disp(unsigned char wela,dula,point)
{
P0 = 0x00;
P2_6 = 1;
P2_6 = 0;
P0 = Seg_Wela[wela];
P2_7 = 1;
P2_7 = 0;
if(point == 1)
P0 = Seg_Dula[dula] | 0x80;
else
P0 = Seg_Dula[dula];
P2_6 = 1;
P2_6 = 0;
}
P0 = Seg_Dula[dula] | 0x80;这一句就是现实小点,让最高位为1.
unsigned char Seg_Point[6] = {0,1,0,1,0,1};
Seg_Disp(Seg_Pos,Seg_Buf[Seg_Pos],Seg_Point[Seg_Pos]);
LED灯闪烁
bit Seg_Flag;
Seg_Buf[0+Clock_Set_Index*2] = Seg_Flag?Clock_Set[Clock_Set_Index]/10%10:10;
其他功能
/* 其他显示函数 */
void Led_Proc()
{
if(Alarm_Flag == 1)
{
if(Clock_Disp[0] == Alara[0] && Clock_Disp[1] == Alara[1] && Clock_Disp[2] == Alara[2])
Alarm_Enable_Flag = 1;
if(Alarm_Enable_Flag == 1)
{
P2_3 = 0;//蜂鸣器
P1 = Led; //不断变化
}
else
{
P2_3 = 1;//关闭
P1 = 0xff;//关闭
}
}
else
{
P2_3 = 1;//关闭
P1 = 0xff;//关闭
}
}
if(Key_Down != 0)
Alarm_Enable_Flag = 0;
用Alarm_Enable_Flag来判断是否使能,到定时时间了开启,否则按任意按键复位。
完整代码
main.c
/* 头文件声明区 */
#include <REGX52.H>//单片机寄存器专用头文件
#include <Key.h>//按键底层驱动专用头文件
#include <Seg.h>//数码管底层驱动专用头文件
/* 变量声明区 */
unsigned char Key_Val,Key_Down,Key_Old;//按键专用变量
unsigned char Key_Slow_Down;//按键减速专用变量
unsigned char Seg_Buf[6] = {10,10,10,10,10,10};//数码管显示数据存放数组
unsigned char Seg_Pos;//数码管扫描专用变量
unsigned int Seg_Slow_Down;//数码管减速专用变量
unsigned char Seg_Disp_Mode; //0-时钟显示模式 1-时钟设置界面 2-闹钟显示界面
unsigned char Clock_Disp[3] = {23,59,55};
unsigned int Timer_1000Ms;
unsigned char Seg_Point[6] = {0,1,0,1,0,1};
unsigned char Clock_Set[3];
unsigned char Clock_Set_Index;//0-小时 1-分钟 2-秒种
unsigned int Timer_500Ms;
bit Seg_Flag;
unsigned char Alara[] = {0,0,0};
unsigned char Alara_Set[3];
bit Alarm_Flag = 1;
unsigned char Led;
bit Alarm_Enable_Flag;
/* 键盘处理函数 */
void Key_Proc()
{
if(Key_Slow_Down) return;
Key_Slow_Down = 1;//键盘减速程序
Key_Val = Key_Read();//实时读取键码值
Key_Down = Key_Val & (Key_Old ^ Key_Val);//捕捉按键下降沿
Key_Old = Key_Val;//辅助扫描变量
if(Key_Down != 0)
Alarm_Enable_Flag = 0;
switch(Key_Down)
{
case 1:
Clock_Set_Index = 0;
Clock_Set[0] = Clock_Disp[0];
Clock_Set[1] = Clock_Disp[1];
Clock_Set[2] = Clock_Disp[2];
Seg_Disp_Mode = 1;
break;
case 2:
Clock_Set_Index = 0;
Alara_Set[0] = Alara[0];
Alara_Set[1] = Alara[1];
Alara_Set[2] = Alara[2];
Seg_Disp_Mode = 2;
break;
case 3:
if(Seg_Disp_Mode ==1 )
{
Clock_Set_Index++;
if(Clock_Set_Index == 3)
Clock_Set_Index = 0;
}
break;
case 4:
Alarm_Flag ^=1;
break;
case 5:
if(Seg_Disp_Mode == 1)
{
Clock_Set[Clock_Set_Index]++;
if(Clock_Set[Clock_Set_Index] == (Clock_Set_Index==0?24:60))
Clock_Set[Clock_Set_Index] = 0;
}
if(Seg_Disp_Mode == 2)
{
Alara_Set[Clock_Set_Index]++;
if(Alara_Set[Clock_Set_Index] == (Clock_Set_Index==0?24:60))
Alara_Set[Clock_Set_Index] = 0;
}
break;
case 6:
if(Seg_Disp_Mode == 1)
{
Clock_Set[Clock_Set_Index]--;
if(Clock_Set[Clock_Set_Index] == 255)
Clock_Set[Clock_Set_Index] = Clock_Set_Index == 0?23:59;
}
if(Seg_Disp_Mode == 2)
{
Alara_Set[Clock_Set_Index]--;
if(Alara_Set[Clock_Set_Index] == 255)
Alara_Set[Clock_Set_Index] = Clock_Set_Index == 0?23:59;
}
break;
case 7:
if(Seg_Disp_Mode == 1)
{
Clock_Disp[0] = Clock_Set[0];
Clock_Disp[1] = Clock_Set[1];
Clock_Disp[2] = Clock_Set[2];
}
if(Seg_Disp_Mode == 2)
{
Clock_Disp[0] = Alara_Set[0];
Clock_Disp[1] = Alara_Set[1];
Clock_Disp[2] = Alara_Set[2];
}
Seg_Disp_Mode = 0;
break;
case 8:
Seg_Disp_Mode = 0;
break;
}
}
/* 信息处理函数 */
void Seg_Proc()
{
//unsigned char i;//用于for循环
if(Seg_Slow_Down) return;
Seg_Slow_Down = 1;//数码管减速程序
switch(Seg_Disp_Mode)
{
case 0://时钟显示模式
Seg_Buf[0] = Clock_Disp[0]/10%10;
Seg_Buf[1] = Clock_Disp[0]%10;
Seg_Buf[2] = Clock_Disp[1]/10%10;
Seg_Buf[3] = Clock_Disp[1]%10;
Seg_Buf[4] = Clock_Disp[2]/10%10;
Seg_Buf[5] = Clock_Disp[2]%10;
// for(i=0;i<3;i++)
// {
// Seg_Buf[0+2*i] = Clock_Disp[i]/10%10;
// Seg_Buf[1+2*i] = Clock_Disp[i]%10;
// }
break;
case 1://时钟显示模式
Seg_Buf[0] = Clock_Set[0]/10%10;
Seg_Buf[1] = Clock_Set[0]%10;
Seg_Buf[2] = Clock_Set[1]/10%10;
Seg_Buf[3] = Clock_Set[1]%10;
Seg_Buf[4] = Clock_Set[2]/10%10;
Seg_Buf[5] = Clock_Set[2]%10;
// switch(Clock_Set_Index)
// {
// case 0:
// Seg_Buf[0] = Seg_Flag?Clock_Set[0]/10%10:10;
// Seg_Buf[1] = Seg_Flag?Clock_Set[0]%10:10;
// break;
//
// case 1:
// Seg_Buf[2] = Seg_Flag?Clock_Set[1]/10%10:10;
// Seg_Buf[3] = Seg_Flag?Clock_Set[1]%10:10;
// break;
//
// case 2:
// Seg_Buf[4] = Seg_Flag?Clock_Set[2]/10%10:10;
// Seg_Buf[5] = Seg_Flag?Clock_Set[2]%10:10;
// break;
//
// }
Seg_Buf[0+Clock_Set_Index*2] = Seg_Flag?Clock_Set[Clock_Set_Index]/10%10:10;
Seg_Buf[1+Clock_Set_Index*2] = Seg_Flag?Clock_Set[Clock_Set_Index]%10:10;
break;
case 2:
Seg_Buf[0] = Alara_Set[0]/10%10;
Seg_Buf[1] = Alara_Set[0]%10;
Seg_Buf[2] = Alara_Set[1]/10%10;
Seg_Buf[3] = Alara_Set[1]%10;
Seg_Buf[4] = Alara_Set[2]/10%10;
Seg_Buf[5] = Alara_Set[2]%10;
Seg_Buf[0+Clock_Set_Index*2] = Seg_Flag?Alara_Set[Clock_Set_Index]/10%10:10;
Seg_Buf[1+Clock_Set_Index*2] = Seg_Flag?Alara_Set[Clock_Set_Index]%10:10;
break;
}
}
/* 其他显示函数 */
void Led_Proc()
{
if(Alarm_Flag == 1)
{
if(Clock_Disp[0] == Alara[0] && Clock_Disp[1] == Alara[1] && Clock_Disp[2] == Alara[2])
Alarm_Enable_Flag = 1;
if(Alarm_Enable_Flag == 1)
{
P2_3 = 0;//蜂鸣器
P1 = Led; //不断变化
}
else
{
P2_3 = 1;//关闭
P1 = 0xff;//关闭
}
}
else
{
P2_3 = 1;//关闭
P1 = 0xff;//关闭
}
}
/* 定时器0中断初始化函数 */
void Timer0Init(void) //1毫秒@12.000MHz
{
TMOD &= 0xF0; //设置定时器模式
TMOD |= 0x01; //设置定时器模式
TL0 = 0x18; //设置定时初始值
TH0 = 0xFC; //设置定时初始值
TF0 = 0; //清除TF0标志
TR0 = 1; //定时器0开始计时
ET0 = 1; //定时器0中断打开
EA = 1; //总中断打开
}
/* 定时器0中断服务函数 */
void Timer0Server() interrupt 1
{
TL0 = 0x18; //设置定时初始值
TH0 = 0xFC; //设置定时初始值
if(++Key_Slow_Down == 10) Key_Slow_Down = 0;//键盘减速专用
if(++Seg_Slow_Down == 500) Seg_Slow_Down = 0;//数码管减速专用
if(++Seg_Pos == 6) Seg_Pos = 0;//数码管显示专用
Seg_Disp(Seg_Pos,Seg_Buf[Seg_Pos],Seg_Point[Seg_Pos]);
Timer_1000Ms++;
if(Timer_1000Ms == 1000)
{
Timer_1000Ms = 0;
Clock_Disp[2]++;
if (Clock_Disp[2]==60)
{
Clock_Disp[2]=0;
Clock_Disp[1]++;
if (Clock_Disp[1]==60)
{
Clock_Disp[1]=0;
Clock_Disp[0]++;
if(Clock_Disp[0]==24)
Clock_Disp[0] = 0;
}
}
}
Timer_500Ms++;
if(Timer_500Ms == 500)
{
Timer_500Ms = 0;
Seg_Flag ^= 1;
if(Clock_Disp[0]>=12)//后4个灯闪烁
{
Led ^= 0xf0;//高4位取反,低4位不变
}
else
{
Led ^= 0x0f;
}
}
}
/* Main */
void main()
{
Timer0Init();
while (1)
{
Key_Proc();
Seg_Proc();
Led_Proc();
}
}
Key.c
#include <Key.h>
unsigned char Key_Read()
{
unsigned char temp = 0;
P3_0=0; P3_1 =1; P3_2 = 1; P3_3 = 1;
if(P3_4 == 0) temp = 1;
if(P3_5 == 0) temp = 2;
if(P3_6 == 0) temp = 3;
if(P3_7 == 0) temp = 4;
P3_0=1; P3_1 =0; P3_2 = 1; P3_3 = 1;
if(P3_4 == 0) temp = 5;
if(P3_5 == 0) temp = 6;
if(P3_6 == 0) temp = 7;
if(P3_7 == 0) temp = 8;
P3_0=1; P3_1 =1; P3_2 = 0; P3_3 = 1;
if(P3_4 == 0) temp = 9;
if(P3_5 == 0) temp = 10;
if(P3_6 == 0) temp = 11;
if(P3_7 == 0) temp = 12;
P3_0=1; P3_1 =1; P3_2 = 1; P3_3 = 0;
if(P3_4 == 0) temp = 13;
if(P3_5 == 0) temp = 14;
if(P3_6 == 0) temp = 15;
if(P3_7 == 0) temp = 16;
return temp;
}
Key.h
#include <REGX52.H>
unsigned char Key_Read();
Seg.c
#include "Seg.h"
unsigned char Seg_Dula[] = {0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x00};
unsigned char Seg_Wela[] = {0xfe,0xfd,0xfb,0xf7,0xef,0xdf};
void Seg_Disp(unsigned char wela,dula,point)
{
P0 = 0x00;
P2_6 = 1;
P2_6 = 0;
P0 = Seg_Wela[wela];
P2_7 = 1;
P2_7 = 0;
if(point == 1)
P0 = Seg_Dula[dula] | 0x80;
else
P0 = Seg_Dula[dula];
P2_6 = 1;
P2_6 = 0;
}
Seg.h
#include <REGX52.H>
void Seg_Disp(unsigned char wela,dula,point);