×
单片机 > 单片机程序设计 > 详情

51单片机八路抢答器课程设计

发布时间:2021-08-09 发布时间:
|

本人的这个设计改进后解决了前一个版本中1号抢答优先的问题,并增加了锦囊的设置,当参赛选手在回答问题时要求使用锦囊,则主持人按下抢答开始键,计时重新开始。


;八路抢答器电路请看下图是用ps仿真的,已经测试成功


单片机八路抢答器程序


OK EQU 20H;抢答开始标志位


RING EQU 22H;响铃标志位


ORG 0000H


AJMP MAIN


ORG 0003H


AJMP INT0SUB


ORG 000BH


AJMP T0INT


ORG 0013H


AJMP INT1SUB


ORG 001BH


AJMP T1INT


ORG 0040H


MAIN: MOV R1,#30;初设抢答时间为30s


MOV R2,#60;初设答题时间为60s


MOV TMOD,#11H;设置未定时器/模式1


MOV TH0,#0F0H


MOV TL0,#0FFH;越高发声频率越高,越尖


MOV TH1,#3CH


MOV TL1,#0B0H;50ms为一次溢出中断


SETB EA


SETB ET0


SETB ET1


SETB EX0


SETB EX1;允许四个中断,T0/T1/INT0/INT1


CLR OK


CLR RING


SETB TR1


SETB TR0;一开始就运行定时器,以开始显示FFF.如果想重新计数,重置TH1/TL1就可以了


;=====查询程序=====


START: MOV R5,#0BH


MOV R4,#0BH


MOV R3,#0BH


ACALL DISPLAY;未开始抢答时候显示FFF


JB P3.0,NEXT;ddddddd


ACALL DELAY


JB P3.0,NEXT;去抖动,如果"开始键"按下就向下执行,否者跳到非法抢答查询


ACALL BARK;按键发声


MOV A,R1


MOV R6,A;送R1->R6,因为R1中保存了抢答时间


SETB OK;抢答标志位,用于COUNT只程序中判断是否查询抢答


MOV R7,#01H ;读抢答键数据信号标志,这里表示只读一次有用信号


MOV R3,#0AH;抢答只显示计时,灭号数


AJMP COUNT;进入倒计时程序,"查询有效抢答的程序"在COUNT里面


NEXT: JNB P1.0,FALSE1


JNB P1.1,FALSE2


JNB P1.2,FALSE3


JNB P1.3,FALSE4


JNB P1.4,FALSE5


JNB P1.5,FALSE6


JNB P1.6,FALSE7


JNB P1.7,FALSE8


AJMP START


;=====非法抢答处理程序=====


FALSE1: MOV R3,#01H


AJMP ERROR


FALSE2: MOV R3,#02H


AJMP ERROR


FALSE3: MOV R3,#03H


AJMP ERROR


FALSE4: MOV R3,#04H


AJMP ERROR


FALSE5: MOV R3,#05H


AJMP ERROR


FALSE6: MOV R3,#06H


AJMP ERROR


FALSE7: MOV R3,#07H


AJMP ERROR


FALSE8: MOV R3,#08H


AJMP ERROR




;=====INT0(抢答时间R1调整程序)=====


INT0SUB:MOV A,R1


MOV B,#0AH


DIV AB


MOV R5,A


MOV R4,B


MOV R3,#0AH


ACALL DISPLAY;先在两个时间LED上显示R1


JNB P3.4,INC0;P3.4为+1s键,如按下跳到INCO


JNB P3.5,DEC0;P3.5为-1s键,如按下跳到DECO


JNB P3.1,BACK0;P3.1为确定键,如按下跳到BACKO


AJMP INT0SUB


INC0: MOV A,R1


CJNE A,#63H,ADD0;如果不是99,R2加1,如果加到99,R1就置0,重新加起。


MOV R1,#00H


ACALL DELAY1


AJMP INT0SUB


ADD0: INC R1


ACALL DELAY1


AJMP INT0SUB


DEC0: MOV A,R1


JZ SETR1;如果R1为0, R1就置99,


DEC R1


ACALL DELAY1


AJMP INT0SUB


SETR1: MOV R1,#63H


ACALL DELAY1


AJMP INT0SUB


BACK0: RETI


;=====INT1(回答时间R2调整程序)=====


