基于单片机的羽毛球计分器(含proteus仿真和程序)

news2024/12/29 9:44:06

目录

完整文本及仿真、程序可私信我获取

前言

第一章 设计任务及方案 

1.1 设计任务 

1.2 总体设计分析

1.3 功能模块方案设计 

1.4 方案确定 

第二章、硬件设计 

2.1 AT89C51 单片机芯片介绍 

2.1.1 主要特性 

2.1.2 管脚说明 

2.1.3 元件清单 

2.2 电路介绍 

2.2.1 电源部分 

2.2.2 按键部分 

2.2.3 显示部分 

2.2.4 时钟、复位电路 

第三章、软件设计 

3.1 程序流程图 

3.2 模块设计 

3.2.1 主函数 

3.2.2 显示函数 

3.2.3 延时函数 

3.2.4 定时器函数 

3.2.5 中断函数 

3.2.6 字符转换函数 

3.2.7 全局变量定义及函数声明 

第四章、仿真与调试 

4.1 调试的环境 

4.2 按键及功能的调试 

总 结 

参考文献 

附 录


完整文本及仿真、程序可私信我获取

前言

        随着物质生活水平的提高,人们越来越重视生命的质量。据调查运动作为一种绿色消费在人民日常消费中所占得比例呈持续上升的趋势,全民健身运动热潮愈演愈烈,健身器材的市场需求也会不断扩大。羽毛球是一项室内、室外都可以进行的体育运动,在我国羽毛球运动是一项很普及的运动,更深受青少年的喜爱。其比赛规则经过多年的改进变得更公正合理,计分方式也变得多元化。近年来随着科技的发展,单片机的应用在不断深入,单片机的集成度高,通用性好,特别是它具有体积小,重量轻,能耗低,价格便宜,可靠性高,抗干扰能力强和使用方便等独特的优点,所以本课题采用单片机AT89C51作为本设计的核心元件。本设计由控制系统,显示模块,按键驱动模块3部分组成。主要编写了主程序,中断程序,显示程序功能模块程序等。实现羽毛球计分器功能。

第一章 设计任务及方案 

1.1 设计任务 

        设计一个羽毛球电子计分器,能用按键控制其启动、计分、停止、清零, 并在LM1602液晶屏上显示且自动输出比赛结果。

1.2 总体设计分析

        根据功能要求及设计成本,控制系统选用AT89C51芯片。采用按钮开关实现功能控制,按照设计的功能模块共选用8个按钮开关,分别实现启动、A队加分、A队减分、B队加分、B队减分、暂停、停止、清零功能。时钟电路由晶体振荡器、晶震控制芯片和电容组成,采用串行数据传输,为掉电保护电源提供可编程的充电功能,并且可以关闭充电功能。复位电路用来使电路恢复到起始状态的电路设备,确保微机系统中电路稳定可靠工作,是电路图中必不可少的一部分。选用LM1602液晶屏作为显示器件,用于记录两队的分数。

1.3 功能模块方案设计 

表1-1 按键功能

按键

功能说明

显示区域

S3

比赛开始

T00:00 A:B  00:00

S1

A队加一分

T00:30 A:B  01:00

S2

B队加一分

T01:00 A:B  01:01

S4

比赛暂停

T02:36 A:B  03:02

S5

A队减一分

T02:38 A:B  02:02

S6

B队减一分

T02:45 A:B  02:01

S7

时间、比分清零

T00:00 A:B  00:00

S8

比赛结束

END

1.4 方案确定 

选定方案描述:

        在像羽毛球这样的竞技比赛中,计分器占着很大的作用。如果我们就只在心里记着双方的比分,显然是不实际的,而且在现在的乒乓球比赛中采用的都是21分制。因此我们不能再用传统的计分方式了。本次课题采用单片机设计了一个羽毛球的计分器,该计分器操作简单,使用安全,方便,能满足广大羽毛球爱好者的需要。    

图1-1 总设计框图

     

第二章、硬件设计 

2.1 AT89C51 单片机芯片介绍 

        单片机就是一块硅片上集成了中央处理器(cpu)存储器和输入输出接口(并行I/O串行通信口)振荡电路,计数器等电路的一块集成电路,这样的一块集成电路具有一台计算机的基本功能,因而被称为单片微型计算机,简称单片机(MCU)。

图2-1 AT89C51 单片机

2.1.1 主要特性 

•与MCS-51 兼容

•4K字节可编程FLASH存储器

•寿命:1000写/擦循环

•数据保留时间:10年

•全静态工作:0Hz-24MHz

•三级程序存储器锁定

•128×8位内部RAM

•32可编程I/O线

•两个16位定时器/计数器

•5个中断源

•可编程串行通道

•低功耗的闲置和掉电模式

•片内振荡器和时钟电路

2.1.2 管脚说明 

VCC:供电电压。

GND:接地。

