您的当前位置:首页正文

单片机课程设计报告-篮球计时计分器

2022-11-27 来源:欧得旅游网


2010 ~ 2011 学年 第 2 学期

《单片机应用系统设计与制作》

课程设计报告

教学院(部) 电气与电子信息工程学院

教 研 室 电气自动化

指 导 教 师

课程设计时 间 2011.5.30~2011.6.10

课程设计班 级 电气自动化技术2009(*)班

学 号 2009********

姓 名 张 * *

单片机应用系统设计与制作 课程设计成绩评定表

课程设计题目:篮球计时记分器 课程设计答辩或质疑记录: 1、 2、 成绩评定依据: 成绩评定依据: 课程设计考勤情况(20%): 课程设计答辩情况(30%): 完成设计任务及报告规范性(50%): 最终评定成绩(以优、良、中、及格、不及格评定) 指导教师签字:

2011 年 6 月 20 日

2

摘 要

篮球计时计分器以单片机为核心,由计时器、计分器、综合控制器等组成。系统采用模块化设计,主体分为计时显示模块、计分显示模块、定时报警、按键控制键盘模块。每个模块的程序结构简单、任务明确,易于编写、调试和修改。编程后利用Keil软件来进行编译,再将生成的HEX文件装入芯片中,采用Proteus软件仿真,检验功能是否能够正常实现,本设计中系统硬件电路主要由以下几个部分组成:单片机AT89C52、计时电路、计分电路、报警电路和按键开关。该系统具有赛程定时设置、赛程时间暂停、及时刷新甲乙双方的成绩以及赛后成绩暂存等功能。

关键词:单片机,计时,计分,显示器,接口

ABSTRACT

Time basketball scoring device as the core of SCM includes the timer, scoring devices, integrated controller and other components.This system is used of the modular design, in which the main display module is divided into time display module, scoring display module, timing alarm module, and key control keyboard module. Program structure of each module is simple and clear. So it is easy to write, debug and modify. After programming, firstly we can use Keil software to compile and then generate the HEX file into the chip. Secondly we use the Proteus software simulation to test whether the normal function to achieve. The design of hardware circuit mainly consists of the five components, including AT89C52, timing circuit, scoring circuit, alarm circuit and key switch circuit.The system has many features,such as setting the schedule time, scheduling time to pause, refreshing result of both parties timely, storing temporarily results after the match and so on.

KEY WORDS:Microcontroller, Timing, Scoring, Display, Interface

3

目 录

一、设计目的及要求·································· 3

二、方案论证 ······································· 3

三、元件及其功能简介································ 5

四、电路方案设计····································12

五、编程及仿真······································16

六、心得与总结 ····································· 20

附表一、程序清单·····································21

参考文献·············································34

4

课程设计报告

一、设计目的及要求

1、设计目的

通过本次基于C51系列篮球计时计分器的设计,可以了解、熟悉有关单片机开发设计的过程,并加深对单片机的理解和应用以及掌握单片机与外围接口的一些方法和技巧,这主要表现在以下一些方面:

(1) 篮球赛计时计分系统包含了8051系列单片机的最小应用系统的构成,同时在此基础上扩展了一些使用性强的外围接口。

(2) 可以了解到LED显示器的结构、工作原理以及这种显示器的接口实例与具体连接与编程方法。

(3) 怎样利用串行口来扩展显示接口等。 2、设计要求

(1)能记录整个赛程的比赛时间,并能修改比赛时间、暂停比赛时间; (2)能随时刷新甲、乙两队在整个比赛中的比分; (3)比赛时间和24秒结束,能发出报警提示。

二、方案论证

1、单片机的选型

方案一:51单片机

虽然51单片机是8位的,采用总线结构,但具有编程控制简单、接口简单、工作可靠、价格经济、能耗少、容易实现系统小型化。

方案二:61单片机

61单片机是在51的基础上扩展起来的,它是16位非总线结构的,支持16位硬件乘法,还有专门的乘法指令,现在应用非常广泛。

由于本系统结构简单,用51单片机就足够实现其功能,因此本系统采用51单片机来实现。

2、计时、计分方案

方案一:采用计时芯片

5

针对计算机系统对即使芯片的要求,各大芯片厂家退出了键时钟、倒时钟、正时钟各种芯片,可采用自动控制计时芯片,通过触发控制电路使计时器自动地计时,达到预定时间后,芯片重新开始计时(实现倒计时功能);也可以触发控制电路使计时器不计时,达到预定时间后芯片重新开始计时(实现暂停功能),不需要程序干预。计算机可以通过中断或查询方式读取计数器数据,实现计时的暂停的功能,并进行显示,计时功能的时间就无需占用cpu的时间,程序简单,控制精度高,因此在工业控制系统中多采用这一类专用芯片实现计时功能。

