这两年比较火的网红 10 秒挑战规则为:挑战者按下开始按钮开始计时,当挑战者认为 10 秒将到时,再次按下按钮计时暂停,数码管上显示当前的计时时间。再次按下按钮,时间清零,重新开始下一次挑战。
利用 Nebula Pi 开发板的按键 KEY1 和数码管可以完成网红 10 秒挑战器的制作,程序如下:
smg.h:
#ifndef _SMG_H
#define _SMG_H
#include "reg52.h"
sbit Duan = P0^6; //位定义数码管段选
sbit Wei = P0^7; //位定义数码管位选
void DigDisplay(unsigned int Time);
void delay(unsigned int i);
#endif
smg.c:
#include "smg.h"
unsigned char i;
unsigned char code smgduan[] = {0x3F,0x06,0x5B,0x4F,
0x66,0x6D,0x7D,0x07,
0x7F,0x6F,0x77,0x7C,
0x39,0x5E,0x79,0x71,0X76}; //数码管0~F、H段码
void delay(unsigned int i)
{
while(i--);
}
void DigDisplay(unsigned int Time)
{
for(i=1;i<5;i++)
{
switch(i)
{
case(1):
P2 = 0xFE; //选中第一个数码管
Wei = 1;
Wei = 0; //位锁存
P2 = smgduan[Time/1000]; //时间的十位
Duan = 1;
Duan = 0;
break;
case(2):
P2 = 0xFD; //选中第二个数码管
Wei = 1;
Wei = 0; //位锁存
P2 = smgduan[Time/100%10] + 0x80; //时间的个位(+0x80是为了加小数点)
Duan = 1;
Duan = 0;
break;
case(3):
P2 = 0xFB; //选中第二个数码管
Wei = 1;
Wei = 0; //位锁存
P2 = smgduan[Time/10%10]; //时间的0.1s位
Duan = 1;
Duan = 0;
break;
case(4):
P2 = 0xF7; //选中第二个数码管
Wei = 1;
Wei = 0; //位锁存
P2 = smgduan[Time%10]; //时间的0.01s位
Duan = 1;
Duan = 0;
break;
}
delay(100);
P2 = 0x00;
Duan = 1;
Duan = 0; //消影
}
}
KeyState.h:
#ifndef _KEYSTATE_H
#define _KEYSTATE_H
#include "reg52.h"
unsigned char ReadKeyState(void);
void Timer_Init(void);
extern unsigned char Times; //用于按键按下次数的计算
#endif
KeyState.c:
#include "KeyState.h"
sbit Key1 = P1^0; //位定义KEY1按键
unsigned char KeyReturn; //保存按键的返回值
unsigned char Times = 0;
/****宏定义按键的初始、按下和抬起状态****/
#define Key_State_Init 0
#define Key_State_Down 1
#define Key_State_Up 2
unsigned char ReadKeyState(void)
{
static char KeyState = 0; //按键的状态值,初始值为0
unsigned char KeyPress; //保存按键的电平值
KeyPress = Key1; //保存P1.0口电平
switch( KeyState )
{
case Key_State_Init: //初始状态
if( !KeyPress ) //读取IO电平
{
KeyReturn = 0; //按键返回值为0
KeyState = Key_State_Down; //按键的状态转为按键按下的状态
}
break;
case Key_State_Down: //初始状态按下后转为按下状态
if( !KeyPress ) //读取IO电平确认按键是否真的被按下
{
KeyReturn = 1; //按键返回值为1
Times++; //每按下一次按键,按键按下次数+1
KeyState = Key_State_Up; //按键的状态转为按键释放的状态
}
else
{
KeyState = Key_State_Init; //如果IO电平为0,证明按键已抬起,回到初始状态
}
case Key_State_Up: //按下以后转为抬起状态
// if ( !KeyPress ) //如果按键一直按下,即没有抬起
// {
// Times ++; //只要一直按下按键,Times就会10ms增加1
// if( Times == 100 ) //Times=100时,1s定时时间到,标志位取反并且Times值清零
// {
// Flag = Flag;
// Times = 0;
// }
// }
if( KeyPress ) //如果按键抬起了
{
KeyReturn = 2; //按键返回值为2
KeyState = Key_State_Init; //读取IO电平,如果是1,证明按键已释放,回到初始状态
}
}
return KeyReturn;
}
void Timer_Init(void)
{
TMOD = 0x11; //定时器0、1均工作在方式1,定时器0用于时间计算,定时器用于按键值的读取
TH0 = 0xDC;
TL0 = 0x00; //定时器0 10ms定时初值
TH1 = 0xDC;
TL1 = 0x00; //定时器1 10ms定时初值
ET0 = 1; //开定时器0中断
ET1 = 1; //开定时器1中断
EA = 1; //开总中断
TR1 = 1; //打开定时器1
//TR0 = 1; //打开定时器0
}
main.c:
#include "reg52.h"
#include "smg.h"
#include "KeyState.h"
unsigned int time = 0;
unsigned char KeyNumber = 0; //按键值保存变量
void main(void)
{
Timer_Init();
while(1)
{
if( KeyNumber == 1 ) //按下按键开启不同动作
{
if( Times == 1 ) //按下一次按键后,开始计时
{
TH0 = 0xDC; //重新赋初值,防止上次停止时TH0和TL0中存在遗留值
TL0 = 0x00;
TR0 = 1;
}
if( Times == 2 ) //按下两次按键后,停止计时
{
TR0 = 0;
}
if( Times == 3 ) //按下三次按键后,重新开始计时,并将次数清零
{
Times = 0;
time = 0;
}
}
DigDisplay(time);
}
}
void Timer0() interrupt 1 using 1
{
TH0 = 0xDC; //重装初值,定时1ms初值高八位
TL0 = 0x00; //定时1ms初值低八位
time++; //时间加一
if ( time == 9999) time = 0;
}
void Timer1() interrupt 3 using 2
{
TH1 = 0xDC; //重装初值,定时1ms初值高八位
TL1 = 0x00; //定时1ms初值低八位
KeyNumber = ReadKeyState(); //读取按键值
}
视频:
10s.mp4