一、任务说明 

(一)系统总体方案设计与实现

1、系统总体方案设计

本系统由硬件系统和软件系统组成。

硬件系统包括按键控制模块、中央处理AT89C51系统、指示灯显示模块、LED数码管显示模块和扬声器提示模块。

软件系统包括主程序、定时器0中断服务程序、定时器1中断服务程序、延时程序、按键程序和显示程序。

为方便理解,系统框图如下图所示:

图1 系统框图

2、系统总体方案实现

本次单片机课程设计选题是《八路抢答器》。本次课程设计是以八位选手抢答和主持人的控制为出发点。

①只有一个最先抢答有效,其余抢答无效。

②在主持人的控制下,10秒内抢答有效,用数码管显示抢答10秒倒计时,若有抢答直接结束,显示哪个编号抢到,并进入10秒的答题时间。

③若有提前抢答,则犯规,用蜂鸣器响1秒警示。

④有复位按键,用于复位作用,开始新的一轮。

⑤可以设置抢答时间和答题时间,可调范围是0到99秒,超出或低出范围会返回第10秒。

⑥LED警示灯、LED显示屏和蜂鸣器进行倒计时警示,三重的警示,带来极致的紧迫感。

⑦答题时间暂停,可以确定选手最后的答案耗时多长时间,促进选手的公平。

⑧如果选手在规定时间内或违规抢到第一位,不仅屏幕会显示号码,而且对应选手的LED灯会亮起。

(二)硬件电路设计

1、硬件电路图:

①时钟电路模块:

图2 时钟电路

②复位电路模块:

图3 复位电路

③LED显示屏模块:

图4 LED显示屏

④选手抢答按键模块:

图5 选手抢答按键

⑤选手点灯模块:

图6 选手点灯

⑥蜂鸣器提示模块:

图7 蜂鸣器提示

⑦LED灯倒计时警示模块:

图8 LED灯倒计时警示

⑧主持人控制按键模块:

图9 主持人控制按键

2、硬件说明:

本次硬件设计简单来说由:AT89C51最小系统、显示模块、按键模块LED灯和蜂鸣器模块组成。

(三)软件设计

当接通电源开始工作后,单片机中的程序开始运行,将对程序进行初始化。完成初始化后,将进行键盘扫描,同时判断开始按键、调节按键是否按下。最后完成倒计时和选手号码的显示等功能。

软件流程图如下图所示:

图10 软件流程图

二、电路原理图与结果

1、选手违规抢答:以第1位选手违规抢答为例,对应选手的LED灯亮起,LED显示屏显示对应违规选手号码,蜂鸣器先响起1秒警示,如果未进行复位操作,则蜂鸣器将再会响起,同时倒计时警示LED灯会闪烁提示。(第1-8位选手都是如此)

2、抢答时间调整:如果按下抢答时间加键或抢答时间减键,LED显示屏显示对应的调整时间,时间调整范围为0-99秒,超过99秒或低出0秒则返回去10秒。本次将抢答时间增加到15秒。

3、答题时间调整:如果按下答题时间加键或答题时间减键,LED显示屏显示对应的调整时间,时间调整范围为0-99秒,超过99秒或低出0秒则返回去10秒。本次将答题时间减少到8秒。

4、主持人按下开始键:抢答时间开始倒计时,最后几秒抢答时间倒计时警示LED灯将闪烁,要是选手没有选择抢答,则蜂鸣器会不断响起,LED显示屏熄屏,除非按下复位键开启新的一轮。

5、主持人按下开始键:抢答时间开始倒计时,最后几秒抢答时间倒计时警示LED灯将闪烁,要是选手选择抢答,则对应选手的LED灯会亮起。

6、要是选手在抢答时间按下抢答键,进入答题时间:答题时间最后几秒倒计时LED灯亮起,蜂鸣器不断响起,提示按下复位键,开始新的一轮。

6、要是选手在抢答时间按下抢答键,进入答题时间:答题时间内主持人可以按下答题时间暂停键,则显示屏时间暂停,按下答题时间暂停键的第一瞬间LED显示屏熄屏,倒计时LED警示灯亮起,松下答题时间暂停键的第一瞬间LED显示屏显示暂停的时间,倒计时LED警示灯熄灭,除非按下复位键,开始新的一轮。

三、代码说明

