山东大学测控技术与仪器课程设计

合集下载
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

篮球赛电子计时记分牌是根据篮球比赛特点设计的独立的信息采集、分配、评判和显示的系统,能实现比赛时间和分数的实时、准确、快捷处理和呈现。

本设计原理简单,主要采用AT89C52单片机作为微控制器,集合矩阵键盘、数码管和LED指示灯,通过键盘控制记分牌的工作状态,通过数码管和LED指示灯来反馈信息。

本设计在充分考虑了篮球比赛的实际情况基础上设计,具有友好的人机交互接口,并且可以防止人为误操作造成的不良后果,具有一定的实用性。

1 设计任务
1.1 设计的目的和意义
目前球场记分牌在传统操作模式下,采用记分员手动翻动记分牌记分,工作方式单一。

由于种种弊端,电子记分板已经开始在一些大型的体育场流行起来,不仅发展速度迅猛并会逐渐取代传统的电子记分牌。

电子记分板根据篮球比赛的特点,采用单片机为核心控制LED数码管,具有亮度高、可视性好、功耗小、使用寿命长等优点;具有性能稳定,尺寸适中,运输安装方式灵活,物美价廉等特点,特别适用于中、小型体育馆和训练馆。

1.2 设计任务与要求
设计题目:篮球赛电子计时记分牌
设计要求:
(1)分别设计篮球比赛用的计时牌和记分牌;
(2)上下半场各20分钟,要求能随时暂停,启动后继续计时,一场比赛结束后应可清零重新开始比赛;
(3)能按照篮球计分规则计分并显示。

2 硬件系统设计
2.1 总体方案设计
篮球记分器的硬件电路分成主控模块、键盘输入模块、信息提示模块三部分进行设计,系统整体结构如图1所示。

图1 系统硬件结构图
主控模块以AT89C52为核心,完成输入输出信息处理、计时器中断响应、数值计算等,协调整个系统有条不紊地工作。

键盘输入模块作为人机交互接口,允许用户控制系统的工作状态,完成如计时计分开始/暂停、交换场地、计时计分清零、比赛队伍分数调整等功能。

信息提示模块包含4个2位8段数码管、6个LED 和一个蜂鸣器,用于实时显示系统工作状态,方便用户进行下一步操作。

2.2 芯片选型与具体电路设计 2.2.1 单片机的选型
主控模块以AT89C52单片机作为微控制器。

AT89C52单片机是一种低电压,高性能CMOS 8位单片机,片内含8k bytes 的可反复擦写的Flash 只读程序存储器和256 bytes 的随机存取数据存储器(RAM ),器件采用ATMEL 公司的高密度、非易失性存储技术生产,兼容标准MCS-51指令系统,片内置通用8位中央处理器和Flash 存储单元。

由于它的这些优良特性,AT89C52单片机在电子行业中有着广泛的应用。

采用AT89C52作为微控制器,可以很好地满足篮球记分器的系统要求。

2.2.2 复位和振荡电路的设计
图2给出了AT89C52单片机的引脚分布和最小系统接法。

3*3 矩阵键盘
A T89C52 主控模块
信息提示模块 数码管 LED 蜂鸣器
键盘输入模块
图2 AT89C52单片机最小系统原理图
复位电路可以实现上电复位和按键复位两种复位方式:上电复位电路由电容串联电阻构成,由图并结合“电容电压不能突变”的性质,可以知道,当系统一上电,RST脚将会出现高电平,并且这个高电平持续的时间由电路的RC值来决定。

典型的51单片机当RST脚的高电平持续两个机器周期以上就将复位,所以适当组合RC的取值就可以保证可靠的复位。

按键复位电路则是通过按下RESET按键拉高RST引脚电平来实现的。

晶体振荡电路由一个12MHZ石英晶振和两个30pF的电容组成,用于产生稳定的时钟脉冲信号供单片机工作。

2.2.3 键盘输入模块的设计
用户通过键盘输入模块对系统进行控制。

