单片机-篮球计时计分器

项目源码

要求

功能要求

  • 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;
    }
}



评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值