P0口:P0口为一个8位漏级开路双向I/O口,每脚可吸收8TTL门电流。当P0口的管脚第一次写1时,被定义为高阻输入。P0能够用于外部程序数据存储器,它可以被定义为数据/地址的低八位。在FIASH编程时,P0 口作为原码输入口,当FIASH进行校验时,P0输出原码,此时P0外部必须接上拉电阻。

P1口:P1口是一个内部提供上拉电阻的8位双向I/O口,P1口缓冲器能接收输出4TTL门电流。P1口管脚写入1后,被内部上拉为高,可用作输入,P1口被外部下拉为低电平时,将输出电流,这是由于内部上拉的缘故。在FLASH编程和校验时,P1口作为低八位地址接收。

P2口:P2口为一个内部上拉电阻的8位双向I/O口,P2口缓冲器可接收,输出4个TTL门电流,当P2口被写“1”时,其管脚被内部上拉电阻拉高,且作为输入。并因此作为输入时,P2口的管脚被外部拉低,将输出电流。这是由于内部上拉的缘故。P2口当用于外部程序存储器或16位地址外部数据存储器进行存取时,P2口输出地址的高八位。在给出地址“1”时,它利用内部上拉优势,当对外部八位地址数据存储器进行读写时,P2口输出其特殊功能寄存器的内容。P2口在FLASH编程和校验时接收高八位地址信号和控制信号。

P3口:P3口管脚是8个带内部上拉电阻的双向I/O口,可接收输出4个TTL门电流。当P3口写入“1”后,它们被内部上拉为高电平,并用作输入。作为输入,由于外部下拉为低电平,P3口将输出电流(ILL)这是由于上拉的缘故。

P3口也可作为AT89C51的一些特殊功能口,如下表所示:

口管脚 备选功能

P3.0 RXD(串行输入口)

P3.1 TXD(串行输出口)

P3.2 /INT0(外部中断0)

P3.3 /INT1(外部中断1)

P3.4 T0(计时器0外部输入)

P3.5 T1(计时器1外部输入)

P3.6 /WR(外部数据存储器写选通)

P3.7 /RD(外部数据存储器读选通)

P3口同时为闪烁编程和编程校验接收一些控制信号。

RST:复位输入。当振荡器复位器件时,要保持RST脚两个机器周期的高电平时间。

ALE/PROG:当访问外部存储器时,地址锁存允许的输出电平用于锁存地址的低位字节。在FLASH编程期间,此引脚用于输入编程脉冲。在平时,ALE端以不变的频率周期输出正脉冲信号,此频率为振荡器频率的1/6。因此它可用作对外部输出的脉冲或用于定时目的。然而要注意的是:每当用作外部数据存储器时,将跳过一个ALE脉冲。如想禁止ALE的输出可在SFR8EH地址上置0。此时, ALE只有在执行MOVX,MOVC指令是ALE才起作用。另外,该引脚被略微拉高。如果微处理器在外部执行状态ALE禁止,置位无效。

/PSEN:外部程序存储器的选通信号。在由外部程序存储器取指期间,每个机器周期两次/PSEN有效。但在访问外部数据存储器时,这两次有效的/PSEN信号将不出现。

/EA/VPP:当/EA保持低电平时,则在此期间外部程序存储器(0000H-FFFFH),不管是否有内部程序存储器。注意加密方式1时,/EA将内部锁定为RESET;当/EA端保持高电平时,此间内部程序存储器。在FLASH编程期间,此引脚也用于施加12V编程电源(VPP)。

XTAL1:反向振荡放大器的输入及内部时钟工作电路的输入。

XTAL2:来自反向振荡器的输出。

2.1.3 元件清单 

表2-1 元件清单

序号

元器件代号

名称

型号及参数

1

R×18

电阻

10K

2

C3

瓷片电容

10pF

3

XTAL1

晶振

11.0592M

4

C1-C2

瓷片电容

30PF

5

U1

芯片

AT89C51

6

LM1602

液晶屏

1

7

S1-S8

按钮

8

2.2 电路介绍 

2.2.1 电源部分 

         电源主要采用+5V电源,安全且节能环保,符合设计要求和环保要求。

2.2.2 按键部分 

        按键部分主要由A加分按钮、A误操作按钮、B加分按钮、B误操作按钮、开始计时按钮,暂停按钮,清零按钮,停止按钮八部分组成。其中S1为A加分按钮,S2为B加分按钮,S3为开始计时按钮,S4暂停按钮,S5为A误操作按钮,S6为B误操作按钮,S7为清零按钮,S8为停止按钮。

图2-2 按钮部分

2.2.3 显示部分 

        显示由LM1602液晶屏显示,显示功能区分为三个模块,分别为第一行显示比赛场次及谁获胜,第二行1-6位显示比赛时间,7-16行显示比分。时钟部分构成单片机的最小系统。

图2-3 LM1602液晶屏

2.2.4 时钟、复位电路 

图2-4 时钟、复位电路

第三章、软件设计 