方案二:软件控制

利用MCS—51内部的定时/计数器进行中断定时,配合软件延时实现计时。该方案节省硬件成本。

方案二可以综合运用定时器/计数器、中断以及程序设计的知识,更适合做课程设计使用,因此本系统采用软件方案来实现计时。 3、数码管显示方式

点亮LED显示器有两种方式:一是静态显示;二是动态显示。 方案一:静态显示

静态显示,就是每一个显示器都要占用单独的具有锁存功能的I/O接口,用于笔划段字形代码。这样单片机只要把要显示的字形代码发送到接口电路,就不用管它了,直到要显示新的数据时,再发送新的字形码,因此,使用这种方法单片机中CPU的开销小。这种电路的优点在于:在同一时间可以显示不同的字符;但缺点就是占用端口资源较多。从图可以看出,每位LED显示器需要单独占用8根端口线。

方案二:动态显示

动态驱动是将所有数码管的8个显示笔划\"a,b,c,d,e,f,g,dp \"的同名端连在一起,另外为每个数码管的公共极COM增加位元选通控制电路,位元选通由各自独立的I/O线控制,当单片机输出字形码时,所有数码管都接收到相同的字形码,但究竟是那个数码管会显示出字形,取决于单片机对位元选通COM端电路的控制,所以我们只要将需要显示的数码管的选通控制打开,该位元就显示出字形,没有选通的数码管就不会亮。

透过分时轮流控制各个LED数码管的COM端,就使各个数码管轮流受控显示,这就是动态驱动。在轮流显示过程中,每位元数码管的点亮时间为1~2ms,由于人的视觉暂留现象及发光二极体的余辉效应,尽管实际上各位数码管并非同时点亮,但只要扫描的速度足够快,给人的印象就是一组稳定的显示资料,不会有闪烁感。

6

由于动态显示和静态显示的显示效果是一样的,动态显示能够节省大量的I/O埠,而且功耗更低。所以在本系统中选用动态显示

静态显示图 动态显示图

4、系统结构方框图

本系统的核心控制元件是单片机AT89C52,在它的基础上加上一些输入控制和输出显示模块,来实现调整和显示篮球比赛时的时间和分数的设置。

三、元件及其功能简介

1、单片机AT89C52 ①、单片机AT89C52简介

AT89C52是一个低电压,高性能CMOS 8位单片机,片内含8k bytes的可反复擦写的Flash只读程序存储器和256 bytes的随机存取数据存储器(RAM),器件采用ATMEL

7

公司的高密度、非易失性存储技术生产,兼容标准MCS-51指令系统,片内置通用8位中央处理器和Flash存储单元,AT89C52单片机在电子行业中有着广泛的应用。 AT89C52为8 位通用微处理器,采用工业标准的C51内核,在内部功能及管脚排布上与通用的8xc52 相同,其主要用于会聚调整时的功能控制。功能包括对会聚主IC 内部寄存器、数据RAM及外部接口等功能部件的初始化,会聚调整控制,会聚测试图控制,红外遥控信号IR的接收解码及与主板CPU通信等。 ②、基本功能特性 1、兼容MCS51指令系统

2、8k可反复擦写(大于1000次)Flash ROM; 3、32个双向I/O口; 4、256x8bit内部RAM;

5、3个16位可编程定时/计数器中断; 6、时钟频率0-24MHz;

7、2个串行中断,可编程UART串行通道; 8、2个外部中断源,共8个中断源; 9、2个读写中断口线,3级加密位;

10、低功耗空闲和掉电模式,软件设置睡眠和唤醒功能;

11、有PDIP、PQFP、TQFP及PLCC等几种封装形式,以适应不同产品的需求。 ③、主要管脚及接口

XTAL1(19 脚)和XTAL2(18 脚)为振荡器输入输出端口,外接12MHz 晶振。RST/Vpd(9 脚)为复位输入端口,外接电阻电容组成的复位电路。VCC(40 脚)和VSS(20 脚)为供电端口,分别接+5V电源的正负端。P0~P3 为可编程通用I/O 脚,其功能用途由软件定义,在本设计中,P0 端口(32~39 脚)被定义为N1 功能控制端口,分别与N1的相应功能管脚相连接,13 脚定义为IR输入端,10 脚和11脚定义为I2C总线控制端口,分别连接N1的SDAS(18脚)和SCLS(19脚)端口,12 脚、27 脚及28 脚定义为握手信号功能端口,连接主板CPU 的相应功能端,用于当前制式的检测及会聚调整状态进入的控制功能。

P0 口:P0 口是一组8 位漏极开路型双向I/O 口, 也即地址/数据总线复用口。作为输出口用时,每位能吸收电流的方式驱动8 个TTL逻辑门电路,对端口P0 写“1”时,可作为高阻抗输入端用。 在访问外部数据存储器或程序存储器时,

