单片机篮球计时计分器设计与实现

单片机-篮球计时计分器实现

  • 要求
  • 功能要求
  • 显示要求
  • 附加功能
  • 电路图
  • 位选
  • 段选
  • 演示
  • 代码
  • 项目源码

    要求

    功能要求

  • 1、用8只数码管作为显示器件,最左边2只数码管显示甲队比分,最右边2只数码管显示乙队比分,最大显示范围是0—99分,当超过99分后从0重新开始计数,中间4只显示每节时间12分00秒倒计时,每节比赛结束时LED灯亮以示告警。
  • 5个按键开关,K1键控制时间的开始和暂停,按下K2键甲队加1分,K3键按下甲队减1分,K4键乙队加1分,K5键乙队减1分。
  • 显示要求

  • 系统开机时:计时时D1实现秒闪烁,以指示秒的变化,暂停时D1常亮。
  • 比分超过99分时:D3亮表示甲队100分,D4亮代表乙队。
  • 比分超过99分时:D3亮表示甲队100分,D4亮代表乙队。
  • 附加功能

  • 半场换场后,甲乙两队比分交换显示。
  • 实现对比赛时间的实时修改。(k6、k7 分钟加减,k8 秒加)
  • 电路图

    位选

    74LS138 是一种三-八译码器,它将三个输入线的不同组合映射到八个输出线上。这种译码器通常用于数字电路中,以选择其中一个输出线。74LS138 的三个输入线通常称为A2、A1 和 A0,它们可以采用二进制编码,用于选择要激活的输出线。这三个输入线有 2^3 = 8 种可能的组合,因此有 8 个输出线,每个输出线对应一个输入组合。要计算 74LS138 的输出线的激活情况,你需要查看输入线 A、B 和 C 的值,并确定哪个输出线处于激活状态。激活状态的输出线的编号可以通过以下公式来计算:

    Output_Line = A + B * 2 + C* 4
    其中 * 表示乘法运算,A、B 和 C 可以取 0 或 1。例如,如果 A = 1,B = 0,C = 1,那么:
    Output_Line = 1 * 4 + 0 * 2 + 1 = 4 + 0 + 1 = 5因此,在这种情况下,输出线 5 将被激活。

    段选

    一个8位数码管 每一段与二进制的对应关系:a b c d e f g dp,我们使用的是7SEG-MPX8-CA-BLUE 是共阳极数码管1点亮: 数字1就是:0 1 1 0 0 0 0 0 = 0x60;

    演示

    暂停恢复与加减
    请添加图片描述
    比分交换与时间加减
    请添加图片描述

    代码

    #include<reg51.h>
    #include<math.h>
    
    #define	SmLed	P0
    sbit S1 = P2 ^ 0;
    sbit S2 = P2 ^ 1;
    sbit S3= P2 ^ 2;
    // 按键
    sbit k2 = P1 ^ 0;
    sbit k3 = P1 ^ 1;
    sbit k4 = P1 ^ 2;
    sbit k5 = P1 ^ 3;
    sbit k6 = P2 ^ 3;
    sbit k7 = P2 ^ 4;
    sbit k8 = P2 ^ 5;
    // 指示灯
    sbit d1 = P1 ^ 4;
    sbit d2 = P1 ^ 5;
    sbit d3 = P1 ^ 6;
    sbit d4 = P1 ^ 7;
    unsigned char tab[11] = {0xfc, 0x60, 0xda, 0xf2,
                             //   0,   1,    2,   3  //
                             0x66, 0xb6, 0xbe, 0xe0, 0xfe, 0xf6, 0x00};
    // 分钟
    int minute = 10;
    // 秒
    int second = 10;
    // 定时中断记数
    int count = 0;
    // 左分数
    int lscore = 90;
    // 右分数
    int rscore = 0;
    // 定时状态, 1 正常,0 暂停
    int flag = 1;
    												 
    void delay(int c)
    {
        int i, j;
        for (i = 100; i > 0; i--)
        {
            for (j = c; j > 0; j--)
                ;
        }
    }
    void show()
    {
    		// 第一位
    		S1 = 0; S2 = 0;S3 =0;
    		SmLed = tab[lscore/10];
    		delay(0);
    		// 第二位 s1+2xs2+4xs3 = 1
    		S1 = 1; S2 = 0;S3 =0;
    		SmLed = tab[lscore%10];
    		delay(0);
    		// 第三位
    		S1 = 0; S2 = 1;S3 =0;
    		SmLed = tab[minute/10];
    		delay(0);
    			// 第四位
    		S1 = 1; S2 = 1;S3 =0;
    		SmLed = tab[minute%10];
    		delay(0);
    			// 第五位
    		S1 = 0; S2 = 0;S3 =1;
    		SmLed = tab[second/10];
    		delay(0);
    			// 第六位
    		S1 = 1; S2 = 0;S3 =1;
    		SmLed = tab[second%10];
    		delay(0);
    			// 第七位
    		S1 = 0; S2 = 1;S3 =1;
    		SmLed = tab[rscore/10];
    		delay(0);
    				// 第八位
    		S1 = 1; S2 = 1;S3 =1;
    		SmLed = tab[rscore%10];
    		delay(0);
    		
    }
    
    
    // 按键扫描
    void key_scan()
    {
        // k2 左边积分加
        if (k2 == 0)
        {
            // 按键消抖要比消除残影长一点
            delay(40);
            if (k2 == 0)
            {
                // 分数加
                lscore++;
                if (lscore == 100)
                {
                    // 分数到100分让 d3 常亮
                    d3 = 1;
                    lscore = 0;
                }
                // 按键抬起才退出 防止长按多次加分
                while (k2 == 0);
            }
        }
        // 左边积分减
        if (k3 == 0)
        {
            // 延时消抖
            delay(40);
            if (k3 == 0)
            {
                // d3灯亮(lscore>100)
                if (lscore)
                {
                    lscore--;
                }
                else
                {
                    if(d3){
    									d3 = 0;
    									lscore = 99;
    								}
                }
                while (k3 == 0);
            }
        }
        //  k4 k5 同上
        if (k4 == 0)
        {
            delay(40);
            if (k4 == 0)
            {
                rscore++;
                if (rscore == 100)
                {
                    d4 = 1;
                    rscore = 0;
                }
                while (k4 == 0);
            }
        }
        if (k5 == 0)
        {
            delay(40);
            if (k5 == 0)
            {
    
                if (rscore)
                {
                    rscore--;
                }
                else
                {
                    if (d4)
                    {
    									d4 = 0;
    									rscore = 99;
                    }
                }
                while (k5 == 0);
            }
        }
    		if (k6 == 0)
        {
            delay(40);
            if (k6 == 0)
            {
    					flag = 0;
    					TR0=0;
    					minute++;
    					if(minute > 12) {
    						minute = 12;
    						second = 0;
    					}
              while (k6 == 0);
            }
        }
    		if (k7 == 0)
        {
            delay(40);
            if (k7 == 0)
            {
    					flag = 0;
    					TR0=0;
    					minute--;
    					if(minute < 0) {
    						minute = 0;
    						second = 0;
    					}
              while (k7 == 0);
            }
        }
    		if (k8 == 0)
        {
            delay(40);
            if (k8 == 0)
            {
    					flag = 0;
    					TR0=0;
    					second++;
    					if(second >= 60) {
    						second = 0;
    					}
              while (k8 == 0);
            }
        }
    }
    // 定时器初始化
    void Timer_initial(void)
    {
        TMOD = 0x01; // 工作方式1
          // 25ms 12Mhz
        TH0 = (65536-25000)/256;
        TL0 = (65536-25000)%256;
        IE = 0x82;
        TR0 = 1; // 定时计算器1
        IT0 = 1;
        EX0 = 1;
        EA = 1;
    }
    // 计时结束的暂停函数
    void game_stop()
    {
        int i, j;
        for (i = 10; i > 0; i--)
        {
            for (j = 10; j > 0; j--)
            {
                show();
            }
        }
    }
    // 定时结束 交换比分
    void exchange()
    {
        int temp = lscore;
    
        game_stop();
        // 暂停结束 重新开始计时
        // 交换比分
        lscore = rscore;
        rscore = temp;
        // 重置参数
        count = 0;
        flag = 1;
        minute = 12;
        second = 0;
    
        if (lscore >= 100)
        {
            d3 = 1;
            lscore -= 100;
        }
        if (rscore >= 100)
        {
            d4 = 1;
            rscore -= 100;
        }
        // d2 熄灭 暂停灯
        d2 = 0;
        // 开始计时
        TR0 = 1;
    }
    void dinit(){
    	d1 = 0;
    	d2 = 0;
    	d3 =0;
    	d4 =0 ;
    }
    
    void main(){
    	// 定时 初始化
        Timer_initial();
    	dinit();
    	while(1){
    		        // 显示
            show();
            // 按键扫描
            key_scan();
    	}
    }
    // 定时中断
    void time0_int() interrupt 1
    {
        // 初始化 定时参数
        TR0 = 0;
        TH0 = (65536-25000)/256;
        TL0 = (65536-25000)%256;
        TR0 = 1;
        // 记录中断次数 1次25ms
        count++;
        // 40次1s
        if (count == 40)
        {
            // d1 闪烁
             d1 = !d1;
            count = 0;
            // 倒计时 对分,秒进行减操作
            if (second)
    				{
    					// 秒不为0 直接减
    					second--;
    				}
    				else
    				{
    					if (minute)
    					{
    						   // 只是秒为0 分钟减1 秒重置为59
                    minute--;
                    second = 59;
    					
    					}
    						else
    						{// 当 分 秒 都为 0 结束
    							
    							 // 停止记时
                    TR0 = 0;
                    // 因为暂停时除了d2其他指示灯全灭  所以要将 d3 d4 记录的分数加到 lscore 与 rscore上
                     lscore = 100*d3 + lscore;
                     rscore = 100*d4 + rscore;
                    // 熄灭全部指示灯 点亮暂停灯
    								dinit();
                    d2 = 1;
                    // 一小节结束 暂停与交换比分
                    exchange();
    						}
    				}
        }
    }
    // 外部中断 暂停与恢复计时
    void key() interrupt 0
    {
        if (flag)
        {
            TR0 = 0;
            flag = 0;
            // 暂停时 d1常亮
            d1 = 1;
        }
        else
        {
            TR0 = 1;
            flag = 1;
        }
    }
    
    
    
    
    物联沃分享整理
    物联沃-IOTWORD物联网 » 单片机篮球计时计分器设计与实现

    发表评论