Protues的程序应用——篮球得分计数器
Protues的程序应用——篮球得分计数器

Protues的程序应用——篮球得分计数器

本文只作为教学演示作用,如有问题及时私信我!

一、任务要求

使用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;
}

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注