3.1 程序流程图 

        系统的操作过程和工作过程在程序的设计过程中起着很重要的指导作用,因此在软件设计之前应首先分析羽毛球比赛记分器的工作原理。当比赛开始时,先判断是哪队得分,每次加分加1分。如果不小心加错分了,则按键减去多加的分。当比赛开始时,首先按下开始按钮S1显示开始工作,加分和误操作,暂停等按钮可工作。设计程序流程图如图3-1。

图3-1 程序流程图

3.2 模块设计 

3.2.1 主函数 
void main()
{	
	EA = 1;           //开总中断
    ConfigTimer0(1);  //配置T0定时1ms
	InitLcd1602();    //初始化液晶
    while (1)
    {
	 KeyDriver();	//调用按键功能
	 if(k==1)
	 LcdInit();	 //显示字幕
	
    }
}
3.2.2 显示函数 
/* 等待液晶准备好 */
void LcdWaitReady()
{
    unsigned char sta;
    LCD1602_DB = 0xFF;
    LCD1602_RS = 0;
    LCD1602_RW = 1;
    do {
        LCD1602_E = 1;
        sta = LCD1602_DB; //读取状态字
        LCD1602_E = 0;
    } while (sta & 0x80); //bit7等于1表示液晶正忙,重复检测直到其等于0为止
}
/* 向LCD1602液晶写入一字节命令,cmd-待写入命令值 */
void LcdWriteCmd(unsigned char cmd)
{
    LcdWaitReady();
    LCD1602_RS = 0;
    LCD1602_RW = 0;
    LCD1602_DB = cmd;
    LCD1602_E  = 1;
    LCD1602_E  = 0;
}
//显示字母及计时器
void LcdInit()
{
   if(flag1s == 1)
	   {
	     sec++;
		 flag1s = 0;
	   }
	   if(sec>=60)
	  { minute++;
	    sec = 0;
	    if(minute>59)
		minute = 59;
	  }
	   LcdShowStr(0, 1, "T");
	  len = LongToString(str, minute);
	  LcdShowStr(1, 1, str);
	  LcdShowStr(3, 1, ":");
	  len = LongToString(str, sec);
	  LcdShowStr(4, 1, str);
	  LcdShowStr(7, 1, "A:B");
	  len = LongToString(str, a);
	  LcdShowStr(11, 1, str);
	  LcdShowStr(13, 1, ":");
	  len = LongToString(str, b);
	  LcdShowStr(14, 1, str);	   	 
}
/* 向LCD1602液晶写入一字节数据,dat-待写入数据值 */
void LcdWriteDat(unsigned char dat)
{
    LcdWaitReady();
    LCD1602_RS = 1;
    LCD1602_RW = 0;
    LCD1602_DB = dat;
    LCD1602_E  = 1;
    LCD1602_E  = 0;
}
/* 设置显示RAM起始地址,亦即光标位置,(x,y)-对应屏幕上的字符坐标 */
void LcdSetCursor(unsigned char x, unsigned char y)
{
    unsigned char addr;
    
    if (y == 0)  //由输入的屏幕坐标计算显示RAM的地址
        addr = 0x00 + x;  //第一行字符地址从0x00起始
    else
        addr = 0x40 + x;  //第二行字符地址从0x40起始
    LcdWriteCmd(addr | 0x80);  //设置RAM地址
}
/* 在液晶上显示字符串,(x,y)-对应屏幕上的起始坐标,str-字符串指针 */
void LcdShowStr(unsigned char x, unsigned char y, unsigned char *str)
{
    LcdSetCursor(x, y);   //设置起始地址
    while (*str != '\0')  //连续写入字符串数据,直到检测到结束符
    {
        LcdWriteDat(*str++);
    }
}
/* 区域清除,清除从(x,y)坐标起始的len个字符位 */
void LcdAreaClear(unsigned char x, unsigned char y, unsigned char len)
{
    LcdSetCursor(x, y);   //设置起始地址
    while (len--)         //连续写入空格
    {
        LcdWriteDat(' ');
    }
}

