历史上的今天
今天是:2025年08月20日(星期三)
2021年08月20日 | 51单片机-综合例程
2021-08-20 来源:eefocus
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单片机-多文件编写
史海拾趣
|
一分钱,在现在物价飞涨的年代,早已经退出了货币交流的的历史舞台,成为财务意义上的最小计量单位。当年“我在马路边,捡到一分钱”的童谣,不会再发生了,一分钱,已经买不了任何东西。 一分钱,已经真的不值钱了吗?让我们来看年看电子物料的 ...… 查看全部问答> |
|
转自:窗户纸 http://www.getproject.com.cn/post/95.html 想像一下,如果有这么一个“裸体”温度计,就放在自己家里的书柜上,等朋友来了,一定会吸引不少眼光,你也可以借机炫耀一番。 不过放在家里的话,有可能曝光率不够高,那我们就随身携 ...… 查看全部问答> |
|
65元一个 http://item.taobao.com/item_detail.jhtml?item_id=76d334109aebd88799ad63cdbcce7d08&x_id=db2… 查看全部问答> |
|
EVC 中选择默认设备下拉菜单选项中只有Emulator没有Device 以前写的程序在PPC 2003中模拟,现在更换了设备,新设备系统是WinCE .net 5.0 ,编译时选择STANDARDSDK ,Win32(WCE ARMV4)Release可是Select default device选项中只有STANDARDSDK Emulator,没有device选择,新设备可以和PC机同步,我想编译后 ...… 查看全部问答> |
|
【问TI】cc2500属于zigbee范凑吗,用的那个协议栈,zigbee2006协议栈在其上适不适用 如题,没什么说的,随便问问,我看ez430用的好像不是zigbee协议栈来的,所以咨询下。… 查看全部问答> |
|
书籍太多,看不过来,整理一些出掉。[霸王条款:]仅限北京当面交易,到昌平线地铁沙河站取,不快递(1. 书籍太重,2. (即使你买一本)本人懒,没时间发)。 500页以下10元一本,500页以上的15元一本。部分书籍可商议。 买2本430的书籍可送430(f ...… 查看全部问答> |
|
【英雄帖】【急!!】基于msp430g2553+qc12864b串行显示问题 #include #include\"LCD12864P.h\" void main() { WDTCTL = WDTPW + WDTHOLD; Ini_Lcd(); lcd_pos(1,0); &n ...… 查看全部问答> |




