1.其他按键的使用
我们之前都是让P2.3输出低电平来让K1, K2, K3, K4作为独立按键,那我们要想用K13,K14,K15,K16做独立按键时只要P2.0输出低电平就可以了。下面是简化的原理图
2.美女与男人
作为本章的最后一个题目,我们结合所有学过的知识做一个综合例程,实现美女与男人的游戏的功能代码。
游戏规则如下:
美女和男人各持一枚硬币
两人都出正面时:男人得3块钱
两人都出反面时:男人得1块钱
两人出一正一反时:女人得2块钱
3.开发板的实现
我们这样做模拟,程序的开始定义两个全局变量man和woman初始化为30,意为每人各持30块钱用来显示在左右端的两个数码管上,男人的钱显示在左边的数码管,女人的钱显示在右边的数码管。
我们用K13作为给男人加3块钱的同时也给女人减3块的功能。
用K14作为给男人加1块钱的同时也给女人减1块的功能。
用K15作为给男人减2块钱的同时给女人加2块的功能。
三个按键都是不支持连按!
我们规定,谁先达到45块钱及以上时就算谁赢!
比如男人的钱到达或超过45块钱时,女人的钱就不显示了,这两个数码管熄灭,如果是女人的钱到达或超过45块时,男人的钱就不显示了,这是用来表明谁的钱还在显示谁就是赢家的常识。
决出胜负的时候,此时的游戏结束,蜂鸣器就间隔鸣叫,鸣叫的时候所有数码管熄灭,不鸣叫的时候就只有4个数码管亮着,数码管呈现间隔显示,蜂鸣器间隔鸣叫。要想重新开始游戏必须复位开发板重启!
4.部分代码改写
初始化LedBuff[]数组的时候第2和第3号元素为0xBF,让数码管2和数码管3显示中间那一杠。
本讲的例程主函数的死循环执行完一次循环的时间比以往的例程要多,所以times的判断我们只需要它超过300即可,而不是像以前一样要超过500才执行功能代码。
因为用上了3个按键,每个按键功能被封装为一个函数了,所以我们定义了一个宏“#define TIMES 300”,3个按键的函数判断times时,只需书写“if(times>=TIMES&&KEYxx==1)”即可,以后我们写的代码死循环里比这次的例程执行一遍循环的时间还长的话,把宏改为比300还小的数就可以了。
还有如果单独循环“SEG_task();”会使所有数码管显示很暗,这是因为这个函数是这样循环执行的
第一次循环
P0=0xFF;
ADDR2 = 0;ADDR1 = 0;ADDR0 = 0;P0=LedBuff[0];i++;
第二次循环
P0=0xFF;
ADDR2 = 0;ADDR1 = 0;ADDR0 = 1;P0=LedBuff[1];i++;
……
每一次循环里“P0=LedBuff[x];”持续的时间不够多又要开始执行“P0=0xFF;”,所以“P0=0xFF;”的刷新率太高就会使数码管的亮度变暗,要想解决这个问题就必须使“P0=LedBuff[x];”持续的时间多一点再执行“P0=0xFF;”,所以我们在“SEG_task();”后用上短暂的延时。
而为什么以前的例程里“SEG_task();”没有这种现象出现,这个大家回去看一下就知道以前的 “SEG_task();”还要执行下面这些代码
LedBuff[0] = LedChar[cnt%10];
if(cnt>=10) LedBuff[1]= LedChar[(cnt/10)%10];
if(cnt>=100) LedBuff[2]= LedChar[(cnt/100)%10];
if(cnt==0){ LedBuff[1]=0xFF;LedBuff[2]=0XFF; }
这些代码的执行占用了时间,所以给“P0=LedBuff[x];”保持住了一段时间的点亮,避免了长时间被“P0=0xFF;”刷新。
#include
sbit ADDR2 = P1^2;
sbit ADDR1 = P1^1;
sbit ADDR0 = P1^0;
sbit ENLED = P1^4;
sbit ADDR3 = P1^3;
sbit BEEP = P1^6;
sbit KEY13 = P2^4;
sbit KEY14 = P2^5;
sbit KEY15 = P2^6;
#define TIMES 300 //此例程的主循环里循环一次所要花费的时间比以往的例程要多,所以按键的times判断需要减少到300,不然还是500的话需要我们长按住一段时间才会响应功能代码
unsigned char code LedChar[16]={0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,0x80,0x90,0x88,0x83,0xC6,0xA1,0x86,0x8E};//数码管状态值初始化
unsigned char LedBuff[6]={0xFF, 0xFF, 0xBF, 0xBF, 0xFF, 0xFF};//初始化数码管显示缓存区
unsigned char man=30,woman=30;//初始化男人和女人的钱
void UPDATE_LED()//更新数码管显示缓存区
{
LedBuff[5]=LedChar[man/10];
LedBuff[4]=LedChar[man%10];
LedBuff[1]=LedChar[woman/10];
LedBuff[0]=LedChar[woman%10];
}
void SEG_task()//数码管显示函数
{
static unsigned char i=0;
P0=0xFF;//端口状态全部熄灭数码管里的LED达到刷新作用
switch(i)
{
case 0:
ADDR2 = 0;ADDR1 = 0;ADDR0 = 0;P0=LedBuff[0];i++;break;
case 1:
ADDR2 = 0;ADDR1 = 0;ADDR0 = 1;P0=LedBuff[1];i++;break;
case 2:
ADDR2 = 0;ADDR1 = 1;ADDR0 = 0;P0=LedBuff[2];i++;break;
case 3:
ADDR2 = 0;ADDR1 = 1;ADDR0 = 1;P0=LedBuff[3];i++;break;
case 4:
ADDR2 = 1;ADDR1 = 0;ADDR0 = 0;P0=LedBuff[4];i++;break;
case 5:
ADDR2 = 1;ADDR1 = 0;ADDR0 = 1;P0=LedBuff[5];i=0;break;
}
}
void KEY13_task()
{
static unsigned char key_up=1;
static unsigned int times=0; //用来记录进入过按键判断语句的次数
if(key_up==0)
{
times++;
if(times>=TIMES&&KEY13==1)
{
times=0;
man+=3; //男人的钱加3块
woman-=3; //女人的钱减3块
UPDATE_LED();//更新数码管显示缓存区
}
}
key_up=KEY13;
}
void KEY14_task()
{
static unsigned char key_up=1;
static unsigned int times=0; //用来记录进入过按键判断语句的次数
if(key_up==0)
{
times++;
if(times>=TIMES&&KEY14==1)
{
times=0;
man+=1; //男人的钱加1块
woman-=1; //女人的钱减1块
UPDATE_LED();//更新数码管显示缓存区
}
}
key_up=KEY14;
}
void KEY15_task()
{
static unsigned char key_up=1;
static unsigned int times=0; //用来记录进入过按键判断语句的次数
if(key_up==0)
{
times++;
if(times>=TIMES&&KEY15==1)
{
times=0;
man-=2; //男人的钱减2块
woman+=2; //女人的钱加2块
UPDATE_LED();//更新数码管显示缓存区
}
}
key_up=KEY15;
}
void BEEP_ON(unsigned char x)
{
unsigned int i,time;
for(time=0;time<2000;time++)//“time<2000”决定鸣叫的时间
{
if(x==1)BEEP=!BEEP;
else BEEP=0;
for(i=0;i<30;i++);
}
}
void main()
{
unsigned int i,x;//做循环和延时用
ADDR3 = 1;//使能三八译码器
ENLED = 0;//
P2 = 0xFE;//让K13,K14,K15能具备有被拉低的条件先
UPDATE_LED();//更新数码管显示缓存区
while(1)
{
SEG_task(); //数码管显示函数
KEY13_task();//K13按键的任务
KEY14_task();//K14按键的任务
KEY15_task();//K15按键的任务
if(man>=45 || woman>=45)//只要其中一方的钱到达45块及以上就结束游戏,程序进入死循环
{
if(man>=45){LedBuff[1]=0xFF; LedBuff[0]=0xFF;}//不再显示女人的钱
else {LedBuff[5]=0xFF; LedBuff[4]=0xFF;} //不再显示男人的钱
while(1)
{
P0=0xFF; //熄灭所有数码管
BEEP_ON(1); //蜂鸣器鸣叫一段时间
for(i=0;i<300;i++) //让数码管显示一段时间
{
SEG_task();
for(x=0;x<200;x++);//加此延时是为了让数码管显示亮一点,不然仅让“SEG_task();”循环,显示就会暗一些
}
}
}
}
}
“man+=3;”就是“man= man+3;”的简化书写。
2.感言
我们现在是模块化编程了,在了解了美女与男人的游戏题目后,阅读主函数都清晰明朗很多。
这个题目的要求就像是全国电子设计竞赛一样,需要我们一步一步地完成每个模块功能,包括以后做产品项目,模块化编程是为了灵活运用和增加可读性,以后在做其他项目时遇到相似的要求我们拿来主义即可,维护起来也方便,但大家都需要习惯写很详细的注释才行。
在本讲代码的基础上其实也可以简单地改写成一个篮球简易计分器的功能,如果大家能自己实现的出来,以后去打球拿块开发板去计分也可骗骗一些不懂的同学,认为这是很高大上的玩意。
上一篇:51单片机-双模式函数封装
下一篇:51单片机-多文件编写
推荐阅读最新更新时间:2024-11-10 10:37
设计资源 培训 开发板 精华推荐
- CPU防着凉电路
- AD8335-EVAL,评估套件使用户能够快速熟悉 AD8335 四路 VGA 的工作特性和特性
- 使用 NXP Semiconductors 的 SA58631 的参考设计
- LT1171CT、5V/2.5A 高效 5V 降压转换器的典型应用
- NCP302LSN30T1 3V 电压检测器用于微控制器系统负载感应的典型应用
- 基于STM32F103RCT6的单片机学习板
- LT8570EDD 1MHz VFD(真空荧光显示器)电源开关的典型应用
- 智能电池管理系统
- 具有轻松驱动输入电流消除功能的 LTC2480、16 位 ADC 的典型应用
- LT3761IMSE-1 具有 25:1 PWM 调光功能的汽车前照灯用 94% 效率升压 LED 驱动器的典型应用电路