基于单片机的篮球计数器设计
作者:***
摘要:本次课程设计是使用51单片机完成篮球计数器的设计。为达到本次的设计目标,我决定使用全部的八个数码管,分别显示节次、时间、A队得分和B队得分;一开始是计划使用矩阵按键来完成加分减分暂停等功能,由于单片机端口经常有冲突,我就改用了独立按键,使用独立按键K1和K4完成对A、B两队的加分;使用串口来与上位机进行信息通讯,反映A、B得分;此外我增添了液晶屏功能,获胜的一方会在液晶屏上显示;
关键词: 数码管、独立按键、串口、LED。
1 系统整体设计
1.1功能需求分析
(1)选定第一二三四数码管显示A、B两队得分。
(2)通过两个加分按钮可以给A队或B队加分,K1,K4来加分。
(3)每10S为一局,局数到第三局时,A队和B队分数自动互换,意味着中场交换场地。
(4)每一节为10S,数码管实时显示比赛比分,及倒计时功能。
(5)能够显示是第几节,当前比分是多少,同时把最终的结果通过发送字符2和3发送到上位机的串口助手上。
(6)上位机发送字符,单片机接受到表示比赛正式开始每10S为一局,局数也要显示在数码管上,此时按加分键才有效。篮球比赛一共四节,前2节时,到第三节开始自动互换比分。
(7)获胜的一方会在液晶屏上显示
1.2功能结构层次图
2 硬件电路设计
2.1 2.1所需单片机硬件部分
(1)单片机核心:单片机最小系统三要素为电源、晶振和复位电路
电源:目前主流单片机的电源分为5V和3.3V这两个标准,而我们使用的是需要5V的供电系统,开发板是使用USB口输出的5V直流电直接供电的。
晶振:又叫晶体振荡器,它起到的作用是为单片机系统提供基准时钟信号,单片机内部所有的工作都是以这个时钟信号为步调基准来进行工作的。STC89C52单片机的18引脚和19引脚是晶振引脚,接了一个11.0592MHz的晶振,外加两个20pF的电容,电容的作用是帮助晶振起振,并维持振荡信号稳定。
复位电路:单片机复位一般分为三种情况:上电复位、手动复位和程序自动复位。
(2)独立按键模块
独立按键:4条输入线接到单片机的I/O口上,当按下按键K1时,+5V依次通过电阻R1和按键K1最终进入GND形成一条通路,这条线路的全部电压都加到电阻R1上,引脚KeyIn1就是一个低电平。当松开按键后,线路断开,不会有电流通过,Keylnl和+5V应该是等电位,是一个高电平。因此,可以通过引脚KeyInl这个I/O口的高低电平来判断是否有按键按下。
(3)动态数码管模块
动态数码管:多个数码管显示数字的时候,实际上是轮流点亮数码管(一个时刻内只有一个数码管是亮的),利用人眼的视觉暂留现象(也叫余晖效应),就可以做到看起来是所有数码管都同时亮了,这就是动态显示,也叫作动态扫描。
(4)74HC138译码器:在设计单片机电路的时候,单片机的I/O口数量是有限的,有时满足不了设计需求,比如STC89C52一共有32个I/O口,但是为了控制更多的器件,就要使用一些外围的数字芯片,这种数字芯片由简单的输入逻辑来控制输出逻辑,比如74HC138这个三八译码器,从这个名字来分析,三八译码器就是把3种输入状态翻译成8种输出状态。
(5)LED模块:LED(Light-Emitting Diode),即发光二极管,俗称LED小灯,它的种类很多,参数也不尽相同,KST-51开发板用的是普通的贴片发光二极管。这种二极管通常的正向导通电压是1.8~2.2V,工作电流一般在1~20mA。其中,当电流在1~5mA变化时,随着通过LED时,看到的发光二极管的亮度变化就不太明显了。当电流超过20mA时,LED就会有烧坏的危险了,电流越大,烧坏的速度也就越快。所以在使用过程中应该特别注意它在电流参数上的设计要求。
3、软件程序设计
3.1 软件设计思路
(1)完成这次的课题需要用到数码管、独立按键、LED、中断、串口等零零散散的程序,需要把多个程序编排在一起,使之联系紧密,互相融合,共同协作完成本次任务。
(2)先从主要问题入手,完成数码管程序的调试。
(3)数码管程序调试完成后,再调试独立按键模块。
(4)数码管和独立按键都可正常完成任务时,开始编写主函数,按照功能层次结构图来编写,使之能够满足本次课题目标。
(5)最后开始调试串口,使之能与上位机进行通讯,完成信息交流。
3.2 各函数调试后结果
(1)数码管显示字符转换
unsigned char code LedChar[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};//数码管字符转换表
(2)相关定义
unsigned char ledbuff[8]={0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00};//缓冲区
unsigned char i=0;//动态刷新值
unsigned char cnt1=0;//B队分数
unsigned char cnt2=0; //A队分数
unsigned char cnt3=10;//10s计数值
unsigned int cnt4=0;//正在进行的局数
unsigned char cnt5=0;//总时间
unsigned char flagls=0; //1s定时标志
unsigned char t=0;//过渡值
unsigned int sec=0;//中断次数
unsigned char j; //串口信号
bit keysta1=1; //按键
bit keysta2=1;
(3)按键判断if(keysta1!=backup1) //判断按键是否按下
{
if(backup1==0)
{
cnt1++;
}
backup1=keysta1;
}
if(keysta2!=backup2)
{
if(backup2==0)
{
cnt2++;
}
backup2=keysta2;
}
(4)倒计时
if(flagls==1) //10s倒计时
{flagls=0;
ledbuff[4]=LedChar[cnt3%10];
ledbuff[5]= LedChar[cnt3/10%10];
if(cnt3==10)cnt4++;
cnt3--;cnt5++;
if(cnt3==-1)cnt3=10;
} ledbuff[6]= LedChar[cnt4];
(5)交换场地
if(cnt5==22) //双方交换场地
{ t=cnt1;
cnt1=cnt2;
cnt2=t;
ledbuff[0] =LedChar[cnt1%10];
ledbuff[1] =LedChar[cnt1/10%10];
ledbuff[2]=LedChar[cnt2%10];
ledbuff[3]= LedChar[cnt2/10%10];
}
(6)按键消抖
static unsigned char keybuf1=0xff; //按键消抖
static unsigned char keybuf2=0xff;
TH0=0xf8;
TL0=0xCD;
keybuf1=(keybuf1<<1)|key4;
keybuf2=(keybuf2<<1)|key1;
if(keybuf1==0x00)
{keysta1=0;
}
else if(keybuf1==0xFF)
{keysta1=1;
}
if(keybuf2==0x00)
{keysta2=0;
}
else if(keybuf2==0xFF)
{keysta2=1;
}
- 数码管扫描
switch(i)//数码管扫描
{
case 0:x=0;y=0;z=0;i++;P0= ledbuff[0];break;
case 1:x=1;y=0;z=0;i++;P0= ledbuff[1];break;
case 2:x=0;y=1;z=0;i++;P0= ledbuff[2];break;
case 3:x=1;y=1;z=0;i++;P0= ledbuff[3];break;
case 4:x=0;y=0;z=1;i++;P0= ledbuff[4];break;
case 5:x=1;y=0;z=1;i++;P0= ledbuff[5];break;
case 6:x=0;y=1;z=1;i=0;P0= ledbuff[6];break;
default:break;}
- 串口
void ConfigUART(unsigned int baud)//串口配置
{
SCON=0x50;
TMOD&=0x0F;
TMOD|=0x20;
TH1=256-(12000000/12/32)/baud;
TL1=TH1;
ES=1;
TR1=1;
}
void InterruptUART() interrupt 4
{
if(RI)
{
RI=0;
if(SBUF==2) //判断接收字符为2
{SBUF=cnt2;}//返还A队得分
else if(SBUF==3) //判断接收字符为3
{SBUF=cnt1;} //返还B队得分
else{ j=SBUF ;
SBUF=j;
}
if(TI)
{
TI=0;
}
}
}
4 系统仿真与调试
(1)接通电源,烧录程序
(2)上位机发送字符1,开始倒计
(3)按下K1、k4,B队8分A队11分
(4)第三场时B、A交换为A、B分数交换
(5)第四场结束停止计时
(6)液晶屏上显示A队获胜
(7)上位机发送字符2和3,分别接收A、B分数
附录:程序代码
#include<reg52.h>
sbit x=P2^2;
sbit y=P2^3;
sbit z=P2^4;
sbit key1=P3^1;
sbit key4=P3^3;
sbit A=P2^0;
sbit C=P2^7;
void ConfigUART(unsigned int baud);
unsigned char code LedChar[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};//数码管字符转换表
unsigned char ledbuff[8]={0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00};//缓冲区
unsigned char i=0;//动态刷新值
unsigned char cnt1=0;//B队分数
unsigned char cnt2=0; //A队分数
unsigned char cnt3=10;//10s计数值
unsigned int cnt4=0;//正在进行的局数
unsigned char cnt5=0;//总时间
unsigned char flagls=0; //1s定时标志
unsigned char t=0;//过渡值
unsigned int sec=0;//中断次数
unsigned char j; //串口信号
bit keysta1=1; //按键
bit keysta2=1;
#define lcd1602db P0
sbit lcd1602rs=P2^6;
sbit lcd1602rw=P2^5;
sbit lcd1602e=P2^7;
void initlcd1602();
void lcdshowstr(unsigned char x,unsigned char y,unsigned char *str);
void lcdwritecmd(unsigned char cmd);
void lcdwritedat(unsigned char dat);
void delay(unsigned int L);
void main()
{
unsigned char str[8];
bit backup1=1;
bit backup2=1;
EA=1;
TMOD=0x01;
TH0=0xFC;
TL0=0x67;
ET0=1;
TR0=1;
P2=0xF7;
P0=0x3f;
while(1)//总循环
{
ConfigUART(9600);//波特率
while(cnt5==44)//四次比赛后不再计时,led显示获胜方
{
if(cnt1>cnt2) {unsigned char str[]= " win B";
initlcd1602();
lcdshowstr(4,0,str);
while(1);}
else { unsigned char str[]=" win A";
initlcd1602();
lcdshowstr(4,0,str) ;
while(1);} }
if(j!='\0') //有字符信号开始比赛
{
if(keysta1!=backup1) //判断按键是否按下
{
if(backup1==0)
{
cnt1++;
}
backup1=keysta1;
}
if(keysta2!=backup2)
{
if(backup2==0)
{
cnt2++;
}
backup2=keysta2;
}
if(flagls==1) //10s倒计时
{flagls=0;
ledbuff[4]=LedChar[cnt3%10];
ledbuff[5]= LedChar[cnt3/10%10];
if(cnt3==10)cnt4++;
cnt3--;cnt5++;
if(cnt3==-1)cnt3=10;
} ledbuff[6]= LedChar[cnt4];
if(cnt5==22) //双方交换场地
{ t=cnt1;
cnt1=cnt2;
cnt2=t;
ledbuff[0] =LedChar[cnt1%10];
ledbuff[1] =LedChar[cnt1/10%10];
ledbuff[2]=LedChar[cnt2%10];
ledbuff[3]= LedChar[cnt2/10%10];
} }
} }
void InterrupTimer() interrupt 1
{
static unsigned char keybuf1=0xff; //按键消抖
static unsigned char keybuf2=0xff;
TH0=0xf8;
TL0=0xCD;
keybuf1=(keybuf1<<1)|key4;
keybuf2=(keybuf2<<1)|key1;
if(keybuf1==0x00)
{keysta1=0;
}
else if(keybuf1==0xFF)
{keysta1=1;
}
if(keybuf2==0x00)
{keysta2=0;
}
else if(keybuf2==0xFF)
{keysta2=1;
}
TH0=0xFC;//1s计时
TL0=0X67;
sec++;
if(sec>=1000)
{sec=0;
flagls=1;
}
ledbuff[0]=LedChar[cnt1%10];
ledbuff[1]= LedChar[cnt1/10%10];
ledbuff[2]=LedChar[cnt2%10];
ledbuff[3]= LedChar[cnt2/10%10];
switch(i)//数码管扫描
{
case 0:x=0;y=0;z=0;i++;P0= ledbuff[0];break;
case 1:x=1;y=0;z=0;i++;P0= ledbuff[1];break;
case 2:x=0;y=1;z=0;i++;P0= ledbuff[2];break;
case 3:x=1;y=1;z=0;i++;P0= ledbuff[3];break;
case 4:x=0;y=0;z=1;i++;P0= ledbuff[4];break;
case 5:x=1;y=0;z=1;i++;P0= ledbuff[5];break;
case 6:x=0;y=1;z=1;i=0;P0= ledbuff[6];break;
default:break;}
}
void ConfigUART(unsigned int baud)//串口配置
{
SCON=0x50;
TMOD&=0x0F;
TMOD|=0x20;
TH1=256-(12000000/12/32)/baud;
TL1=TH1;
ES=1;
TR1=1;
}
void lcdwaitready()
{
unsigned char sta;
lcd1602db=0xff;
lcd1602rs=0;
lcd1602rw=1;
do{
lcd1602e=1;
sta=lcd1602db;
lcd1602e=0;
}
while(sta&0x80);
}
void lcdwritecmd(unsigned char cmd)
{
lcdwaitready();
lcd1602rs=0;
lcd1602rw=0;
lcd1602db=cmd;
//delay(5);
lcd1602e=1;
//delay(5);
lcd1602e=0;
}
void lcdwritedat(unsigned char dat)
{
lcdwaitready();
lcd1602rs=1;
lcd1602rw=0;
lcd1602db=dat;
lcd1602e=1;
lcd1602e=0;
}
void lcdsetcursor(unsigned char x,unsigned char y)
{
unsigned char addr;
if(y==0)
addr=0x00+x;
else
addr=0x40+x;
lcdwritecmd(addr|0x80);
}
void lcdshowstr(unsigned char x,unsigned char y,unsigned char *str)
{
lcdsetcursor(x,y);
while(*str!= '\0')
{
lcdwritedat(*str++);
}
}
void initlcd1602()
{
lcdwritecmd(0x38);
lcdwritecmd(0x0c);
lcdwritecmd(0x06);
lcdwritecmd(0x01);
}
void InterruptUART() interrupt 4
{
if(RI)
{
RI=0;
if(SBUF==2) //判断接收字符为2
{SBUF=cnt2;}//返还A队得分
else if(SBUF==3) //判断接收字符为3
{SBUF=cnt1;} //返还B队得分
else{ j=SBUF ;
SBUF=j;
}
if(TI)
{
TI=0;
}
}
}