/* 初始化1602液晶 */
void InitLcd1602()
{
    LcdWriteCmd(0x38);  //16*2显示,5*7点阵,8位数据接口
  //  LcdWriteCmd(0x0C);  //显示器开,光标关闭
    LcdWriteCmd(0x06);  //文字不动,地址自动+1
    LcdWriteCmd(0x01);  //清屏
}
3.2.3 延时函数 
void delay()
{
   unsigned int i,j;
   for(i=0;i<9000;i++)
   for(j=0;j<4;j++);
}
3.2.4 定时器函数 
/* 配置并启动T0,ms-T0定时时间 */
void ConfigTimer0(unsigned int ms)
{
    unsigned long tmp;  //临时变量
    
    tmp = 11059200 / 12;      //定时器计数频率
    tmp = (tmp * ms) / 1000;  //计算所需的计数值
    tmp = 65536 - tmp;        //计算定时器重载值
    tmp = tmp + 12;           //补偿中断响应延时造成的误差
    T0RH = (unsigned char)(tmp>>8);  //定时器重载值拆分为高低字节
    T0RL = (unsigned char)tmp;
    TMOD &= 0xF0;   //清零T0的控制位
    TMOD |= 0x01;   //配置T0为模式1
    TH0 = T0RH;     //加载T0重载值
    TL0 = T0RL;
    ET0 = 1;        //使能T0中断
}
3.2.5 中断函数 
/* T0中断服务函数,配置定时器时间 */
void InterruptTimer0() interrupt 1
{
   static  unsigned count = 0;
    TH0 = T0RH;  //重新加载重载值
    TL0 = T0RL;
	count++;
	if(count>=1000)
	{
	   count = 0;
	   flag1s = 1;
	}
}
3.2.6 字符转换函数 
//将数字转换为字符
unsigned char LongToString(unsigned char *str, signed long dat)
{
	signed char i = 0;
	signed char len = 0;
	unsigned char buf[3];	
    for(i=0;i<2;i++)
	{
	  buf[i] = dat%10;
	  dat = dat/10;
	}
	len = i;
	for(i=1;i>=0;i--)
	{
	   *str++ = buf[i] + '0';
	}
	*str = '\0';
	return len;		
}
3.2.7 全局变量定义及函数声明 
#include <reg52.h>
#define LCD1602_DB  P0
sbit LCD1602_RS = P1^0;
sbit LCD1602_RW = P1^1;
sbit LCD1602_E  = P1^5;
unsigned char T0RH = 0;
unsigned char T0RL = 0;
sbit KEY_IN_1  = P2^0;
sbit KEY_IN_2  = P2^1;
sbit KEY_IN_3  = P2^2;
sbit KEY_IN_4  = P2^3;
sbit KEY_IN_5  = P2^4;
sbit KEY_IN_6  = P2^5;
sbit KEY_IN_7  = P2^6;
sbit KEY_IN_8  = P2^7;
bit flag1s = 0;	  //定时1s标志
char a = 0;		  //A的分数
char b = 0;		  //B的分数
 bit k=1;			//开显示开关
unsigned char minute = 0; //定时器分钟
unsigned char sec = 0;	  //定时器秒
unsigned char len = 0;	  //字符串转换长度
unsigned char str[3];	  //字符转换指针
void InitLcd1602();
void ConfigTimer0(unsigned int ms);
void LcdShowStr(unsigned char x, unsigned char y, unsigned char *str);
unsigned char LongToString(unsigned char *str, signed long dat);
void KeyDriver();
void LcdInit();

第四章、仿真与调试 

4.1 调试的环境 

        在Keil4.0中运行编写的程序,将生成的 .hex文件导入protues7.0中以连接好的电路的单片机中。

4.2 按键及功能的调试 

图4-1 电路原理图

        按下按钮S3表示比赛开始,定时器开始计时,其他按钮允许工作。A队赢球时,按一下S1按钮,A队加一分。B队赢球时,按一下S1按钮,B队加一分。若出现误加分情况,按钮S5\S6分别对A\B队减一分。如比赛过程中出现紧急情况需暂停比赛时,计分器S4按钮可实现暂停功能,其定时器暂停工作,加减分按钮失效,保证比赛的公正性。比赛结束时按钮S8实现停止功能,数据保存。按钮S7实现清零功能,比赛结束,可对下场比赛进行计时。

图4-2 比赛结果仿真图

        当A队获得第一场胜利时,屏幕上会有“1Awin”字样,B队获得第二场胜利,显示“1Awin2Bwin”字样。A队再次获胜后,计分器会自动进入停止状态,加分减分按钮失效,液晶屏显示此次比赛所用时间以及“1Awin2Bwin3Awin”,表示此次比赛A队为获胜方。

总 结 

        通过这两周的课程设计,我发现了自己的很多不足,自己知识的很多漏洞,看到了自己的实践经验还是比较缺乏,在这个过程中,我也曾经因为实践经验的缺乏失落过,也曾经仿真成功而热情高涨。生活就是这样,汗水预示着结果也见证着收获。劳动是人类生存生活永恒不变的话题。虽然这只是一次的极简单的课程制作,可是平心而论,也耗费了我们不少的心血。通过这次课程设计,我想说:为完成这次课程设计我确实很辛苦,但苦中仍有乐,我对单片机的产品开发有了系统的认识,从硬件的设计到软件的设计再到软硬件的联合工作。我懂得了以前没有接触到的知识,通过大量的查阅资料,让我对单片机有了清晰的认识。

软件设计方面不仅得考虑软件设计的合理性,更得从实用性。在软件设计时,查阅了大量软件工程方面的书籍,使得软件的时间复杂度有所降低,而且将软件的功能模块化,利用了模块化的编程思想,根据电路设计出了高效的软件。在软硬件联合工作方面实现了完美的链接,设计出了符合要求且高效率的程序。

以前种种艰辛这时就变成了最甜美的回忆!对我而言,知识上的收获重要,精神上的丰收更加可喜。让我知道了学无止境的道理。我们每一个人永远不能满足于现有的成就,人生就像在爬山,一座山峰的后面还有更高的山峰在等着你。挫折是一份财富,经历是一份拥有。这次课程设计必将成为我人生旅途上一个非常美好的回忆!

