本文只作为教学演示作用,如有问题及时私信我!
一、任务要求
使用Protues进行51单片机设计一个篮球比赛计时计分器:
二、任务所需原件及原理图
篮球得分计数器原理图
运行效果图如下所示:
二、部分电路分析
1、数码管部分
本任务采用的是八段共阳极数码管组成的显示电路,下面分析他的运行过程(本文不涉及到寄存器部分,只分析基础原理):
数码管其实多个LED按照一定顺序排列,并加上遮罩所构成的元件。
根据连接方式的不同,数码管分为共阳和共阴。共阳在这端输出低电平时点亮,高电平时会熄灭,共阴则相反。
2、蜂鸣器部分
当控制信号(连接到R5和Q1的基极)为低电平时,PNP晶体管会导通。导通是指晶体管的发射极(通常接高电平)和集电极之间会形成一个低阻通路,允许电流流过,因此蜂鸣器会响起。当控制信号为高电平时,PNP晶体管关闭,阻断了电流的流通,蜂鸣器则不会发声。
三、代码部分
#include<reg51.h>
#define uchar unsigned char
#define uint unsigned int
sbit LED_RED = P1^0; //定义LED指示灯接口
sbit LED_YELLOW = P1^1; //定义LED指示灯接口
sbit LED_GREEN = P1^2; //定义LED指示灯接口
sbit K1=P1^3; //定义按键接口
sbit K2=P1^4;
sbit K3=P1^5;
sbit K4=P1^6;
sbit K5=P1^7;
//蜂鸣器引脚
sbit BUZZ=P3^2;
uchar Display_data[6]= {0,0,0,0,0,0}; //存储要显示的数值
uchar time_count=0,time_1s=0;
uchar status=0; //比赛的状态
uchar A_val=0,B_val=0; //AB得分
uchar Run_time=0;//比赛时间
uchar game_over_falg=0;// 比赛结束标志位
uint game_over_delay=0; //比赛结束后的延时
//************************************
//定时器初始化
//************************************
void Time0_init()
{
TMOD |= 0x01; //使用模式1,16位定时器
TH0 = (65536-10000)/256; //定时器装入初始值10ms
TL0 = (65536-10000)%256;
EA = 1; //总中断
ET0 = 1;//定时器0初始化
TR0 = 1;
}
void delay_ms(uint i)//1ms延时
{
uchar x,j;
for(j=0; j<i; j++)
for(x=0; x<=148; x++);
}
//扫描按键
uchar KEY_Scan()
{
static uchar key_up=1;//按键松开标志
if(key_up&&(K1==0||K2==0||K3==0||K4==0||K5==0))
{
delay_ms(5);//去除抖动
key_up=0;
if(K1==0)return 1;
else if(K2==0)return 2;
else if(K3==0)return 3;
else if(K4==0)return 4;
else if(K5==0)return 5;
} else if(K1==1&&K2==1&&K3==1&&K4==1&&K5==1)key_up=1;
return 0;// 无按键按下
}
//数码管刷新函数
void Dis_num()
{
uchar table[]= {0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0x88,0x83,0xc6,0xa1,0x86,0x8e,0xf7,0XAF,0XFF}; //共阳数码管编码
static uchar i;
P0 = 0xff;
P2=1<<i;
P0 = table[Display_data[i]];
i++;
if(i>5)i=0;
}
//*************************************
//主函数
///***********************************
void main(void)
{
uchar key_num;
//初始化指示灯
LED_YELLOW = 1;
LED_GREEN=1;
LED_RED=1;
BUZZ=1;
Time0_init();
while(1)
{
if(status==0) //比赛停止
{
LED_YELLOW = 1;
LED_GREEN=1;
LED_RED=0;
}
else if(status==1) //比赛暂停
{
LED_YELLOW = 0;
LED_GREEN=1;
LED_RED=1;
}
else if(status==2) //比赛开始
{
LED_YELLOW = 1;
LED_GREEN=0;
LED_RED=1;
}
key_num = KEY_Scan(); //获取按键值
switch(key_num)
{
case 1: //开始
if(status==0)
{
Run_time=10;
status=2;
game_over_falg=0;
BUZZ=1;//关闭蜂鸣器
}
break;
case 2: //暂停
if(status==2)
status=1;
else if(status==1)
status=2;
break;
case 3: //清除
status=0;
A_val=0;
B_val=0;
Run_time=0;
break;
case 4: //A加分
if(status==2)
A_val+=2;
if(A_val>99)A_val=99;
break;
case 5: //B加分
if(status==2)
B_val+=2;
if(B_val>99)B_val=99;
break;
}
Display_data[0]=A_val/10;
Display_data[1]=A_val%10;
Display_data[2]=B_val/10;
Display_data[3]=B_val%10;
Display_data[4]=Run_time/10;
Display_data[5]=Run_time%10;
Dis_num();//显示
}
}
//****************************************************
//10ms定时器中断
//****************************************************
void time0(void)interrupt 1
{
if(status==2)//比赛开始才计时
{
time_count++;
if(time_count>=100)//1s时间
{
time_1s++;
time_count=0;
if(time_1s>=60)//60s
{
time_1s=0;
Run_time--;
if(Run_time==0)
{
game_over_falg=1;//完成比赛标志
status=0; //停止比赛
BUZZ=0; //打开蜂鸣器
}
}
}
}
if(status==0) //比赛停止
{
time_count=0;
time_1s=0;
}
if(game_over_falg)
{
game_over_delay++;
if(game_over_delay>=500)//5000ms
{
game_over_delay=0;
game_over_delay=0;
BUZZ=1;//关闭蜂鸣器
}
}
else
game_over_delay=0;
TH0=(65536-10000)/256;
TL0=(65536-10000)%256;
}
四、代码解析
主函数(main
)
- 初始化并持续检测按键输入,并根据输入更新得分、比赛状态和时间。
- 根据比赛状态更新LED指示灯状态。
- 持续调用
Dis_num
函数刷新显示。
void main(void)
{
uchar key_num;
//初始化指示灯
LED_YELLOW = 1;
LED_GREEN=1;
LED_RED=1;
BUZZ=1;
Time0_init();
while(1)
{
if(status==0) //比赛停止
{
LED_YELLOW = 1;
LED_GREEN=1;
LED_RED=0;
}
else if(status==1) //比赛暂停
{
LED_YELLOW = 0;
LED_GREEN=1;
LED_RED=1;
}
else if(status==2) //比赛开始
{
LED_YELLOW = 1;
LED_GREEN=0;
LED_RED=1;
}
key_num = KEY_Scan(); //获取按键值
switch(key_num)
{
case 1: //开始
if(status==0)
{
Run_time=10;
status=2;
game_over_falg=0;
BUZZ=1;//关闭蜂鸣器
}
break;
case 2: //暂停
if(status==2)
status=1;
else if(status==1)
status=2;
break;
case 3: //清除
status=0;
A_val=0;
B_val=0;
Run_time=0;
break;
case 4: //A加分
if(status==2)
A_val+=2;
if(A_val>99)A_val=99;
break;
case 5: //B加分
if(status==2)
B_val+=2;
if(B_val>99)B_val=99;
break;
}
Display_data[0]=A_val/10;
Display_data[1]=A_val%10;
Display_data[2]=B_val/10;
Display_data[3]=B_val%10;
Display_data[4]=Run_time/10;
Display_data[5]=Run_time%10;
Dis_num();//显示
}
}
定时器中断处理(time0
函数)
- 在比赛进行(
status==2
)时进行计时,每10ms递增time_count
。 - 每当
time_count
累计到100(即1秒),递增time_1s
计数器。 - 当
time_1s
累计到60(即1分钟),减少Run_time
计数器的值。 - 如果
Run_time
减到0,则标记比赛结束,停止比赛并响起蜂鸣器。 - 如果比赛已结束,则在5000ms后关闭蜂鸣器。
void time0(void)interrupt 1
{
if(status==2)//比赛开始才计时
{
time_count++;
if(time_count>=100)//1s时间
{
time_1s++;
time_count=0;
if(time_1s>=60)//60s
{
time_1s=0;
Run_time--;
if(Run_time==0)
{
game_over_falg=1;//完成比赛标志
status=0; //停止比赛
BUZZ=0; //打开蜂鸣器
}
}
}
}
if(status==0) //比赛停止
{
time_count=0;
time_1s=0;
}
if(game_over_falg)
{
game_over_delay++;
if(game_over_delay>=500)//5000ms
{
game_over_delay=0;
game_over_delay=0;
BUZZ=1;//关闭蜂鸣器
}
}
else
game_over_delay=0;
TH0=(65536-10000)/256;
TL0=(65536-10000)%256;
}