INT1SUB:MOV A,R2


MOV B,#0AH


DIV AB


MOV R5,A


MOV R4,B


MOV R3,#0AH


ACALL DISPLAY


JNB P3.4,INC1


JNB P3.5,DEC1


JNB P3.1,BACK1


AJMP INT1SUB


INC1: MOV A,R2


CJNE A,#63H,ADD1


MOV R2,#00H


ACALL DELAY1


AJMP INT1SUB


ADD1: INC R2


ACALL DELAY1


AJMP INT1SUB


DEC1: MOV A,R2


JZ SETR2


DEC R2


ACALL DELAY1


AJMP INT1SUB


SETR2: MOV R2,#63H


ACALL DELAY1


AJMP INT1SUB


BACK1: RETI


;=====倒计时程序(抢答倒计时和回答倒计时都跳到改程序)=====


REPEAT:MOV A,R2 ;使用锦囊时重新计时


MOV R6,A


CLR RING


COUNT: MOV R0,#00H;重置定时器中断次数


MOV TH1,#3CH


MOV TL1,#0B0H;重置定时器


RECOUNT:MOV A,R6;R6保存了倒计时的时间,之前先将抢答时间或回答时间给R6


MOV B,#0AH


DIV AB;除十分出个位/十位


MOV 30H,A;十位存于(30H)


MOV 31H,B;个位存于(31H)


MOV R5,30H;取十位


MOV R4,31H;取个位


MOV A,R6


SUBB A,#07H


JNC LARGER;大于5s跳到LARGER,小于等于5s会提醒


MOV A,R0


CJNE A,#0AH,FULL;1s中0.5s向下运行


CLR RING


AJMP CHECK


FULL: CJNE A,#14H,CHECK;下面是1s的情况,响并显示号数并清R0,重新计


SETB RING


MOV A,R6


JZ QUIT;计时完毕


MOV R0,#00H


DEC R6;一秒标志减1


AJMP CHECK


LARGER: MOV A,R0


CJNE A,#14H,CHECK;如果1s向下运行,否者跳到查"停/显示"


DEC R6;计时一秒R6自动减1


MOV R0,#00H


CHECK: JNB P3.1,QUIT;如按下停止键退出


JNB OK,CHECKK ;只在回答倒计时才有效


AJMP NEXTT


CHECKK:JNB P3.0,REPEAT ;判断是否使用锦囊


NEXTT: ACALL DISPLAY


JB OK,ACCOUT;如果是抢答倒计时,如是则查询抢答,否者跳过查询继续倒数(这里起到锁抢答作用)


AJMP RECOUNT


ACCOUT:


MOV A,36H


JNB ACC.0,TRUE1


JNB ACC.1,TRUE2


JNB ACC.2,TRUE3


JNB ACC.3,TRUE4


JNB ACC.4,TRUE5


JNB ACC.5,TRUE6


JNB ACC.6,TZ1


JNB ACC.7,TZ2


AJMP RECOUNT


TZ1:JMP TRUE7


TZ2:JMP TRUE8


QUIT: CLR OK;如果按下了"停止键"执行的程序


CLR RING


AJMP START


;=====正常抢答处理程序=====


TRUE1: ACALL BARK


MOV A,R2


MOV R6,A;抢答时间R2送R6


MOV R3,#01H


CLR OK;因为答题的计时不再查询抢答,所以就锁了抢答


AJMP COUNT


TRUE2:ACALL BARK


MOV A,R2


MOV R6,A


MOV R3,#02H


CLR OK


AJMP COUNT


TRUE3:ACALL BARK


MOV A,R2


MOV R6,A


MOV R3,#03H


CLR OK


AJMP COUNT


TRUE4:ACALL BARK


MOV A,R2


MOV R6,A


MOV R3,#04H


CLR OK


AJMP COUNT


TRUE5:ACALL BARK


MOV A,R2


MOV R6,A


MOV R3,#05H


CLR OK


AJMP COUNT


TRUE6: ACALL BARK


MOV A,R2


MOV R6,A


MOV R3,#06H


CLR OK


AJMP COUNT


TRUE7:ACALL BARK


MOV A,R2


MOV R6,A


MOV R3,#07H


CLR OK


AJMP COUNT


TRUE8:ACALL BARK