参考文献 

[1] 林立,张俊亮.单片机原理及应用——基于Proteus和KeilC[M].北京电子工业出版社,2014

[2] 陈忠平.基于Proteus的51系列单片机设计与仿真[M].北京电子工业出版社,2015

[3] 陈海宴.51单片机原理及应用[M].北京航空航天大学出版社,2010.

[4] 刘守义等.单片机技术基础[M].西安电子科技大学出版社,2007.
[5] 钟富昭等.8051单片机典型模块设计与应用[M].人民邮电出版社,2007.

[6] 隋清江等.基于Proteus的LCDl602接口设计与仿真[J].微计算机信息,2010.7-1:17l-172.

[7] 郭志卓,陈振军.基于单片机控制的电子计分器设计[J].电脑知识与技术,2014,10(12):2861-2863.

[8] 雷道仲,罗政球,廖永忠.基于单片机的球赛计时计分器设计[J].湖南第一师范学报,2009,9(04):164-166.

[9] 王文军.基于C51单片机的多功能计时计分器设计[J].科学与财富,2016,(9):674-674,675. DOI:10.3969/j.issn.1671-2226.2016.09.631.

[10] 牛军,王萍.无线电子打分计分系统的设计与实现[J].南阳理工学院学报,2015,7(04):1-4. 

[11] 王文军.基于C51单片机的多功能计时计分器设计[J].科学与财富,2016,(9):674-674,675. DOI:10.3969/j.issn.1671-2226.2016.09.631.

[12] 耿天寿.单片机控制的计时计分显示系统[C].//第三届全国电子技术应用大会.北京:山西大学,1993:193~196页.

[13] 伍学珍,岑斌.无线数传的计分计时系统[C].//中国通信集成电路技术与应用研讨会论文集.广西水利电力职业技术学院,2005:79-84.

[14] 赵学军,熊发明.球类比赛计时记分操作台的设计[C].//中国自动化学会中南六省(区)第20届学术年会.北京:2003:148-150.

[15] 陈雷,刘茂元.基于单片机计数计时仪的设计与制作[C].//2016年全国高等学校物理基础课程教育学术研讨会论文集.西藏大学,2016:73-77.

附 录 

#include <reg52.h>
#define LCD1602_DB  P0
sbit LCD1602_RS = P1^0;
sbit LCD1602_RW = P1^1;
sbit LCD1602_E  = P1^5;
unsigned char T0RH = 0;
unsigned char T0RL = 0;
sbit KEY_IN_1  = P2^0;
sbit KEY_IN_2  = P2^1;
sbit KEY_IN_3  = P2^2;
sbit KEY_IN_4  = P2^3;
sbit KEY_IN_5  = P2^4;
sbit KEY_IN_6  = P2^5;
sbit KEY_IN_7  = P2^6;
sbit KEY_IN_8  = P2^7;
bit flag1s = 0;	  //定时1s标志
char a = 0;		  //A的分数
char b = 0;		  //B的分数
 bit k=1;			//开显示开关
unsigned char minute = 0; //定时器分钟
unsigned char sec = 0;	  //定时器秒
unsigned char len = 0;	  //字符串转换长度
unsigned char str[3];	  //字符转换指针
void InitLcd1602();
void ConfigTimer0(unsigned int ms);
void LcdShowStr(unsigned char x, unsigned char y, unsigned char *str);
unsigned char LongToString(unsigned char *str, signed long dat);
void KeyDriver();
void LcdInit();

void main()
{	
	EA = 1;           //开总中断
    ConfigTimer0(1);  //配置T0定时1ms
	InitLcd1602();    //初始化液晶
    while (1)
    {
	 KeyDriver();	//调用按键功能
	 if(k==1)
	 LcdInit();	 //显示字幕
	
    }
}