8

这组口线分时转换地址(低8 位)和数据总线复用,在访问期间激活内部上拉电阻。在Flash 编程时,P0 口接收指令字节,而在程序校验时,输出指令字节,校验时,要求外接上拉电阻。 P1 口:P1 是一个带内部上拉电阻的8 位双向I/O 口, P1 的输出缓冲级可驱动(吸收或输出电流)4 个TTL 逻辑门电路。对端口写“1”,通过内部的上拉电阻把端口拉到高电平,此时可作输入口。作输入口使用时,因为内部存在上拉电阻,某个引脚被外部信号拉低时会输出一个电流(IIL)。 与AT89C51 不同之处是,P1.0 和P1.1 还可分别作为定时/计数器2 的外部计数输入(P1.0/T2)和输入(P1.1/T2EX), Flash 编程和程序校验期间,P1 接收低8 位地址。 P1.0和P1.1的第二功能 引脚号 功能特性 9

P1.0 P1.1 T2,时钟输出 T2EX(定时/计数器2) P2 口:P2 是一个带有内部上拉电阻的8 位双向I/O 口,P2 的输出缓冲级可驱动(吸收或输出电流)4 个TTL 逻辑门电路。对端口P2 写“1”,通过内部的上拉电阻把端口拉到高电平,此时可作输入口,作输入口使用时,因为内部存在上拉电阻,某个引脚被外部信号拉低时会输出一个电流(IIL)。 在访问外部程序存储器或16 位地址的外部数据存储器(例如执行MOVX @DPTR 指令)时,P2 口送出高8 位地址数据。在访问8 位地址的外部数据存储器(如执行MOVX @RI 指令)时,P2 口输出P2 锁存器的内容。 Flash 编程或校验时,P2亦接收高位地址和一些控制信号。 P3 口:P3 口是一组带有内部上拉电阻的8 位双向I/O 口。P3 口输出缓冲级可驱动(吸收或输出电流)4 个TTL 逻辑门电路。对P3 口写入“1”时,它们被内部上拉电阻拉高并可作为输入端口。此时,被外部拉低的P3 口将用上拉电阻输出电流(IIL)。P3 口除了作为一般的I/O 口线外,更重要的用途是它的第二功能。 P3口第二功能 端口引脚 P3.0 P3.1 P3.2 P3.3 P3.4 P3.5 P3.6 P3.7 RXD(串行输入口) TXD(串行输出口) /INT0(外部中断0) /INT1(外部中断1) T0(记时器0外部输入) T1(记时器1外部输入) /WR(外部数据存储器写选通) /RD(外部数据存储器读选通) 第二功能 RST:复位输入。当振荡器工作时,RST引脚出现两个机器周期以上高电平将使单片机复位。 10

ALE/PROG:当访问外部程序存储器或数据存储器时,ALE(地址锁存允许)输出脉冲用于锁存地址的低8 位字节。一般情况下,ALE 仍以时钟振荡频率的1/6 输出固定的脉冲信号,因此它可对外输出时钟或用于定时目的。要注意的是:每当访问外部数据存储器时将跳过一个ALE 脉冲。 对Flash 存储器编程期间,该引脚还用于输入编程脉冲(PROG)。 如有必要,可通过对特殊功能寄存器(SFR)区中的8EH 单元的D0 位置位,可禁止ALE 操作。该位置位后,只有一条MOVX 和MOVC指令才能将ALE 激活。此外,该引脚会被微弱拉高,单片机执行外部程序时,应设置ALE禁止位无效。

PSEN:程序储存允许(PSEN)输出是外部程序存储器的读选通信号,当AT89C52 由外部程序存储器取指令(或数据)时,每个机器周期两次PSEN 有效,即输出两个脉冲。在此期间,当访问外部数据存储器,将跳过两次PSEN信号。 XTAL1:振荡器反相放大器的及内部时钟发生器的输入端。 XTAL2:振荡器反相放大器的输出端。 ④、中断

AT89C52 共有6 个中断向量:两个外中断(INT0 和INT1),3 个定时器中断(定时器0、1、2)和串行口中断。

这些中断源可通过分别设置专用寄存器IE 的置位或清0 来控制每一个中断的允许或禁止。IE 也有一个总禁止位EA,它能控制所有中断的允许或禁止。 定时器2 的中断是由T2CON 中的TF2 和EXF2 逻辑或产生的,当转向中断服务程序时,这些标志位不能被硬件清除,事实上,服务程序需确定是TF2 或EXF2 产生中断,而由软件清除中断标志位。