键盘采用3*3矩阵式按键,其中按键“START/PAUSE”控制计时计分的开始与暂停,按键“EXCHANGE”用于在半场结束后交换双方记分牌上的分数,按键“CLEAR”用于在比赛结束后清除比分,其余的按键“A+1”、A+2”、“A+3”、“B+1”、“B+2”、“B+3”用于给参加比赛的A、B两队加上相应的分数。

3*3矩阵按键的6条引线分别接至AT89C52的I/O口P3_0~P3_5,在单片机内部采用行列扫描法检测到按键按下,从而执行相应的任务。

矩阵键盘的连接方式如图3所示。

图3 矩阵键盘的连接方式
2.2.4 信息提示模块的设计
信息提示模块包含4个2位8段共阴极数码管(图4)、6个LED指示灯(图5)和一个蜂鸣器。

4个数码管分别用两位数字显示比赛分钟、秒钟和赛场上两个篮板的分数。

由于单片机I/O口资源有限,为了不占用太多的接口,在此使用P0口向数码管同时送出数据(段选信号)和地址(位选信号),使用两个74HC573锁存器来分离数据和地址,而P2_0和P2_1口分别用于使能段选锁存器和位选锁存器。

由于P0口的电流驱动能力有限,所以外接了排阻RP1,从而增强了对数码管的驱动能力。

图4 数码管连接原理图
LED1、LED2、LED3分别指示比赛状态“开始”、“暂停”和“结束”;LED4用于“进球”指示,在比赛进行时按下任何一个加分按键,“进球”指示灯会闪一下;在上半场比赛结
束后按下“EXCHANGE”键,“交换场地”指示灯LED5会亮,同时两个篮板的比分互换。

“ERROR!”指示灯LED6用于指示用户的操作出错。

6个LED采用共阳极连接方式,其阴极分别接单片机P1_0~P1_5口,当单片机某口输出低电平时,对应的LED亮。

图5 LED指示灯连接原理图
蜂鸣器接在P1_6口上,在半场结束或比赛结束后会发出提示音。

2.3 系统总体电路
图6给出了系统硬件原理总图。

图6 系统硬件原理总

2.4 系统所用元器件
本系统所用的元器件清单如表1所示。

表1 本系统所用的元器件
元器件名称数量
电阻8
电容 3
单片机A T89C52 1
锁存器74HC573 2
LED 6
2位8段数码管 4
蜂鸣器 1
排阻 1
12M晶振 1
按键开关10
5V电源 1
导线若干
3 软件系统设计
3.1 软件系统总体设计方案
单片机程序采用美国Keil Software公司出品的51系列兼容单片机C语言开发系统Keil C编写。

与汇编相比,C语言在功能上、结构性、可读性、可维护性上有明显的优势,因而易学易用。

Keil提供了包括C编译器、宏汇编、连接器、库管理和一个功能强大的仿真调试器等在内的完整开发方案,通过一个集成开发环境(uVision)将这些部分组合在一起。

Keil采用工程方式集中管理源程序,编写单片机程序首先要建立工程,然后在工程中添加源代码文件。

在本系统的工程中包含6个C代码文件,对应功能介绍如下:My_func.h ——自定义的头文件。

存放常用宏定义、单片机I/O位定义、数据类型定义和所有函数的声明。

在其他C文件里只需要写一句#include "my_func.h",即可直接调用任意函数,省去了重复写定义和声明的麻烦。

Main.c ——包含主程序main(),是整个程序执行的入口。

在main()函数里,调用init()进行单片机的初始化,并在大循环里调用key_respond()和display()不断扫描按键输入、输出显示数据。

同时设置定时器T0以工作方式1计时,从而在中断服务程序void Timer() interrupt 1里实现1s间隔的倒计时。

Key_scan.c ——包含按键扫描程序key_scan()。

该函数采用行扫描法获取按键的状态,并将对应的键码传给Key_respond.c中的函数key_respond()。

Key_respond.c ——包含按键响应函数key_respond()。

该函数里决定是否对按键请求进行响应:如果不响应,则调用宏LED_ERROR()使“ERROR!”指示灯闪动;如果响应,则调用相应函数完成不同的操作,如比赛状态的开始和暂停、加分、交换场地和分数清零等。

Display.c ——包含数码管显示驱动函数display()。

