51单片机课设,比赛计分器

本来是用汇编写的,但是汇编属实学的不怎么好,于是自学用C来写,效果还不错

比赛计分器

一、 需求分析(从用户角度 UML

1.1 设计内容

本项目设计开发一款个比赛计分器,在重竞技比赛项目中(拳击,跆拳道),由3个裁判员对运动员评判。当一方运动员有效攻击后,裁判员立刻给这个运动员加分。如果有2个或2个以上裁判同时(一秒内)按键,则给该方运动员加一分。比赛期间(2分钟)得分多判定为胜利方。

 

1.2 设计目标

比赛计分器要实现的功能如下:

(1)能够提供三个裁判的评分按键,当一秒钟内有2个或者3个裁判按键,则有效分加1。 

(2)显示1分钟倒计时,并可以按键控制实践走停,开始和结束时候有蜂鸣器响声,时间开始响1s,时间结束响1s

(3)按下按键可以对两队进行警告,同时记录警告次数。

(4)对误判可以进行减分。

(5)数码管显示时间,得分,警告次数。

1.3实验平台和工具

实验平台为:keil

 

 

 

 

 

实验工具为:89c51单片机

 

 

 

 

1.3 设计的功能分析

 单片机实现比赛计分器功能。使用单片机数码管,独立按键,蜂鸣器以及矩阵键盘四个模块。数码管用来显示时间倒计时,双方警告次数以及得分。蜂鸣器在开始时以及快结束前五秒时响1s。独立按键k1按下开始,k2按下暂停,k3按下第一队警告次数加1k4按下第二队警告次数加1。矩阵按键s1s2s3,一秒内按下任意两个或三个,第一队得分加1,按下s4得分减1。矩阵按键s5s6s7,一秒内按下任意两个或三个,第二队得分加1,按下s8得分减1

1.5 设计的非功能性分析

通过本程序的设计可设计出一个简易的比赛计分器,应用于实际生活中也是非常简易方便的。

 

二、 总体设计

2.1总体方案设计

1)裁判按键设置

S1:提供裁判1对第一队的评分按键

S2:提供裁判2对第一队的评分按键

S3:提供裁判3对第一队的评分按键

S5:提供裁判1对第二队的评分按键

S6:提供裁判2对第二队的评分按键

S7:提供裁判3对第二队的评分按键

 

2)评分判断设置

通过启动定时器T0来判断1s之内有几个裁判按键,设计一个50ms的定时器,中断20次后即为1s,若一秒钟内有2个或者3个裁判按键,则有效分加1;否则,不加分。

(3) 分数显示设置

通过P0口将分数显示至数码管。

(4) 减分设置

按下S4或S5第一队或第二队分数减1。

(5) 警告次数显示设置

按下K3或K4,第一队或第二队警告次数加1。

(6) 开始,暂停设置

按下K1开始,按下K2暂停

2.2 演示支持方案(如何利用开发板资源或外接模块,实现功能演示的方案,传感器(或模拟)演示方案)

在单片机下载完成后,51单片机的8位动态数码管全部显示为0,

一二个显示时间,三四个分别显示两队警告次数,五六个显示第一队得分,七八个显示第二队得分。

在按下独立按键K1后,第一二个数码管显示60并开始倒计时,同时蜂鸣器响1s,若按下独立按键K2便暂停并且要再次按下K1才能开始。当倒计时为5s时,蜂鸣器也再次响1s。在这60s期间,矩阵按键s1,s2,s3在1秒内按下任意两个第一队得分加一,若出现误判,按下矩阵按键s4使得分减一,若第一队出现犯规可按下独立按键K3便使警告次数加1。同理第二队矩阵按键s5,s6,s7在1秒内按下任意两个第二队得分加一,若出现误判,按下矩阵按键s8使得分减一,若第二队出现犯规可按下独立按键K4便使警告次数加1。

2.3 单片机资源分配设计(包括RAM资源分配,I/O资源分配)

没有具体的要求。

三、 模块设计与实现(介绍本课设主要模块的设计思路,实现方法,可以通过流程图,状态图,关键代码,显示效果等多种手段说明)

 

 

 

 

1.独立按键模块:

 

 

 

 

由图可知k1对应的为p3.1口,k2对应的为p3.0口,k3对应的为p3.2口,k4对应的为p3.3口;本课设中使用到的是k1和k2按键,由上图知按键的一端已经连接到GND,而在另一端则是通过按下来检测,当未被按下时p3口的前四位默认为高电平,即1。按下后即为0,其中的抖动可使用延时来消除;代码如图:

 

 

 

 

 

  1. 动态数码管:

 

 

 

 

