要求
功能要求
- 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;
}
}