在这个函数里实现比赛分数设置、比分交换、计时控制等,并通过P0口送出段选信号,通过P2_0和P2_1送出位选信号,从而控制数码管的动态显示。

My_func.c ——被调用函数的集合,包含延时函数void delay_ms(unsigned int xms)、初始化函数init()和蜂鸣器发声函数sounder()。

3.2 软件系统流程图
单片机程序总体流程如图7所示。

图7 单片机程序总体流程图
CLEAR 键 按下?
N N
下半场 结束?
蜂鸣提示
Y 清除比分
Y
Y
开机/复位
初始化
START 键按下?
N
开始计时、计分
加分键 按下?
加分
Y
Y N
上半场 结束?
蜂鸣提示
Y
EXCHANGE
键按下?
互换比分
N
N
3.2.1 主程序流程图
在主程序文件main.c 中包含两部分内容,分别是主函数和中断服务函数。

首先是主函数void main(),这是整个程序执行的入口,在这个函数里,首先调用init()进行单片机的初始化,然后进入大循环,反复调用key_respond()和display()两个函数不断扫描按键输入并输出显示数据。

在中断服务函数void Timer() interrupt 1里,设置定时器T0以工作方式1计时,计时时长为50ms ,计时器每溢出一次,变量intr_num 自增一次,直至intr_num 等于20,于是计时时长达到1s 。

在中断服务程序里,计时每达到1s ,篮球计时牌上的秒钟数就自减1;秒钟减到0后,分钟自减1,然后秒钟从59开始继续自减。

主程序和中断服务程序流程如图8(a)、8(b)所示。

图8(a) 主程序流程图
图8(b) 中断服务程序流程图
N
比赛时间减1s
计时 满1s ?
Y
中断:计时器装初值
计时满
50ms ?
Y
N
开始
初始化
显示比分、时间
执行按键对应动作
有按键
按下?
Y
N
3.2.2 按键检测子程序设计
(1)原理与分析
按键检测子程序包括key_scan.c 和key_respond.c 两个C 文件。

在key_scan.c 中采用行扫描法判断是哪个键被按下,返回相应的键码,如果没有按键按下,则返回0。

在key_respond.c 中调用key_scan.c 中的函数,根据得到的不同键码来执行不同操作,如果键码为0,则不执行任何操作。

对矩阵键盘的检测,有两种常用方法:行扫描法和线反转法。

在此采用行扫描法,其识别按键的过程介绍如下。

① 判断键盘中有无键按下:将全部行线置低电平,然后检测列线的状态。

只要有一列的电平为低,则表示键盘中有键被按下,而且闭合的键位于低电平线与4根行线相交叉的4个按键之中。

若所有列线均为高电平,则键盘中无键按下。

② 判断闭合键所在的位置:在确认有键按下后,即可进入确定具体闭合键的过程。

其方法是:依次将行线置为低电平,即在置某根行线为低电平时,其它线为高电平。

在确定某根行线位置为低电平后,再逐行检测各列线的电平状态。

若某列为低,则该列线与置为低电平的行线交叉处的按键就是闭合的按键。

(2) 流程图
按键检测子程序执行流程如图9所示。

图9 按键检测子程序流程图
3.2.3 数码管显示子程序设计
动态显示的特点是将所有位数码管的段选线并联在一起,由位选线控制是哪一位数码管有效,从而大大地简化了硬件电路。

选亮数码管采用动态扫描显示。

所谓动态扫描
有无按键
按下?
Y
返回键码0
N
确定所在行列
返回相应键码
Y
键码 非0?
执行按键相应操作
N
显示即轮流向各位数码管送出字形码和相应的位选,利用发光管的余辉和人眼视觉暂留作用,使人的感觉好像各位数码管同时都在显示。