代码部分主要由四个模块组成,分别为主程序、显示子程序、时间按键调整子程序、选手按键子程序、开始键子程序、延迟子程序、定时器T0初始化子程序和蜂鸣器和LED灯子程序。

1、主程序:

主程序完成定时器0的初始化、74LS138芯片的初始化和扫描主持人按键,进行对应的操作。

2、显示子程序:

此函数大方向分为开始键按下和开始键没有按下的两种情况。同时两个大方向又各自细分两个小方向。当开始键按下,则有选手在抢答时间按下显示选手号码在LED显示屏上,要是没有则不显示号码。同时显示屏上显示抢答和答题的倒计时。当开始键没有按下,如果有人违规抢答,则显示屏显示违规号码。如果按下答题时间或抢答时间调整键,则对应显示屏进行更新数据操作。

3、时间按键调整子程序:

此函数很简单,要是按下抢答时间或答题时间调整键,则对应时间将进行操作,调整范围为0-99秒,超出99秒或低于0秒,则返回到10秒。

4、选手按键子程序:

以K1为例,程序一直判断按键引脚电压,按下按键电压为0。按键会产生抖动,需要进行消抖处理,先进行消抖延迟10ms,如果按键电压还是0,确定没问题K1进行操作,令按键数目num为1,供主函数处理按键消息。同时将74LS138的对应输入口赋值,数码管显示工作,定时器1和0也进行对应工作。K1-K8功能都是一样的操作。

5、开始键子程序:

如果按下开始键,程序一直判断按键引脚电压,按下按键电压为0。按键会产生抖动,需要进行消抖处理,先进行消抖延迟10ms,如果按键电压还是0,确定没问题K0进行操作.将对应的标志位进行开始工作,将清除违规标志位、开始抢答时间调整键标志位和答题计时时间调整键标志位停止运行。

6、延迟子程序:

确定51单片机为12MHz频率,以此确定ms的延迟子函数。

7、定时器T0初始化子程序:

将定时器T0进行初始化,运用方式1,即16位计数器。取高八位和第八位寄存器进行定时操作。

8、蜂鸣器和LED灯子程序:

用定时器0和定时器1确定蜂鸣器响多久和LED灯亮。

四、源代码

#include

#define uchar unsigned char

#define uint unsigned int

char s;

uchar num=0;//谁抢到的号码,初始化为0

char snaptime=10;//抢答时间

char answertime=10;//答题时间

uint t0,t1; //T0,T1定时器

bit flag,s_flag=1,b_flag,fall_flag;//标志位

bit K_snaptimeflag,K_answertimeflag;//时间调整标志位

sbit K0=P3^0;

sbit beep=P3^7;//蜂鸣器输出口

sbit led=P2^4;//指示灯输出口

sbit K1=P1^0;

sbit K2=P1^1;

sbit K3=P1^2;

sbit K4=P1^3;

sbit K5=P1^4;

sbit K6=P1^5;

sbit K7=P1^6;

sbit K8=P1^7;

sbit K_Time=P2^5;//答题暂停键

sbit K_startcount=P2^6;//开始抢答时间+调整键

sbit K_timecount=P3^4;//答题计时时间+调整键

sbit K_startcount0=P2^7;//开始抢答时间-调整键

sbit K_timecount0=P3^5;//答题计时时间-调整键

sbit G=P3^1;

sbit H=P3^2;

sbit I=P3^3;

sbit J=P3^6;

uchar code tabledu[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};

uchar code tablewe[]={0XFE,0XFD,0XFB,0XF7};

void delay(uint n)//延时n毫秒

