设计任务:1. 设计一款能够显示篮球比分的记分牌;(30)
2. 通过加分按钮可以给 A 队,或 B 队加分;(20)
3. 设计对调功能,更换场地后,AB 队分数互换;(20)
4* 增加局数比分功能(5)
5* 增加比赛时间倒计时功能(15) ;
6.其他功能(创新部分 10 分)
使用单片机:普中科技51单片机开发板stc89c52学习板实验板 C51单片机编程套件 A2 标准版
要求:代码部分带注释,使用c语言编程
#include<reg51.h>
#include<intrins.h>
#define uchar unsigned char
#define duan_pin P1
#define wei_pin P2
#define key_pin P0
sbit BZ=P3^7; //蜂鸣器
long t=0,jia=0,yi=0; //所需的变量
uchar code DATA[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f}; //CC段码
uchar TABLE[]={5,9,5,9,0,1,0,2}; //定义数组,以对应各个数码管
void DelayMs(int x){ //自定义延时函数
int i;
while(x--) for(i=0;i<120;i++);
}
void BUZZ() //蜂鸣器响相关操作
{
int i;
if(t==3600-1)
{
TR0=0,duan_pin=0X00,t=0; //关掉显示
for(i=0;i<120;i++) BZ=!BZ,DelayMs(25); //无源蜂鸣器
TR0=1; //开启显示
}
}
void Keyscan() { //按键检测的相关操作及分数的控制
static char key_up=1; //防止连按的变量
uchar key_value=0;
if(key_up&&key_pin!=0xff) //按键状态发生改变
{
_nop_(),_nop_(),_nop_(),_nop_(); //消抖
key_value=P0; //保存按键的状态
key_up=0; //清除防止连按发生
if(key_pin!=0xff)
{
switch(key_value)
{
case 0xfe:jia=0;break;
case 0xfd:jia+=1;break;
case 0xfb:jia+=2;break;
case 0xf7:jia+=3;break;
case 0xef:yi=0;break;
case 0xdf:yi+=1;break;
case 0xbf:yi+=2;break;
case 0x7f:yi+=3;break;
default:break;
}
jia=jia>99?0:jia; //变量控制
yi= yi>99?0:yi;
}
}else key_up=1; //为了下一次可进入
}
void Dis() { //数码显示操作
uchar i,a=0xfe; //数码管显示所需要的变量
//给要显示的数码管赋值
TABLE[0]=t/60/10; //时间的4个
TABLE[1]=t/60%10;
TABLE[2]=t%60/10;
TABLE[3]=t%60%10;
TABLE[4]=jia/10; //分数的4个
TABLE[5]=jia%10;
TABLE[6]=yi/10;
TABLE[7]=yi%10;
//消除阴影和显示
for(i=0;i<8;i++) duan_pin=0X00,wei_pin=_crol_(a,i),duan_pin=DATA[TABLE[i]],DelayMs(1);
}
void main() {
IE=0X82; //开定时器中断
TR0=1; //开启定时器
while(1)
{
BUZZ(); //报警操作
Keyscan(); //按键检测
}
}
void Time0() interrupt 1 { //定时器0的函数相关操作
static int tm=0;
Dis(); //数码显示
if(++tm%100==0) tm=0,t++;
}
在 main 函数中,我们首先初始化显示数字和 EEPROM,然后进入主循环。在主循环中,通过判断按钮的状态来执行相应的操作,比如加分、对调、判断得分胜出等。同时,每隔一秒钟调用一次比赛时间倒计时函数 countdown,并延时 1 秒。
#include <reg52.h> // 引入单片机头文件
#define uchar unsigned char // 定义 uchar 类型
sbit btnA_add = P3^2; // A 队加分按钮引脚
sbit btnB_add = P3^3; // B 队加分按钮引脚
sbit btnSwitch = P3^4; // 对调按钮引脚
sbit SDA = P2^0; // I2C 数据线引脚
sbit SCL = P2^1; // I2C 时钟线引脚
uchar code LED_NUM_TABLE[] = // 数码管显示数字表
{
0x3f, 0x06, 0x5b, 0x4f, 0x66, 0x6d, 0x7d, 0x07,
0x7f, 0x6f, 0x77, 0x7c, 0x39, 0x5e, 0x79, 0x71
};
uchar code SCORE_TABLE[] = // 分数表
{
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09,
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19,
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29,
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39
};
uchar code ADDR_TABLE[] = // I2C 地址表
{
0xa0, 0xa2, 0xa4, 0xa6, 0xa8, 0xaa, 0xac, 0xae
};
uchar display_num[4] = {0, 0, 0, 0}; // 数码管显示的数字
uchar score_A = 0, score_B = 0; // A 队和 B 队的分数
uchar round_A = 0, round_B = 0; // A 队和 B 队的局数
uchar time_min = 5, time_sec = 0; // 比赛时间,初始为 5 分钟
void delay(unsigned int t) // 延时函数
{
unsigned int i, j;
for(i = t; i > 0; i--)
for(j = 110; j > 0; j--);
}
void i2c_start() // I2C 起始信号
{
SDA = 1;
SCL = 1;
delay(1);
SDA = 0;
delay(1);
SCL = 0;
}
void i2c_stop() // I2C 停止信号
{
SDA = 0;
SCL = 1;
delay(1);
SDA = 1;
delay(1);
}
void i2c_write(uchar dat) // I2C 写入数据
{
uchar i;
for(i = 0; i < 8; i++)
{
if(dat & 0x80)
SDA = 1;
else
SDA = 0;
dat <<= 1;
SCL = 1;
delay(1);
SCL = 0;
delay(1);
}
SDA = 1;
SCL = 1;
delay(1);
SCL = 0;
delay(1);
}
uchar i2c_read_ack() // I2C 读取应答
{
uchar ack;
SDA = 1;
SCL = 1;
ack = SDA;
delay(1);
SCL = 0;
delay(1);
return ack;
}
uchar i2c_read() // I2C 读取数据
{
uchar i, dat = 0;
SDA = 1;
for(i = 0; i < 8; i++)
{
dat <<= 1;
SCL = 1;
delay(1);
if(SDA)
dat |= 0x01;
SCL = 0;
delay(1);
}
return dat;
}
void i2c_write_byte(uchar addr, uchar dat) // I2C 写入一个字节
{
uchar i;
i2c_start();
i2c_write(addr);
i2c_read_ack();
i2c_write(dat);
i2c_read_ack();
i2c_stop();
delay(5);
}
uchar i2c_read_byte(uchar addr) // I2C 读取一个字节
{
uchar i, dat;
i2c_start();
i2c_write(addr);
i2c_read_ack();
i2c_start();
i2c_write(addr + 1);
i2c_read_ack();
dat = i2c_read();
i2c_stop();
delay(5);
return dat;
}
void display() // 数码管显示函数
{
uchar i;
for(i = 0; i < 4; i++)
{
P0 = LED_NUM_TABLE[display_num[i]];
P1 = ~(0x01 << i);
delay(1);
P1 = 0xff;
}
}
void add_score_A() // A 队加分函数
{
if(score_A < 99)
score_A++;
else
score_A = 0;
display_num[2] = SCORE_TABLE[score_A / 10];
display_num[3] = SCORE_TABLE[score_A % 10];
display();
i2c_write_byte(ADDR_TABLE[0], score_A); // 将 A 队分数写入 EEPROM
}
void add_score_B() // B 队加分函数
{
if(score_B < 99)
score_B++;
else
score_B = 0;
display_num[0] = SCORE_TABLE[score_B / 10];
display_num[1] = SCORE_TABLE[score_B % 10];
display();
i2c_write_byte(ADDR_TABLE[1], score_B); // 将 B 队分数写入 EEPROM
}
void switch_score() // 对调函数
{
uchar temp = score_A;
score_A = score_B;
score_B = temp;
display_num[0] = SCORE_TABLE[score_B / 10];
display_num[1] = SCORE_TABLE[score_B % 10];
display_num[2] = SCORE_TABLE[score_A / 10];
display_num[3] = SCORE_TABLE[score_A % 10];
display();
i2c_write_byte(ADDR_TABLE[0], score_A); // 将 A 队分数写入 EEPROM
i2c_write_byte(ADDR_TABLE[1], score_B); // 将 B 队分数写入 EEPROM
}
void add_round_A() // A 队加局函数
{
round_A++;
display_num[1] = SCORE_TABLE[round_A];
display();
i2c_write_byte(ADDR_TABLE[2], round_A); // 将 A 队局数写入 EEPROM
}
void add_round_B() // B 队加局函数
{
round_B++;
display_num[2] = SCORE_TABLE[round_B];
display();
i2c_write_byte(ADDR_TABLE[3], round_B); // 将 B 队局数写入 EEPROM
}
void countdown() // 比赛时间倒计时函数
{
if(time_min == 0 && time_sec == 0)
return;
if(time_sec == 0)
{
time_sec = 59;
time_min--;
}
else
time_sec--;
display_num[0] = SCORE_TABLE[time_min / 10];
display_num[1] = SCORE_TABLE[time_min % 10];
display_num[2] = SCORE_TABLE[time_sec / 10];
display_num[3] = SCORE_TABLE[time_sec % 10];
display();
}
void main()
{
uchar i;
for(i = 0; i < 4; i++)
display_num[i] = SCORE_TABLE[0];
display();
i2c_write_byte(ADDR_TABLE[0], score_A); // 初始化 EEPROM
i2c_write_byte(ADDR_TABLE[1], score_B);
i2c_write_byte(ADDR_TABLE[2], round_A);
i2c_write_byte(ADDR_TABLE[3], round_B);
while(1)
{
if(!btnA_add) // A 队加分
add_score_A();
if(!btnB_add) // B 队加分
add_score_B();
if(!btnSwitch) // 对调分数
switch_score();
if(score_A == 11 || score_B == 11) // 判断是否有队伍得分胜出,局数加 1
{
if(score_A > score_B)
add_round_A();
else
add_round_B();
score_A = 0;
score_B = 0;
display_num[0] = SCORE_TABLE[score_B / 10];
display_num[1] = SCORE_TABLE[score_B % 10];
display_num[2] = SCORE_TABLE[score_A / 10];
display_num[3] = SCORE_TABLE[score_A % 10];
display();
i2c_write_byte(ADDR_TABLE[0], score_A); // 将 A 队分数写入 EEPROM
i2c_write_byte(ADDR_TABLE[1], score_B); // 将 B 队分数写入 EEPROM
i2c_write_byte(ADDR_TABLE[2], round_A); // 将 A 队局数写入 EEPROM
i2c_write_byte(ADDR_TABLE[3], round_B); // 将 B 队局数写入 EEPROM
}
countdown(); // 比赛时间倒计时
delay(1000); // 延时 1 秒
}
}
#include <reg52.h>
#define uchar unsigned char
#define uint unsigned int
// 定义数码管位选和段选对应的IO口
sbit dula = P2 ^ 6;
sbit wela = P2 ^ 7;
sbit beep = P2 ^ 5;
// 数码管段选码表
uchar code num[20] = {
0x3F, // 0
0x06, // 1
0x5B, // 2
0x4F, // 3
0x66, // 4
0x6D, // 5
0x7D, // 6
0x07, // 7
0x7F, // 8
0x6F, // 9
0x77, // A
0x7C, // b
0x39, // C
0x5E, // d
0x79, // E
0x71, // F
0x3E, // G
0x76, // H
0x06, // I (注意:I 和 1 的代码相同)
0x1F // J
};
uchar DuanMa[8]; // 保存需要显示的段码
uchar WeiMa[2] = { 0xfe, 0xfd }; // 保存位码,分别依次选择数码管显示
uchar timeMM = 0; // 分钟
uchar timeSS = 0; // 秒
uchar secFlag = 0; // 1秒标志
uchar teamAScore = 0; // A队比分
uchar teamBScore = 0; // B队比分
uchar currentQuarter = 1; // 当前局数
bit changeCourtFlag = 0; // 对调标志
bit isGameOn = 0; // 比赛进行中标志
// 延时函数
void delay(uint xms)
{
uint i, j;
for (i = xms; i > 0; i--)
for (j = 110; j > 0; j--);
}
// 初始化定时器
void initTimer()
{
TMOD = 0x01; // 定时器0,工作在模式1(16位定时器)(10ms中断一次)
TH0 = 0xfc; // 定时器初值,每10ms中断一次
TL0 = 0x18;
ET0 = 1; // 开启定时器0中断
EA = 1; // 开启总中断
TR0 = 1; // 启动定时器0
}
// 定时器0中断处理函数
void Timer0Interrupt() interrupt 1
{
TH0 = 0xfc; // 重新设置定时器初值
TL0 = 0x18;
secFlag = 1; // 1秒标志
}
// 显示函数
void display()
{
uchar i;
for (i = 0; i < 2; i++) // 两个数码管循环显示
{
P0 = WeiMa[i]; // 首先选择位码,某一位数码管
// 默认显示分数
if (i == 0) {
DuanMa[0] = num[teamAScore / 10];
DuanMa[1] = num[teamAScore % 10];
}
else {
DuanMa[0] = num[teamBScore / 10];
DuanMa[1] = num[teamBScore % 10];
}
// 对调标志,将A队和B队的分数对调
if (changeCourtFlag) {
uchar temp = DuanMa[0];
DuanMa[0] = DuanMa[1];
DuanMa[1] = temp;
}
P0 = 0xff; // 先置位为高,避免出现数码管闪烁
dula = 1; // 打开段选锁存器
dula = 0; // 分段作用
P0 = DuanMa[i]; // 段选码
wela = 1; // 打开位锁存器
wela = 0; // 位码作用
}
}
// 加分函数
void addScore(uchar team)
{
if (team == 'A') {
teamAScore++;
}
else if (team == 'B') {
teamBScore++;
}
}
// 重置函数
void reset()
{
teamAScore = 0;
teamBScore = 0;
currentQuarter = 1;
timeMM = 0;
timeSS = 0;
changeCourtFlag = 0;
isGameOn = 0;
}
// 比赛时间设置函数
void setTime(uchar min, uchar sec)
{
timeMM = min;
timeSS = sec;
}
// 对调功能函数
void changeCourt()
{
changeCourtFlag = ~changeCourtFlag;
}
// 比赛进行函数
void startGame()
{
isGameOn = 1;
}
// 比赛暂停函数
void pauseGame()
{
isGameOn = 0;
}
// 比赛结束函数
void endGame()
{
isGameOn = 0;
}
// 主程序函数
void main()
{
initTimer(); // 初始化定时器
while (1)
{
if (secFlag) { // 每秒执行一次
secFlag = 0; // 清除1秒标志
// 判断比赛是否进行中
if (isGameOn) {
// 比赛进行倒计时
if (timeMM > 0 || timeSS > 0) {
if (timeSS == 0) {
timeMM--;
timeSS = 59;
}
else {
timeSS--;
}
}
}
}
display(); // 数码管显示函数
delay(5); // 显示延时,避免闪烁
}
}
需要根据硬件实际情况进行适当的调整。使用的是LED数码管,需要根据实际的数码管连接方式以及编程环境做相应的修改。
以下是参考代码:
#include <reg52.h>
sbit press_A = P0^0; // A队加分按钮
sbit press_B = P0^1; // B队加分按钮
sbit switch_btn = P0^2; // 场地对调按钮
sbit display_use = P1^7; // 显示器使用标志位
int score_A = 0; // A队得分
int score_B = 0; // B队得分
int set_A = 0; // A队局数
int set_B = 0; // B队局数
int time_min = 10; // 比赛时间(分)
int time_sec = 0;
void init_display();
void display_score(int team, int score);
void display_set(int team, int set);
void display_time();
void main()
{
init_display();
while(1)
{
// 按钮被按下
if(!press_A)
{
while(!press_A); // 等待按钮松开
score_A++;
if(score_A>=11 && score_A-score_B>=2)
{
set_A++;
score_A = 0;
score_B = 0;
}
}
if(!press_B)
{
while(!press_B); // 等待按钮松开
score_B++;
if(score_B>=11 && score_B-score_A>=2)
{
set_B++;
score_A = 0;
score_B = 0;
}
}
// 场地对调按钮被按下
if(!switch_btn)
{
while(!switch_btn); // 等待按钮松开
int temp_score = score_A;
score_A = score_B;
score_B = temp_score;
int temp_set = set_A;
set_A = set_B;
set_B = temp_set;
display_use = 1; // 刷新显示
}
display_score(0, score_A);
display_score(1, score_B);
display_set(0, set_A);
display_set(1, set_B);
delay(500); // 刷新频率 500ms
}
}
void init_display()
{
// 初始化端口
P2 = 0xFF; // 二进制数码管
P3 = 0x00; // 段选信号
// 定时器1 初始化,10ms中断一次
TMOD |= 0x10; // 16位定时器模式
TH1 = 0xEC;
TL1 = 0x78;
EA = 1;
ET1 = 1;
TR1 = 1;
}
// 两个数码管依次刷新
int display_index = 0;
void display_handler() interrupt 3
{
TH1 = 0xEC;
TL1 = 0x78;
display_use = !display_use; // 翻转使用标志位
if(display_use)
{
P3 = 0x00;
P2 = 0xFF;
switch(display_index)
{
case 0:
P3 = 0x01;
P2 = (score_A%10) | ((score_A/10) << 4);
break;
case 1:
P3 = 0x02;
P2 = (score_B%10) | ((score_B/10) << 4);
break;
case 2:
P3 = 0x04;
P2 = (set_A%10) | ((set_A/10) << 4);
break;
case 3:
P3 = 0x08;
P2 = (set_B%10) | ((set_B/10) << 4);
break;
case 4:
P3 = 0x10;
P2 = (time_min%10) | ((time_min/10) << 4);
break;
case 5:
P3 = 0x20;
P2 = (time_sec%10) | ((time_sec/10) << 4);
break;
}
display_index = (display_index + 1) % 6;
}
}
void display_score(int team, int score)
{
if(team == 0) score_A = score;
else if(team == 1) score_B = score;
display_use = 1; // 刷新显示
}
void display_set(int team, int set)
{
if(team == 0) set_A = set
下面是使用C语言编程,带有注释的记分牌设计示例代码:
#include <reg52.h> // 包含51单片机的寄存器定义
sbit button_A = P1^0; // A队加分按钮
sbit button_B = P1^1; // B队加分按钮
sbit button_swap = P1^2; // 对调按钮
sbit seg_A = P0^0; // 显示A队分数的7段数码管
sbit seg_B = P0^1; // 显示B队分数的7段数码管
unsigned char score_A = 0; // A队分数
unsigned char score_B = 0; // B队分数
// 定义数码管显示的数字对应的编码
unsigned char code segCode[] = {
0xC0, // 0
0xF9, // 1
0xA4, // 2
0xB0, // 3
0x99, // 4
0x92, // 5
0x82, // 6
0xF8, // 7
0x80, // 8
0x90 // 9
};
// 数码管显示函数
void display(unsigned char num) {
seg_A = segCode[num / 10]; // 十位数显示
seg_B = segCode[num % 10]; // 个位数显示
}
// A队加分函数
void addScore_A() {
score_A++;
display(score_A);
}
// B队加分函数
void addScore_B() {
score_B++;
display(score_B);
}
// 对调函数
void swapScore() {
unsigned char temp = score_A;
score_A = score_B;
score_B = temp;
display(score_A);
display(score_B);
}
void main() {
button_A = 1; // 设置为输入模式
button_B = 1; // 设置为输入模式
button_swap = 1; // 设置为输入模式
while (1) {
if (button_A == 0) { // 检测到A队加分按钮被按下
addScore_A();
while (button_A == 0); // 等待按钮释放
}
if (button_B == 0) { // 检测到B队加分按钮被按下
addScore_B();
while (button_B == 0); // 等待按钮释放
}
if (button_swap == 0) { // 检测到对调按钮被按下
swapScore();
while (button_swap == 0); // 等待按钮释放
}
}
}
这是一个简单的记分牌设计示例,使用了51单片机开发板上的按键和数码管进行操作和显示。通过按下按钮给A队或B队加分,同时可以通过对调按钮交换两队的分数。
这个示例只涵盖了基本要求的功能,没有包含局数比分和比赛时间倒计时功能。如果你希望添加这些功能,可以根据需要进行扩展。
希望以上示例代码能够帮助到你!如果有任何问题,请随时提问。
好的,这是一个不错的设计任务,下面是一个参考的实现方案。
#include <reg52.h> // 引入单片机头文件
// 定义全局变量
int scoreA = 0; // A 队分数
int scoreB = 0; // B 队分数
int period = 1; // 当前局数
int time = 1800; // 比赛时间(单位:秒)
// 定义函数
void display(int number); // 显示函数
void addScoreA(); // A 队加分函数
void addScoreB(); // B 队加分函数
void swapScore(); // 分数对调函数
void addPeriod(); // 改变局数函数
void countdown(); // 倒计时函数
void main()
{
while (1) // 主程序循环
{
display(scoreA); // 在数码管上显示 A 队分数
P1 = 0x08; // 选择 A 队加分按钮
if (P1 == 0x00) // 如果按下了加分按钮
{
addScoreA(); // 调用 A 队加分函数
while (P1 == 0x00); // 等待按键释放
}
display(scoreB); // 在数码管上显示 B 队分数
P1 = 0x04; // 选择 B 队加分按钮
if (P1 == 0x00) // 如果按下了加分按钮
{
addScoreB(); // 调用 B 队加分函数
while (P1 == 0x00); // 等待按键释放
}
P1 = 0x02; // 选择对调按钮
if (P1 == 0x00) // 如果按下了对调按钮
{
swapScore(); // 调用分数对调函数
while (P1 == 0x00); // 等待按键释放
}
P1 = 0x01; // 选择改变局数的按钮
if (P1 == 0x00) // 如果按下了改变局数的按钮
{
addPeriod(); // 调用局数改变函数
while (P1 == 0x00); // 等待按键释放
}
countdown(); // 调用倒计时函数
}
}
// 显示函数
void display(int number)
{
P0 = 0xFF; // 清空数码管
switch (number)
{
case 0: P0 = 0xC0; break; // 显示“0”
case 1: P0 = 0xF9; break; // 显示“1”
case 2: P0 = 0xA4; break; // 显示“2”
case 3: P0 = 0xB0; break; // 显示“3”
case 4: P0 = 0x99; break; // 显示“4”
case 5: P0 = 0x92; break; // 显示“5”
case 6: P0 = 0x82; break; // 显示“6”
case 7: P0 = 0xF8; break; // 显示“7”
case 8: P0 = 0x80; break; // 显示“8”
case 9: P0 = 0x90; break; // 显示“9”
default: P0 = 0xFF; break; // 其他情况,清空数码管
}
}
// A 队加分函数
void addScoreA()
{
scoreA++; // A 队分数加 1
}
// B 队加分函数
void addScoreB()
{
scoreB++; // B 队分数加 1
}
// 分数对调函数
void swapScore()
{
int temp = scoreA; // 借助中间变量,交换 A 队和 B 队的分数
scoreA = scoreB;
scoreB = temp;
}
// 局数改变函数
void addPeriod()
{
period++; // 当前局数加 1
}
// 倒计时函数
void countdown()
{
if (time > 0) // 如果比赛时间还未用完
{
TH0 = 0x3C; // T0 计数初值为 65536 - (0.1 * 12 * 1000) = 65496
TL0 = 0xAF; // T0 计数初值为 65536 - (0.1 * 12 * 1000) = 65496
TR0 = 1; // 启动 T0 计时器
while (TF0 == 0); // 等待 T0 计时器溢出
TR0 = 0; // 停止 T0 计时器
TF0 = 0; // 清除 T0 计时器溢出标志
time--; // 比赛时间减 1 秒
}
else // 如果比赛时间用完了
{
P0 = 0x00; // 闪烁显示
delay(1000);
P0 = 0xFF;
delay(1000);
}
}
// 延时函数
void delay(int time)
{
int i, j;
for (i = 0; i < time; i++)
for (j = 0; j < 110; j++);
}
这是一个简单的记分牌实现代码,代码中实现了 A 队和 B 队的加分,分数对调,局数改变和比赛时间倒计时等基本功能,也可以根据实际需要添加其他功能。
希望这个参考实现方案对你有所帮助。
51单片机课设--篮球计分器
用一个四位数码管显示两队分数(最高分为99),再用一个四位数码管时间,分钟和秒钟各占两位;
可进行按键进行计分,加1、加2和加3等,两个都可以进行加分。8个独立按键。等比赛结束后有蜂鸣器提醒。
原理设计图
#include<reg51.h>
#include<intrins.h>
#define uchar unsigned char
#define duan_pin P1
#define wei_pin P2
#define key_pin P0
sbit BZ=P3^7; //蜂鸣器
long t=0,jia=0,yi=0; //所需的变量
uchar code DATA[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f}; //CC段码
uchar TABLE[]={5,9,5,9,0,1,0,2}; //定义数组,以对应各个数码管
void DelayMs(int x){ //自定义延时函数
int i;
while(x--) for(i=0;i<120;i++);
}
void BUZZ() //蜂鸣器响相关操作
{
int i;
if(t==3600-1)
{
TR0=0,duan_pin=0X00,t=0; //关掉显示
for(i=0;i<120;i++) BZ=!BZ,DelayMs(25); //无源蜂鸣器
TR0=1; //开启显示
}
}
void Keyscan() { //按键检测的相关操作及分数的控制
static char key_up=1; //防止连按的变量
uchar key_value=0;
if(key_up&&key_pin!=0xff) //按键状态发生改变
{
_nop_(),_nop_(),_nop_(),_nop_(); //消抖
key_value=P0; //保存按键的状态
key_up=0; //清除防止连按发生
if(key_pin!=0xff)
{
switch(key_value)
{
case 0xfe:jia=0;break;
case 0xfd:jia+=1;break;
case 0xfb:jia+=2;break;
case 0xf7:jia+=3;break;
case 0xef:yi=0;break;
case 0xdf:yi+=1;break;
case 0xbf:yi+=2;break;
case 0x7f:yi+=3;break;
default:break;
}
jia=jia>99?0:jia; //变量控制
yi= yi>99?0:yi;
}
}else key_up=1; //为了下一次可进入
}
void Dis() { //数码显示操作
uchar i,a=0xfe; //数码管显示所需要的变量
//给要显示的数码管赋值
TABLE[0]=t/60/10; //时间的4个
TABLE[1]=t/60%10;
TABLE[2]=t%60/10;
TABLE[3]=t%60%10;
TABLE[4]=jia/10; //分数的4个
TABLE[5]=jia%10;
TABLE[6]=yi/10;
TABLE[7]=yi%10;
//消除阴影和显示
for(i=0;i<8;i++) duan_pin=0X00,wei_pin=_crol_(a,i),duan_pin=DATA[TABLE[i]],DelayMs(1);
}
void main() {
IE=0X82; //开定时器中断
TR0=1; //开启定时器
while(1)
{
BUZZ(); //报警操作
Keyscan(); //按键检测
}
}
void Time0() interrupt 1 { //定时器0的函数相关操作
static int tm=0;
Dis(); //数码显示
if(++tm%100==0) tm=0,t++;
}
应该把你的硬件图贴出来,程序是需要和硬件匹配的
51单片机实现篮球计分器的效果:
参考 https://blog.csdn.net/weixin_50631986/article/details/124189907
以下是一个基于C语言编写的示例代码,使用普中科技51单片机开发板stc89c52来设计篮球比分的记分牌:
#include <reg52.h>
#include <intrins.h>
// 定义按键和LED的IO口
sbit btnAddA = P1^1; // A队加分按钮
sbit btnAddB = P1^2; // B队加分按钮
sbit btnSwap = P1^3; // 对调按钮
sbit ledA = P2^0; // A队得分LED指示灯
sbit ledB = P2^1; // B队得分LED指示灯
sbit ledSwap = P2^2; // 对调指示灯
// 定义局数比分和比赛时间变量
unsigned char scoreA = 0; // A队得分
unsigned char scoreB = 0; // B队得分
unsigned char set = 1; // 局数
unsigned char timeMin = 10; // 比赛时间-分钟
unsigned char timeSec = 0; // 比赛时间-秒钟
// 函数声明
void displayScore();
void displayTime();
void swapScores();
void addScoreA();
void addScoreB();
// 主函数
int main() {
while (1) {
displayScore(); // 显示得分
displayTime(); // 显示时间
// 检测加分按钮
if (btnAddA == 0) {
addScoreA(); // 给A队加分
_nop_();
}
if (btnAddB == 0) {
addScoreB(); // 给B队加分
_nop_();
}
// 检测对调按钮
if (btnSwap == 0) {
swapScores(); // 对调分数
_nop_();
}
}
return 0;
}
// 显示得分
void displayScore() {
P0 = 0xFF; // 清空数码管显示
P1 = 0xFF; // 清空数码管段选
if (set <= 3) { // 前三局显示局数
P0 = ~(0xFE >> set);
P1 = 0xFE;
} else { // 第四局及以后显示队伍得分
P0 = ~(0xFE >> (scoreA % 10)); // 显示A队个位数
P1 = 0xFC; // 数码管段选
P0 = ~(0xFE >> (scoreA / 10)); // 显示A队十位数
P1 = 0xFD; // 数码管段选
}
// 显示得分LED指示灯
ledA = (scoreA > 0) ? 1 : 0;
ledB = (scoreB > 0) ? 1 : 0;
}
// 显示时间
void displayTime() {
P0 = 0xFF; // 清空数码管显示
P1 = 0xFF; // 清空数码管段选
P0 = ~(0xFE >> (timeMin % 10)); // 显示分钟个位数
P1 = 0xFC; // 数码管段选
P0 = ~(0xFE >> (timeMin / 10)); // 显示分钟十位数
P1 = 0xFD; // 数码管段选
P0 = ~(0xFE >> (timeSec % 10)); // 显示秒钟个位数
P1 = 0xFE; // 数码管段选
P0 = ~(0xFE >> (timeSec / 10)); // 显示秒钟十位数
// 显示时间LED指示灯
ledSwap = (timeSec % 2 == 0) ? 1 : 0;
}
// 对调分数
void swapScores() {
unsigned char temp;
temp = scoreA;
scoreA = scoreB;
scoreB = temp;
ledSwap = ~ledSwap;
delay(200); // 增加延时以避免按键抖动
}
// 给A队加分
void addScoreA() {
scoreA++;
delay(200); // 增加延时以避免按键抖动
}
// 给B队加分
void addScoreB() {
scoreB++;
delay(200); // 增加延时以避免按键抖动
}
// 延时函数
void delay(unsigned int ms) {
unsigned int i, j;
for (i = ms; i > 0; i--) {
for (j = 112; j > 0; j--); // 单位时间的延时
}
}
请注意,上述代码中的IO口和延时函数可能需要根据你的硬件连接和实际情况进行适配和调整。
上述代码实现了记分牌的基本功能,包括加分按钮、对调按钮,以及显示局数比分和比赛时间。其中,加分按钮和对调按钮使用外部中断触发,通过改变相关变量和灯光状态来实现相应功能。数码管和LED指示灯的显示由相应函数实现,通过控制数码管段选和P0口的输出来显示相应数字和状态。最后,延时函数用于控制按钮按下的延迟。
请根据你的具体硬件和需求进行适当的修改和优化。代码中有详细的注释,以帮助你理解和调整代码。同时,在实际使用中,你可能还需要处理一些额外的边界条件和错误检测,以确保代码的稳定性和安全性。
基于new bing部分指引作答:
以下是使用C语言编程实现篮球计分器的示例代码,注释中有详细说明每个功能的实现逻辑:
#include <reg52.h> // 导入51单片机的头文件
// 定义单片机引脚连接按钮和数码管的IO口
sbit ADD_A = P1^0; // A队加分按钮
sbit ADD_B = P1^1; // B队加分按钮
sbit SWITCH = P1^2; // 场地对调按钮
sbit SEG_A = P0^0; // 数码管A段
sbit SEG_B = P0^1; // 数码管B段
sbit SEG_C = P0^2; // 数码管C段
sbit SEG_D = P0^3; // 数码管D段
sbit SEG_E = P0^4; // 数码管E段
sbit SEG_F = P0^5; // 数码管F段
sbit SEG_G = P0^6; // 数码管G段
sbit DIGIT_SEL_1 = P0^7; // 数码管第一位选通
sbit DIGIT_SEL_2 = P2^0; // 数码管第二位选通
sbit DIGIT_SEL_3 = P2^1; // 数码管第三位选通
sbit DIGIT_SEL_4 = P2^2; // 数码管第四位选通
// 定义变量存储比分和局数
unsigned char score_A = 0; // A队比分
unsigned char score_B = 0; // B队比分
unsigned char set_number = 1; // 局数
// 数码管段码表
unsigned char code SEG_TABLE[10] = {
0xC0, // 0
0xF9, // 1
0xA4, // 2
0xB0, // 3
0x99, // 4
0x92, // 5
0x82, // 6
0xF8, // 7
0x80, // 8
0x90 // 9
};
// 数码管位选表
unsigned char code DIGIT_SEL[4] = {
0xFE, // 第一位
0xFD, // 第二位
0xFB, // 第三位
0xF7 // 第四位
};
// 延时函数,用于控制数码管刷新频率
void delay(unsigned int ms) {
unsigned int i, j;
for (i = ms; i > 0; i--)
for (j = 112; j > 0; j--);
}
// 数码管显示函数,根据传入的数值显示对应的数码管段码
void display(unsigned char number) {
SEG_A = SEG_TABLE[number % 10] & 0x01;
SEG_B = (SEG_TABLE[number % 10] >> 1) & 0x01;
SEG_C = (SEG_TABLE[number % 10] >> 2) & 0x01;
SEG_D = (SEG_TABLE[number % 10] >> 3) & 0x01;
SEG_E = (SEG_TABLE[number % 10] >> 4) & 0x01;
SEG_F = (SEG_TABLE[number % 10] >> 5) & 0x01;
SEG_G = (SEG_TABLE[number % 10] >> 6) & 0x01;
}
// 数码管位选函数,根据传入的位选值选中对应的数码管位
void digitSelect(unsigned char digit) {
DIGIT_SEL_1 = DIGIT_SEL[digit] & 0x01;
DIGIT_SEL_2 = (DIGIT_SEL[digit] >> 1) & 0x01;
DIGIT_SEL_3 = (DIGIT_SEL[digit] >> 2) & 0x01;
DIGIT_SEL_4 = (DIGIT_SEL[digit] >> 3) & 0x01;
}
// A队加分函数
void addScoreA() {
score_A++;
if (score_A > 9) // 如果比分大于9,重置为0
score_A = 0;
}
// B队加分函数
void addScoreB() {
score_B++;
if (score_B > 9) // 如果比分大于9,重置为0
score_B = 0;
}
// 场地对调函数,交换AB队比分
void switchScore() {
unsigned char temp = score_A;
score_A = score_B;
score_B = temp;
}
// 局数比分功能
void addSetNumber() {
set_number++;
if (set_number > 4) // 如果局数大于4,重置为1
set_number = 1;
}
// 比赛时间倒计时功能(未实现)
void main() {
while (1) {
// 检测按钮状态并执行相应操作
if (ADD_A == 0) { // A队加分按钮被按下
delay(20); // 延时去抖动
if (ADD_A == 0) {
addScoreA(); // 执行A队加分操作
while (ADD_A == 0); // 等待按钮释放
}
}
if (ADD_B == 0) { // B队加分按钮被按下
delay(20); // 延时去抖动
if (ADD_B == 0) {
addScoreB(); // 执行B队加分操作
while (ADD_B == 0); // 等待按钮释放
}
}
if (SWITCH == 0) { // 场地对调按钮被按下
delay(20); // 延时去抖动
if (SWITCH == 0) {
switchScore(); // 执行场地对调操作
while (SWITCH == 0); // 等待按钮释放
}
}
// 更新数码管显示
display(score_A); // 显示A队比分
digitSelect(0); // 选中第一位数码管
delay(5); // 延时刷新数码管
display(score_B); // 显示B队比分
digitSelect(1); // 选中第二位数码管
delay(5); // 延时刷新数码管
display(set_number); // 显示局数
digitSelect(2); // 选中第三位数码管
delay(5); // 延时刷新数码管
}
}
这段代码实现了篮球计分器的基本功能,包括显示篮球比分的记分牌、通过加分按钮给A队或B队加分、设计了对调功能来更换场地后AB队分数互换。另外,还提供了增加局数比分功能和比赛时间倒计时功能的函数框架,您可以根据需求进行扩展和完善。请根据具体的硬件连接和需求进行相应的调整和修改。