数码管动态显示的正确操作顺序应该是:
(1)段选赋值
(2)位选赋值
(3)位选左移
(4)延时
(5)消影
以8只数码管同时显示数字“0”~“7”为例来说明:
#include <reg52.h>
unsigned char code num_table[10]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,
0x7F,0x6F}; //共阴极数码管字型码0~9
/*---------------------毫秒延时------------------------*/
void delay_ms(unsigned int xms)
{
unsigned int i,j;
for (i=xms;i>0;i--)
for (j=110;j>0;j--);
}
/*-------------------数码管显示------------------------*/
void display(void)
{
unsigned char i;
while(1)
{
P2=0x7f; //P2=0111,1111
for (i=0;i<8;i++)
{
P0=num_table[i]; //线选信号
P2=P2<<1|P2>>7; //位选信号(先循环左移再赋给P2)
delay_ms(5);
P0=0x00; //先延时后消影!
}
}//while
4 系统调试
在系统完成之际,调试过程中发现了一些问题。

首先是数码管显示部分,在单片机执行其他任务如等待按键释放或蜂鸣器发声的时候,数码管就会灭掉,我尝试了很多解决办法,但最后还是没有拿出一个比较满意的方案。

究其原因,8051系列单片机是单任务系统,在执行“等待按键释放”这一任务时,就会停止对数码管的驱动,导致数码管熄灭。

使用锁存器可以保持数码管的显示,但是数字是“死”的,即在另一任务结束之前无法刷新。

另一个问题是实物演示过程中出现的,当我将程序下载到开发板上运行时,有一行按键始终无法响应,但是在Proteus里仿真却是正常的。

最终证明是按键消抖延时的问题,这让我意识到仿真和实物是有差距的,只有亲自接触实物,才能真正学好单片机。

设计之初,我使用了P0口输出数据(段选信号)、P2口输出地址(位选信号)的方案对数码管进行驱动。

这样的就不必使用锁存器,但是却占用了额外的I/O口。

经过考虑,为了节省宝贵的接口资源,我改用了P0口分时输出数据和地址的设计方案,加上了两个74HC573锁存器,同样达到了很好的显示效果。

之前使用P0口和P2口共同驱动数码管的方案如图10所示(键盘和指示灯模块已省略)。

图10 使用P0口和P2口共同驱动数码管的方案
经过反复调试,系统能够正常地运行。

最终仿真结果如下图11:
图11 最终仿真结果
5 总结
这一次的课程设计,我的课题是《篮球赛电子计时记分牌》。

由于这一系统包含单片机基础、数码管动态显示、矩阵键盘扫描、定时器和中断等知识体系,涉及面较广,通过这一课程设计,可以更好地检测和巩固学到的知识,加深自己对电子世界的认识。

在本次的设计中,针对每一个模块都曾有好几个方案,在反复比较论证之后,才得出最佳方案并应用于系统。

在各个模块的设计中,我除了得到了正确的结果之外,更多的是面对错误和失败,而这些错误大多数是由于自己对该部分电路原理掌握的不够透彻而造成的。

通过查阅资料,连接、调试电路和程序,我得出了一下几条心得体会,以后在设计过程中可以借鉴:
(1)在Proteus里,电路状态不正常且不易发现问题时,使用电流计和电压计可直观检测电路动态变化,这也是Proteus里非常好用的一个功能;
(2)电流表、电压表显示数值为0时,不一定是接法的问题,可以试着调整量程,可能是量程选大了;
(3)Proteus里的电源默认是5V,需要改动电压时,点击属性,在string项里填上需要的数值就可以了,如+15V;
(4)画完电路后怎么一次性去掉proteus元器件的TEXT标号?
打开菜单template—set design defaults,把shou hidden text的勾去掉即可;
(5)在keil工程中如何创建能用于所有C文件的全局变量?
在头文件里声明extern uchar glb_num;在主函数前定义uchar glb_num;
(6)Proteus里可变电阻不好找,代号是POT-HG;按钮开关是button,拨动开关是switch。

参考文献
[1] 郭文川主编. 单片机原理与接口技术. 北京:中国农业出版社,2007.
[2] 郭天祥主编.新概念51单片机C语言教程.北京:电子工业出版社,2008.
附录:篮球赛电子计时记分牌单片机程序代码
/*======================================*/
//文件名:My_func.h
#ifndef MY_FUNC_H //防止重复定义
#define MY_FUNC_H
/*---------------头文件-----------------*/
#include <reg52.h>
#include <intrins.h>
/*---------------宏定义-----------------*/
#define PLAY_TIME 1
#define ON 0
#define OFF 1
#define _MINUTE 1
#define _SECOND 2
#define _GRADE_A 3
#define _GRADE_B 4
#define LED_INIT() {LED_run = 1; LED_pause = 1; LED_end = 0;
LED_shoot = 1; LED_exchg = 1; LED_error=1;}
#define LED_RUN() {LED_run = 0; LED_pause = 1; LED_end = 1;}
#define LED_PAUSE() {LED_run = 1; LED_pause = 0; LED_end = 1;}
#define LED_END() {LED_run = 1; LED_pause = 1; LED_end = 0;}
#define LED_EXCHG() {LED_exchg = !LED_exchg;}
#define LED_SHOOT() {LED_shoot = 0; delay_ms(500); LED_shoot = 1;}
#define LED_ERROR() {LED_error = 0; delay_ms(500); LED_error = 1;}
#define TIMER_START() {TR0 = 1;} //启动T0
#define TIMER_PAUSE() {TR0 = 0;} //暂停T0
#define TIMER_LOAD() {TH0 = (65536-50000)/256; TL0 = (65536-50000)%256;} #define TIMER_INIT() {TMOD = 0x01; TH0 = (65536-50000)/256;
TL0 = (65536-50000)%256; EA = 1; ET0 = 1;}
/*------------数据类型定义--------------*/
typedef unsigned char uchar;
typedef unsigned int uint;
/*----------------位定义----------------*/
sbit LED_run = P1^0;
sbit LED_pause = P1^1;
sbit LED_end = P1^2;
sbit LED_shoot = P1^3;
sbit LED_exchg = P1^4;
sbit LED_error = P1^5;
sbit SOUNDER = P1^6;
sbit LE_duan = P2^0;
sbit LE_wei =P2^1;
/*----------------函数声明--------------*/
extern void init (void);
extern void delay_ms (uint xms);
extern void sounder(void);
extern uchar key_scan (void);
extern void key_respond (void);
extern void game_start(void);
extern void game_pause (void);
extern void game_clear (void);
extern void display (void);
extern uchar time_grade_increase(uchar item,char inc_num); extern void time_grade_set(uchar item,uchar num);
/*--------------------------------------*/
#endif
/*======================================*/
//文件名:main.c
#include <reg52.h>
#include "my_func.h"
uchar intr_num = 0;
/*----------------主程序---------------*/
void main()
{
init(); //初始化
while (1)
{
key_respond();
display();
}
}
/*------------计时器T0溢出中断服务程序------------*/
void Timer() interrupt 1 //T0中断
{
TIMER_LOAD(); //T0装初值
intr_num++;
if (intr_num == 20)
{
intr_num = 0;
time_grade_increase(_SECOND,-1);
}
}
/*-----------------------------------------------*/
/*===============================================*/
//文件名:key_scan.c
#include <reg52.h>
#include "my_func.h"
/*-------------------按键检测程序----------------*/
//返回键码(没有键按下时返回0)
uchar key_scan()
{
uchar temp,key=0;
P3 = 0xfe; //检测第1列
temp = P3; //读取P3口状态(将P3状态赋给temp,然后操作temp,是为了不对P3口产生影响!)
temp = temp&0xf8; //temp低3位(对应P3_0、P3_1、P3-2)清零,只检测高5位(其实是P3_3、P3_4、P3-5这三根列线)的状态。

(0xf8是temp低3位清零后,没有按键按下的状态)
if (temp!=0xf8) //第一次检测到按键按下(P3_3、P3_4、P3-5这三根列线中出现了0)
{
delay_ms(10); //延时消抖
temp=P3; //重新读取P3口状态
temp = temp&0xf8;
if (temp!=0xf8) //确定按键按下
{
temp=P3; //再次读取P3口状态
switch (temp)
{
case 0xf6 : //START/PAUSE键按下
key = 11; //第1行第1列
break;
case 0xee :
key = 12;
break;
case 0xde :
key = 13;
break;
default:
break;
}
while (temp!=0xf8) {temp=P3; temp=temp&0xf8;} //等待按键释放}
}
P3 = 0xfd; //检测第2列
temp = P3;
temp = temp&0xf8;
if (temp!=0xf8)
{
delay_ms(10);
temp=P3;
temp = temp&0xf8;
if (temp!=0xf8)
{
temp=P3;
switch (temp)
{
case 0xf5 :
key = 21;
break;
case 0xed :
key = 22;
break;
case 0xdd :
key = 23;
break;
default:
break;
}
while (temp!=0xf8) {temp=P3; temp=temp&0xf8;} }
}
P3 = 0xfb; //检测第3列
temp = P3;
temp = temp&0xf8;
if (temp!=0xf8)
{
delay_ms(10);
temp=P3;
temp = temp&0xf8;
if (temp!=0xf8)
{
temp=P3;
switch (temp)
{
case 0xf3 :
key = 31;
break;
case 0xeb :
key = 32;
break;
case 0xdb :
key = 33;
break;
default:
break;
}
while (temp!=0xf8) {temp=P3; temp=temp&0xf8;}
}
}
return key;
}
/*-----------------------------------------------*/
/*===============================================*/
//文件名:key_respond.c
#include <reg52.h>
#include "my_func.h"
/*--------------------按键响应------------------*/
void key_respond()
{
uchar key = key_scan(); //获取键码
if (key!=0) //有键按下
{
if (LED_run==ON) //游戏进行中,响应除了EXCHANGE和CLEAR之外的按键
{
if (key == 11) game_pause();
else if (key == 21) {time_grade_increase(_GRADE_A,1); LED_SHOOT();}
else if (key == 22) {time_grade_increase(_GRADE_A,2); LED_SHOOT();}
else if (key == 23) {time_grade_increase(_GRADE_A,3); LED_SHOOT();}
else if (key == 31) {time_grade_increase(_GRADE_B,1); LED_SHOOT();}
else if (key == 32) {time_grade_increase(_GRADE_B,2); LED_SHOOT();}
else if (key == 33) {time_grade_increase(_GRADE_B,3); LED_SHOOT();}
else LED_ERROR();
}
else if (LED_pause==ON) //游戏暂停,只响应START/PAUSE键(半场结束才响应EXCHANGE键)
{
if (key == 11) game_start();
else LED_ERROR();
}
else if (LED_end==ON) //游戏结束,只响应START/PAUSE和CLEAR键
{
if (key == 11) game_start();
else if (key == 13) game_clear();
else LED_ERROR();
}
}
}
/*------------------------------------------------*/
void game_start()
{
if ((time_grade_increase(_MINUTE,0)==0)&&(time_grade_increase(_SECOND,0)==0)) //半场结束
{
if (LED_end == ON) init(); //如果是下半场结束,重新开始
else if (LED_end == OFF) //如果是上半场结束
{
time_grade_set(_MINUTE,PLAY_TIME);
time_grade_set(_SECOND,0);
TIMER_LOAD();
}
}
TIMER_START();
LED_RUN();
}
/*------------------------------------------------*/
void game_pause()
{
TIMER_PAUSE();
LED_PAUSE();
}
/*------------------------------------------------*/
void game_clear() //(比赛结束)比分清零
{
init();
}
/*------------------------------------------------*/
/*================================================*/
//文件名:display.c
#include <reg52.h>
#include <intrins.h>
#include "my_func.h"
char minute,second,grade_A,grade_B;
uchar code num_table[10]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F}; //共阴极数码管显示0~9的字型码
/*-----------------8只数码管显示数字---------------------*/
void display()
{
uchar display_table[8] = {0}; //display_table[8]存放8只数码管将要显示的字型码
uchar i,display_3_num,display_4_num,temp_wei;
if (second<0) {second = 59; minute--;} //秒进位到分钟
if (minute==-1) //半场结束
{
TIMER_PAUSE(); //暂停计时
if (LED_exchg == OFF) //如果是上半场
{
LED_PAUSE();
sounder(); //蜂鸣器提示
while (key_scan()!=12)
{
LED_EXCHG(); //灯闪烁
delay_ms(500);
} //响应EXCHANGE键
LED_exchg = ON;
}
else if (LED_exchg == ON) //如果是下半场
{
LED_END();
sounder(); //蜂鸣器提示
}
time_grade_set(_MINUTE,0); //计时清零
time_grade_set(_SECOND,0);
}
if (grade_A>99) {grade_A = 99; LED_ERROR();} //比分超出显示范围if (grade_B>99) {grade_B = 99; LED_ERROR();}
if (LED_exchg==ON) {display_3_num = grade_B; display_4_num = grade_A;} //下半场,比分交换
else if (LED_exchg==OFF) {display_3_num = grade_A; display_4_num = grade_B;} //上半场,比分不交换
display_table[0] = num_table[(uchar)(minute/10)]; //第1只数码管
display_table[1] = num_table[(uchar)(minute%10)]; //第2只数码管
display_table[2] = num_table[(uchar)(second/10)];
display_table[3] = num_table[(uchar)(second%10)];
display_table[4] = num_table[(uchar)(display_3_num/10)];
display_table[5] = num_table[(uchar)(display_3_num%10)];
display_table[6] = num_table[(uchar)(display_4_num/10)];
display_table[7] = num_table[(uchar)(display_4_num%10)];//第8只数码管
temp_wei=0xfe; //位选初值1111,1110
for (i=0;i<8;i++)
{
P0 = 0x00; //消影!
LE_duan = 1; //打开段选锁存端
_nop_();
P0 = display_table[i]; //段选信号
_nop_();
LE_duan = 0; //关闭段选锁存端
P0 = 0xFF; //消影!
LE_wei = 1; //打开位选锁存端
P0 = temp_wei; //位选信号
LE_wei = 0; //关闭位选锁存端
temp_wei = temp_wei<<1|temp_wei>>7; //位选信号循环左移
delay_ms(1);
}
LE_wei = 1;
P0 = 0xFF;
LE_wei = 0;
}
/*-----------------增大指定显示项的数字-----------------*/
//显示项可以是_MINUTE、_SECOND、_GRADE_A、_GRADE_B。

uchar time_grade_increase(uchar item,char inc_num)
{
uchar temp;
switch (item)
{
case _MINUTE:
minute += inc_num;
temp = minute;
break;
case _SECOND:
second += inc_num;
temp = second;
break;
case _GRADE_A:
grade_A += inc_num;
temp = grade_A;
break;
case _GRADE_B:
grade_B += inc_num;
temp = grade_B;
break;
default:
break;
}
return temp;
}
/*-----------------给指定的显示项置数--------------------*/
//显示项可以是_MINUTE、_SECOND、_GRADE_A、_GRADE_B。

void time_grade_set(uchar item,uchar num)
{
switch (item)
{
case _MINUTE:
minute = num;
break;
case _SECOND:
second = num;
break;
case _GRADE_A:
grade_A = num;
break;
case _GRADE_B:
grade_B = num;
break;
default:
break;
}
}
/*-----------------------------------------------*/
/*===============================================*/
//文件名:my_func.c
#include <reg52.h>
#include "my_func.h"
/*---------------初始化-----------------*/
void init (void)
{
TIMER_INIT(); //定时器初始化,装初值,等待计时开始
LED_INIT(); //LED(即游戏状态)初始化
SOUNDER = 0; //关闭蜂鸣器
time_grade_set(_MINUTE,PLAY_TIME);
time_grade_set(_SECOND,0);
time_grade_set(_GRADE_A,0);
time_grade_set(_GRADE_B,0);
}
/*---------------毫秒延时---------------*/
void delay_ms(unsigned int xms)
{
unsigned int i,j;
for (i=xms;i>0;i--)
for (j=110;j>0;j--);
}
/*---------------蜂鸣器发声------------*/
//连续响5声后停止发声
void sounder()
{
uint m,n;
uchar i=5;
while (i--)
{
for(m=0;m<800;m++)
{
for(n=0;n<47;n++); //延时
SOUNDER = !SOUNDER; //取反输出到喇叭的信号}
delay_ms(500);
}
}
/*===============================================*/。

相关文档
最新文档