首先是数码管的片选,本次课设采用的52单片机使用的是38译码器,即如上图中:通过p2.2、p2.3、p2.4三位2^3=8位来判断使用哪一个数码管工作(亮);例如当p2.2=1;p2.3=1;p2.4=0时,对应的十六进制数值为6,则从右往左数的第七个数码管会亮,即图中的LED7;具体对应关系如下图:

P2.2

P2.3

P2.4

LED(位)

0

0

0

LED1

0

0

1

LED2

0

1

0

LED3

0

1

1

LED4

1

0

0

LED5

1

0

1

LED6

1

1

0

LED7

1

1

1

LED8

然后是数码管模块的数字显示,如下图:

 

 

 

 

数码管电路的接法有共阴和共阳两种,本次用的单片机里的数码管采用的是共阴接法。
从其中取出一个数码管进行分析

 

 

 

 


单个数码管

此处为一个8位的数码管,想要数码管显示出想要的数字,则需要对数码管进行高低电平的设置1为高电平,0为低电平,分别对 a,b,c,d,e,f,g,dp进行1和0的编写;

 

 

 

如图中所示,数字2的 八位二进制就可以表示为 0101 1011,读数为从dp依次读到a,转化为十六进制则是0x5b。

  1. 定时器中断:

 

 

 

由该图可知定时器T0的中断入口为0BH,将中断的子程序入口设为0BH即可。由于本课设整体就是基于时间的累加,因此核心也是定时器的计时功能。在使用定时器0工作于方式1,中断使用定时器的溢出中断,设置TH0、TL0初值为0D8H、0F0H,即可产生每10ms一次的溢出中断,又定义R0为100,通过DJNZ指令达到使每过10ms*100=1s才执行对应的计时计费操作来实现功能。如图:

 

 

 

 

  1. 蜂鸣器模块:

 

 

 

 

 

 

蜂鸣器发声原理是电流通过电磁线圈,使电磁线圈产生磁场来驱动振动膜发声的,因此需要一定的电流才能驱动它,单片机IO引脚输出的电流较小,单片机输出的TTL电平基本上驱动不了蜂鸣器,因此需要增加一个电流放大的电路。S51增强型单片机实验板通过一个三极管C8550来放大驱动蜂鸣器。蜂鸣器的正极接到VCC(+5V)电源上面,蜂鸣器的负极接到三极管的发射极E,三极管的基级B经过限流电阻R1后由单片机的P1.5引脚控制,当P1.5输出高电平电磁式有源蜂鸣器,电磁式有源蜂鸣器产品质量好时,三极管T1截止,没有电流流过线圈,蜂鸣器不发声;当P1.5输出低电平时,三极管导通,这样蜂鸣器的电流形成回路,发出声音。因此,我们可以通过程序控制P1.5脚的电平来使蜂鸣器发出声音和关闭.程序中改变单片机P1.5引脚输出波形的频率,就可以调整控制蜂鸣器音调,产生各种不同音色、音调的声音。

四、 系统集成设计(与其它系统通信、连接,和相互作用设计,参考结构,根据项目增减)

没有使用。

五、  系统测试

5.1 系统测试

 

 

 

 

5.2 单元测试

 

 

 

 

 

 

 

 

 

 

 

 5.3非功能性测试

 

开始前;

 

 

 

 

 

 

 

 

 

 

 

开始时:

 

 

具体介绍:

 

 

 

 

六、 收获与总结

通过本次单片机课程设计,我更加理解了实践出真知的重要性,不仅要拥有足够的理论知识,同时也应该懂得用于实践,只有通过不断反复的测试与失败,才能获得成功。当然,这其中也有很多问题,第一、由于对课本理论的不熟悉导致编程出现错误。第二,这次课设是对我的学习态度的一次检验。这次课设所遇到的多半问题多数都是由于我们不够严谨,考虑问题全部全面,周不周到。第三,我认识到,无论做什么事情,只要你足够坚强,有足够的毅力与决心,有足够的挑战困难的勇气,就没有什么办不到的。

 

附录1原理图

 

 

 

 

 

 

 

 

 

 

 

 

 

 

附录2 源程序清单

#include <reg51.h>

#define uint unsigned int   //无符号化

#define uchar unsigned char

 

uchar num = 0;

sbit led0 = P2^0;   //位定义

sbit led2 = P2^2;

sbit led3 = P2^3;

sbit led4 = P2^4;

sbit beep = P1^5;

sbit K1 = P3^1;

sbit K2 = P3^0;

sbit K3 = P3^2;

sbit K4 = P3^3;

 

 

uchar  DisplayData[8];