定时器0 和定时器1 的标志位TF0 和TF1 在定时器溢出那个机器周期的S5P2 状态置位,而会在下一个机器周期才查询到该中断标志。然而,定时器2 的标志位TF2 在定时器溢出的那个机器周期的S2P2 状态置位,并在同一个机器周期内查询到该标志。 ⑤、Flash存储器的编程

AT89C52单片机内部有8k字节的Flash PEROM,这个Flash 存储阵列出厂时已处于擦除状态(即所有存储单元的内容均为FFH),用户随时可对其进行编程。编程接口可接收高电压(+12V)或低电压(Vcc)的允许编程信号。低电压编程模式适合于用户在线编程系统,而高电压编程模式可与通用EPROM 编程器兼容。

11

AT89C52 单片机中,有些属于低电压编程方式,而有些则是高电压编程方式,用户可从芯片上的型号和读取芯片内的签名字节获得该信息。

AT89C52 的程序存储器阵列是采用字节写入方式编程的,每次写入一个字节,要对整个芯片内的PEROM 程序存储器写入一个非空字节,必须使用片擦除的方式将整个存储器的内容清除。 2、报警器 ①、报警器的分类

蜂鸣器有两类3大品种。一类是压电式,一类是电磁式,电磁式又有两大品种,铁振膜式和动圈式,二者原理一样只是结构不同。所有蜂鸣器都有两种类型:纯蜂鸣器和带驱动的蜂鸣器,蜂鸣器都是用音频信号驱动的,都是交流驱动。 ②、报警器工作原理

电磁式蜂鸣器由振荡器、电磁线圈、磁铁、震动膜片以及外壳等组成。接通电源后,振荡器产生的音频信号通过电磁线圈,使得电磁线圈产生了一个磁场。振动膜片在电磁线圈和磁铁的相互作用下,周期性地振动发声。 3、芯片74HC154

①、简介:4线—16线译码器,可以实现地址的扩展。 ②、引脚说明

1-11 13-17 :输出端。 12 :Gnd电源地

18-19 :使能输入端、低电平有效 20-23 :地址输入端 24 :VCC电源正 4、RESPACK—8

接在51单片机的P0口,因为P0口内部没有上拉电阻,不能输出高电平,所以要接上拉电阻。排阻就是好多电阻连在一起,他们有一个公共端1端为公共端接VCC或地。 5、LED数码管

LED显示器又称为数码管,LED显示器由8个发光二极管组成。中7个长条形的发光管排列成“日”字形,另一个点形的发光管在显示器的右下角作为显示小数点用,它能显示各种数字及部份英文字母。LED显示器有两种不同的形式:一种

12

是8个发光二极管的阳极都连在一起的,称之为共阳极LED显示器;另一种是8个发光二极管的阴极都连在一起的,称之为共阴极LED显示器。如图所示。本设计采用的是共阴极数码管显示。

7段LED数码管

共阴极与共阳极LED显示器

共阳极与共阴极LED显示器显示数字、字母与显示代码之间的对应关系:

显示字共阴极段码 共阳极段码 显示字符 符 0 1 2 3 4 3FH 06H 5BH 4FH 66H C0 F9 A4 B0 99H 8 9 A B C 7FH 6FH 77H 7CH 39H 80H 90H 88H 83H C6 共阴极段码 共阳极段码 13

5 6 7 6DH 7DH 07H 92H 82H F8 D E F 5EH 79H 71H A1H 86H 8EH

四、电路方案设计

1、功能控制电路

该控制电路可以实现篮球比赛的节数、时间、24秒复位、比赛暂停、两队的分数加减等功能的设置。采用7个复位开关一端共地,另一端接入与门,再连接到单片机的13号脚(P3.3/INT1口),实现外部中断1请求。

①、赛程时间设置

在计时电路中,“修改移位开关”和“红队加、减分开关”共同用来设置比赛的节次、剩余时间等。比如:比赛时间为第一小节剩余10分钟,则通过按“修改移位开关”,使数码管1进入修改模式,再按“红队加、减分开关”键,设定本场比赛的小节数,使数码管1显示“1”即可;继续按动“修改移位开关”可以使其他的数码管进入修改模

14

式,按以上方法修改即可。当比赛结束时,如果由于一些特殊原因需要增加比赛时间,这时增加比赛时间同样由以上方法来设置。

②、赛程时间启动/暂停设置

当时间设置完成后,这时,如果裁判吹响开始的哨声时,则应立即按下按“暂停/启动”键,表示赛程开始,计时显示则开始倒计时,在此过程中24秒也开始倒计,在24秒倒计到06秒时,蜂鸣器发出警报,报警灯开始闪烁,如果24秒倒计为00前,没有被复位(有人24秒进攻违例),则比赛自动暂停。如果无进攻违例,则需要记分人员手动复位24秒(按控制键盘中的“复位”开关即可)。比赛暂停后,需要按“暂停/启动”键来激活时间倒计。

③、比分刷新控制

由于在比赛中,甲、乙两队的比分是不断在变化的,所以需要设置比分刷新控制装置;此部分功能由计分电路中的所示的按键开关“红队加分”、“红队减分”、“蓝队加分”、“蓝队减分”来完成的。

2、时钟产生方式

采用内部时钟方式(在单片机的XTAL1和XTAL2引脚外接晶振即可),途中,电容器C1和C2的作用是稳定频率和快速起振。

15

3、复位电路

该电路采用:按键与上电复位

上电复位要求接通电源后,单片机自动实现复位操作。上电瞬间RST引脚获得高电平,随着电容C3的充电,RST引脚的高电平将逐渐下降。RST引脚的高电平只要能保持足够的时间(两个机械周期),单片机就可以进行复位操作。

按下复位开关时,短接电容C3,使RST引脚瞬间得到高电平也可实现复位功能。

4、 显示电路

显示电路是由数码管组成的,主要用来显示篮球比赛过程中的节次、24秒、比赛剩余时间、两队分数。

在此电路中,单片机的P1口用于控制4位LED的段选码:P2口的P2.0—P2.3用于控制4位LED位选码。由于所有的段选码连在一起,所以同一瞬间只能显示同一种字符。但如果要显示不同字符,则要由位选码来控制,系统通过74HC154来扩展P2.0—P2.3端子来实现AT89c52对数码管的选码。(如果LED为共阴极则P2.0—P2.3输出为高电平,如果LED为共阳极则P2.0—P2.3输出为低电平。)

16

显示电路的主电路图如下:

17

5、电路总图

综上所述,结合以上各个电路,加上适当的组件,即可得到篮球比赛计时计分器的总设计图:

五、编程与仿真

1、keil软件的应用

利用keil软件,编写程序,并进行调试,调试结果出现0个错误时,即可生成hex文件(部分程序流程图如下)。

计时程序部分流程图:

18

定时中断初始化 按下调时开关 开放定时中断 立即数00H取出,LE输出高电平 经过P1.0发送代码,然后将LE清零 启动定时器,T0开始定时 调用定时中断程序

记分程序部分流程图:

按下计分键 输出低电平,外部中断产生 调用中断程序 串行数据输出移位脉冲输出 显示数据,两队相应比分变化 串行口发送完毕,标志清零

19

程序流程图:

HEX文件的生成方式:在所建工程上右键→下拉菜单中点击‘options for target‘target1’’→点击输出选项卡→勾中创建hex文件(如下图)→确定→运行。即可再所建工程的文件夹下找到hex文件

20

2、proteus的应用

按照原理图搭建防真电路图,加载hex文件运行即可。

Hex文件加载方式:双击仿真电路图中的AT89C52单片机→单击program file项后面的文件夹图标→选中刚刚建立的hex文件→确定(如下图所示)→确定

3、进行电路仿真

以上准备工作全部完成后就可以进行电路仿真啦,单击开始进行仿真。运行效果图如下:

21

六、 心得与总结

在本次设计中,我通过基于典型单片机AT89C52的设计和应用,对于单片机工作原理,功能有了宏观的了解,并对单片机汇编程序的应用有了新的、进一步的认识。

在设计的过程中,我发现很多的问题,给我的感觉就是下手很难,很不顺手,看似很简单的电路,要动手把它给设计出来,是很难的一件事,主要原因是我们没有经常动手设计过电路。另外单片机系统的知识似懂非懂,而且很多知识当时弄明白了,现在要用的时候又不记得,造成我用了大量的时间去查阅各种资料和程序命令,因此整个过程时间安排不合理。由于设计的计划没有安排好,设计的时间极为仓促,尤其是在仿真调试的过程中出现了很大的问题。另外资料的查找也是一大难题,这就要求我们在以后的学习中,应该注意到这一点,更重要的是我们要学会把从书本中学到的知识和实际的电路联系起来,这不论是对我们以后的就业还是学习,都会起到很大的促进和帮助。

本次设计测试结果以及不足之处:计时电路可完成倒计时、暂停、继续等功能,在比赛时间到后可进行报警。记分电路工作正常,可完成对比分的刷新与暂存。但在测试过程中发现,在比赛上半场时间到后,不能进行比分的交换。

进行分析后得出结论如下:系统电路部分设计没有原则性的错误,基本达到本次课程设计的要求。

22

附表一

程序编程清单:

#include

#define uchar unsigned char #define uint unsigned int #define TH_value 0xb1 #define TL_value 0xe0 //定时器工作于方式1,每20ms产生一个中断 sbit speak=P3^7; sbit ext=P3^2; sbit led=P3^4;

/**********BCD码字***************/ uchar code bcd[]={ 0x00,0x01,0x02,0x03, 0x04,0x05,0x06,0x07, 0x08,0x09,0x0A,0x0B, 0x0C,0x0D,0x0E,0x0F };

/************0~9数字显示**************/ uchar code table[]={ 0x3f,0x06,0x5b,0x4f, 0x66,0x6d,0x7d,0x07, 0x7f,0x6f,0x00};

uchar munite; //比赛剩余分位数 uchar second; //比赛剩余秒位数 uchar part; //当前比赛的节次 uchar s24; //24秒标志 uchar red_mark; //红队得分 uchar blue_mark; //蓝队得分 uchar key_move; //设置位移动 uchar key_red_add; //红队得分增加1 uchar key_red_mul; //红队得分减少1 uchar key_blue_add; //蓝队得分增加1 uchar key_blue_mul; //蓝队得分减少1 uchar key_pause; //暂停

uchar key_reset; //24秒复位及进入下一节复位 uchar time_tick1,time_tick2; uchar station; //状态标志位 uchar flag; //跳亮标志位

uchar talk1,talk2,num,num1; //报警信号标志 /*******函数声明********/ void init();

void init_timer(); void init_extra(); uchar key_scan();

void scanf(uchar p,uchar tw,uchar m,uchar s,uchar r,uchar b); void scanf1(uchar p,uchar r,uchar b); void scanf2(uchar tw,uchar r,uchar b); void scanf3(uchar m,uchar r,uchar b); void scanf4(uchar s,uchar r,uchar b); void play24(); void playstop1(); void playstop2();

23

