嵌入式设计应用
在知识竞赛、文体娱乐活动(抢答赛活动)中,能准确、公正、直观地判断出抢答者的座位号。更好的促进各个团体的竞争意识,让选手门体验到战场般的压力感
传统抢答器只是大概判断出抢答成功或犯规选手台号,无法显示出每个选手的抢答时间。而今抢答器可以通过数据来说明裁决结果的准确性、公平性。使比赛大大增加了娱乐性的同时,也更加公平、公正。
新增无线抢答器更是抢答器史上的一大改革
软件功能更强大:
搭配全新升级版软件,采用嵌入式PPT设计,可支持三种格式题库导入(文本文档、WORD、Excel),15O道题导入只需20秒,导入的题目直接以PPT方式展现,可直接在展现页面进行题目再修改。此款软件还提供多种背景模板,供客户选择使用,点击任何一款即可自动导入到题目中。非常简单便捷。
抢答精度更高:
国内首台可以将所有选手抢答时间同步显示出来并自动排序的抢答器,且精度高达0.00001秒。开创抢答领域新时代,让比赛没有争议且更具娱乐性。
主机接线更少:一条
主线串连所有分组计分显示屏;最大程度减少了布线的繁琐。
抢答模式更齐全:根据
公司多年的大赛经验,将各类大型赛事所用的抢答模式归结为四种:即淘汰模式、快速式、直接式、无限时式,全部纳入此款软件,所以功能相当齐全。
抢答节奏可调:
目前国内抢答器抢答开始令的语音都是固定的,客户无法调节,新款抢答器增加了可调节功能,客户可以根据自己的需要来自行调节比赛节奏,同时软件还提供男生、女生两种语音主持模式,更具人性化。
软件操作更简单:操作
方面进行了多种自动识别功能,简化比赛操作步骤,正式比赛时只需操作5、6个按键即可完成比赛。
电子抢答器
1电子抢答器的中心构造一般都是由抢答器由单片机以及外围电路组成,其搭配的配件不同又分为,非语音非记分抢答器和语音记分抢答器。
多适用于学校和企事业单位举行的简单的抢答活动。
非语音记分抢答器构造很简单,就是一个抢答器的主机和一个抢答按钮组成,在抢答过程中选手是没有记分的显示屏。
语音记分抢答器是有一个抢答器的主机和主机的显示屏和选手的记分显示屏。
抢答按钮
根据公司多年的大赛经验抢答盒对比赛现场气氛起到非常重要的作用。知识竞赛是属于娱乐学习的范畴,所以比赛的现场气氛非常重要,抢答盒的2个技术指示灯可直接影响比赛气围:1,抢答盒行程多少。2,抢答盒体积大小。
1,抢答盒行行程。直接决定比赛的现场气氛,而决定抢答盒行程的有2点:1,模具的行程。2,按钮的行程。模具行程要在5~6MM为最佳,按钮行程在2~3mm为最佳,这样既能保证抢答的精确度,又可以保证比赛现场氛围。抢答盒的行程如果小于5mm,,选手在抢答时场面就会显得过于安静,从现场看感觉还有抢答已经抢答结束了。但行程在5~6mm的选手抢答幅度就会很大,比赛气氛就会热闹很多。
2,抢答盒大小要适中,如果太小的话,抢答时一般用手指点抢答,这样太轻也不利于比赛现场气氛,本公司设计的这种抢答盒,适用手掌大力拍打来 抢答,这样能很好的烘托出比赛的激烈程度。
总体方案设计
通过查阅大量相关技术资料,并结合自己的实际知识,我主要提出了两种技术方案来实现系统功能。下面我将首先对这两种方案的组成框图和实现原理分别进行说明,并分析比较它们的特点,然后阐述我最终选择方案的原因。
抢答器采用STC12C5A60S2(或STC89C52)单片机作为控制核心,抢答器可以完成运算控制、信号识别以及显示功能的实现。由于用了单片机,使其技术比较成熟,应用起来方便、简单并且单片机周围的辅助电路也比较少,便于控制和实现。整个系统具有极其灵活的可编程性,能方便地对系统进行功能的扩张和更改性。
抢答电路模块
抢答器的工作原理是采用单片机最小系统,用查询式键盘进行抢答。通过抢答按键模块,链接按键进行抢答。其工作原理为:主持人按清零键后,选手可按键抢答,单片机锁存信号,屏蔽外界信号,同时通过5510显示抢答成功的选手编号,并有蜂鸣器发声。此时定时器工作,开始答题倒计时,到时间结束,主持人将系统清零。原理图如下:
复位电路的设计
复位电路的设计该复位电路采用上电自动复位和手动复位两种复位方式,要实现复位只需在,STC12C5A60S2单片机的RESET~I脚上加上5ms的高电平就可以了。上电复位是利用电容的充电来实现的,即上电瞬间RESET端的电位与Vcc相同,随着电容上储能增加,电容电压也逐渐增大,充电电流减小,RESET端的电位。这样就会建立一个脉冲电压,调节电容与电阻的大小可对脉冲的持续时间进行调节。通常若采用1 2MHz的晶振时,复位元件参数为10 LI F的电解电容和10kQ的电阻。按钮复位电路是通过按下复位按钮时,电源对RESET端,维持两个机器周期的高电平实现复位的。
晶振电路的设计
STC12单片机的定时控制功能是用时钟电路和振荡器完成的,而根据硬件电路的不同,连接方式分为内部时钟方式和外部时钟方式。内部时钟方式,是单片机内部有一个用于构成振荡器的高增益反相放大器,该高增益反相放大器的输入端为芯片引脚XTAL1,输出端引脚XTAL2。这两个引脚跨接石英晶体振荡器和微调电容,就构成一个稳定的自激振荡器,电路如图所示。
电路中电容C1、C2典型值通常选择为30pF左右。对外接电容的值虽然没有严格的要求,但电容的大小会影响振荡器频率的高低,振荡器的稳定性和起振的快速性。晶振的频率通常在1.2MHZ-12MHZ之间。晶振的频率越高,则系统的时钟频率也就越高,单片机的运行速度也就越快。本设计采用内部时钟方式。
蜂鸣器提示报警电路
其主要在于当单片机执行中断后,当输出信号时能够在很短的时间里让扬声器工并持续一定的时间。当抢答器程序响应,使三极管导通,蜂鸣器的放大电路被接通,与此同时,喇叭发出声响。由于自激蜂鸣器是直流电压驱动的,不需要利用交流信号进行驱动,只需对驱动口输出驱动电平并通过三极管放大驱动电流就能使蜂鸣器发出声音。单片机驱动他激蜂鸣器的方式有两种:一种是PWM 输出口直接驱动,另一种是利用I/O 定时翻转电平产生驱动波形对蜂鸣器进行驱动。
PWM 输出口直接驱动是利用PWM 输出口本身可以输出一定的方波来直接驱动蜂鸣器。在单片机的软件设置中有几个系统寄存器是用来设置PWM 口的输出的,可以设置占空比、周期等等,通过设置这些寄存器产生符合蜂鸣器要求的频率的波形之后,只要打开PWM 输出,PWM 输出口就能输出该频率的方波,这个时候利用这个波形就可以驱动蜂鸣器了。比如频率为2000Hz 的蜂鸣器的驱动,可以知道周期为500μs,这样只需要把PWM 的周期设置为500μs,占空比电平设置为250μs,就能产生一个频率为2000Hz 的方波,通过这个方波再利用三极管就可以去驱动这个蜂鸣器了。
利用I/O 定时翻转电平来产生驱动波形的方式会比较麻烦一点,必须利用定时器来做定时,通过定时翻转电平产生符合蜂鸣器要求的频率的波形,这个波形就可以用来驱动蜂鸣器了。比如为2500Hz 的蜂鸣器的驱动,可以知道周期为400μs,这样只需要驱动蜂鸣器的I/O 口每200μs 翻转一次电平就可以产生一个频率为2500Hz,占空比为1/2 duty的方波,再通过三极管放大就可以驱动这个蜂鸣器了。当蜂鸣器发声时,发光二激光点亮。
显示电路
显示电路可由LED或LCD来实现。此处选用ULF-3461BS来显示。
电源电路
下载程序接口
本系统程序下载接口采用的是美信公司专门为电脑的RS-232标准串口设计的单电源电平转换芯片MAX232,使用+5v单电源供电。
第一部分是电荷泵电路。由1、2、3、4、5、6脚和4只电容构成。功能是产生+12v和-12v两个电源,提供给RS-232串口电平的需要。第二部分是数据转换通道。由7、8、9、10、11、12、13、14脚构成两个数据通道。其中13脚(R1IN)、12脚(R1OUT)、11脚(T1IN)、14脚(T1OUT)为第一数据通道。8脚(R2IN)、9脚(R2OUT)、10脚(T2IN)、7脚(T2OUT)为第二数据通道。TTL/CMOS数据从T1IN、T2IN输入转换成RS-232数据从T1OUT、T2OUT送到电脑DB9插头;DB9插头的RS-232数据从R1IN、R2IN输入转换成TTL/CMOS数据后从R1OUT、R2OUT输出。第三部分是供电。15脚GND、16脚VCC(+5v)。
键盘电路
键盘有很多种形式。比如独立按键,矩阵键盘,编码键盘等。在日常开发中经常会
用到键盘。但键盘会占用大量的IO,比如说4*4矩阵键盘,会用到单片机的8个IO口。而AD键盘,既是利用AD转换芯片,将键盘输出的模拟电压值进行转换,然后将转换后的数字量传送给单片机,这样就可以节省7个IO口,让单片机流出其余的IO 口供其他外围电路使用。
程序初始化:上电后,设置单片机的中断入口及其他状态标志设置,清除相关中断标志,初始化外部显示电路,显示屏点亮。 端口设置及初始化:关显示电路,按键电路对应I/O口输出LOC,以便进行按键检测。
抢答过程:显示倒计时,扫描到有效按键按下,倒计时停止倒计,进入答题倒计时,蜂鸣器鸣叫10S,然后等待复位。如果在抢答时间内,没有扫描到有效按键,一直倒计时,到倒计为零的时候,没抢答,蜂鸣器长鸣10S后,显示“无人抢答”。 按键扫描:采用动态扫描,检测到按键按下,软件消抖,然后确认按键。 抢答结束:清除本次抢答相关标志,清倒计时和通道抢答确认显示。
本系统抢答器能实现如下功能:
①、由主持人控制答题开始,通过一个总的控制按钮,并且蜂鸣器 发声提示。再次按下时可以对单片机进行复位。
②、同时主持人按钮控制着30S的抢答倒计时,当时间到仍没有人抢答时,蜂鸣器发声报警,同时屏幕显示无人抢答,等待主持人按键复位,进行下一轮抢答 ③、当有一个抢答按钮被按下后,单片机进行锁存,屏蔽其他选手号,此时蜂鸣器报警提示,并进入答题倒计时30S,若超时,则蜂鸣器报警,屏幕显示答题超时,此时等待主持人复位。
六、主要程序
/*======================================================= 主函数
=======================================================*/ void main(void) {
system_init();//系统初始化 // IP = 0x20; while(1) {
seg_change();//转换显示的内容 key_handle();//键盘处理函数 switch(SPK_Flag) {
case SPK_NO: break;
case SPK_MUSIC: SpkMusic(); break; //播放音乐1 case SPK_ALARM: SpkAlarm(); break; } } }
/*======================================================= 系统初始化函数
=======================================================*/ void system_init(void) {
//定时器0 初始化 定时时间2ms TMOD = 0x01;
TH0 = 0x3c; //50微妙 TL0 = 0xb0;
EA = 1;
ET0 = 1; TR0 = 1;
SEG_RAM[0]=SEG_no; //这位不显示 有人抢答时,s显示抢答选手号 或则 无人抢答时 显示 F
SEG_RAM[1]=SEG_no; SEG_RAM[2]=SEG_no; SEG_RAM[3]=SEG_no;
SEG_RAM[4]=SEG_no;//初始化记分器分数 SEG_RAM[5]=SEG_no; SEG_RAM[6]=SEG_no;
SEG_RAM[7]=SEG_0;//始终显示0 }
/*======================================================= 键盘扫描函数
=======================================================*/ unsigned char key_scan(void) {
unsigned char keyvalue=NO_KEY; if(KEY_PORT != 0xff) {
delay();delay();delay();delay(); delay();delay();delay();delay(); delay();delay();delay();delay(); delay();delay();delay();delay(); switch (KEY_PORT) {
case 0xff: break;//无键按下 case 0xfe: keyvalue = PLAYER_1; break; case 0xfd: keyvalue = PLAYER_5; break; case 0xfb: keyvalue = PLAYER_2; break; case 0xf7: keyvalue = RST_KEY; break; case 0xef: keyvalue = PLAYER_3; break; case 0xdf: keyvalue = ADD_KEY; break; case 0xbf: keyvalue = PLAYER_4; break; case 0x7f: keyvalue = UP_KEY; break; }
while(KEY_PORT != 0xff);//松手检测 }
return (keyvalue);
}
/*======================================================= 键盘处理函数
=======================================================*/ void key_handle(void) {
unsigned char keytemp; keytemp = key_scan(); switch(keytemp) {
case NO_KEY: break;
case PLAYER_1: case PLAYER_2: case PLAYER_3: case PLAYER_4: case PLAYER_5:
if(QD_Flag==QD_GO) {
QD_Flag = QD_OK; //切换到抢答成功状态 SEG_RAM[0] = table_duan[keytemp+1]; //第一个数码管显示抢答选手号
QD_show_num = keytemp;
SPK_Flag = SPK_MUSIC; //蜂鸣器 播放音乐 }
break; case RST_KEY:
QD_Flag = QD_GO; SPK_Flag = SPK_NO; QD_timectr=100;
SEG_RAM[0] = SEG_no; break; case ADD_KEY:
JFQ_ctr[QD_show_num]++; //对应选手 记分器 加分 break; case UP_KEY:
QD_show_num++;
if(QD_show_num==5)QD_show_num=0;
SEG_RAM[0] = table_duan[QD_show_num+1];
break; } }
/*======================================================= 定时器0中断服务程序
=======================================================*/ void Timer0_ISR(void) interrupt 1 {
static unsigned char t0_2ms_counter = 0,tt; //50毫秒计数器 ET2=0;
TL0 = 0x30; //2ms TH0 = 0xf8;
t0_2ms_counter++;
seg_display(); //2毫秒 扫描数码管 if(t0_2ms_counter==250) //500ms / 2ms = 250 { //0.5s到 if(QD_timectr==0)
{ //抢答时间到,无人抢答,切换到抢答失败状态 QD_Flag = QD_NO;
tt++;
if(tt==1)SPK_Flag = SPK_ALARM; //蜂鸣器 播放报警音 else SPK_Flag = SPK_NO; }
if(QD_Flag==QD_GO) QD_timectr-=5; //在抢答倒计时期间 倒计时减0.5
}
ET2=1; }
/*======================================================= 数码管显示函数
=======================================================*/ void seg_display(void) {
static unsigned char i=0; LED_WEI = table_wei[i]; LED_DUAN = SEG_RAM[i]; i++;
if(i》7) i=0; }
/*======================================================= 数码管显示转换函数
=======================================================*/ void seg_change(void) {
if (QD_timectr《100) //取值为0~100
SEG_RAM[1]= SEG_no; //最高位为0则不显示 else
SEG_RAM[1]= SEG_1; //最高位显示1 SEG_RAM[2] = table_duandot[QD_timectr%100/10]; SEG_RAM[3] = table_duan[QD_timectr%10];
if(QD_Flag==2) SEG_RAM[0] = SEG_F; //显示‘F’ 无人抢答 if(JFQ_ctr[QD_show_num]》=100) {
SEG_RAM[4]=table_duan[JFQ_ctr[QD_show_num]/100];
SEG_RAM[5]=table_duan[JFQ_ctr[QD_show_num]%100/10]; SEG_RAM[6]=table_duan[JFQ_ctr[QD_show_num]%10]; }
else if (JFQ_ctr[QD_show_num]《100 && JFQ_ctr[QD_show_num]》=10) {
SEG_RAM[4]=SEG_no;//不显示0
SEG_RAM[5]=table_duan[JFQ_ctr[QD_show_num]%100/10]; SEG_RAM[6]=table_duan[JFQ_ctr[QD_show_num]%10]; }
else if (JFQ_ctr[QD_show_num]《10 && JFQ_ctr[QD_show_num]》0) {
SEG_RAM[4]=SEG_no;//不显示0 SEG_RAM[5]=SEG_no;//不显示0
SEG_RAM[6]=table_duan[JFQ_ctr[QD_show_num]%10]; } else {
SEG_RAM[4]=SEG_no;//不显示0 SEG_RAM[5]=SEG_no;//不显示0 SEG_RAM[6]=SEG_no;//不显示0 } }
/*======================================================= 延时函数(延时1毫秒)
=======================================================*/
void delay(void) //延时1MS {
unsigned char a,b; for(b=102;b》0;b--) for(a=3;a》0;a--); }
/*======================================================== 播放音乐 和 报警声音
=======================================================*/ unsigned int g_ucSoundLongCNT; //
/************************************************* * 函数名称:void T2Init(void) * 创建日期:2005.6.17
* 功能描述:定时器T2初始化 * 入口参数:uT2Reg:定时器初值 * 返回值: 无 * 修改日志:
*************************************************/ void T2Init(unsigned int uT2Reg) {
CP_RL2=0; //16位自动重载
T2MOD=0x00; //计数增加,外部捕获禁止 RCLK=0; TCLK=0;
TL2=RCAP2L=uT2Reg&0x00ff; TH2=RCAP2H=uT2Reg》》8;
TR2=1; // 启动定时器 ET2=1; //t2开中断 EA=1; }
/************************************************* * 函数名称:void MusicPlay(uchar ucSL[],uint uST[]) * 创建日期:2005.7.12
* 功能描述:播放某首音乐的函数
* 入口参数:ucSL[]:音节长度的数组;uST[]:音乐频率的数组 * 返回值: 无 * 修改日志:
*************************************************/
void MusicPlay(unsigned char ucSL[],unsigned int uST[])
{
unsigned char i=0; //float fTmp=“0”;
while((ucSL[i]!=0)||(uST[i]!=0)) {
//fTmp=(float)11059/(float)12000;
T2Init(0xffff-uST[i]*((float)11059/(float)12000)*4); //11。0592M的晶体 //我添加了*5
g_ucSoundLongCNT=((3*ucSL[i]*75000L)/8)/uST[i]; //*1000我改为 75000
while(g_ucSoundLongCNT!=0); //等待计数器为0 TR2=0; //暂时关闭定时器 i++; }
BUZZER = 1; }
/************************************************* * 函数名称:void T2Init(void) * 创建日期:2005.7.11
* 功能描述:用于音乐的音调半周期定时 * 入口参数:无 * 返回值: 无 * 修改日志:
*************************************************/ void T2ISR(void) interrupt 5 using 1 {
TF2=0; //手动清除溢出标志 if(g_ucSoundLongCNT!=0) {
g_ucSoundLongCNT--; }
BUZZER=~BUZZER; }
全部0条评论
快来发表一下你的评论吧 !