#define GPIO_KEY P1

uchar KeyValue1=0xff; //存放读取到的键值

uchar KeyValue2=0xff;

uchar KeyValue=0xff;

uint time_jsq1=0;

uint time_jsq2=0;

uchar flag_start1=0;    //记录当前时间

uchar flag_start2=0;

uint time_start1=0;    //记录加分开始时间

uint time_start11=0; //记录减分开始时间

uint time_start111=0;//记录警告开始时间

uint time_start2=0;

uint time_start22=0;

uint time_start222=0;

uint time_end1=0;      //记录结束时间

uint time_end2=0;

 

uchar key_num1=-1;           //记录第一次读取到的键值

uchar key_num11=-1;          //记录第二次读取到的键值

uchar key_num2=-1;

uchar key_num22=-1;

uchar  num_fenshu1=0;               //记录分数

uchar  num_fenshu2=0;

uint i=0,time=0;

uint j=0,k=0,A=0;

uint A1=0;

uint jinggao1=0,jinggao2=0;

void KeyDown(void);

uchar code duanxuan[] = {0x3f,0x06,0x5b,0x4f,   //0,1,2,3

0x66,0x6d,0x7d,0x07,   //4,5,6,7

0x7f,0x6f,0x77,0x7c,   //8,9,A,B

0x39,0x5e,0x79,0x71};   //C,D,E,F

 

 

/*******************************************************************************

* 函数名:      : fp

* 功能    : 蜂鸣器延时

*******************************************************************************/

void fp(uint i)       //蜂鸣器延时

{

while(i--);

}

 

/*******************************************************************************

* 函数名:      : delay

* 功能    : 延时函数,i=1大概1us

*******************************************************************************/

void delay(uint i)

{

while(i--);

}

 

/*******************************************************************************

* 函数名:      : Display

* 功能    : 显示数码管

*******************************************************************************/

void Display(int j,int k,uchar m,uchar n,int a,int b) //xianshi

{

uchar ii;

DisplayData[0]=duanxuan[j]; //duanxuan[j];

DisplayData[1]=duanxuan[k]; //duanxuan[k];

DisplayData[2]=duanxuan[m%100/10]; //duanxuan[m%100/10];

DisplayData[3]=duanxuan[m%10]; //duanxuan[m%10];

DisplayData[4]=duanxuan[n%100/10];

DisplayData[5]=duanxuan[n%10];

DisplayData[6]=duanxuan[a];

DisplayData[7]=duanxuan[b];

for(ii=0;ii<8;ii++)

{

switch(ii)//位选点亮的灯管

{

case(0):led2=1,led3=1,led4=1;break;   //1

case(1):led2=0,led3=1,led4=1;break;   //2

case(2):led2=1,led3=1,led4=0;break; //5  

case(3):led2=0,led3=1,led4=0;break;   //6

case(4):led2=1,led3=0,led4=0;break;   //7

case(5):led2=0,led3=0,led4=0;break;   //8

case(6):led2=1,led3=0,led4=1;break; //3

case(7):led2=0,led3=0,led4=1;break;   //4

}

P0=DisplayData[ii];//送到P0

delay(50); //延时

P0=0x00;//消影

 }

}

 

void main()