MOV A,R2


MOV R6,A


MOV R3,#08H


CLR OK


AJMP COUNT


;=====犯规抢答程序=====


ERROR: MOV R0,#00H


MOV TH1,#3CH


MOV TL1,#0B0H


MOV 34H,R3;犯规号数暂存与(34H)


HERE: MOV A,R0


CJNE A,#06H,FLASH;0.3s向下运行->灭并停响


CLR RING


MOV R3,#0AH


MOV R4,#0AH


MOV R5,#0AH;三灯全灭


AJMP CHECK1


FLASH: CJNE A,#0CH,CHECK1;下面是0.8s的情况,响并显示号数并清R0,重新计


SETB RING


MOV R0,#00H


MOV R3,34H;取回号数


MOV R5,#0BH


MOV R4,#0BH;显示FF和号数


AJMP CHECK1


CHECK1: JNB P3.1,QUIT1


ACALL DISPLAY


AJMP HERE


QUIT1: CLR RING


CLR OK


AJMP START


;=====显示程序=====


DISPLAY:MOV DPTR,#DAT1;查表显示程序,利用P0口做段选码口输出/P2低三位做位选码输出,


MOV A,R3


MOVC A,@A+DPTR


MOV P2,#0feH


MOV P0,A


ACALL DELAY2


MOV DPTR,#DAT2


MOV A,R5


MOVC A,@A+DPTR


MOV P2,#0fdH


MOV P0,A


ACALL DELAY2


MOV A,R4


MOVC A,@A+DPTR


MOV P2,#0fbH


MOV P0,A


ACALL DELAY2


RET


DAT1:DB 00h,06h,5bh,4fh,66h,6dh,7dh,07h,7fh,6fh,00H,71H


;"灭","1","2","3","4","5","6","7","8","9","灭","F"


DAT2:DB 3fh,06h,5bh,4fh,66h,6dh,7dh,07h,7fh,6fh,00H,71H


;第一个为零,其他与上相同,因为十位如果为零显示熄灭


;====加减时间延时(起到不会按下就加N个数)======


DELAY1: MOV 35H,#08H


LOOP0: ACALL DISPLAY


DJNZ 35H,LOOP0


RET


;=====延时4236个机器周期(去抖动用到)=====


DELAY: MOV 32H,#12H


LOOP: MOV 33H,#0AFH


LOOP1: DJNZ 33H,LOOP1


DJNZ 32H,LOOP


RET


;=====延时4236个机器周期(显示用到)=====


DELAY2: MOV 32H,#43H


LOOP3: MOV 33H,#1EH


MOV A,R7 ;每隔60~70个机器周期读一次P1口,全为1时为无效数据,继续读,有一个不为1时,转到正常抢答处理


JNZ AAAA1 ;没读到有效数据时继续转到AAAA1


LOOP2: DJNZ 33H,LOOP2


DJNZ 32H,LOOP3


RET


;=====读抢答按键数据口程序=====


;由于在读抢答数据口的时候,单片机首先进入倒计时程序,再调用显示程序,最后才检测按键口


;然而在检测按键口时动态扫描要调用三次(4ms)延时程序.这样就会导致读数据口出现滞后,造成1号优先最高.8号最低.


;故采用在延时子程序中加了读数据口程序.保证了灵敏度和可靠性


AAAA1: MOV A,P1


CJNE A,#0FFH,AA1 ;当不全为1时的数据为有效数据


AA0: MOV 36H,A ;将有效数据送到36H暂存


AJMP LOOP2


AA1: DEC R7


AJMP AA0




;=====发声程序=====


BARK: SETB RING


ACALL DELAY1


ACALL DELAY1


CLR RING;按键发声


RET


;=====TO溢出中断(响铃程序)=====


T0INT: MOV TH0,#0ECH


MOV TL0,#0FFH


JNB RING,OUT;


CPL P3.6;RING标志位为1时候P3.6口不短取反使喇叭发出一定频率的声音


OUT: RETI


;=====T1溢出中断(计时程序)=====


T1INT: MOV TH1,#3CH


MOV TL1,#0B0H


INC R0


RETI


END



『本文转载自网络,版权归原作者所有,如有侵权请联系删除』

热门文章 更多
STM32单片机的复用端口初始化的步骤及方法