基于C语言的单片机八路抢答器课程设计详解

一、任务说明 

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

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<reg51.h> 

#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<n;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;
 	}
}

物联沃分享整理
物联沃-IOTWORD物联网 » 基于C语言的单片机八路抢答器课程设计详解

发表评论