{

 

TMOD = 0X01;

TH0 = (65536-45872)/256; //高八位

TL0 = (65536-45872)%256; //低八位

EA = 1;          //总开关

ET0 = 1;           //定时器0

TR0 = 1;

led0 = 0;                 

if(K1==0)

time=60;

while(time!=0)

{

KeyDown();

if(num == 20)

{

num = 0;

time--;

j=time/10,k=time%10;

}

if(led0 == 0&&(time==60||time==5))

{

beep = ~beep;

fp(1);

}

Display(j,k,num_fenshu1,num_fenshu2,jinggao1,jinggao2);

 

 

 if(KeyValue1!=0xff) //按键是否按下

 {

   if((KeyValue1==0||KeyValue1==1||KeyValue1==2)&&flag_start1==0&&A==0&&TR0==1)

 {

   flag_start1=1;

 time_start1=time_jsq1;

 key_num1=KeyValue1;  

 KeyValue1=0xff;

 KeyValue=0xff;

 }

 if((KeyValue1==0||KeyValue1==1||KeyValue1==2)&&flag_start1==1&&key_num1!=KeyValue1&&key_num11==-1&&time_start1!=0&&TR0==1)

 {

 num_fenshu1=num_fenshu1+1;   //分数加一

 key_num11=KeyValue1;

 }

 

 if(KeyValue1==7&&time_jsq1-time_start11>=5&&num_fenshu1>0&&TR0==1)

 {

 time_start11=time_jsq1;

 num_fenshu1=num_fenshu1-1;  //减分

 KeyValue1=0xff;

 KeyValue=0xff;

 }

 }

 if(time_jsq1-time_start1>20||TR0==0)//大于1s全部恢复初值进行下一次

 {

 A=0;

   time_start1=0;

 time_end1=0;

 flag_start1=0;

 key_num11=-1;

 key_num1=-1;

 KeyValue1=0xff;

 KeyValue=0xff;

 }  

 

 if(KeyValue2!=0xff) //同上

 {

   if((KeyValue2==3||KeyValue2==4||KeyValue2==5)&&flag_start2==0&&A1==0&&TR0==1)

 {

   flag_start2=1;

 time_start2=time_jsq2;

 key_num2=KeyValue2;  

 KeyValue2=0xff;

 }

 if((KeyValue2==3||KeyValue2==4||KeyValue2==5)&&flag_start2==1&&key_num2!=KeyValue2&&key_num22==-1&&time_start2!=0&&TR0==1)

 {

 num_fenshu2=num_fenshu2+1;   

 key_num22=KeyValue2;

 }

 if(KeyValue2==6&&time_jsq2-time_start22>=5&&num_fenshu2>0&&TR0==1)

 {

 time_start22=time_jsq2;

 num_fenshu2=num_fenshu2-1;

 KeyValue2=0xff;

 }

 }

 if(time_jsq2-time_start2>20||TR0==0)

 {

 A1=0;

   time_start2=0;

 time_end2=0;

 flag_start2=0;

 key_num22=-1;

 key_num2=-1;

 KeyValue2=0xff;

 }

 

 if(K2==0)

 {

 beep = ~beep;

 fp(10);

 TR0=0;

 }

  if(K1==0)

 {

 beep = ~beep;

 fp(10);

 TR0=1;

 }

 

 

 if(K3==0&&time_jsq1-time_start111>=5&&TR0==1)  //A队警告

 {

 time_start111=time_jsq1;

 jinggao1=jinggao1+1;

 if(jinggao1>9)

 {

 jinggao1=15;

 break;

 }

 }

 

 if(K4==0&&time_jsq2-time_start222>=5&&TR0==1)  //B队警告

 {

   time_start222=time_jsq2;

 jinggao2=jinggao2+1;

 if(jinggao2>9)

 {

 jinggao2=15;

 break;

 }

 }

 

}

 

 

for(i=1;i>=0;i++)    //结束后显示

{

Display(j,k,num_fenshu1,num_fenshu2,jinggao1,jinggao2);

if(K1==0)

break;

}

 

 

}

 

 

/*******************************************************************************

* 函数名:      : TR0_time

* 功能    : 定时器中断,每溢出一次0.05s

*******************************************************************************/

void TR0_time() interrupt 1 //dingshiqizhongduan

{

TH0 = (65536-45872)/256;

TL0 = (65536-45872)%256;

num++;

  time_jsq1++;

  time_jsq2++;

}

 

/*******************************************************************************

* 函数名        : KeyDown

* 功能    : 判断按下哪个按键

*******************************************************************************/

void KeyDown(void)

{

char a=0;

GPIO_KEY=0x0f;

if(GPIO_KEY!=0x0f)//判断是否按下

{

delay(10);//延时消抖

if(GPIO_KEY!=0x0f)//再次判断是否按下

{

//

GPIO_KEY=0X0F;

switch(GPIO_KEY)

{

case(0X07): KeyValue=0;break;

case(0X0b): KeyValue=1;break;

case(0X0d): KeyValue=2;break;

case(0X0e): KeyValue=7;break;

}

//

GPIO_KEY=0XF0;

switch(GPIO_KEY)

{

case(0X70): KeyValue1=KeyValue;break;

}

 

}

 

if(GPIO_KEY!=0x0f)//同上

{

delay(10);

if(GPIO_KEY!=0x0f)

{

 

GPIO_KEY=0X0F;//低四位全置1

switch(GPIO_KEY)

{

case(0X07): KeyValue2=0;break;

case(0X0b): KeyValue2=1;break;

case(0X0d): KeyValue2=2;break;

case(0X0e): KeyValue2=3;break;

}

GPIO_KEY=0XF0;

switch(GPIO_KEY)

{

case(0Xb0): KeyValue2=KeyValue2+3;break;

}

 

}

}

 

}

while((a<50)&&(GPIO_KEY!=0xf0))  //判断是否松开

{

a++;

}

}

posted @ 2022-03-14 22:41  安良  阅读(1361)  评论(0编辑  收藏  举报