void delay()
{
   unsigned int i,j;
   for(i=0;i<9000;i++)
   for(j=0;j<4;j++);
}
/* 等待液晶准备好 */
void LcdWaitReady()
{
    unsigned char sta;
    LCD1602_DB = 0xFF;
    LCD1602_RS = 0;
    LCD1602_RW = 1;
    do {
        LCD1602_E = 1;
        sta = LCD1602_DB; //读取状态字
        LCD1602_E = 0;
    } while (sta & 0x80); //bit7等于1表示液晶正忙,重复检测直到其等于0为止
}
/* 向LCD1602液晶写入一字节命令,cmd-待写入命令值 */
void LcdWriteCmd(unsigned char cmd)
{
    LcdWaitReady();
    LCD1602_RS = 0;
    LCD1602_RW = 0;
    LCD1602_DB = cmd;
    LCD1602_E  = 1;
    LCD1602_E  = 0;
}
/* 按键驱动函数,检测按键动作,调度相应动作函数,需在主循环中调用 */
void KeyDriver()
{
   static bit star = 0;		  //开始比赛
   unsigned char but = 0;		 //胜利标志
   static unsigned char cnt = 0; //比赛次数
   static unsigned char cnta = 0; //A胜利次数
   static unsigned char cntb = 0; //B胜利次数 
  if(KEY_IN_3 == 0) {   delay();  star = 1; TR0 = 1;k=1;} 
	if(star == 1)
	{	
    	LcdWriteCmd(0x0C);  //显示器开,光标关闭   		
	   if(KEY_IN_1 ==0)  { a++; delay();}
	   if(KEY_IN_2 ==0)  { b++; delay();}
	   if(KEY_IN_4 ==0)  { TR0 = 0; star=0; delay(); }
	   if(KEY_IN_5 ==0)  { a--; if(a<0)a=0; delay();}
	   if(KEY_IN_6 ==0)  { b--; if(b<0)b=0; delay(); }	     
	}
	  if(KEY_IN_7 ==0)  { a=0; b=0; sec=0; minute=0; 
	     TR0=0;star=0;cnta=0; cntb=0; cnt=0; LcdShowStr(0, 0, "                "); delay();}
	  if(KEY_IN_8 ==0){ a=0;  b=0;   sec=0;   minute=0; LcdShowStr(0, 0, "                ");
	     k=0;cnta=0;cntb=0;cnt=0;LcdWriteCmd(0x01); delay();}	
	  if(a>=21 && (a-b)>=2 ) {cnt++; cnta++; but = 1; a = 0; b = 0; }	
	  if(b>=21 && (b-a)>=2 ) {cnt++; cntb++; but = 2; a = 0; b = 0; }
	  if(cnt==2&&(cnta==2||cntb==2)) {TR0 = 0; star = 0;}
	    switch(cnt)
	    {
	     case 1: if(but==1) LcdShowStr(0, 0, "1Awin"); if(but==2) LcdShowStr(0, 0, "1Bwin");break;
		 case 2: if(but==1) LcdShowStr(5, 0, "2Awin"); if(but==2) LcdShowStr(5, 0, "2Bwin");break;
		 case 3: if(but==1) LcdShowStr(10, 0, "3Awin"); if(but==2) LcdShowStr(10, 0, "3Bwin"); TR0=0;star=0;break;
		 default: break;
		}
}
//显示字母及计时器
void LcdInit()
{
   if(flag1s == 1)
	   {
	     sec++;
		 flag1s = 0;
	   }
	   if(sec>=60)
	  { minute++;
	    sec = 0;
	    if(minute>59)
		minute = 59;
	  }
	   LcdShowStr(0, 1, "T");
	  len = LongToString(str, minute);
	  LcdShowStr(1, 1, str);
	  LcdShowStr(3, 1, ":");
	  len = LongToString(str, sec);
	  LcdShowStr(4, 1, str);
	  LcdShowStr(7, 1, "A:B");
	  len = LongToString(str, a);
	  LcdShowStr(11, 1, str);
	  LcdShowStr(13, 1, ":");
	  len = LongToString(str, b);
	  LcdShowStr(14, 1, str);	   	 
}

 //将数字转换为字符
unsigned char LongToString(unsigned char *str, signed long dat)
{
	signed char i = 0;
	signed char len = 0;
	unsigned char buf[3];	
    for(i=0;i<2;i++)
	{
	  buf[i] = dat%10;
	  dat = dat/10;
	}
	len = i;
	for(i=1;i>=0;i--)
	{
	   *str++ = buf[i] + '0';
	}
	*str = '\0';
	return len;		
}

/* 向LCD1602液晶写入一字节数据,dat-待写入数据值 */
void LcdWriteDat(unsigned char dat)
{
    LcdWaitReady();
    LCD1602_RS = 1;
    LCD1602_RW = 0;
    LCD1602_DB = dat;
    LCD1602_E  = 1;
    LCD1602_E  = 0;
}
/* 设置显示RAM起始地址,亦即光标位置,(x,y)-对应屏幕上的字符坐标 */
void LcdSetCursor(unsigned char x, unsigned char y)
{
    unsigned char addr;
    
    if (y == 0)  //由输入的屏幕坐标计算显示RAM的地址
        addr = 0x00 + x;  //第一行字符地址从0x00起始
    else
        addr = 0x40 + x;  //第二行字符地址从0x40起始
    LcdWriteCmd(addr | 0x80);  //设置RAM地址
}
/* 在液晶上显示字符串,(x,y)-对应屏幕上的起始坐标,str-字符串指针 */
void LcdShowStr(unsigned char x, unsigned char y, unsigned char *str)
{
    LcdSetCursor(x, y);   //设置起始地址
    while (*str != '\0')  //连续写入字符串数据,直到检测到结束符
    {
        LcdWriteDat(*str++);
    }
}
/* 区域清除,清除从(x,y)坐标起始的len个字符位 */
void LcdAreaClear(unsigned char x, unsigned char y, unsigned char len)
{
    LcdSetCursor(x, y);   //设置起始地址
    while (len--)         //连续写入空格
    {
        LcdWriteDat(' ');
    }
}