/*********延时程序,t=1时,延时1ms************/ void delay(uchar t) { int i,j; for(j=0;j/***********主程序************/ void main() { init(); init_timer(); init_extra(); //初始化 while(1) { if(station==0) //状态0:比赛状态 { scanf(part,s24,munite,second,red_mark,blue_mark); if(time_tick1==50) { time_tick1=0; if(second==0) //时间计数 { if(munite==0) { if(part>=4) { talk2=1; //终场报警操作 TR0=0; //关闭定时器中断0 TR1=1; } else { talk2=1; //小节结束报警 TR1=1; TR0=0; } } else { munite--; second=59; } } else second--; if(s24==0) //24秒计数 { TR0=0; } else { if(s24<2) { talk2=1; TR1=1;

24

时间

TR0=0; key_pause=0; } else if(s24<8) { talk1=1; TR1=1; } s24--; //6秒提醒 } }

if(second==0&&munite==0) //操作进入下一节比赛 { if(key_reset==1) { s24=0x18; part++; key_reset=0; if(part==10) talk2=1; //比赛太久,报警 if(part<5) //判断是否为加时赛,不是,延长12分钟 { munite=0x0c; second=0x00; } else //加时赛,延长5分钟 { munite=0x05; second=0x00; } } }

if(second!=0||munite!=0) //操作24秒复位 { if(key_reset==1) { if(second<0x18&&munite==0)//当比赛剩余时间少于24秒时,sS4为当前剩余 { key_reset=0; s24=second; } else { key_reset=0; s24=0x18; } } }

if(key_red_add==1) { key_red_add=0; if(red_mark<0xff) red_mark++; }

if(key_red_mul==1)

//当时间大于24秒时,S24复位为24秒

//红队得分操作加

//红队得分操作减

25

{ key_red_mul=0; if(red_mark>0) red_mark--; } if(key_blue_add==1) //蓝队得分操作加 { key_blue_add=0; if(blue_mark<0xff) blue_mark++; } if(key_blue_mul==1) //蓝队得分操作减 { key_blue_mul=0; if(blue_mark>0) blue_mark--; } }

if(station==1) //比赛节次操作 { TR1=1; flag=0; while(station==1) { if(flag==0) scanf1(part,red_mark,blue_mark); if(flag==1) scanf(part,s24,munite,second,red_mark,blue_mark); if(key_red_add==1) //比赛节次操作加 { key_red_add=0; if(part<0x09) part++; } if(key_red_mul==1) //比赛节次操作减 { key_red_mul=0; if(part>1) part--; } } if(station!=1) { TR1=0; flag=0; } }

if(station==2) //24秒操作 { TR1=1; flag=0; while(station==2) { if(flag==0) scanf2(s24,red_mark,blue_mark); if(flag==1)

26

scanf(part,s24,munite,second,red_mark,blue_mark); if(key_red_add==1) //24秒操作加.MAX=24 { key_red_add=0; if(s24<0x18) s24++; } if(key_red_mul==1) //24秒操作减 { key_red_mul=0; if(s24>0) s24--; } } if(station!=2) { TR1=0; flag=0; } }

if(station==3) //计时分操作 { TR1=1; flag=0; while(station==3) { if(flag==0) scanf3(munite,red_mark,blue_mark); if(flag==1) scanf(part,s24,munite,second,red_mark,blue_mark); if(key_red_add==1) //分操作加,MAX=60 { key_red_add=0; if(munite<0x3c) munite++; } if(key_red_mul==1) //分操作减 { key_red_mul=0; if(munite>0) munite--; } } if(station!=3) { TR1=0; flag=0; } }

if(station==4) { TR1=1; flag=0; while(station==4) { if(flag==0)

//计时秒操作

27

} } }

/************初始化************/ void init() { munite=0x01; second=0x00; red_mark=0x00; blue_mark=0x00; part=0x01; s24=0x18; station=0x00; key_pause=0; key_move=0x00; key_red_add=0x00; key_red_mul=0x00; key_blue_add=0x00; key_blue_mul=0x00; key_reset=0x00; flag=0x00; }

/************定时器0初始化**************/ void init_timer() { TMOD=0x11; TH0=TH_value; TL0=TL_value; TH1=TH_value; TL1=TL_value; ET0=1; ET1=1;

scanf4(second,red_mark,blue_mark);

if(flag==1) scanf(part,s24,munite,second,red_mark,blue_mark); if(key_red_add==1) //秒操作加,MAX=60 { key_red_add=0; if(second<0x3c) second++; } if(key_red_mul==1) //秒操作减 { key_red_mul=0; if(second>0) second--; } }

if(station!=4) { TR1=0; flag=0; }

28

time_tick1=0; time_tick2=0; }

/**************外部中断源初始化****************/ void init_extra() { EX0=1; EX1=1; IT0=1; IT1=1; EA=1; }

/*****************定时器0***************/ void timer0()interrupt 1 { time_tick1++; TH0=TH_value; TL0=TL_value; }

/*************定时器1***************/ void timer1()interrupt 3 { EA=0; TH1=TH_value; TL1=TL_value; time_tick2++; if(time_tick2==50) { led=~led; time_tick2=0x00; if(flag==0) flag=1; //跳亮标志位 else flag=0; } if(talk1==1) { EA=0; TH1=0xFD; TL1=0xF7; EA=1; speak=~speak; num++; if(num==200) { num=0; talk1=0; TR1=0; } } if(talk2==1) { EA=0; TH1=0xFD; TL1=0xF7; EA=1; speak=~speak;

29

num++; if(num==200) { num1++; num=0; if(num1==4) { num1=0; talk2=0; TR1=0; } } } EA=1; }

/***********外部中断0************/ void extra0()interrupt 0 { if(key_pause==1) { key_pause=0; TR0=0; } else { if(s24==0) ; else { key_pause=1; TR0=1; } } }

/***********外部中断1*****************/ void extra1()interrupt 2 { uchar dtemp; dtemp=key_scan(); switch(dtemp) { case 0xFE:key_move=1;break; case 0xFD:key_reset=1;break; case 0xF7:key_red_add=1;break; case 0xDF:key_red_mul=1;break; case 0xEF:key_blue_add=1;break; case 0xBF:key_blue_mul=1;break; default:break; } if(key_move==1) { station++; if(station==5) station=0; key_move=0; }

30

}

/*************键盘扫描****************/ uchar key_scan() { uchar temp; P1=0xFF; temp=P1; delay(3); if(temp==P1) { return temp; } }

/***************数码管驱动*******************/ void scanf(uchar p,uchar tw,uchar m,uchar s,uchar r,uchar b) { P2=bcd[0]; P0=table[p]; delay(1);

P2=bcd[1]; P0=table[tw/10]; delay(1);

P2=bcd[2]; P0=table[tw%10]; delay(1);

P2=bcd[3]; P0=table[m/10]; delay(1);

P2=bcd[4]; P0=table[m%10]; delay(1);

P2=bcd[5]; P0=table[s/10]; delay(1);

P2=bcd[6]; P0=table[s%10]; delay(1);

P2=bcd[7]; P0=table[r/100]; delay(1);

P2=bcd[8]; P0=table[r/10%10]; delay(1);

P2=bcd[9]; P0=table[r%10]; delay(1);

P2=bcd[10]; P0=table[b/100]; delay(1);

P2=bcd[11]; P0=table[b/10%10]; delay(1);

P2=bcd[12]; P0=table[b%10]; delay(1); }

31

/***************数码管驱动*******************/ void scanf1(uchar p,uchar r,uchar b) { P2=bcd[0]; P0=table[p]; delay(1);

P2=bcd[1]; P0=table[10]; delay(1);

P2=bcd[2]; P0=table[10]; delay(1);

P2=bcd[3]; P0=table[10]; delay(1);

P2=bcd[4]; P0=table[10]; delay(1);

P2=bcd[5]; P0=table[10]; delay(1);

P2=bcd[6]; P0=table[10]; delay(1);

P2=bcd[7]; P0=table[r/100]; delay(1);

P2=bcd[8]; P0=table[r/10%10]; delay(1);

P2=bcd[9]; P0=table[r%10]; delay(1);

P2=bcd[10]; P0=table[b/100]; delay(1);

P2=bcd[11]; P0=table[b/10%10]; delay(1);

P2=bcd[12]; P0=table[b%10]; delay(1); }

/***************数码管驱动*******************/ void scanf2(uchar tw,uchar r,uchar b) { P2=bcd[0]; P0=table[10]; delay(1);

P2=bcd[1]; P0=table[tw/10]; delay(1);

P2=bcd[2]; P0=table[tw%10]; delay(1);

P2=bcd[3]; P0=table[10];

32

}

/***************数码管驱动*******************/ void scanf3(uchar m,uchar r,uchar b) { P2=bcd[0]; P0=table[10]; delay(1);

P2=bcd[1]; P0=table[10]; delay(1);

P2=bcd[2]; P0=table[10]; delay(1);

P2=bcd[3]; P0=table[m/10]; delay(1);

P2=bcd[4]; P0=table[m%10]; delay(1);

P2=bcd[5]; P0=table[10]; delay(1);

P2=bcd[6]; P0=table[10]; delay(1);

P2=bcd[7]; P0=table[r/100]; delay(1);

P2=bcd[8];

delay(1); P2=bcd[4]; P0=table[10]; delay(1); P2=bcd[5]; P0=table[10]; delay(1); P2=bcd[6]; P0=table[10]; delay(1); P2=bcd[7];

P0=table[r/100]; delay(1); P2=bcd[8];

P0=table[r/10%10]; delay(1); P2=bcd[9];

P0=table[r%10]; delay(1); P2=bcd[10]; P0=table[b/100]; delay(1); P2=bcd[11];

P0=table[b/10%10]; delay(1); P2=bcd[12]; P0=table[b%10]; delay(1);

33

}

/***************数码管驱动*******************/ void scanf4(uchar s,uchar r,uchar b) { P2=bcd[0]; P0=table[10]; delay(1);

P2=bcd[1]; P0=table[10]; delay(1);

P2=bcd[2]; P0=table[10]; delay(1);

P2=bcd[3]; P0=table[10]; delay(1);

P2=bcd[4]; P0=table[10]; delay(1);

P2=bcd[5]; P0=table[s/10]; delay(1);

P2=bcd[6]; P0=table[s%10]; delay(1);

P2=bcd[7]; P0=table[r/100]; delay(1);

P2=bcd[8]; P0=table[r/10%10]; delay(1);

P2=bcd[9]; P0=table[r%10]; delay(1);

P2=bcd[10]; P0=table[b/100]; delay(1);

P2=bcd[11]; P0=table[b/10%10]; delay(1);

P2=bcd[12]; P0=table[b%10]; delay(1);

P0=table[r/10%10];

delay(1); P2=bcd[9];

P0=table[r%10]; delay(1); P2=bcd[10]; P0=table[b/100]; delay(1); P2=bcd[11];

P0=table[b/10%10]; delay(1); P2=bcd[12]; P0=table[b%10]; delay(1);

34

}

/*************24秒提醒报警****************/ void play24() { uchar i; for(i=0;i<50;i++) { speak=~speak; delay(5); } }

/*************比赛时间提醒报警************/ void playstop1() { uchar i; for(i=0;i<100;i++) { speak=~speak; delay(5); } }

/**************结束报警****************/ void playstop2() { uchar i; for(i=0;i<200;i++) { speak=~speak; delay(5); }

35

参考文献

[1]电气与电子信息工程学院. 单片机实验指导书

[2]熊静琪 《计算机控制技术》 (北京:电子工业出版社,2003)

[3]黄忠霖 《控制系统MATIAB计算及仿真》 (北京:国防工业出版社, 2004) [4]彭为等 《单片机典型系统设计实例精讲》 (北京:电子工业出版社,2007) [5]王庆利等《单片机设计案例实践教程》 (北京:北京邮电大学出版社,2008) [6]韩志军等 《单片机应用系统设计——入门向导与设计实例》(北京:机械工业出版社,2005)

[7]皮大能等 《单片机课程设计指导书》 (北京:北京理工大学出版社,2010) [8] 李全利 《单片机原理及接口技术》 (北京:高等教育出版社,2009.1) [9] 丁明亮、 唐前辉 《51单片机应用设计与仿真-基于Keil C和Proteus 》 (北京航空航天大学出版社, 2009)

[10]仿真论坛 http://proteus.5d6d.com

36

因篇幅问题不能全部显示,请点此查看更多更全内容