摘要
在信息化高速发展的时代,抢答在智力竞赛中是一种常见的答题方式。在抢答时,对于谁先谁后抢答,何时抢答,如何计算答题时间等问题,仅仅凭借人的主观判断,容易出现误判,所以需要一种智能抢答器来解决这些问题。本设计为六路抢答器,它可以准确公正的判断出首位抢答者,通过数码管显示手段指示出首位抢答者。本设计能够实现优先抢答,具有数字集成电路的锁存性。
一. 功能要求
1.设计一款6路或以上的抢答器,由答题者控制,每一路都具有独立的开关控制。
2.设计一个抢答控制开关,由主持人控制,当主持人按下开关后,才允许答题者进行抢答,若主持人没有按下控制开关,则不允许答题者抢答。
3.设定抢答时间,在抢答倒计时为0之前,答题者可进行抢答,当倒计时为0后,则不允许答题者抢答,如果答题者抢答则视为违规抢答。
4.设定答题时间,在倒计时为0之前,答题者进行答题,倒计时为0后,答题者不可以答题。答题者答完题后,由主持人按下控制键,结束答题。
5.主持人按下控制开关允许答题者抢答后,数字LED显示抢答倒计时,答题者抢答成功后,数字LED显示当前答题者号数,及剩余答题时间,并进行倒计时。
6.当答题者未在抢答倒计时内规定抢答时,则视为答题者违规抢答,数字LED显示答题者号数,时间显示数码管显示值为00.
二、系统硬件设计
2.1 系统功能结构图
图1 系统工作原理图
2.2按键模块
2.2.1按键模块电路图
图2按键模块电路图
2.2.2按键模块功能
开始按键的功能是主持人按下开始后,进行抢答倒计时30s.按键1-6的功能是答题者在抢答时间按下按键后,视为成功抢答,若不在抢答时间内,视为犯规抢答。成功抢答后,进行答题倒计时。完成答题后,由主持人按下清零键清零。
2.3 显示器模块
2.3.1显示器模块电路图
图3显示器模块电路图
2.3.2显示器模块功能
显示器采用四个显示数码管,它们的数据线有八根,片选线有四根。当进行抢答倒计时的时候,右边的两个显示倒计时,左边的不显示,当进行答题倒计时的时候,最左边的一个显示答题者的号码,右边的两个显示答题倒计时。当答题者犯规抢答的时候,最左边的显示答题者的号码,右边的两个显示数字0。当清零后,最左边的和右边的两个,显示的都是0.从左往右数的第二个数码管不显示任何东西。
2.4 单片机模块
2.4.1单片机模块电路图
图4单片机模块电路图
2.4.2单片机模块功能
在硬件上该单片机的P3口的P3.2、P3.3作为主持人的控制开关,P1口的P1.0-P1.5作为答题者的抢答开关,P2与P0口共同作为显示数码管的地址线输出口,P0口作为显示数码管的数据线输出口。且在Proteus中可以直接编辑该单片机的属性,从而直接为其选择12M的晶振周期,因此没有外接的晶振模块。
在软件上,该单片机的作为程序的存储器及运行器,源程序的输入从P3、P1口输入,源程序的输出从P2、P0口输出。
三、 系统软件设计
3.1 C语言源程序数据结构设计
3.1.1 段码数组
unsigned char code
table[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x76};//数字0~9
该数组的作用是,显示数字时从这个数组中查找对应的段码送到数码管中。
3.2 C语言源程序函数描述
3.2.1延时函数 void delay(uchar x)
函数的参数有一个无符号字符类型的参数,即x毫秒。此函数作用是延时,即数码管显示某个数字时延迟一定时间。具体实现方法是利用两层嵌套for循环,达到延迟一定时间的目的。
3.2.2 抢答函数 void qiangdaz()
此函数没有参数,它的作用是实现主持人控制开关按下后,开始倒计时,并判断出是几号答题者抢答的,然后进入回答函数,执行相应的操作。实现方法是,利用三层for循环,前两层的作用是秒的十位与个位的递减,第三层的作用在一秒内刷新数码管一定的次数。也就是三层for循环在一秒内秒把十位与个位同时刷新相同的次数。然后,每次刷新时再判断,是否有答题者抢答以及抢答者的号码,若有抢答的人就进入回答函数。具体的硬件方法是,每次显示数字时,利用P2口作为片选口选择需要点亮的数码管,然后再利用P0口向数码管送入相对于数字的共阴极段码并延时,然后对下一个数码管做类似的操作。判断是否有人抢答时,利用P1口的电平变化,正常情况下,P1口的值为0xff,如果有人按下抢答开关,那么P1口的值不再是0xff,然后再判断抢答者的号码,过程是,先对P1口取反,然后再判断P1口的值,0x01,0x02,0x04,0x08,0x10,0x20对应的抢答者的号码分别是1,2,3,4,5,6.
3.2.3 回答函数 void huida(uchar b)
此函数有一个无符号字符类型的参数,即b号答题者。它的作用是实现答题者抢答成功后,显示抢答者的号码、答题倒计时,且判断主持人是否按下清零开关。实现方法同样是,与抢答函数中类似的三层for循环,只不过需要多显示一个抢答者的号码,且第三层for循环中的判断是判断主持人是否按键。具体的硬件方法是,显示数字与抢答函数类似,判断按键时需要判断P3口的值,P3口的值为0xff,如果主持人按下抢答开关,那么P3口的值不再是0xff,具体过程是先对P3口取反,然后再判断P3口的值,0x04,0x08对应的分别是主持人按下开始键,清零键而区**只对主持人按下清零键执行相应的操作,即,把显示数码管的需要显示数字都改为0,然后退出回答函数。
3.2.4 犯规函数 void fangui(uchar f)
此函数的参数是一个无符号字符类型的参数,即f号答题者。这个函数的作用是答题者犯规抢答后,显示犯规答题者的号数,一段时间后自动消失
3.2.5 主函数 void main()
此函数没有参数。它是我所知的所有C语言程序必须的。首先是一个死循环,然后判断主持是否按键,若主持人按键,则进入抢答函数,主持人没有按键时,再判断答题者是否按键,如果答题者按键,则进入犯规函数。然后如此循环下去。
3.3 C语言源程序算法描述
3.3.1主函数流程图
图5主函数流程图
3.3.2 抢答函数流程图
图6抢答函数流程图
3.3.3 犯规函数流程图
图7犯规函数流程图
3.3.4 回答函数流程图
图8回答函数流程图
4 仿真与性能测试
4.1 C语言程序在Proteus电路图中运行结果图
1.未产生任何按键时与程序运行结果如图9
图9
2.主持人按键开始抢答运行结果如图10
图10
3.答题者按键抢答成功,答题运行结果如图11
图11
4.答题者答题结束清零运行结果如图12
图12
5.答题者犯规抢答运行结果如图13
图13
参考文献
[1] 江世明.基于Proteus的单片机应用技术.北京:电子工业出版社,2008
[2] 楼然苗,李光飞.单片机课程设计指导.北京:北京航空航天大学出版社,2007
[4] 徐钧爱.单片机C语言编程与Proteus仿真技术.北京:电子工业出版社,2016
[5] 赵全利,肖兴达.单片机原理及应用技术.北京:机械工业出版社,2007
[6] 潘新民,王燕芳.微型计算机控制技术.北京:电子工业出版社,2011
[7] 万光毅.单片机实验与实践教程.北京:北京航空航天大学出版社,2003
[8] 冯波琴,吴宁.微机计算机原理与接口技术.北京:清华大学出版社,2007
[9] 李泉溪.单片机原理与应用实例仿真.北京:北京航空航天大学出版社,2009
[10] 郭建江.单片机技术与应用.南京:南京东南大学出版社,2008
Proteus 总电路图
图14
附代码
#include <reg51.h>
#include <absacc.h>
#define wdz XBYTE [0xf002] //位地址
#define ddz XBYTE [0xf004] //段地址
#define uchar unsigned char
//主持人按键P3口
sbit zcr=P3^2;
//开始键
sbit new=P3^3;
//清零键
unsigned char code
table[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x76};
//数字0~9
uchar gws=9,qdsws=2,dtsws=5;
//个位数,抢答十位数,定时十位数
uchar numzcr=0,numxs=0,numnew,keyxs,keyzcr;
//主持人,选手,主持人清零,选手接口,主持人接口
void delay(uchar x)//延时 x ms
{
int i,j,k;
k=x+x;
for(i=0;i<k;i++)
{ for(j=0;j<250;j++);}
} //延时 x ms 结束
void huida(int b); //回答函数
void qiangda()//抢答函数,抢答倒计时30s
{
int i,j,k;
for (i=2;i>=0;i--)
{
for (j=9;j>=0;j--)
{
for (k=0;k<50;k++)//保持不闪
{
wdz=0x02;
ddz=table;//十位数字
delay(2);
wdz=0x01;
ddz=table[j];//个位数字
delay(2);
if (P1!=0XFF)
{
keyxs=~P1;
switch(keyxs)
{
case 0x01:numxs=1;break;
case 0x02:numxs=2;break;
case 0x04:numxs=3;break;
case 0x08:numxs=4;break;
case 0x10:numxs=5;break;
case 0x20:numxs=6;break;
default:break;
}
huida(numxs);
return;//抢答结束
}
}
}
}
}//抢答函数结束
void huida(uchar b) //答题倒计时60s
{
int i,j,k,m,n;
for (i=5;i>=0;i--)
{
for (j=9;j>=0;j--)
{
for (k=0;k<50;k++) //保持不闪
{
wdz=0x08;
ddz=table;//选手号码
delay(1);
wdz=0x02;
ddz=table;//十位数字
delay(1);
wdz=0x01;
ddz=table[j];//个位数字
delay(1);
if (P3!=0XFF)//主持人是否按键
{
delay(1);
if (P3!=0XFF)//再次确认
{
keyzcr=~P3;
switch(keyzcr)
{
case 0x04:numzcr=1;break; //开始,暂停
case 0x08:numnew=1;break; //清零
default:break;
}
if (numzcr==0)//暂停,不过暂时还做不到。
{
for (m=0;m<200;m++)//延迟一段时间
{
wdz=0x08;
ddz=table;//选手号码
delay(1);
wdz=0x02;
ddz=table;//十位数字
delay(1);
wdz=0x01;
ddz=table[j];//个位数字
delay(1);
}
return;//结束
} //暂停结束
else if (numnew==1) //清零
{
for (n=0;n<200;n++)//延迟一段时间
{
wdz=0x08;
ddz=table[0];//选手号码0
delay(1);
wdz=0x02;
ddz=table[0];//十位数字0
delay(1);
wdz=0x01;
ddz=table[0];//个位数字0
delay(1);
}
return;//结束
}//清零结束
else
{ } // default 情况下什么都不做
}//确认结束
}// 按键结束
}//第三个for结束
}
}
}//回答函数结束
void fangui(uchar f) //犯规抢答函数
{
int i;
for (i=0;i<100;i++)//延迟一段时间
{
wdz=0x08;
ddz=table[f];//选手号码
delay(1);
wdz=0x02;
ddz=table[0];//十位数字0
delay(1);
wdz=0x01;
ddz=table[0];//个位数字0
delay(1);
}
}//犯规抢答函数结束
void main()
{
while(1)
{
if(zcr==0)//判断主持人是否按键
{
delay(1);
if(zcr==0)
{
numzcr=1;
qiangda();//数码管显示数字,抢答倒计时开始
}
}
else if(new==0)//判断是否清零
{
delay(1);
if(new==0)
P2=0xff;
P0=0xff;//从头开始
}
else if (P1!=0XFF)
{
delay(1);
if (P1!=0XFF)
{
keyxs=~P1;
switch(keyxs)
{
case 0x01:numxs=1;break;
case 0x02:numxs=2;break;
case 0x04:numxs=3;break;
case 0x08:numxs=4;break;
case 0x10:numxs=5;break;
case 0x20:numxs=6;break;
default:break;
}
fangui(numxs);
return; //犯规显示结束
}
}//最后一个else if结束
}//while结束
}//main结束
#include <reg51.h>
#include <absacc.h>
#define wdz XBYTE [0xf002] //位地址
#define ddz XBYTE [0xf004] //段地址
#define uchar unsigned char
//主持人按键P3口
sbit zcr=P3^2;
//开始键
sbit new=P3^3;
//清零键
unsigned char code
table[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x76};
//数字0~9
uchar gws=9,qdsws=2,dtsws=5;
//个位数,抢答十位数,定时十位数
uchar numzcr=0,numxs=0,numnew,keyxs,keyzcr;
//主持人,选手,主持人清零,选手接口,主持人接口
void delay(uchar x)//延时 x ms
{
int i,j,k;
k=x+x;
for(i=0;i<k;i++)
{ for(j=0;j<250;j++);}
} //延时 x ms 结束
void huida(int b); //回答函数
void qiangda()//抢答函数,抢答倒计时30s
{
int i,j,k;
for (i=2;i>=0;i--)
{
for (j=9;j>=0;j--)
{
for (k=0;k<50;k++)//保持不闪
{
wdz=0x02;
ddz=table;//十位数字
delay(2);
wdz=0x01;
ddz=table[j];//个位数字
delay(2);
if (P1!=0XFF)
{
keyxs=~P1;
switch(keyxs)
{
case 0x01:numxs=1;break;
case 0x02:numxs=2;break;
case 0x04:numxs=3;break;
case 0x08:numxs=4;break;
case 0x10:numxs=5;break;
case 0x20:numxs=6;break;
default:break;
}
huida(numxs);
return;//抢答结束
}
}
}
}
}//抢答函数结束
void huida(uchar b) //答题倒计时60s
{
int i,j,k,m,n;
for (i=5;i>=0;i--)
{
for (j=9;j>=0;j--)
{
for (k=0;k<50;k++) //保持不闪
{
wdz=0x08;
ddz=table;//选手号码
delay(1);
wdz=0x02;
ddz=table;//十位数字
delay(1);
wdz=0x01;
ddz=table[j];//个位数字
delay(1);
if (P3!=0XFF)//主持人是否按键
{
delay(1);
if (P3!=0XFF)//再次确认
{
keyzcr=~P3;
switch(keyzcr)
{
case 0x04:numzcr=1;break; //开始,暂停
case 0x08:numnew=1;break; //清零
default:break;
}
if (numzcr==0)//暂停,不过暂时还做不到。
{
for (m=0;m<200;m++)//延迟一段时间
{
wdz=0x08;
ddz=table;//选手号码
delay(1);
wdz=0x02;
ddz=table;//十位数字
delay(1);
wdz=0x01;
ddz=table[j];//个位数字
delay(1);
}
return;//结束
} //暂停结束
else if (numnew==1) //清零
{
for (n=0;n<200;n++)//延迟一段时间
{
wdz=0x08;
ddz=table[0];//选手号码0
delay(1);
wdz=0x02;
ddz=table[0];//十位数字0
delay(1);
wdz=0x01;
ddz=table[0];//个位数字0
delay(1);
}
return;//结束
}//清零结束
else
{ } // default 情况下什么都不做
}//确认结束
}// 按键结束
}//第三个for结束
}
}
}//回答函数结束
void fangui(uchar f) //犯规抢答函数
{
int i;
for (i=0;i<100;i++)//延迟一段时间
{
wdz=0x08;
ddz=table[f];//选手号码
delay(1);
wdz=0x02;
ddz=table[0];//十位数字0
delay(1);
wdz=0x01;
ddz=table[0];//个位数字0
delay(1);
}
}//犯规抢答函数结束
void main()
{
while(1)
{
if(zcr==0)//判断主持人是否按键
{
delay(1);
if(zcr==0)
{
numzcr=1;
qiangda();//数码管显示数字,抢答倒计时开始
}
}
else if(new==0)//判断是否清零
{
delay(1);
if(new==0)
P2=0xff;
P0=0xff;//从头开始
}
else if (P1!=0XFF)
{
delay(1);
if (P1!=0XFF)
{
keyxs=~P1;
switch(keyxs)
{
case 0x01:numxs=1;break;
case 0x02:numxs=2;break;
case 0x04:numxs=3;break;
case 0x08:numxs=4;break;
case 0x10:numxs=5;break;
case 0x20:numxs=6;break;
default:break;
}
fangui(numxs);
return; //犯规显示结束
}
}//最后一个else if结束
}//while结束
}//main结束
————————————————
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/djdbbdbb/article/details/144084384
|
|