/* 初始化1602液晶 */
void InitLcd1602()
{
    LcdWriteCmd(0x38);  //16*2显示,5*7点阵,8位数据接口
  //  LcdWriteCmd(0x0C);  //显示器开,光标关闭
    LcdWriteCmd(0x06);  //文字不动,地址自动+1
    LcdWriteCmd(0x01);  //清屏
}

/* 配置并启动T0,ms-T0定时时间 */
void ConfigTimer0(unsigned int ms)
{
    unsigned long tmp;  //临时变量
    
    tmp = 11059200 / 12;      //定时器计数频率
    tmp = (tmp * ms) / 1000;  //计算所需的计数值
    tmp = 65536 - tmp;        //计算定时器重载值
    tmp = tmp + 12;           //补偿中断响应延时造成的误差
    T0RH = (unsigned char)(tmp>>8);  //定时器重载值拆分为高低字节
    T0RL = (unsigned char)tmp;
    TMOD &= 0xF0;   //清零T0的控制位
    TMOD |= 0x01;   //配置T0为模式1
    TH0 = T0RH;     //加载T0重载值
    TL0 = T0RL;
    ET0 = 1;        //使能T0中断
}

/* T0中断服务函数,配置定时器时间 */
void InterruptTimer0() interrupt 1
{
   static  unsigned count = 0;
    TH0 = T0RH;  //重新加载重载值
    TL0 = T0RL;
	count++;
	if(count>=1000)
	{
	   count = 0;
	   flag1s = 1;
	}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1621963.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

黑马微服务课程2

课程地址&#xff1a;2024最新SpringCloud微服务开发与实战&#xff0c;java黑马商城项目微服务实战开发&#xff08;涵盖MybatisPlus、Docker、MQ、ES、Redis高级等&#xff09;_哔哩哔哩_bilibili 课程名称&#xff1a;2024最新SpringCloud微服务开发与实战&#xff0c;java…

《数据密集型应用系统设计》笔记——第一部分 数据系统基础(ch1-4)

写在前面&#xff1a;对DDIA这本书慕名已久&#xff0c;粗看书里的一些知识都或多或少了解&#xff0c;但仔细阅读下来&#xff0c;还是缺少对细节的认识。目前看了四个章节&#xff0c;这本书一直在围绕两个问题&#xff1a;是什么和为什么&#xff0c;来做阐述&#xff0c;针…

AI大模型探索之路-训练篇3:大语言模型全景解读

文章目录 前言一、语言模型发展历程1. 第一阶段&#xff1a;统计语言模型&#xff08;Statistical Language Model, SLM&#xff09;2. 第二阶段&#xff1a;神经语言模型&#xff08;Neural Language Model, NLM&#xff09;3. 第三阶段&#xff1a;预训练语言模型&#xff08…

【高阶数据结构】B树 {B树的概念;B树的实现:节点设计,查找,插入,遍历,删除;B树的性能分析;B+树和B*树;B树的应用}

一、常见的搜索结构 以上结构适合用于数据量相对不是很大&#xff0c;能够一次性存放在内存中&#xff0c;进行数据查找的场景。如果数据量很大&#xff0c;比如有100G数据&#xff0c;无法一次放进内存中&#xff0c;那就只能放在磁盘上了&#xff0c;如果放在磁盘上&#xff…

Maven多模块快速升级超好用Idea插件-MPVP

功能&#xff1a;多模块maven项目快速升级指定版本插件&#xff0c;并提供预览和相关升级模块日志能力。 可快速进行版本升级&#xff0c;进行部署到Maven仓库。 安装&#xff1a; 可在idea插件中心进行安装 / 下载资源拖动安装 MPVP(Maven) - IntelliJ IDEs Plugin | Marke…

IPv4 NAT(含Cisco配置)

IPv4 NAT&#xff08;含Cisco配置&#xff09; IPv4私有空间地址 类RFC 1918 内部地址范围前缀A10.0.0.0 - 10.255.255.25510.0.0.0/8B172.16.0.0 - 172.31.255.255172.16.0.0/12C192.168.0.0 - 192.168.255.255192.168.0.0/16 这些私有地址可在企业或站点内使用&#xff0c…

【第35天】SQL进阶-SQL高级技巧-透视表(SQL 小虚竹)

回城传送–》《100天精通MYSQL从入门到就业》 文章目录 零、前言一、练习题目二、SQL思路初始化数据什么是透视表实战体验 三、总结四、参考 零、前言 今天是学习 SQL 打卡的第 35 天。 ​ 我的学习策略很简单&#xff0c;题海策略 费曼学习法。如果能把这些题都认认真真自己…

网络安全-Diffie Hellman密钥协商

密钥协商是保密通信双方&#xff08;或更多方&#xff09;通过公开信道来共同形成密钥的过程。一个密钥协商方案中&#xff0c;密钥的值是某个函数值&#xff0c;其输入量由两个成员&#xff08;或更多方&#xff09;来提供。密钥协商的记过是参与协商的双方&#xff08;或更多…

消息服务应用1——java项目使用websocket

在当前微服务项目中&#xff0c;由于业务模块众多&#xff0c;消息服务的使用场景变得异常活跃。而WebSocket由于其自身的可靠性强&#xff0c;实时性好&#xff0c;带宽占用更小的优势&#xff0c;在实时通讯应用场景中独占鳌头&#xff0c;加上HTML5标准的普及流行&#xff0…

MultiHeadAttention在Tensorflow中的实现原理

前言 通过这篇文章&#xff0c;你可以学习到Tensorflow实现MultiHeadAttention的底层原理。 一、MultiHeadAttention的本质内涵 1.Self_Atention机制 MultiHeadAttention是Self_Atention的多头堆嵌&#xff0c;有必要对Self_Atention机制进行一次深入浅出的理解&#xff0c;这…

Docker 入门篇(一)-- 简介与安装教程(Windows和Linux)

一、Docker简介 Docker是一个开源的应用容器引擎&#xff0c;让开发者可以打包他们的应用以及依赖包到一个可移植的容器中&#xff0c;然后发布到任何Linux机器上&#xff0c;也可以实现虚拟化。容器是完全使用沙箱机制&#xff0c;相互之间没有任何接口&#xff08;类似iPhon…

记录海豚调度器删除工作流实例失败的解决办法(DolphinScheduler的WebUI删除失败)

本博客记录以下问题解决办法&#xff1a;使用dolphinscheduler的WebUI运行工作流后出现内存占用过高导致的任务阻塞问题&#xff0c;并且在删除工作流实例时总是报错无法删除 解决步骤 在前端页面无法删除&#xff0c;于是搜索资料&#xff0c;发现可以登录数据库进行工作流实…

【C语言 |预处理指令】预处理指令详解(包括编译与链接)

目录 一、编译与链接 1.翻译环境 -预处理 -编译 -汇编 -链接 2.执行环境 二、预定义符号 三、#define定义常量 四、#define定义宏 五、带有副作用的宏参数 六、宏替换的规则 七、 宏函数的对比 八、#和## 1.#运算符 2.##运算符 九、命名约定 十、#undef 十一、 命…

【服务器部署篇】Linux下Tomcat安装和配置

作者介绍&#xff1a;本人笔名姑苏老陈&#xff0c;从事JAVA开发工作十多年了&#xff0c;带过刚毕业的实习生&#xff0c;也带过技术团队。最近有个朋友的表弟&#xff0c;马上要大学毕业了&#xff0c;想从事JAVA开发工作&#xff0c;但不知道从何处入手。于是&#xff0c;产…

Linux网络编程---Socket编程

一、网络套接字 一个文件描述符指向一个套接字(该套接字内部由内核借助两个缓冲区实现。) 在通信过程中&#xff0c;套接字一定是成对出现的 套接字通讯原理示意图&#xff1a; 二、预备知识 1. 网络字节序 内存中的多字节数据相对于内存地址有大端和小端之分 小端法&…

Ubuntu终端常用指令

cat cat 读取文件的内容 1、ls 一、 1、ll 显示当前目录下文件的详细信息,包括读写权限,文件大小,文件生成日期等(若想按照更改的时间先后排序,则需加-t参数,按时间降序(最新修改的时间排在最前)执行: $ ll -t, 按时间升序执行: $ ll -t | tac): ll 2、查看当前所处路径(完整…

Qt中常用对话框

Qt中的对话框&#xff08;QDialog&#xff09;是用户交互的重要组件&#xff0c;用于向用户提供特定的信息、请求输入、或进行决策。Qt提供了多种标准对话框以及用于自定义对话框的类。以下将详细介绍几种常用对话框的基本使用、使用技巧以及注意事项&#xff0c;并附带C示例代…

node.js 解析post请求 方法一

前提&#xff1a;依旧以前面发的node.js服务器动态资源处理代码 具体见 http://t.csdnimg.cn/TSNW9为模板&#xff0c;在这基础上进行修改。与动态资源处理代码不同的是&#xff0c;这次的用户信息我们借用表单来实现。post请求解析来获取和展示用户表单填写信息 1》代码难点&…

全彩屏负氧离子监测站的使用

TH-FZ5在繁忙的都市生活中&#xff0c;我们往往忽视了一个至关重要的问题——空气质量。随着工业化的进程加速&#xff0c;空气污染已成为影响人们健康的一大隐患。为了实时监测和了解身边的空气质量&#xff0c;全彩屏负氧离子监测站应运而生&#xff0c;成为了我们守护呼吸健…

企业集成平台建设方案(技术方案+功能设计)

企业集成平台建设方案及重点难点攻坚 基础支撑平台主要承担系统总体架构与各个应用子系统的交互&#xff0c;第三方系统与总体架构的交互。需要满足内部业务在该平台的基础上&#xff0c;实现平台对于子系统的可扩展性。基于以上分析对基础支撑平台&#xff0c;提出了以下要求&…