{

uint i=0,j=0;

for(i=0;i

for(j=0;j<123;j++);

}

void T0_Init(void)//定时器T0初始化

{

TMOD=0X01;//使用定时器T0的模式1

TH0=(65536-2000)/256;

TL0=(65536-2000)%256;

TH1=(65536-2000)/256;

TL1=(65536-2000)%256;

ET0=1;

ET1=1;

EA=1;

P0=0;

}

void Start_Scan(void) //开始键扫描

{

if(K0==0)

{

delay(10);

if(K0==0)

{

while(!K0);

TR0=1;//启动定时器0工作

s=snaptime;

t0=0;

flag=1;

s_flag=1;

b_flag=1;

num=0;

beep=1;

led=1;

fall_flag=0;//清除违规标志位

K_snaptimeflag=0;//开始抢答时间调整键停止运行

K_answertimeflag=0;//答题计时时间调整键停止运行

}

}

}

void Select_Scan(void)//八路选择键扫描(哪个键先按下,哪个优先级最高)

{

if(K1==0)

{

delay(10);

if(K1==0)

{

while(!K1);

{

G=0;

H=0;

I=0;

J=1;

num=1;//数码管显示第1位

TR0=0;//关闭定时器0工作,时间停止

TR1=1;//打开定时器1工作 。使扬声器响一声

s_flag=0;//关闭开始键标志位,使再按其他七个键不会响应

delay(10);

}

while(!K_Time);

{

s=answertime;

TR0=1;

t0=0;

TR1=1;

}

}

}

if(K2==0)

{

delay(10);

if(K2==0)

{

while(!K2);

{

G=1;

H=0;

I=0;

J=1;

num=2;

TR0=0;

TR1=1;

s_flag=0;

delay(10);

}

while(!K_Time);

{

s=answertime;

TR0=1;

t0=0;

TR1=1;

}

}

}

if(K3==0)

{

delay(10);

if(K3==0)

{

while(!K3);

{

G=0;

H=1;

I=0;

J=1;

num=3;

TR0=0;

TR0=0;

TR1=1;

s_flag=0;

delay(10);

}

while(!K_Time);

{

s=answertime;

TR0=1;

t0=0;

TR1=1;

}

}

}

if(K4==0)

{

delay(10);

if(K4==0)

{

while(!K4);

{

G=1;

H=1;

I=0;

J=1;

num=4;

TR0=0;

TR1=1;

s_flag=0;

delay(10);

}

while(!K_Time);

{

s=answertime;

TR0=1;

t0=0;

TR1=1;}

}

}

if(K5==0)

{

delay(10);

if(K5==0)

{

while(!K5);

{

G=0;

H=0;

I=1;

J=1;

num=5;

TR0=0;

TR1=1;

s_flag=0;

delay(10);

}

while(!K_Time);

{

s=answertime;

TR0=1;

t0=0;

TR1=1;

}

}

}

if(K6==0)

{

delay(10);

if(K6==0)

{

while(!K6);

{

G=1;

H=0;

I=1;

J=1;

num=6;

TR0=0;

TR1=1;

s_flag=0;

delay(10);

}

while(!K_Time);

{

s=answertime;

TR0=1;

t0=0;

TR1=1;

}

}

}

if(K7==0)

{

delay(10);

if(K7==0)

{

while(!K7);

{

G=0;

H=1;

I=1;

J=1;

num=7;

TR0=0;

TR1=1;

s_flag=0;

delay(10);

}

while(!K_Time);

{

s=answertime;

TR0=1;

t0=0;

TR1=1;}

}

}

if(K8==0)

{

delay(10);

if(K8==0)

{

while(!K8);

{

G=1;

H=1;

I=1;

J=1;

num=8;

TR0=0;

TR1=1;

s_flag=0;

delay(10);

}

while(!K_Time);

{

s=answertime;

TR0=1;

t0=0;

TR1=1;

}

}

}

}

void display(void)

{

if(flag==1)//开始键按下,开始计时抢答

{

if(num!=0)//如果有人抢答,则显示相应的号码

{

P0=tabledu[num];//显示几号抢到了

P2=tablewe[0];

delay(2);

P0=0;

P2=0XFF;

}

else//否则没人抢答,则前面不显示几号

{

P0=0;

P2=0XFF;

}

P0=tabledu[s/10];//显示抢答倒计时的十位

P2=tablewe[2];

delay(2);

P0=0;

P2=0XFF;

P0=tabledu[s%10];//显示抢答倒计时的个位

P2=tablewe[3];

delay(2);

P2=0XFF;

P0=0;

}

if(flag==0)//如果开始键没有按下,若有违规者,则显示违规号码

{

if(fall_flag==1)//违规违规

{

if(num!=0)

{

P0=tabledu[num];//显几号违规了

P2=tablewe[0];

delay(2);

P0=0;

P2=0XFF;

P0=tabledu[15];

P2=tablewe[2];

delay(2);

P0=0;//消隐

P2=0XFF;

P0=tabledu[15];

P2=tablewe[3];

delay(2);

P0=0;

P2=0XFF;

}

else

{

P0=0;

P2=0XFF;

}

}

else

{

if(K_snaptimeflag==1)

{

P0=0XF9;//第1位数码管(表示抢答时间调整)

P2=tablewe[0];

delay(2);

P0=0;

P2=0XFF;

P0=tabledu[snaptime/10];//第x位数码管(表示抢答时间调整)

P2=tablewe[2];

delay(2);

P0=0;

P2=0XFF;

P0=tabledu[snaptime%10];

P2=tablewe[3];

delay(2);

P0=0;

P2=0XFF;

}

else if(K_answertimeflag==1)

{

P0=0X07;//第x位数码管(表示答题时间调整)

P2=tablewe[0];

delay(2);

P0=0;

P2=0XFF;

P0=0X31;

P2=tablewe[1];

delay(2);

P0=0;

P2=0XFF;

P0=tabledu[answertime/10];

P2=tablewe[2];

delay(2);

P0=0;

P2=0XFF;

P0=tabledu[answertime%10];

P2=tablewe[3];

delay(2);

P0=0;

P2=0XFF;

}

}

}

}

void Time_Scan(void)//调整时间键扫描

{

if(K_startcount==0)//抢答时间调整

{

delay(10);

if(K_startcount==0)

{

while(!K_startcount);

snaptime++;

if(snaptime==99||snaptime==0)

{

snaptime=10;

}

K_snaptimeflag=1; //将抢答时间标志位置1

K_answertimeflag=0; //同时关闭答题时间标志位

}

}

if(K_timecount==0) //答题时间调整

{

delay(10);

if(K_timecount==0)

{

while(!K_timecount);

answertime++;

if(answertime==99||answertime==0)

{

answertime=10;

}

K_answertimeflag=1;

K_snaptimeflag=0;

}

}

if(K_startcount0==0)//抢答时间调整

{

delay(10);

if(K_startcount0==0)

{

while(!K_startcount0);

snaptime--;

if(snaptime==99||snaptime==0)

{

snaptime=10;

}

K_snaptimeflag=1; //将抢答时间标志位置1

K_answertimeflag=0; //同时关闭答题时间标志位

}

}

if(K_timecount0==0) //答题时间调整

{

delay(10);

if(K_timecount0==0)

{

while(!K_timecount0);

answertime--;

if(answertime==99||answertime==0)

{

answertime=10;

}

K_answertimeflag=1;

K_snaptimeflag=0;

}

}

}

void main(void)

{

T0_Init();

G=0;

H=0;

I=0;

J=0;

while(1)

{

Start_Scan(); //开始键扫描

if((flag==0)&(s_flag==1)) //当开始键没按下及没有人违规时才可进行时间调整

{

Time_Scan();

}

if((flag==1)&(s_flag==0))//当开始键按下及有人抢答才进行开始回答计时倒计时

{

led=0;

if(K_Time==0)

{

delay(10);

if(K_Time==0)

{

while(!K_Time);

TR0=0;

t0=0;

TR1=1;

}

}

}

if((flag==0)&(s_flag==1)) //违规

{

Select_Scan();

if(num!=0) //开始键没有按下时,有人按下了抢答器,则置违规标志位

{

fall_flag=1;

led=0;

}

}

if((flag==1)&(s_flag==1)) //如果开始键按下且抢答键没有人按下,则进行八路抢答键扫描

{

Select_Scan();

}

display(); //显示到数码管上

}

}

void timer0(void) interrupt 1//定时器0

{

TH0=(65536-2000)/256; //2ms

TL0=(65536-2000)%256;

if(b_flag) //开始(START)键按下,嘟一声(长1秒),表示开始抢答

{

beep=~beep;

}

else

beep=1;

if(s<5) //抢答时间快到报警,每1秒响一声且红灯闪烁,响5声

{

if(s%1==0)

{

b_flag=1;

led=0;

}

else

{

b_flag=0;

led=1;

}

}

t0++;

if(t0==500) //1秒

{

t0=0;

s--;

b_flag=0; //关闭开始键按下响一秒的嘟声

if(s==-1)

{

s=20;

TR0=0;

flag=0; //显示F FF

s_flag=1;

num=0;

led=1;

}

}

}

void timer1(void) interrupt 3 //定时器1处理有人按下抢答器嘟一声(长1秒)

{

TH1=(65536-2000)/256;

TL1=(65536-2000)%256;

beep=~beep;

t1++;

if(t1==500)

{

t1=0;

TR1=0;

}

}

相关链接

评论可见,请评论后查看内容,谢谢!!!
 您阅读本篇文章共花了: